From 219ba511c824bc44149d55c570f723dcd0f0217d Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 21 Nov 2017 14:44:25 +0100 Subject: Document the size of bool --- src/libcore/mem.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libcore') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index d57fbdf55f8..486093f261c 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -189,6 +189,7 @@ pub fn forget(t: T) { /// Type | size_of::\() /// ---- | --------------- /// () | 0 +/// bool | 1 /// u8 | 1 /// u16 | 2 /// u32 | 4 -- cgit 1.4.1-3-g733a5 From cba5f6bd01bc3ba692c355ca82212db069cd800c Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Tue, 5 Dec 2017 18:07:28 +0100 Subject: Rewrite Borrow's trait documentation. --- src/libcore/borrow.rs | 147 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 132 insertions(+), 15 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 61558034e63..76f6215fae6 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -12,26 +12,143 @@ #![stable(feature = "rust1", since = "1.0.0")] -/// A trait for borrowing data. +// impl Borrow for String +// impl Borrow for Arc +// impl HashSet { fn get(&self, q: &Q) where K: Borrow } + +/// A trait identifying how borrowed data behaves. +/// +/// If a type implements this trait, it signals that a reference to it behaves +/// exactly like a reference to `Borrowed`. As a consequence, if a trait is +/// implemented both by `Self` and `Borrowed`, all trait methods that +/// take a `&self` argument must produce the same result in both +/// implementations. +/// +/// As a consequence, this trait should only be implemented for types managing +/// a value of another type without modifying its behavior. Examples are +/// smart pointers such as [`Box`] or [`Rc`] as well the owned version of +/// slices such as [`Vec`]. +/// +/// A relaxed version that allows providing a reference to some other type +/// without any further promises is available through [`AsRef`]. +/// +/// When writing generic code, a use of `Borrow` should always be justified +/// by additional trait bounds, making it clear that the two types need to +/// behave identically in a certain context. If the code should merely be +/// able to operate on any type that can produce a reference to a given type, +/// you should use [`AsRef`] instead. +/// +/// The companion trait [`BorrowMut`] provides the same guarantees for +/// mutable references. +/// +/// [`Box`]: ../boxed/struct.Box.html +/// [`Rc`]: ../rc/struct.Rc.html +/// [`Vec`]: ../vec/struct.Vec.html +/// [`AsRef`]: ../convert/trait.AsRef.html +/// [`BorrowMut`]: trait.BorrowMut.html +/// +/// # Examples +/// +/// As a data collection, [`HashMap`] owns both keys and values. If the key’s +/// actual data is wrapped in a managing type of some kind, it should, +/// however, still be possible to search for a value using a reference to the +/// key’s data. For instance, if the key is a string, then it is likely +/// stored with the hash map as a [`String`], while it should be possible +/// to search using a [`&str`][`str`]. Thus, `insert` needs to operate on a +/// string while `get` needs to be able to use a `&str`. +/// +/// Slightly simplified, the relevant parts of `HashMap` look like this: +/// +/// ``` +/// use std::borrow::Borrow; +/// use std::hash::Hash; +/// +/// pub struct HashMap { +/// # marker: ::std::marker::PhantomData<(K, V)>, +/// // fields omitted +/// } +/// +/// impl HashMap { +/// pub fn insert(&self, key: K, value: V) -> Option +/// where K: Hash + Eq +/// { +/// # unimplemented!() +/// // ... +/// } +/// +/// pub fn get(&self, k: &Q) -> Option<&V> +/// where K: Borrow, +/// Q: Hash + Eq + ?Sized +/// { +/// # unimplemented!() +/// // ... +/// } +/// } +/// ``` +/// +/// The entire hash map is generic over the stored type for the key, `K`. +/// When inserting a value, the map is given such a `K` and needs to find +/// the correct hash bucket and check if the key is already present based +/// on that `K` value. It therefore requires `K: Hash + Eq`. +/// +/// In order to search for a value based on the key’s data, the `get` method +/// is generic over some type `Q`. Technically, it needs to convert that `Q` +/// into a `K` in order to use `K`’s [`Hash`] implementation to be able to +/// arrive at the same hash value as during insertion in order to look into +/// the right hash bucket. Since `K` is some kind of owned value, this likely +/// would involve cloning and isn’t really practical. +/// +/// Instead, `get` relies on `Q`’s implementation of `Hash` and uses `Borrow` +/// to indicate that `K`’s implementation of `Hash` must produce the same +/// result as `Q`’s by demanding that `K: Borrow`. +/// +/// As a consequence, the hash map breaks if a `K` wrapping a `Q` value +/// produces a different hash than `Q`. For instance, image you have a +/// type that wraps a string but compares ASCII letters case-insensitive: +/// +/// ``` +/// use std::ascii::AsciiExt; +/// +/// pub struct CIString(String); +/// +/// impl PartialEq for CIString { +/// fn eq(&self, other: &Self) -> bool { +/// self.0.eq_ignore_ascii_case(&other.0) +/// } +/// } /// -/// In general, there may be several ways to "borrow" a piece of data. The -/// typical ways of borrowing a type `T` are `&T` (a shared borrow) and `&mut T` -/// (a mutable borrow). But types like `Vec` provide additional kinds of -/// borrows: the borrowed slices `&[T]` and `&mut [T]`. +/// impl Eq for CIString { } +/// ``` /// -/// When writing generic code, it is often desirable to abstract over all ways -/// of borrowing data from a given type. That is the role of the `Borrow` -/// trait: if `T: Borrow`, then `&U` can be borrowed from `&T`. A given -/// type can be borrowed as multiple different types. In particular, `Vec: -/// Borrow>` and `Vec: Borrow<[T]>`. +/// Because two equal values need to produce the same hash value, the +/// implementation of `Hash` need to reflect that, too: /// -/// If you are implementing `Borrow` and both `Self` and `Borrowed` implement -/// `Hash`, `Eq`, and/or `Ord`, they must produce the same result. +/// ``` +/// # use std::ascii::AsciiExt; +/// # use std::hash::{Hash, Hasher}; +/// # pub struct CIString(String); +/// impl Hash for CIString { +/// fn hash(&self, state: &mut H) { +/// for c in self.0.as_bytes() { +/// c.to_ascii_lowercase().hash(state) +/// } +/// } +/// } +/// ``` /// -/// `Borrow` is very similar to, but different than, `AsRef`. See -/// [the book][book] for more. +/// Can `CIString` implement `Borrow`? It certainly can provide a +/// reference to a string slice via its contained owned string. But because +/// its `Hash` implementation differs, it cannot fulfill the guarantee for +/// `Borrow` that all common trait implementations must behave the same way +/// and must not, in fact, implement `Borrow`. If it wants to allow +/// others access to the underlying `str`, it can do that via `AsRef` +/// which doesn’t carry any such restrictions. /// -/// [book]: ../../book/first-edition/borrow-and-asref.html +/// [`Hash`]: ../hash/trait.Hash.html +/// [`HashMap`]: ../collections/struct.HashMap.html +/// [`String`]: ../string/struct.String.html +/// [`str`]: ../primitive.str.html +/// #[stable(feature = "rust1", since = "1.0.0")] pub trait Borrow { /// Immutably borrows from an owned value. -- cgit 1.4.1-3-g733a5 From c4ea700041f78a016dca557c2da86006a7bbedf8 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Tue, 5 Dec 2017 18:28:29 +0100 Subject: Remove trailing white space. --- src/libcore/borrow.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 76f6215fae6..4d4a07f59d1 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -100,12 +100,12 @@ /// /// Instead, `get` relies on `Q`’s implementation of `Hash` and uses `Borrow` /// to indicate that `K`’s implementation of `Hash` must produce the same -/// result as `Q`’s by demanding that `K: Borrow`. +/// result as `Q`’s by demanding that `K: Borrow`. /// /// As a consequence, the hash map breaks if a `K` wrapping a `Q` value /// produces a different hash than `Q`. For instance, image you have a /// type that wraps a string but compares ASCII letters case-insensitive: -/// +/// /// ``` /// use std::ascii::AsciiExt; /// @@ -148,7 +148,7 @@ /// [`HashMap`]: ../collections/struct.HashMap.html /// [`String`]: ../string/struct.String.html /// [`str`]: ../primitive.str.html -/// +/// #[stable(feature = "rust1", since = "1.0.0")] pub trait Borrow { /// Immutably borrows from an owned value. -- cgit 1.4.1-3-g733a5 From 85e8a9ba00e8ac090ceaac619110264e8e8bf6c6 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 7 Dec 2017 16:50:37 +0100 Subject: Include feedback and try to make examples build on all channels. --- src/libcore/borrow.rs | 60 +++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 4d4a07f59d1..77006193a58 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -12,10 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -// impl Borrow for String -// impl Borrow for Arc -// impl HashSet { fn get(&self, q: &Q) where K: Borrow } - /// A trait identifying how borrowed data behaves. /// /// If a type implements this trait, it signals that a reference to it behaves @@ -26,10 +22,10 @@ /// /// As a consequence, this trait should only be implemented for types managing /// a value of another type without modifying its behavior. Examples are -/// smart pointers such as [`Box`] or [`Rc`] as well the owned version of -/// slices such as [`Vec`]. +/// smart pointers such as [`Box`] or [`Rc`] as well the owned version +/// of slices such as [`Vec`]. /// -/// A relaxed version that allows providing a reference to some other type +/// A relaxed version that allows converting a reference to some other type /// without any further promises is available through [`AsRef`]. /// /// When writing generic code, a use of `Borrow` should always be justified @@ -41,23 +37,24 @@ /// The companion trait [`BorrowMut`] provides the same guarantees for /// mutable references. /// -/// [`Box`]: ../boxed/struct.Box.html -/// [`Rc`]: ../rc/struct.Rc.html -/// [`Vec`]: ../vec/struct.Vec.html +/// [`Box`]: ../boxed/struct.Box.html +/// [`Rc`]: ../rc/struct.Rc.html +/// [`Vec`]: ../vec/struct.Vec.html /// [`AsRef`]: ../convert/trait.AsRef.html /// [`BorrowMut`]: trait.BorrowMut.html /// /// # Examples /// -/// As a data collection, [`HashMap`] owns both keys and values. If the key’s -/// actual data is wrapped in a managing type of some kind, it should, -/// however, still be possible to search for a value using a reference to the -/// key’s data. For instance, if the key is a string, then it is likely -/// stored with the hash map as a [`String`], while it should be possible -/// to search using a [`&str`][`str`]. Thus, `insert` needs to operate on a -/// string while `get` needs to be able to use a `&str`. +/// As a data collection, [`HashMap`] owns both keys and values. If +/// the key’s actual data is wrapped in a managing type of some kind, it +/// should, however, still be possible to search for a value using a +/// reference to the key’s data. For instance, if the key is a string, then +/// it is likely stored with the hash map as a [`String`], while it should +/// be possible to search using a [`&str`][`str`]. Thus, `insert` needs to +/// operate on a `String` while `get` needs to be able to use a `&str`. /// -/// Slightly simplified, the relevant parts of `HashMap` look like this: +/// Slightly simplified, the relevant parts of `HashMap` look like +/// this: /// /// ``` /// use std::borrow::Borrow; @@ -70,15 +67,16 @@ /// /// impl HashMap { /// pub fn insert(&self, key: K, value: V) -> Option -/// where K: Hash + Eq +/// where K: Hash + Eq /// { /// # unimplemented!() /// // ... /// } /// /// pub fn get(&self, k: &Q) -> Option<&V> -/// where K: Borrow, -/// Q: Hash + Eq + ?Sized +/// where +/// K: Borrow, +/// Q: Hash + Eq + ?Sized /// { /// # unimplemented!() /// // ... @@ -86,10 +84,11 @@ /// } /// ``` /// -/// The entire hash map is generic over the stored type for the key, `K`. -/// When inserting a value, the map is given such a `K` and needs to find -/// the correct hash bucket and check if the key is already present based -/// on that `K` value. It therefore requires `K: Hash + Eq`. +/// The entire hash map is generic over a key type `K`. Because these keys +/// are stored by with the hash map, this type as to own the key’s data. +/// When inserting a key-value pair, the map is given such a `K` and needs +/// to find the correct hash bucket and check if the key is already present +/// based on that `K`. It therefore requires `K: Hash + Eq`. /// /// In order to search for a value based on the key’s data, the `get` method /// is generic over some type `Q`. Technically, it needs to convert that `Q` @@ -103,10 +102,11 @@ /// result as `Q`’s by demanding that `K: Borrow`. /// /// As a consequence, the hash map breaks if a `K` wrapping a `Q` value -/// produces a different hash than `Q`. For instance, image you have a -/// type that wraps a string but compares ASCII letters case-insensitive: +/// produces a different hash than `Q`. For instance, imagine you have a +/// type that wraps a string but compares ASCII letters ignoring their case: /// /// ``` +/// # #[allow(unused_imports)] /// use std::ascii::AsciiExt; /// /// pub struct CIString(String); @@ -121,10 +121,10 @@ /// ``` /// /// Because two equal values need to produce the same hash value, the -/// implementation of `Hash` need to reflect that, too: +/// implementation of `Hash` needs to reflect that, too: /// /// ``` -/// # use std::ascii::AsciiExt; +/// # #[allow(unused_imports)] use std::ascii::AsciiExt; /// # use std::hash::{Hash, Hasher}; /// # pub struct CIString(String); /// impl Hash for CIString { @@ -145,7 +145,7 @@ /// which doesn’t carry any such restrictions. /// /// [`Hash`]: ../hash/trait.Hash.html -/// [`HashMap`]: ../collections/struct.HashMap.html +/// [`HashMap`]: ../collections/struct.HashMap.html /// [`String`]: ../string/struct.String.html /// [`str`]: ../primitive.str.html /// -- cgit 1.4.1-3-g733a5 From fc6c6383f6999d87c92be3dfd5f09c357be41135 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Wed, 13 Dec 2017 08:48:29 +0100 Subject: Fix documentation links. --- src/libcore/borrow.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 77006193a58..33e4c8780d6 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -37,10 +37,10 @@ /// The companion trait [`BorrowMut`] provides the same guarantees for /// mutable references. /// -/// [`Box`]: ../boxed/struct.Box.html -/// [`Rc`]: ../rc/struct.Rc.html -/// [`Vec`]: ../vec/struct.Vec.html -/// [`AsRef`]: ../convert/trait.AsRef.html +/// [`Box`]: ../../std/boxed/struct.Box.html +/// [`Rc`]: ../../std/rc/struct.Rc.html +/// [`Vec`]: ../../std/vec/struct.Vec.html +/// [`AsRef`]: ../../std/convert/trait.AsRef.html /// [`BorrowMut`]: trait.BorrowMut.html /// /// # Examples @@ -144,10 +144,10 @@ /// others access to the underlying `str`, it can do that via `AsRef` /// which doesn’t carry any such restrictions. /// -/// [`Hash`]: ../hash/trait.Hash.html -/// [`HashMap`]: ../collections/struct.HashMap.html -/// [`String`]: ../string/struct.String.html -/// [`str`]: ../primitive.str.html +/// [`Hash`]: ../../std/hash/trait.Hash.html +/// [`HashMap`]: ../../std/collections/struct.HashMap.html +/// [`String`]: ../../std/string/struct.String.html +/// [`str`]: ../../std/primitive.str.html /// #[stable(feature = "rust1", since = "1.0.0")] pub trait Borrow { -- cgit 1.4.1-3-g733a5 From a2cdeb58f680b87b5bdb6a17cba857ac51307c8f Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Thu, 21 Dec 2017 20:23:47 -0500 Subject: Expose float from_bits and to_bits in libcore. --- src/libcore/num/dec2flt/rawfp.rs | 39 ++++++--------------------------------- src/libcore/num/f32.rs | 24 +++++++++++++++++------- src/libcore/num/f64.rs | 24 +++++++++++++++++------- src/libcore/num/mod.rs | 11 +++++++++++ src/libstd/f32.rs | 5 ++--- src/libstd/f64.rs | 5 ++--- 6 files changed, 55 insertions(+), 53 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index 12960fed045..143a05a1944 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -27,11 +27,10 @@ //! Many functions in this module only handle normal numbers. The dec2flt routines conservatively //! take the universally-correct slow path (Algorithm M) for very small and very large numbers. //! That algorithm needs only next_float() which does handle subnormals and zeros. -use u32; use cmp::Ordering::{Less, Equal, Greater}; +use convert::TryInto; use ops::{Mul, Div, Neg}; use fmt::{Debug, LowerExp}; -use mem::transmute; use num::diy_float::Fp; use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan}; use num::Float; @@ -66,12 +65,6 @@ pub trait RawFloat : Float + Copy + Debug + LowerExp /// Returns the mantissa, exponent and sign as integers. fn integer_decode(self) -> (u64, i16, i8); - /// Get the raw binary representation of the float. - fn transmute(self) -> u64; - - /// Transmute the raw binary representation into a float. - fn from_bits(bits: u64) -> Self; - /// Decode the float. fn unpack(self) -> Unpacked; @@ -159,7 +152,7 @@ impl RawFloat for f32 { /// Returns the mantissa, exponent and sign as integers. fn integer_decode(self) -> (u64, i16, i8) { - let bits: u32 = unsafe { transmute(self) }; + let bits = self.to_bits(); let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 }; let mut exponent: i16 = ((bits >> 23) & 0xff) as i16; let mantissa = if exponent == 0 { @@ -172,16 +165,6 @@ impl RawFloat for f32 { (mantissa as u64, exponent, sign) } - fn transmute(self) -> u64 { - let bits: u32 = unsafe { transmute(self) }; - bits as u64 - } - - fn from_bits(bits: u64) -> f32 { - assert!(bits < u32::MAX as u64, "f32::from_bits: too many bits"); - unsafe { transmute(bits as u32) } - } - fn unpack(self) -> Unpacked { let (sig, exp, _sig) = self.integer_decode(); Unpacked::new(sig, exp) @@ -210,7 +193,7 @@ impl RawFloat for f64 { /// Returns the mantissa, exponent and sign as integers. fn integer_decode(self) -> (u64, i16, i8) { - let bits: u64 = unsafe { transmute(self) }; + let bits = self.to_bits(); let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; let mantissa = if exponent == 0 { @@ -223,15 +206,6 @@ impl RawFloat for f64 { (mantissa, exponent, sign) } - fn transmute(self) -> u64 { - let bits: u64 = unsafe { transmute(self) }; - bits - } - - fn from_bits(bits: u64) -> f64 { - unsafe { transmute(bits) } - } - fn unpack(self) -> Unpacked { let (sig, exp, _sig) = self.integer_decode(); Unpacked::new(sig, exp) @@ -296,14 +270,14 @@ pub fn encode_normal(x: Unpacked) -> T { "encode_normal: exponent out of range"); // Leave sign bit at 0 ("+"), our numbers are all positive let bits = (k_enc as u64) << T::EXPLICIT_SIG_BITS | sig_enc; - T::from_bits(bits) + T::from_bits(bits.try_into().unwrap_or_else(|_| unreachable!())) } /// Construct a subnormal. A mantissa of 0 is allowed and constructs zero. pub fn encode_subnormal(significand: u64) -> T { assert!(significand < T::MIN_SIG, "encode_subnormal: not actually subnormal"); // Encoded exponent is 0, the sign bit is 0, so we just have to reinterpret the bits. - T::from_bits(significand) + T::from_bits(significand.try_into().unwrap_or_else(|_| unreachable!())) } /// Approximate a bignum with an Fp. Rounds within 0.5 ULP with half-to-even. @@ -363,8 +337,7 @@ pub fn next_float(x: T) -> T { // too is exactly what we want! // Finally, f64::MAX + 1 = 7eff...f + 1 = 7ff0...0 = f64::INFINITY. Zero | Subnormal | Normal => { - let bits: u64 = x.transmute(); - T::from_bits(bits + 1) + T::from_bits(x.to_bits() + T::Bits::from(1u8)) } } } diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 43d38926c97..dc37bce8eb0 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -140,6 +140,8 @@ pub mod consts { reason = "stable interface is via `impl f{32,64}` in later crates", issue = "32110")] impl Float for f32 { + type Bits = u32; + /// Returns `true` if the number is NaN. #[inline] fn is_nan(self) -> bool { @@ -171,7 +173,7 @@ impl Float for f32 { const EXP_MASK: u32 = 0x7f800000; const MAN_MASK: u32 = 0x007fffff; - let bits: u32 = unsafe { mem::transmute(self) }; + let bits = self.to_bits(); match (bits & MAN_MASK, bits & EXP_MASK) { (0, 0) => Fp::Zero, (_, 0) => Fp::Subnormal, @@ -215,12 +217,7 @@ impl Float for f32 { fn is_sign_negative(self) -> bool { // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus // applies to zeros and NaNs as well. - #[repr(C)] - union F32Bytes { - f: f32, - b: u32 - } - unsafe { F32Bytes { f: self }.b & 0x8000_0000 != 0 } + self.to_bits() & 0x8000_0000 != 0 } /// Returns the reciprocal (multiplicative inverse) of the number. @@ -274,4 +271,17 @@ impl Float for f32 { // multiplying by 1.0. Should switch to the `canonicalize` when it works. (if self < other || other.is_nan() { self } else { other }) * 1.0 } + + /// Raw transmutation to `u32`. + #[inline] + fn to_bits(self) -> u32 { + unsafe { mem::transmute(self) } + } + + /// Raw transmutation from `u32`. + #[inline] + fn from_bits(v: u32) -> Self { + // It turns out the safety issues with sNaN were overblown! Hooray! + unsafe { mem::transmute(v) } + } } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 4ff80a2f05d..5c217167f98 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -140,6 +140,8 @@ pub mod consts { reason = "stable interface is via `impl f{32,64}` in later crates", issue = "32110")] impl Float for f64 { + type Bits = u64; + /// Returns `true` if the number is NaN. #[inline] fn is_nan(self) -> bool { @@ -171,7 +173,7 @@ impl Float for f64 { const EXP_MASK: u64 = 0x7ff0000000000000; const MAN_MASK: u64 = 0x000fffffffffffff; - let bits: u64 = unsafe { mem::transmute(self) }; + let bits = self.to_bits(); match (bits & MAN_MASK, bits & EXP_MASK) { (0, 0) => Fp::Zero, (_, 0) => Fp::Subnormal, @@ -213,12 +215,7 @@ impl Float for f64 { /// negative sign bit and negative infinity. #[inline] fn is_sign_negative(self) -> bool { - #[repr(C)] - union F64Bytes { - f: f64, - b: u64 - } - unsafe { F64Bytes { f: self }.b & 0x8000_0000_0000_0000 != 0 } + self.to_bits() & 0x8000_0000_0000_0000 != 0 } /// Returns the reciprocal (multiplicative inverse) of the number. @@ -272,4 +269,17 @@ impl Float for f64 { // multiplying by 1.0. Should switch to the `canonicalize` when it works. (if self < other || other.is_nan() { self } else { other }) * 1.0 } + + /// Raw transmutation to `u64`. + #[inline] + fn to_bits(self) -> u64 { + unsafe { mem::transmute(self) } + } + + /// Raw transmutation from `u64`. + #[inline] + fn from_bits(v: u64) -> Self { + // It turns out the safety issues with sNaN were overblown! Hooray! + unsafe { mem::transmute(v) } + } } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 851c0a0dd6f..94efde6d41d 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2872,6 +2872,10 @@ pub enum FpCategory { reason = "stable interface is via `impl f{32,64}` in later crates", issue = "32110")] pub trait Float: Sized { + /// Type used by `to_bits` and `from_bits`. + #[stable(feature = "core_float_bits", since = "1.24.0")] + type Bits: ops::Add + From + TryFrom; + /// Returns `true` if this value is NaN and false otherwise. #[stable(feature = "core", since = "1.6.0")] fn is_nan(self) -> bool; @@ -2933,6 +2937,13 @@ pub trait Float: Sized { /// Returns the minimum of the two numbers. #[stable(feature = "core_float_min_max", since="1.20.0")] fn min(self, other: Self) -> Self; + + /// Raw transmutation to integer. + #[stable(feature = "core_float_bits", since="1.24.0")] + fn to_bits(self) -> Self::Bits; + /// Raw transmutation from integer. + #[stable(feature = "core_float_bits", since="1.24.0")] + fn from_bits(v: Self::Bits) -> Self; } macro_rules! from_str_radix_int_impl { diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index e5b1394f070..18eb2a27b91 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1016,7 +1016,7 @@ impl f32 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn to_bits(self) -> u32 { - unsafe { ::mem::transmute(self) } + num::Float::to_bits(self) } /// Raw transmutation from `u32`. @@ -1060,8 +1060,7 @@ impl f32 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn from_bits(v: u32) -> Self { - // It turns out the safety issues with sNaN were overblown! Hooray! - unsafe { ::mem::transmute(v) } + num::Float::from_bits(v) } } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index f4d804fd508..cabb2c48054 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -971,7 +971,7 @@ impl f64 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn to_bits(self) -> u64 { - unsafe { ::mem::transmute(self) } + num::Float::to_bits(self) } /// Raw transmutation from `u64`. @@ -1015,8 +1015,7 @@ impl f64 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn from_bits(v: u64) -> Self { - // It turns out the safety issues with sNaN were overblown! Hooray! - unsafe { ::mem::transmute(v) } + num::Float::from_bits(v) } } -- cgit 1.4.1-3-g733a5 From 556fb02e43a16de50764af55db20f64ac17e7f23 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Sat, 23 Dec 2017 17:51:06 -0500 Subject: Move Bits constraints to RawFloat::RawBits --- src/libcore/num/dec2flt/rawfp.rs | 23 +++++++++++++++++++---- src/libcore/num/mod.rs | 2 +- 2 files changed, 20 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index 143a05a1944..77180233a23 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -28,8 +28,8 @@ //! take the universally-correct slow path (Algorithm M) for very small and very large numbers. //! That algorithm needs only next_float() which does handle subnormals and zeros. use cmp::Ordering::{Less, Equal, Greater}; -use convert::TryInto; -use ops::{Mul, Div, Neg}; +use convert::{TryFrom, TryInto}; +use ops::{Add, Mul, Div, Neg}; use fmt::{Debug, LowerExp}; use num::diy_float::Fp; use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan}; @@ -55,13 +55,24 @@ impl Unpacked { /// /// Should **never ever** be implemented for other types or be used outside the dec2flt module. /// Inherits from `Float` because there is some overlap, but all the reused methods are trivial. -pub trait RawFloat : Float + Copy + Debug + LowerExp - + Mul + Div + Neg +pub trait RawFloat + : Float + + Copy + + Debug + + LowerExp + + Mul + + Div + + Neg +where + Self: Float::RawBits> { const INFINITY: Self; const NAN: Self; const ZERO: Self; + /// Same as `Float::Bits` with extra traits. + type RawBits: Add + From + TryFrom; + /// Returns the mantissa, exponent and sign as integers. fn integer_decode(self) -> (u64, i16, i8); @@ -142,6 +153,8 @@ macro_rules! other_constants { } impl RawFloat for f32 { + type RawBits = u32; + const SIG_BITS: u8 = 24; const EXP_BITS: u8 = 8; const CEIL_LOG5_OF_MAX_SIG: i16 = 11; @@ -183,6 +196,8 @@ impl RawFloat for f32 { impl RawFloat for f64 { + type RawBits = u64; + const SIG_BITS: u8 = 53; const EXP_BITS: u8 = 11; const CEIL_LOG5_OF_MAX_SIG: i16 = 23; diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 94efde6d41d..ebf8a9597fe 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2874,7 +2874,7 @@ pub enum FpCategory { pub trait Float: Sized { /// Type used by `to_bits` and `from_bits`. #[stable(feature = "core_float_bits", since = "1.24.0")] - type Bits: ops::Add + From + TryFrom; + type Bits; /// Returns `true` if this value is NaN and false otherwise. #[stable(feature = "core", since = "1.6.0")] -- cgit 1.4.1-3-g733a5 From 4829d502cceb779468ab7f69a95223bd31a5cf46 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 5 Jan 2018 01:11:20 +0000 Subject: Make UnsafeCell::into_inner safe This fixes #35067. It will require a Crater run as discussed in that issue. --- src/libcore/cell.rs | 13 ++++--------- src/libcore/sync/atomic.rs | 6 +++--- 2 files changed, 7 insertions(+), 12 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index c5375d1e00c..ec0d1b704dc 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -450,7 +450,7 @@ impl Cell { /// ``` #[stable(feature = "move_cell", since = "1.17.0")] pub fn into_inner(self) -> T { - unsafe { self.value.into_inner() } + self.value.into_inner() } } @@ -569,7 +569,7 @@ impl RefCell { // compiler statically verifies that it is not currently borrowed. // Therefore the following assertion is just a `debug_assert!`. debug_assert!(self.borrow.get() == UNUSED); - unsafe { self.value.into_inner() } + self.value.into_inner() } /// Replaces the wrapped value with a new one, returning the old value, @@ -1220,11 +1220,6 @@ impl UnsafeCell { /// Unwraps the value. /// - /// # Safety - /// - /// This function is unsafe because this thread or another thread may currently be - /// inspecting the inner value. - /// /// # Examples /// /// ``` @@ -1232,11 +1227,11 @@ impl UnsafeCell { /// /// let uc = UnsafeCell::new(5); /// - /// let five = unsafe { uc.into_inner() }; + /// let five = uc.into_inner(); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub unsafe fn into_inner(self) -> T { + pub fn into_inner(self) -> T { self.value } } diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index e334d2014af..af125959f3f 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -285,7 +285,7 @@ impl AtomicBool { #[inline] #[stable(feature = "atomic_access", since = "1.15.0")] pub fn into_inner(self) -> bool { - unsafe { self.v.into_inner() != 0 } + self.v.into_inner() != 0 } /// Loads a value from the bool. @@ -695,7 +695,7 @@ impl AtomicPtr { #[inline] #[stable(feature = "atomic_access", since = "1.15.0")] pub fn into_inner(self) -> *mut T { - unsafe { self.p.into_inner() } + self.p.into_inner() } /// Loads a value from the pointer. @@ -1050,7 +1050,7 @@ macro_rules! atomic_int { #[inline] #[$stable_access] pub fn into_inner(self) -> $int_type { - unsafe { self.v.into_inner() } + self.v.into_inner() } /// Loads a value from the atomic integer. -- cgit 1.4.1-3-g733a5 From 25574e58b68dae94f7d9931b5e648a327a94ecd1 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 9 Jan 2018 11:39:23 -0800 Subject: Make core::ops::Place an unsafe trait --- src/liballoc/binary_heap.rs | 2 +- src/liballoc/boxed.rs | 2 +- src/liballoc/linked_list.rs | 4 ++-- src/liballoc/vec.rs | 2 +- src/liballoc/vec_deque.rs | 4 ++-- src/libcore/ops/place.rs | 5 ++++- src/libstd/collections/hash/map.rs | 2 +- 7 files changed, 12 insertions(+), 9 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/binary_heap.rs b/src/liballoc/binary_heap.rs index 94bbaf92ce9..3041f85cd4c 100644 --- a/src/liballoc/binary_heap.rs +++ b/src/liballoc/binary_heap.rs @@ -1211,7 +1211,7 @@ where T: Clone + Ord { #[unstable(feature = "collection_placement", reason = "placement protocol is subject to change", issue = "30172")] -impl<'a, T> Place for BinaryHeapPlace<'a, T> +unsafe impl<'a, T> Place for BinaryHeapPlace<'a, T> where T: Clone + Ord { fn pointer(&mut self) -> *mut T { self.place.pointer() diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 6f125cdba81..c8ab3f681f8 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -142,7 +142,7 @@ pub struct IntermediateBox { #[unstable(feature = "placement_in", reason = "placement box design is still being worked out.", issue = "27779")] -impl Place for IntermediateBox { +unsafe impl Place for IntermediateBox { fn pointer(&mut self) -> *mut T { self.ptr as *mut T } diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs index 3ac5a85d721..ccb2da46f8d 100644 --- a/src/liballoc/linked_list.rs +++ b/src/liballoc/linked_list.rs @@ -1286,7 +1286,7 @@ impl<'a, T> Placer for FrontPlace<'a, T> { #[unstable(feature = "collection_placement", reason = "placement protocol is subject to change", issue = "30172")] -impl<'a, T> Place for FrontPlace<'a, T> { +unsafe impl<'a, T> Place for FrontPlace<'a, T> { fn pointer(&mut self) -> *mut T { unsafe { &mut (*self.node.pointer()).element } } @@ -1341,7 +1341,7 @@ impl<'a, T> Placer for BackPlace<'a, T> { #[unstable(feature = "collection_placement", reason = "placement protocol is subject to change", issue = "30172")] -impl<'a, T> Place for BackPlace<'a, T> { +unsafe impl<'a, T> Place for BackPlace<'a, T> { fn pointer(&mut self) -> *mut T { unsafe { &mut (*self.node.pointer()).element } } diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 301e44632b8..4a8982bf85c 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2544,7 +2544,7 @@ impl<'a, T> Placer for PlaceBack<'a, T> { #[unstable(feature = "collection_placement", reason = "placement protocol is subject to change", issue = "30172")] -impl<'a, T> Place for PlaceBack<'a, T> { +unsafe impl<'a, T> Place for PlaceBack<'a, T> { fn pointer(&mut self) -> *mut T { unsafe { self.vec.as_mut_ptr().offset(self.vec.len as isize) } } diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index f56aa23a4eb..df49c1df082 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -2564,7 +2564,7 @@ impl<'a, T> Placer for PlaceBack<'a, T> { #[unstable(feature = "collection_placement", reason = "placement protocol is subject to change", issue = "30172")] -impl<'a, T> Place for PlaceBack<'a, T> { +unsafe impl<'a, T> Place for PlaceBack<'a, T> { fn pointer(&mut self) -> *mut T { unsafe { self.vec_deque.ptr().offset(self.vec_deque.head as isize) } } @@ -2610,7 +2610,7 @@ impl<'a, T> Placer for PlaceFront<'a, T> { #[unstable(feature = "collection_placement", reason = "placement protocol is subject to change", issue = "30172")] -impl<'a, T> Place for PlaceFront<'a, T> { +unsafe impl<'a, T> Place for PlaceFront<'a, T> { fn pointer(&mut self) -> *mut T { let tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1); unsafe { self.vec_deque.ptr().offset(tail as isize) } diff --git a/src/libcore/ops/place.rs b/src/libcore/ops/place.rs index 9fb171e7b92..4c8c6e63fc6 100644 --- a/src/libcore/ops/place.rs +++ b/src/libcore/ops/place.rs @@ -27,10 +27,13 @@ /// implementation of Place to clean up any intermediate state /// (e.g. deallocate box storage, pop a stack, etc). #[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait Place { +pub unsafe trait Place { /// Returns the address where the input value will be written. /// Note that the data at this address is generally uninitialized, /// and thus one should use `ptr::write` for initializing it. + /// + /// This function must return a valid (non-zero) pointer to + /// a location at which a value of type `Data` can be written. fn pointer(&mut self) -> *mut Data; } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 7a79a472d58..595b01ff77c 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1932,7 +1932,7 @@ impl<'a, K, V> Placer for Entry<'a, K, V> { #[unstable(feature = "collection_placement", reason = "placement protocol is subject to change", issue = "30172")] -impl<'a, K, V> Place for EntryPlace<'a, K, V> { +unsafe impl<'a, K, V> Place for EntryPlace<'a, K, V> { fn pointer(&mut self) -> *mut V { self.bucket.read_mut().1 } -- cgit 1.4.1-3-g733a5 From c9ae249265c5da207ba0d8a2f8be95e58817e1dc Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Thu, 4 Jan 2018 11:34:03 -0800 Subject: Add transpose conversions for Option and Result These impls are useful when working with combinator methods that expect an option or a result, but you have a Result, E> instead of an Option> or vice versa. --- src/libcore/option.rs | 29 +++++++++++++++ src/libcore/result.rs | 29 +++++++++++++++ src/test/run-pass/result-opt-conversions.rs | 57 +++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 src/test/run-pass/result-opt-conversions.rs (limited to 'src/libcore') diff --git a/src/libcore/option.rs b/src/libcore/option.rs index d8f3ec38cf3..76cea587038 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -884,6 +884,35 @@ impl Option { } } +impl Option> { + /// Transposes an `Option` of a `Result` into a `Result` of an `Option`. + /// + /// `None` will be mapped to `Ok(None)`. + /// `Some(Ok(_))` and `Some(Err(_))` will be mapped to `Ok(Some(_))` and `Err(_)`. + /// + /// # Examples + /// + /// ``` + /// #![feature(transpose_result)] + /// + /// #[derive(Debug, Eq, PartialEq)] + /// struct SomeErr; + /// + /// let x: Result, SomeErr> = Ok(Some(5)); + /// let y: Option> = Some(Ok(5)); + /// assert_eq!(x, y.transpose()); + /// ``` + #[inline] + #[unstable(feature = "transpose_result", issue = "47338")] + pub fn transpose(self) -> Result, E> { + match self { + Some(Ok(x)) => Ok(Some(x)), + Some(Err(e)) => Err(e), + None => Ok(None), + } + } +} + // This is a separate function to reduce the code size of .expect() itself. #[inline(never)] #[cold] diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 2ace3d2aee8..3801db94e15 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -909,6 +909,35 @@ impl Result { } } +impl Result, E> { + /// Transposes a `Result` of an `Option` into an `Option` of a `Result`. + /// + /// `Ok(None)` will be mapped to `None`. + /// `Ok(Some(_))` and `Err(_)` will be mapped to `Some(Ok(_))` and `Some(Err(_))`. + /// + /// # Examples + /// + /// ``` + /// #![feature(transpose_result)] + /// + /// #[derive(Debug, Eq, PartialEq)] + /// struct SomeErr; + /// + /// let x: Result, SomeErr> = Ok(Some(5)); + /// let y: Option> = Some(Ok(5)); + /// assert_eq!(x.transpose(), y); + /// ``` + #[inline] + #[unstable(feature = "transpose_result", issue = "47338")] + pub fn transpose(self) -> Option> { + match self { + Ok(Some(x)) => Some(Ok(x)), + Ok(None) => None, + Err(e) => Some(Err(e)), + } + } +} + // This is a separate function to reduce the code size of the methods #[inline(never)] #[cold] diff --git a/src/test/run-pass/result-opt-conversions.rs b/src/test/run-pass/result-opt-conversions.rs new file mode 100644 index 00000000000..0f6da002dda --- /dev/null +++ b/src/test/run-pass/result-opt-conversions.rs @@ -0,0 +1,57 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(transpose_result)] + +#[derive(Copy, Clone, Debug, PartialEq)] +struct BadNumErr; + +fn try_num(x: i32) -> Result { + if x <= 5 { + Ok(x + 1) + } else { + Err(BadNumErr) + } +} + +type ResOpt = Result, BadNumErr>; +type OptRes = Option>; + +fn main() { + let mut x: ResOpt = Ok(Some(5)); + let mut y: OptRes = Some(Ok(5)); + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + x = Ok(None); + y = None; + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + x = Err(BadNumErr); + y = Some(Err(BadNumErr)); + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + let res: Result, BadNumErr> = + (0..10) + .map(|x| { + let y = try_num(x)?; + Ok(if y % 2 == 0 { + Some(y - 1) + } else { + None + }) + }) + .filter_map(Result::transpose) + .collect(); + + assert_eq!(res, Err(BadNumErr)) +} -- cgit 1.4.1-3-g733a5 From 96157ef8422298e66bcbf7dc1b2b28dd6d90b745 Mon Sep 17 00:00:00 2001 From: Dan Aloni Date: Fri, 12 Jan 2018 13:18:33 +0200 Subject: Derive std::cmp::Reverse as Copy or Clone If the type parameter is Copy or Clone, then `Reverse` should be too. --- src/libcore/cmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 266cae3c122..e6759d1bad9 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -343,7 +343,7 @@ impl Ordering { /// v.sort_by_key(|&num| (num > 3, Reverse(num))); /// assert_eq!(v, vec![3, 2, 1, 6, 5, 4]); /// ``` -#[derive(PartialEq, Eq, Debug)] +#[derive(PartialEq, Eq, Debug, Copy, Clone)] #[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub struct Reverse(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T); -- cgit 1.4.1-3-g733a5 From f25f4687093c1c7e69a06fa7fa6cc3cc6f9aa9d1 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 16 Jan 2018 08:51:24 -0800 Subject: Adjust wording of Placer trait safety requirements --- src/libcore/ops/place.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/place.rs b/src/libcore/ops/place.rs index 4c8c6e63fc6..b3dcf4e7ee9 100644 --- a/src/libcore/ops/place.rs +++ b/src/libcore/ops/place.rs @@ -32,8 +32,8 @@ pub unsafe trait Place { /// Note that the data at this address is generally uninitialized, /// and thus one should use `ptr::write` for initializing it. /// - /// This function must return a valid (non-zero) pointer to - /// a location at which a value of type `Data` can be written. + /// This function must return a pointer through which a value + /// of type `Data` can be written. fn pointer(&mut self) -> *mut Data; } -- cgit 1.4.1-3-g733a5 From fdfb964a821a2f61353146629977eecafc0aa947 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 18 Jan 2018 15:28:10 +0000 Subject: Document the behaviour of infinite iterators on potentially-computable methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It’s not entirely clear from the current documentation what behaviour calling a method such as `min` on an infinite iterator like `RangeFrom` is. One might expect this to terminate, but in fact, for infinite iterators, `min` is always nonterminating (at least in the standard library). This adds a quick note about this behaviour for clarification. --- src/libcore/iter/iterator.rs | 4 ++++ src/libcore/iter/mod.rs | 14 ++++++++++++++ 2 files changed, 18 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 35cd7441c66..209a22d534a 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -24,6 +24,10 @@ fn _assert_is_object_safe(_: &Iterator) {} /// This is the main iterator trait. For more about the concept of iterators /// generally, please see the [module-level documentation]. In particular, you /// may want to know how to [implement `Iterator`][impl]. +/// +/// Note: Methods on infinite iterators that generally require traversing every +/// element to produce a result may not terminate, even on traits for which a +/// result is determinable in finite time. /// /// [module-level documentation]: index.html /// [impl]: index.html#implementing-iterator diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 06c29b47bf9..3a5a72d1b87 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -297,8 +297,22 @@ //! ``` //! //! This will print the numbers `0` through `4`, each on their own line. +//! +//! Bear in mind that methods on infinite iterators, even those for which a +//! result can be computed in finite time, may not terminate. Specifically, +//! methods such as [`min`], which in the general case require traversing +//! every element in the iterator, are likely never to terminate for any +//! infinite iterators. +//! +//! ``` +//! let positives = 1..; +//! let least = positives.min().unwrap(); // Oh no! An infinite loop! +//! // `positives.min` causes an infinite loop, so we won't reach this point! +//! println!("The least positive number is {}.", least); +//! ``` //! //! [`take`]: trait.Iterator.html#method.take +//! [`min`]: trait.Iterator.html#method.min #![stable(feature = "rust1", since = "1.0.0")] -- cgit 1.4.1-3-g733a5 From 91668fbf230b388330da9591ba310c7e35ef9611 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 18 Jan 2018 17:49:32 +0000 Subject: Make example no_run --- src/libcore/iter/iterator.rs | 2 +- src/libcore/iter/mod.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 209a22d534a..da9af214207 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -24,7 +24,7 @@ fn _assert_is_object_safe(_: &Iterator) {} /// This is the main iterator trait. For more about the concept of iterators /// generally, please see the [module-level documentation]. In particular, you /// may want to know how to [implement `Iterator`][impl]. -/// +/// /// Note: Methods on infinite iterators that generally require traversing every /// element to produce a result may not terminate, even on traits for which a /// result is determinable in finite time. diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 3a5a72d1b87..ae10ac385ab 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -297,14 +297,14 @@ //! ``` //! //! This will print the numbers `0` through `4`, each on their own line. -//! +//! //! Bear in mind that methods on infinite iterators, even those for which a //! result can be computed in finite time, may not terminate. Specifically, //! methods such as [`min`], which in the general case require traversing //! every element in the iterator, are likely never to terminate for any //! infinite iterators. -//! -//! ``` +//! +//! ```no_run //! let positives = 1..; //! let least = positives.min().unwrap(); // Oh no! An infinite loop! //! // `positives.min` causes an infinite loop, so we won't reach this point! -- cgit 1.4.1-3-g733a5 From 37771d42d72d80a3025cf1bbf2aa58df79669a4e Mon Sep 17 00:00:00 2001 From: oberien Date: Thu, 18 Jan 2018 20:49:32 +0100 Subject: Specialize StepBy::nth --- src/libcore/iter/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 06c29b47bf9..443b1567e1b 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -694,6 +694,18 @@ impl Iterator for StepBy where I: Iterator { (f(inner_hint.0), inner_hint.1.map(f)) } } + + #[inline] + fn nth(&mut self, mut n: usize) -> Option { + if self.first_take { + if n == 0 { + self.first_take = false; + return self.iter.next() + } + n -= 1; + } + self.iter.nth(n * self.step) + } } // StepBy can only make the iterator shorter, so the len will still fit. -- cgit 1.4.1-3-g733a5 From 5850f0b742430a1b1b5ae7d2491dce6ca10e20d3 Mon Sep 17 00:00:00 2001 From: oberien Date: Fri, 19 Jan 2018 14:55:20 +0100 Subject: Fix off-by-ones --- src/libcore/iter/mod.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 443b1567e1b..33c00989fd2 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -698,13 +698,16 @@ impl Iterator for StepBy where I: Iterator { #[inline] fn nth(&mut self, mut n: usize) -> Option { if self.first_take { + self.first_take = false; + let first = self.iter.next(); if n == 0 { - self.first_take = false; - return self.iter.next() + return first; } n -= 1; } - self.iter.nth(n * self.step) + // n and self.step are indices, thus we need to add 1 before multiplying. + // After that we need to subtract 1 from the result to convert it back to an index. + self.iter.nth((n + 1) * (self.step + 1) - 1) } } -- cgit 1.4.1-3-g733a5 From d33cc12eed3df459db3c9ae2dd89df9cc6e45dd6 Mon Sep 17 00:00:00 2001 From: oberien Date: Fri, 19 Jan 2018 14:55:34 +0100 Subject: Unit Tests --- src/libcore/tests/iter.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 8997cf9c6bf..e8874991659 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -161,6 +161,24 @@ fn test_iterator_step_by() { assert_eq!(it.next(), None); } +#[test] +fn test_iterator_step_by_nth() { + let mut it = (0..16).step_by(5); + assert_eq!(it.nth(0), Some(0)); + assert_eq!(it.nth(0), Some(5)); + assert_eq!(it.nth(0), Some(10)); + assert_eq!(it.nth(0), Some(15)); + assert_eq!(it.nth(0), None); + + let it = (0..18).step_by(5); + assert_eq!(it.clone().nth(0), Some(0)); + assert_eq!(it.clone().nth(1), Some(5)); + assert_eq!(it.clone().nth(2), Some(10)); + assert_eq!(it.clone().nth(3), Some(15)); + assert_eq!(it.clone().nth(4), None); + assert_eq!(it.clone().nth(42), None); +} + #[test] #[should_panic] fn test_iterator_step_by_zero() { -- cgit 1.4.1-3-g733a5 From f08dec114f6008cb7a906ffd55c221fd30d70987 Mon Sep 17 00:00:00 2001 From: oberien Date: Fri, 19 Jan 2018 21:07:01 +0100 Subject: Handle Overflow --- src/libcore/iter/mod.rs | 31 ++++++++++++++++++++++++++++--- src/libcore/tests/iter.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 33c00989fd2..57e7e03a6ce 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -705,9 +705,34 @@ impl Iterator for StepBy where I: Iterator { } n -= 1; } - // n and self.step are indices, thus we need to add 1 before multiplying. - // After that we need to subtract 1 from the result to convert it back to an index. - self.iter.nth((n + 1) * (self.step + 1) - 1) + // n and self.step are indices, we need to add 1 to get the amount of elements + // When calling `.nth`, we need to subtract 1 again to convert back to an index + // step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1` + let mut step = self.step + 1; + // n + 1 could overflow + // thus, if n is usize::MAX, instead of adding one, we call .nth(step) + if n == usize::MAX { + self.iter.nth(step - 1); + } else { + n += 1; + } + + // overflow handling + while n.checked_mul(step).is_none() { + let div_n = usize::MAX / n; + let div_step = usize::MAX / step; + let nth_n = div_n * n; + let nth_step = div_step * step; + let nth = if nth_n > nth_step { + step -= div_n; + nth_n + } else { + n -= div_step; + nth_step + }; + self.iter.nth(nth - 1); + } + self.iter.nth(n * step - 1) } } diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index e8874991659..e52e119ff59 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -179,6 +179,50 @@ fn test_iterator_step_by_nth() { assert_eq!(it.clone().nth(42), None); } +#[test] +fn test_iterator_step_by_nth_overflow() { + #[cfg(target_pointer_width = "8")] + type Bigger = u16; + #[cfg(target_pointer_width = "16")] + type Bigger = u32; + #[cfg(target_pointer_width = "32")] + type Bigger = u64; + #[cfg(target_pointer_width = "64")] + type Bigger = u128; + + #[derive(Clone)] + struct Test(Bigger); + impl<'a> Iterator for &'a mut Test { + type Item = i32; + fn next(&mut self) -> Option { Some(21) } + fn nth(&mut self, n: usize) -> Option { + self.0 += n as Bigger + 1; + Some(42) + } + } + + let mut it = Test(0); + let root = usize::MAX >> (::std::mem::size_of::() * 8 / 2); + let n = root + 20; + (&mut it).step_by(n).nth(n); + assert_eq!(it.0, n as Bigger * n as Bigger); + + // large step + let mut it = Test(0); + (&mut it).step_by(usize::MAX).nth(5); + assert_eq!(it.0, (usize::MAX as Bigger) * 5); + + // n + 1 overflows + let mut it = Test(0); + (&mut it).step_by(2).nth(usize::MAX); + assert_eq!(it.0, (usize::MAX as Bigger) * 2); + + // n + 1 overflows + let mut it = Test(0); + (&mut it).step_by(1).nth(usize::MAX); + assert_eq!(it.0, (usize::MAX as Bigger) * 1); +} + #[test] #[should_panic] fn test_iterator_step_by_zero() { -- cgit 1.4.1-3-g733a5 From 0be51730ee51c009cdd7cd5f77fcd1f2b898f5b7 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 19 Jan 2018 21:16:34 +0000 Subject: Adjust language as per suggestions --- src/libcore/iter/iterator.rs | 8 ++++---- src/libcore/iter/mod.rs | 12 +++++++----- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index da9af214207..23fded0669a 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -25,10 +25,6 @@ fn _assert_is_object_safe(_: &Iterator) {} /// generally, please see the [module-level documentation]. In particular, you /// may want to know how to [implement `Iterator`][impl]. /// -/// Note: Methods on infinite iterators that generally require traversing every -/// element to produce a result may not terminate, even on traits for which a -/// result is determinable in finite time. -/// /// [module-level documentation]: index.html /// [impl]: index.html#implementing-iterator #[stable(feature = "rust1", since = "1.0.0")] @@ -1430,6 +1426,10 @@ pub trait Iterator { /// Folding is useful whenever you have a collection of something, and want /// to produce a single value from it. /// + /// Note: `fold()`, and similar methods that traverse the entire iterator, + /// may not terminate for infinite iterators, even on traits for which a + /// result is determinable in finite time. + /// /// # Examples /// /// Basic usage: diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index ae10ac385ab..d1fdedd1b23 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -299,15 +299,17 @@ //! This will print the numbers `0` through `4`, each on their own line. //! //! Bear in mind that methods on infinite iterators, even those for which a -//! result can be computed in finite time, may not terminate. Specifically, -//! methods such as [`min`], which in the general case require traversing -//! every element in the iterator, are likely never to terminate for any -//! infinite iterators. +//! result can be determined mathematically in finite time, may not terminate. +//! Specifically, methods such as [`min`], which in the general case require +//! traversing every element in the iterator, are likely not to return +//! successfully for any infinite iterators. //! //! ```no_run //! let positives = 1..; //! let least = positives.min().unwrap(); // Oh no! An infinite loop! -//! // `positives.min` causes an infinite loop, so we won't reach this point! +//! // `positives.min` will either overflow and panic (in debug mode), +//! // or cause an infinite loop (in release mode), so we won't reach +//! // this point! //! println!("The least positive number is {}.", least); //! ``` //! -- cgit 1.4.1-3-g733a5 From f72b7f7c86b16fe8b76c4eb02052943dd6ef1ab2 Mon Sep 17 00:00:00 2001 From: oberien Date: Fri, 19 Jan 2018 22:34:22 +0100 Subject: Optimize StepBy::nth overflow handling --- src/libcore/iter/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 57e7e03a6ce..5923e6dc3ee 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -307,6 +307,7 @@ use fmt; use iter_private::TrustedRandomAccess; use ops::Try; use usize; +use intrinsics; #[stable(feature = "rust1", since = "1.0.0")] pub use self::iterator::Iterator; @@ -718,7 +719,11 @@ impl Iterator for StepBy where I: Iterator { } // overflow handling - while n.checked_mul(step).is_none() { + loop { + let mul = n.checked_mul(step); + if unsafe { intrinsics::likely(mul.is_some())} { + return self.iter.nth(mul.unwrap() - 1); + } let div_n = usize::MAX / n; let div_step = usize::MAX / step; let nth_n = div_n * n; @@ -732,7 +737,6 @@ impl Iterator for StepBy where I: Iterator { }; self.iter.nth(nth - 1); } - self.iter.nth(n * step - 1) } } -- cgit 1.4.1-3-g733a5 From 4a0da4cf2c7a2b5903fd1b8bc124f8963ce1b535 Mon Sep 17 00:00:00 2001 From: oberien Date: Sat, 20 Jan 2018 00:41:21 +0100 Subject: Spacing --- src/libcore/iter/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 5923e6dc3ee..7314fac282b 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -721,7 +721,7 @@ impl Iterator for StepBy where I: Iterator { // overflow handling loop { let mul = n.checked_mul(step); - if unsafe { intrinsics::likely(mul.is_some())} { + if unsafe { intrinsics::likely(mul.is_some()) } { return self.iter.nth(mul.unwrap() - 1); } let div_n = usize::MAX / n; -- cgit 1.4.1-3-g733a5 From ba5d7a66e847f5713633cb792c379a11b774e21f Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 17 Dec 2017 17:28:01 -0500 Subject: Implement Debug for ptr::Shared and ptr::Unique. Fixes https://github.com/rust-lang/rust/issues/46755. --- src/libcore/ptr.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 7f7246df8f2..4da51a33128 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2330,7 +2330,6 @@ impl PartialOrd for *mut T { /// /// Unlike `*mut T`, `Unique` is covariant over `T`. This should always be correct /// for any type which upholds Unique's aliasing requirements. -#[allow(missing_debug_implementations)] #[unstable(feature = "unique", reason = "needs an RFC to flesh out design", issue = "27730")] pub struct Unique { @@ -2343,6 +2342,13 @@ pub struct Unique { _marker: PhantomData, } +#[unstable(feature = "unique", issue = "27730")] +impl fmt::Debug for Unique { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:p}", self.as_ptr()) + } +} + /// `Unique` pointers are `Send` if `T` is `Send` because the data they /// reference is unaliased. Note that this aliasing invariant is /// unenforced by the type system; the abstraction using the @@ -2463,13 +2469,19 @@ impl<'a, T: ?Sized> From<&'a T> for Unique { /// Usually this won't be necessary; covariance is correct for most safe abstractions, /// such as Box, Rc, Arc, Vec, and LinkedList. This is the case because they /// provide a public API that follows the normal shared XOR mutable rules of Rust. -#[allow(missing_debug_implementations)] #[unstable(feature = "shared", reason = "needs an RFC to flesh out design", issue = "27730")] pub struct Shared { pointer: NonZero<*const T>, } +#[unstable(feature = "shared", issue = "27730")] +impl fmt::Debug for Shared { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:p}", self.as_ptr()) + } +} + /// `Shared` pointers are not `Send` because the data they reference may be aliased. // NB: This impl is unnecessary, but should provide better error messages. #[unstable(feature = "shared", issue = "27730")] -- cgit 1.4.1-3-g733a5 From f19baf0977b176ba26277af479a19b71b7ee1fdb Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 22 Dec 2017 18:58:39 +0100 Subject: Rename std::ptr::Shared to NonNull `Shared` is now a deprecated `type` alias. CC https://github.com/rust-lang/rust/issues/27730#issuecomment-352800629 --- src/liballoc/arc.rs | 18 +++---- src/liballoc/heap.rs | 2 +- src/liballoc/lib.rs | 2 +- src/liballoc/linked_list.rs | 28 +++++----- src/liballoc/rc.rs | 20 +++---- src/liballoc/vec.rs | 10 ++-- src/liballoc/vec_deque.rs | 6 +-- src/libcore/ptr.rs | 87 ++++++++++++++++--------------- src/librustc_data_structures/array_vec.rs | 6 +-- src/librustc_data_structures/lib.rs | 2 +- src/libstd/collections/hash/table.rs | 6 +-- src/libstd/lib.rs | 2 +- src/libstd/panic.rs | 6 +-- 13 files changed, 100 insertions(+), 95 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 185af8835d1..49a6220d591 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -25,7 +25,7 @@ use core::intrinsics::abort; use core::mem::{self, align_of_val, size_of_val, uninitialized}; use core::ops::Deref; use core::ops::CoerceUnsized; -use core::ptr::{self, Shared}; +use core::ptr::{self, NonNull}; use core::marker::{Unsize, PhantomData}; use core::hash::{Hash, Hasher}; use core::{isize, usize}; @@ -197,7 +197,7 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// [rc_examples]: ../../std/rc/index.html#examples #[stable(feature = "rust1", since = "1.0.0")] pub struct Arc { - ptr: Shared>, + ptr: NonNull>, phantom: PhantomData, } @@ -234,7 +234,7 @@ impl, U: ?Sized> CoerceUnsized> for Arc {} /// [`None`]: ../../std/option/enum.Option.html#variant.None #[stable(feature = "arc_weak", since = "1.4.0")] pub struct Weak { - ptr: Shared>, + ptr: NonNull>, } #[stable(feature = "arc_weak", since = "1.4.0")] @@ -286,7 +286,7 @@ impl Arc { weak: atomic::AtomicUsize::new(1), data, }; - Arc { ptr: Shared::from(Box::into_unique(x)), phantom: PhantomData } + Arc { ptr: NonNull::from(Box::into_unique(x)), phantom: PhantomData } } /// Returns the contained value, if the `Arc` has exactly one strong reference. @@ -397,7 +397,7 @@ impl Arc { let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); Arc { - ptr: Shared::new_unchecked(arc_ptr), + ptr: NonNull::new_unchecked(arc_ptr), phantom: PhantomData, } } @@ -582,7 +582,7 @@ impl Arc { // Free the allocation without dropping its contents box_free(bptr); - Arc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData } + Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } } } } @@ -609,7 +609,7 @@ impl Arc<[T]> { &mut (*ptr).data as *mut [T] as *mut T, v.len()); - Arc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData } + Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } } } @@ -669,7 +669,7 @@ impl ArcFromSlice for Arc<[T]> { // All clear. Forget the guard so it doesn't free the new ArcInner. mem::forget(guard); - Arc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData } + Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } } } } @@ -991,7 +991,7 @@ impl Weak { pub fn new() -> Weak { unsafe { Weak { - ptr: Shared::from(Box::into_unique(box ArcInner { + ptr: NonNull::from(Box::into_unique(box ArcInner { strong: atomic::AtomicUsize::new(0), weak: atomic::AtomicUsize::new(1), data: uninitialized(), diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index b2bd9d7d8fa..37af9ea5295 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -232,7 +232,7 @@ unsafe impl Alloc for Heap { /// /// This preserves the non-null invariant for types like `Box`. The address /// may overlap with non-zero-size memory allocations. -#[rustc_deprecated(since = "1.19", reason = "Use Unique/Shared::empty() instead")] +#[rustc_deprecated(since = "1.19", reason = "Use Unique/NonNull::empty() instead")] #[unstable(feature = "heap_api", issue = "27700")] pub const EMPTY: *mut () = 1 as *mut (); diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 6ee4f802802..eaad6f1116f 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -103,6 +103,7 @@ #![feature(iter_rfold)] #![feature(lang_items)] #![feature(needs_allocator)] +#![feature(nonnull)] #![feature(nonzero)] #![feature(offset_to)] #![feature(optin_builtin_traits)] @@ -110,7 +111,6 @@ #![feature(placement_in_syntax)] #![feature(placement_new_protocol)] #![feature(rustc_attrs)] -#![feature(shared)] #![feature(slice_get_slice)] #![feature(slice_patterns)] #![feature(slice_rsplit)] diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs index 3ac5a85d721..e6e84101275 100644 --- a/src/liballoc/linked_list.rs +++ b/src/liballoc/linked_list.rs @@ -29,7 +29,7 @@ use core::iter::{FromIterator, FusedIterator}; use core::marker::PhantomData; use core::mem; use core::ops::{BoxPlace, InPlace, Place, Placer}; -use core::ptr::{self, Shared}; +use core::ptr::{self, NonNull}; use boxed::{Box, IntermediateBox}; use super::SpecExtend; @@ -44,15 +44,15 @@ use super::SpecExtend; /// more memory efficient and make better use of CPU cache. #[stable(feature = "rust1", since = "1.0.0")] pub struct LinkedList { - head: Option>>, - tail: Option>>, + head: Option>>, + tail: Option>>, len: usize, marker: PhantomData>>, } struct Node { - next: Option>>, - prev: Option>>, + next: Option>>, + prev: Option>>, element: T, } @@ -65,8 +65,8 @@ struct Node { /// [`LinkedList`]: struct.LinkedList.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { - head: Option>>, - tail: Option>>, + head: Option>>, + tail: Option>>, len: usize, marker: PhantomData<&'a Node>, } @@ -98,8 +98,8 @@ impl<'a, T> Clone for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { list: &'a mut LinkedList, - head: Option>>, - tail: Option>>, + head: Option>>, + tail: Option>>, len: usize, } @@ -157,7 +157,7 @@ impl LinkedList { unsafe { node.next = self.head; node.prev = None; - let node = Some(Shared::from(Box::into_unique(node))); + let node = Some(NonNull::from(Box::into_unique(node))); match self.head { None => self.tail = node, @@ -192,7 +192,7 @@ impl LinkedList { unsafe { node.next = None; node.prev = self.tail; - let node = Some(Shared::from(Box::into_unique(node))); + let node = Some(NonNull::from(Box::into_unique(node))); match self.tail { None => self.head = node, @@ -225,7 +225,7 @@ impl LinkedList { /// /// Warning: this will not check that the provided node belongs to the current list. #[inline] - unsafe fn unlink_node(&mut self, mut node: Shared>) { + unsafe fn unlink_node(&mut self, mut node: NonNull>) { let node = node.as_mut(); match node.prev { @@ -986,7 +986,7 @@ impl<'a, T> IterMut<'a, T> { Some(prev) => prev, }; - let node = Some(Shared::from(Box::into_unique(box Node { + let node = Some(NonNull::from(Box::into_unique(box Node { next: Some(head), prev: Some(prev), element, @@ -1038,7 +1038,7 @@ pub struct DrainFilter<'a, T: 'a, F: 'a> where F: FnMut(&mut T) -> bool, { list: &'a mut LinkedList, - it: Option>>, + it: Option>>, pred: F, idx: usize, old_len: usize, diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 59079f9ba76..aa7b96139fa 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -256,7 +256,7 @@ use core::marker::{Unsize, PhantomData}; use core::mem::{self, align_of_val, forget, size_of_val, uninitialized}; use core::ops::Deref; use core::ops::CoerceUnsized; -use core::ptr::{self, Shared}; +use core::ptr::{self, NonNull}; use core::convert::From; use heap::{Heap, Alloc, Layout, box_free}; @@ -282,7 +282,7 @@ struct RcBox { /// [get_mut]: #method.get_mut #[stable(feature = "rust1", since = "1.0.0")] pub struct Rc { - ptr: Shared>, + ptr: NonNull>, phantom: PhantomData, } @@ -311,7 +311,7 @@ impl Rc { // pointers, which ensures that the weak destructor never frees // the allocation while the strong destructor is running, even // if the weak pointer is stored inside the strong one. - ptr: Shared::from(Box::into_unique(box RcBox { + ptr: NonNull::from(Box::into_unique(box RcBox { strong: Cell::new(1), weak: Cell::new(1), value, @@ -428,7 +428,7 @@ impl Rc { let rc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); Rc { - ptr: Shared::new_unchecked(rc_ptr), + ptr: NonNull::new_unchecked(rc_ptr), phantom: PhantomData, } } @@ -649,7 +649,7 @@ impl Rc { let raw: *const RcBox = self.ptr.as_ptr(); forget(self); Ok(Rc { - ptr: Shared::new_unchecked(raw as *const RcBox as *mut _), + ptr: NonNull::new_unchecked(raw as *const RcBox as *mut _), phantom: PhantomData, }) } @@ -695,7 +695,7 @@ impl Rc { // Free the allocation without dropping its contents box_free(bptr); - Rc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData } + Rc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } } } } @@ -722,7 +722,7 @@ impl Rc<[T]> { &mut (*ptr).value as *mut [T] as *mut T, v.len()); - Rc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData } + Rc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } } } @@ -781,7 +781,7 @@ impl RcFromSlice for Rc<[T]> { // All clear. Forget the guard so it doesn't free the new RcBox. forget(guard); - Rc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData } + Rc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } } } } @@ -1160,7 +1160,7 @@ impl From> for Rc<[T]> { /// [`None`]: ../../std/option/enum.Option.html#variant.None #[stable(feature = "rc_weak", since = "1.4.0")] pub struct Weak { - ptr: Shared>, + ptr: NonNull>, } #[stable(feature = "rc_weak", since = "1.4.0")] @@ -1190,7 +1190,7 @@ impl Weak { pub fn new() -> Weak { unsafe { Weak { - ptr: Shared::from(Box::into_unique(box RcBox { + ptr: NonNull::from(Box::into_unique(box RcBox { strong: Cell::new(0), weak: Cell::new(1), value: uninitialized(), diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 301e44632b8..b14b9d74765 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -78,7 +78,7 @@ use core::num::Float; use core::ops::{InPlace, Index, IndexMut, Place, Placer}; use core::ops; use core::ptr; -use core::ptr::Shared; +use core::ptr::NonNull; use core::slice; use borrow::ToOwned; @@ -1124,7 +1124,7 @@ impl Vec { tail_start: end, tail_len: len - end, iter: range_slice.iter(), - vec: Shared::from(self), + vec: NonNull::from(self), } } } @@ -1745,7 +1745,7 @@ impl IntoIterator for Vec { let cap = self.buf.cap(); mem::forget(self); IntoIter { - buf: Shared::new_unchecked(begin), + buf: NonNull::new_unchecked(begin), phantom: PhantomData, cap, ptr: begin, @@ -2267,7 +2267,7 @@ impl<'a, T> FromIterator for Cow<'a, [T]> where T: Clone { /// [`IntoIterator`]: ../../std/iter/trait.IntoIterator.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { - buf: Shared, + buf: NonNull, phantom: PhantomData, cap: usize, ptr: *const T, @@ -2442,7 +2442,7 @@ pub struct Drain<'a, T: 'a> { tail_len: usize, /// Current remaining range to remove iter: slice::Iter<'a, T>, - vec: Shared>, + vec: NonNull>, } #[stable(feature = "collection_debug", since = "1.17.0")] diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index f56aa23a4eb..8f05a69c5f3 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -23,7 +23,7 @@ use core::iter::{repeat, FromIterator, FusedIterator}; use core::mem; use core::ops::{Index, IndexMut, Place, Placer, InPlace}; use core::ptr; -use core::ptr::Shared; +use core::ptr::NonNull; use core::slice; use core::hash::{Hash, Hasher}; @@ -895,7 +895,7 @@ impl VecDeque { self.head = drain_tail; Drain { - deque: Shared::from(&mut *self), + deque: NonNull::from(&mut *self), after_tail: drain_head, after_head: head, iter: Iter { @@ -2154,7 +2154,7 @@ pub struct Drain<'a, T: 'a> { after_tail: usize, after_head: usize, iter: Iter<'a, T>, - deque: Shared>, + deque: NonNull>, } #[stable(feature = "collection_debug", since = "1.17.0")] diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 4da51a33128..fd8f9138f36 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2321,7 +2321,7 @@ impl PartialOrd for *mut T { /// its owning Unique. /// /// If you're uncertain of whether it's correct to use `Unique` for your purposes, -/// consider using `Shared`, which has weaker semantics. +/// consider using `NonNull`, which has weaker semantics. /// /// Unlike `*mut T`, the pointer must always be non-null, even if the pointer /// is never dereferenced. This is so that enums may use this forbidden value @@ -2452,18 +2452,23 @@ impl<'a, T: ?Sized> From<&'a T> for Unique { } } +/// Previous name of `NonNull`. +#[rustc_deprecated(since = "1.24", reason = "renamed to `NonNull`")] +#[unstable(feature = "shared", issue = "27730")] +pub type Shared = NonNull; + /// `*mut T` but non-zero and covariant. /// /// This is often the correct thing to use when building data structures using /// raw pointers, but is ultimately more dangerous to use because of its additional -/// properties. If you're not sure if you should use `Shared`, just use `*mut T`! +/// properties. If you're not sure if you should use `NonNull`, just use `*mut T`! /// /// Unlike `*mut T`, the pointer must always be non-null, even if the pointer /// is never dereferenced. This is so that enums may use this forbidden value -/// as a discriminant -- `Option>` has the same size as `Shared`. +/// as a discriminant -- `Option>` has the same size as `NonNull`. /// However the pointer may still dangle if it isn't dereferenced. /// -/// Unlike `*mut T`, `Shared` is covariant over `T`. If this is incorrect +/// Unlike `*mut T`, `NonNull` is covariant over `T`. If this is incorrect /// for your use case, you should include some PhantomData in your type to /// provide invariance, such as `PhantomData>` or `PhantomData<&'a mut T>`. /// Usually this won't be necessary; covariance is correct for most safe abstractions, @@ -2471,56 +2476,56 @@ impl<'a, T: ?Sized> From<&'a T> for Unique { /// provide a public API that follows the normal shared XOR mutable rules of Rust. #[unstable(feature = "shared", reason = "needs an RFC to flesh out design", issue = "27730")] -pub struct Shared { +pub struct NonNull { pointer: NonZero<*const T>, } #[unstable(feature = "shared", issue = "27730")] -impl fmt::Debug for Shared { +impl fmt::Debug for NonNull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:p}", self.as_ptr()) } } -/// `Shared` pointers are not `Send` because the data they reference may be aliased. +/// `NonNull` pointers are not `Send` because the data they reference may be aliased. // NB: This impl is unnecessary, but should provide better error messages. -#[unstable(feature = "shared", issue = "27730")] -impl !Send for Shared { } +#[unstable(feature = "nonnull", issue = "27730")] +impl !Send for NonNull { } -/// `Shared` pointers are not `Sync` because the data they reference may be aliased. +/// `NonNull` pointers are not `Sync` because the data they reference may be aliased. // NB: This impl is unnecessary, but should provide better error messages. -#[unstable(feature = "shared", issue = "27730")] -impl !Sync for Shared { } +#[unstable(feature = "nonnull", issue = "27730")] +impl !Sync for NonNull { } -#[unstable(feature = "shared", issue = "27730")] -impl Shared { - /// Creates a new `Shared` that is dangling, but well-aligned. +#[unstable(feature = "nonnull", issue = "27730")] +impl NonNull { + /// Creates a new `NonNull` that is dangling, but well-aligned. /// /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. pub fn empty() -> Self { unsafe { let ptr = mem::align_of::() as *mut T; - Shared::new_unchecked(ptr) + NonNull::new_unchecked(ptr) } } } -#[unstable(feature = "shared", issue = "27730")] -impl Shared { - /// Creates a new `Shared`. +#[unstable(feature = "nonnull", issue = "27730")] +impl NonNull { + /// Creates a new `NonNull`. /// /// # Safety /// /// `ptr` must be non-null. - #[unstable(feature = "shared", issue = "27730")] + #[unstable(feature = "nonnull", issue = "27730")] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { - Shared { pointer: NonZero::new_unchecked(ptr) } + NonNull { pointer: NonZero::new_unchecked(ptr) } } - /// Creates a new `Shared` if `ptr` is non-null. + /// Creates a new `NonNull` if `ptr` is non-null. pub fn new(ptr: *mut T) -> Option { - NonZero::new(ptr as *const T).map(|nz| Shared { pointer: nz }) + NonZero::new(ptr as *const T).map(|nz| NonNull { pointer: nz }) } /// Acquires the underlying `*mut` pointer. @@ -2548,49 +2553,49 @@ impl Shared { /// Acquires the underlying pointer as a `*mut` pointer. #[rustc_deprecated(since = "1.19", reason = "renamed to `as_ptr` for ergonomics/consistency")] - #[unstable(feature = "shared", issue = "27730")] + #[unstable(feature = "nonnull", issue = "27730")] pub unsafe fn as_mut_ptr(&self) -> *mut T { self.as_ptr() } } -#[unstable(feature = "shared", issue = "27730")] -impl Clone for Shared { +#[unstable(feature = "nonnull", issue = "27730")] +impl Clone for NonNull { fn clone(&self) -> Self { *self } } -#[unstable(feature = "shared", issue = "27730")] -impl Copy for Shared { } +#[unstable(feature = "nonnull", issue = "27730")] +impl Copy for NonNull { } -#[unstable(feature = "shared", issue = "27730")] -impl CoerceUnsized> for Shared where T: Unsize { } +#[unstable(feature = "nonnull", issue = "27730")] +impl CoerceUnsized> for NonNull where T: Unsize { } -#[unstable(feature = "shared", issue = "27730")] -impl fmt::Pointer for Shared { +#[unstable(feature = "nonnull", issue = "27730")] +impl fmt::Pointer for NonNull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&self.as_ptr(), f) } } -#[unstable(feature = "shared", issue = "27730")] -impl From> for Shared { +#[unstable(feature = "nonnull", issue = "27730")] +impl From> for NonNull { fn from(unique: Unique) -> Self { - Shared { pointer: unique.pointer } + NonNull { pointer: unique.pointer } } } -#[unstable(feature = "shared", issue = "27730")] -impl<'a, T: ?Sized> From<&'a mut T> for Shared { +#[unstable(feature = "nonnull", issue = "27730")] +impl<'a, T: ?Sized> From<&'a mut T> for NonNull { fn from(reference: &'a mut T) -> Self { - Shared { pointer: NonZero::from(reference) } + NonNull { pointer: NonZero::from(reference) } } } -#[unstable(feature = "shared", issue = "27730")] -impl<'a, T: ?Sized> From<&'a T> for Shared { +#[unstable(feature = "nonnull", issue = "27730")] +impl<'a, T: ?Sized> From<&'a T> for NonNull { fn from(reference: &'a T) -> Self { - Shared { pointer: NonZero::from(reference) } + NonNull { pointer: NonZero::from(reference) } } } diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 57fc78ef531..511c407d45a 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -12,7 +12,7 @@ use std::marker::Unsize; use std::iter::Extend; -use std::ptr::{self, drop_in_place, Shared}; +use std::ptr::{self, drop_in_place, NonNull}; use std::ops::{Deref, DerefMut, Range}; use std::hash::{Hash, Hasher}; use std::slice; @@ -146,7 +146,7 @@ impl ArrayVec { tail_start: end, tail_len: len - end, iter: range_slice.iter(), - array_vec: Shared::from(self), + array_vec: NonNull::from(self), } } } @@ -232,7 +232,7 @@ pub struct Drain<'a, A: Array> tail_start: usize, tail_len: usize, iter: slice::Iter<'a, ManuallyDrop>, - array_vec: Shared>, + array_vec: NonNull>, } impl<'a, A: Array> Iterator for Drain<'a, A> { diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 24048e606df..1d53825ac37 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -21,8 +21,8 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] -#![feature(shared)] #![feature(collections_range)] +#![feature(nonnull)] #![feature(nonzero)] #![feature(unboxed_closures)] #![feature(fn_traits)] diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 96f98efe4aa..73bd5747c10 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -16,7 +16,7 @@ use marker; use mem::{align_of, size_of, needs_drop}; use mem; use ops::{Deref, DerefMut}; -use ptr::{self, Unique, Shared}; +use ptr::{self, Unique, NonNull}; use self::BucketState::*; @@ -873,7 +873,7 @@ impl RawTable { elems_left, marker: marker::PhantomData, }, - table: Shared::from(self), + table: NonNull::from(self), marker: marker::PhantomData, } } @@ -1020,7 +1020,7 @@ impl IntoIter { /// Iterator over the entries in a table, clearing the table. pub struct Drain<'a, K: 'a, V: 'a> { - table: Shared>, + table: NonNull>, iter: RawBuckets<'static, K, V>, marker: marker::PhantomData<&'a RawTable>, } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index bb38fc55091..8a1ba32f7dc 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -283,6 +283,7 @@ #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] #![feature(never_type)] +#![feature(nonnull)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] @@ -297,7 +298,6 @@ #![feature(raw)] #![feature(repr_align)] #![feature(rustc_attrs)] -#![feature(shared)] #![feature(sip_hash_13)] #![feature(slice_bytes)] #![feature(slice_concat_ext)] diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 53c2211745c..68584b7cf25 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -17,7 +17,7 @@ use cell::UnsafeCell; use fmt; use ops::{Deref, DerefMut}; use panicking; -use ptr::{Unique, Shared}; +use ptr::{Unique, NonNull}; use rc::Rc; use sync::{Arc, Mutex, RwLock, atomic}; use thread::Result; @@ -198,8 +198,8 @@ impl UnwindSafe for *const T {} impl UnwindSafe for *mut T {} #[unstable(feature = "unique", issue = "27730")] impl UnwindSafe for Unique {} -#[unstable(feature = "shared", issue = "27730")] -impl UnwindSafe for Shared {} +#[unstable(feature = "nonnull", issue = "27730")] +impl UnwindSafe for NonNull {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl UnwindSafe for Mutex {} #[stable(feature = "catch_unwind", since = "1.9.0")] -- cgit 1.4.1-3-g733a5 From fb03a49c2501c52401b3c987fd455818de1736f2 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 22 Dec 2017 19:12:22 +0100 Subject: Replace Unique with NonZero in Alloc trait --- src/liballoc/allocator.rs | 20 ++++++++++---------- src/liballoc/raw_vec.rs | 2 +- src/libcore/ptr.rs | 7 +++++++ src/test/run-pass/allocator-alloc-one.rs | 2 +- 4 files changed, 19 insertions(+), 12 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/allocator.rs b/src/liballoc/allocator.rs index c2a8f5f8ff9..55e8c0b430f 100644 --- a/src/liballoc/allocator.rs +++ b/src/liballoc/allocator.rs @@ -19,7 +19,7 @@ use core::cmp; use core::fmt; use core::mem; use core::usize; -use core::ptr::{self, Unique}; +use core::ptr::{self, NonNull}; /// Represents the combination of a starting address and /// a total capacity of the returned block. @@ -895,12 +895,12 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. - fn alloc_one(&mut self) -> Result, AllocErr> + fn alloc_one(&mut self) -> Result, AllocErr> where Self: Sized { let k = Layout::new::(); if k.size() > 0 { - unsafe { self.alloc(k).map(|p| Unique::new_unchecked(p as *mut T)) } + unsafe { self.alloc(k).map(|p| NonNull::new_unchecked(p as *mut T)) } } else { Err(AllocErr::invalid_input("zero-sized type invalid for alloc_one")) } @@ -923,7 +923,7 @@ pub unsafe trait Alloc { /// * `ptr` must denote a block of memory currently allocated via this allocator /// /// * the layout of `T` must *fit* that block of memory. - unsafe fn dealloc_one(&mut self, ptr: Unique) + unsafe fn dealloc_one(&mut self, ptr: NonNull) where Self: Sized { let raw_ptr = ptr.as_ptr() as *mut u8; @@ -963,7 +963,7 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. - fn alloc_array(&mut self, n: usize) -> Result, AllocErr> + fn alloc_array(&mut self, n: usize) -> Result, AllocErr> where Self: Sized { match Layout::array::(n) { @@ -971,7 +971,7 @@ pub unsafe trait Alloc { unsafe { self.alloc(layout.clone()) .map(|p| { - Unique::new_unchecked(p as *mut T) + NonNull::new_unchecked(p as *mut T) }) } } @@ -1012,15 +1012,15 @@ pub unsafe trait Alloc { /// reallocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. unsafe fn realloc_array(&mut self, - ptr: Unique, + ptr: NonNull, n_old: usize, - n_new: usize) -> Result, AllocErr> + n_new: usize) -> Result, AllocErr> where Self: Sized { match (Layout::array::(n_old), Layout::array::(n_new), ptr.as_ptr()) { (Some(ref k_old), Some(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone()) - .map(|p|Unique::new_unchecked(p as *mut T)) + .map(|p| NonNull::new_unchecked(p as *mut T)) } _ => { Err(AllocErr::invalid_input("invalid layout for realloc_array")) @@ -1048,7 +1048,7 @@ pub unsafe trait Alloc { /// constraints. /// /// Always returns `Err` on arithmetic overflow. - unsafe fn dealloc_array(&mut self, ptr: Unique, n: usize) -> Result<(), AllocErr> + unsafe fn dealloc_array(&mut self, ptr: NonNull, n: usize) -> Result<(), AllocErr> where Self: Sized { let raw_ptr = ptr.as_ptr() as *mut u8; diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index dbf1fb1367d..621e1906961 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -322,7 +322,7 @@ impl RawVec { // would cause overflow let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; match self.a.alloc_array::(new_cap) { - Ok(ptr) => (new_cap, ptr), + Ok(ptr) => (new_cap, ptr.into()), Err(e) => self.a.oom(e), } } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index fd8f9138f36..89ecb3457fc 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2452,6 +2452,13 @@ impl<'a, T: ?Sized> From<&'a T> for Unique { } } +#[unstable(feature = "unique", issue = "27730")] +impl<'a, T: ?Sized> From> for Unique { + fn from(p: NonNull) -> Self { + Unique { pointer: p.pointer, _marker: PhantomData } + } +} + /// Previous name of `NonNull`. #[rustc_deprecated(since = "1.24", reason = "renamed to `NonNull`")] #[unstable(feature = "shared", issue = "27730")] diff --git a/src/test/run-pass/allocator-alloc-one.rs b/src/test/run-pass/allocator-alloc-one.rs index 712fa2d6001..eaa5bc90805 100644 --- a/src/test/run-pass/allocator-alloc-one.rs +++ b/src/test/run-pass/allocator-alloc-one.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(allocator_api, unique)] +#![feature(allocator_api, nonnull)] use std::heap::{Heap, Alloc}; -- cgit 1.4.1-3-g733a5 From c97c1f7dc3b8c2e5e1c40681094c45cf55be5832 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 22 Dec 2017 19:29:16 +0100 Subject: Mark Unique as perma-unstable, with the feature renamed to ptr_internals. --- src/doc/nomicon | 2 +- src/liballoc/lib.rs | 2 +- src/libcore/ptr.rs | 30 +++++++++++++++--------------- src/libcore/tests/lib.rs | 2 +- src/libcore/tests/ptr.rs | 4 ++-- src/libstd/lib.rs | 2 +- src/libstd/panic.rs | 2 +- src/test/run-pass/issue-23433.rs | 6 +++--- 8 files changed, 25 insertions(+), 25 deletions(-) (limited to 'src/libcore') diff --git a/src/doc/nomicon b/src/doc/nomicon index 2f7b05fd593..fec3182d0b0 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 2f7b05fd5939aa49d52c4ab309b9a47776ba7bd8 +Subproject commit fec3182d0b0a3cf8122e192b3270064a5b19be5b diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index eaad6f1116f..07e4ccc45a9 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -110,6 +110,7 @@ #![feature(pattern)] #![feature(placement_in_syntax)] #![feature(placement_new_protocol)] +#![feature(ptr_internals)] #![feature(rustc_attrs)] #![feature(slice_get_slice)] #![feature(slice_patterns)] @@ -120,7 +121,6 @@ #![feature(trusted_len)] #![feature(unboxed_closures)] #![feature(unicode)] -#![feature(unique)] #![feature(unsize)] #![feature(allocator_internals)] #![feature(on_unimplemented)] diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 89ecb3457fc..e39c520880a 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2330,8 +2330,9 @@ impl PartialOrd for *mut T { /// /// Unlike `*mut T`, `Unique` is covariant over `T`. This should always be correct /// for any type which upholds Unique's aliasing requirements. -#[unstable(feature = "unique", reason = "needs an RFC to flesh out design", - issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0", + reason = "use NonNull instead and consider PhantomData \ + (if you also use #[may_dangle]), Send, and/or Sync")] pub struct Unique { pointer: NonZero<*const T>, // NOTE: this marker has no consequences for variance, but is necessary @@ -2342,7 +2343,7 @@ pub struct Unique { _marker: PhantomData, } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl fmt::Debug for Unique { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:p}", self.as_ptr()) @@ -2353,17 +2354,17 @@ impl fmt::Debug for Unique { /// reference is unaliased. Note that this aliasing invariant is /// unenforced by the type system; the abstraction using the /// `Unique` must enforce it. -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] unsafe impl Send for Unique { } /// `Unique` pointers are `Sync` if `T` is `Sync` because the data they /// reference is unaliased. Note that this aliasing invariant is /// unenforced by the type system; the abstraction using the /// `Unique` must enforce it. -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] unsafe impl Sync for Unique { } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl Unique { /// Creates a new `Unique` that is dangling, but well-aligned. /// @@ -2377,14 +2378,13 @@ impl Unique { } } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl Unique { /// Creates a new `Unique`. /// /// # Safety /// /// `ptr` must be non-null. - #[unstable(feature = "unique", issue = "27730")] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { Unique { pointer: NonZero::new_unchecked(ptr), _marker: PhantomData } } @@ -2418,41 +2418,41 @@ impl Unique { } } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl Clone for Unique { fn clone(&self) -> Self { *self } } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl Copy for Unique { } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl CoerceUnsized> for Unique where T: Unsize { } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl fmt::Pointer for Unique { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&self.as_ptr(), f) } } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl<'a, T: ?Sized> From<&'a mut T> for Unique { fn from(reference: &'a mut T) -> Self { Unique { pointer: NonZero::from(reference), _marker: PhantomData } } } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl<'a, T: ?Sized> From<&'a T> for Unique { fn from(reference: &'a T) -> Self { Unique { pointer: NonZero::from(reference), _marker: PhantomData } } } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl<'a, T: ?Sized> From> for Unique { fn from(p: NonNull) -> Self { Unique { pointer: p.pointer, _marker: PhantomData } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 2c0009569d7..bc7052d676d 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -27,6 +27,7 @@ #![feature(iterator_try_fold)] #![feature(iter_rfind)] #![feature(iter_rfold)] +#![feature(nonnull)] #![feature(nonzero)] #![feature(pattern)] #![feature(raw)] @@ -41,7 +42,6 @@ #![feature(trusted_len)] #![feature(try_from)] #![feature(try_trait)] -#![feature(unique)] #![feature(exact_chunks)] extern crate core; diff --git a/src/libcore/tests/ptr.rs b/src/libcore/tests/ptr.rs index 98436f0e1d1..00f87336f3c 100644 --- a/src/libcore/tests/ptr.rs +++ b/src/libcore/tests/ptr.rs @@ -249,9 +249,9 @@ fn test_set_memory() { } #[test] -fn test_unsized_unique() { +fn test_unsized_nonnull() { let xs: &[i32] = &[1, 2, 3]; - let ptr = unsafe { Unique::new_unchecked(xs as *const [i32] as *mut [i32]) }; + let ptr = unsafe { NonNull::new_unchecked(xs as *const [i32] as *mut [i32]) }; let ys = unsafe { ptr.as_ref() }; let zs: &[i32] = &[1, 2, 3]; assert!(ys == zs); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 8a1ba32f7dc..9f65d61658c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -294,6 +294,7 @@ #![feature(placement_in_syntax)] #![feature(placement_new_protocol)] #![feature(prelude_import)] +#![feature(ptr_internals)] #![feature(rand)] #![feature(raw)] #![feature(repr_align)] @@ -315,7 +316,6 @@ #![feature(try_from)] #![feature(unboxed_closures)] #![feature(unicode)] -#![feature(unique)] #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(vec_push_all)] diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 68584b7cf25..6f7d8ddb770 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -196,7 +196,7 @@ impl<'a, T: RefUnwindSafe + ?Sized> UnwindSafe for &'a T {} impl UnwindSafe for *const T {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl UnwindSafe for *mut T {} -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl UnwindSafe for Unique {} #[unstable(feature = "nonnull", issue = "27730")] impl UnwindSafe for NonNull {} diff --git a/src/test/run-pass/issue-23433.rs b/src/test/run-pass/issue-23433.rs index aa13d6fad47..37cc1b134c3 100644 --- a/src/test/run-pass/issue-23433.rs +++ b/src/test/run-pass/issue-23433.rs @@ -10,13 +10,13 @@ // Don't fail if we encounter a NonZero<*T> where T is an unsized type -#![feature(unique)] +#![feature(nonnull)] -use std::ptr::Unique; +use std::ptr::NonNull; fn main() { let mut a = [0u8; 5]; - let b: Option> = Some(Unique::from(&mut a)); + let b: Option> = Some(NonNull::from(&mut a)); match b { Some(_) => println!("Got `Some`"), None => panic!("Unexpected `None`"), -- cgit 1.4.1-3-g733a5 From 2d51e7458037187eb789caacf3180c14f3d84614 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 22 Dec 2017 19:47:27 +0100 Subject: Remove a deprecated (renamed) and unstable method of NonNull --- src/libcore/ptr.rs | 7 ------- 1 file changed, 7 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index e39c520880a..6cb84615d09 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2557,13 +2557,6 @@ impl NonNull { pub unsafe fn as_mut(&mut self) -> &mut T { &mut *self.as_ptr() } - - /// Acquires the underlying pointer as a `*mut` pointer. - #[rustc_deprecated(since = "1.19", reason = "renamed to `as_ptr` for ergonomics/consistency")] - #[unstable(feature = "nonnull", issue = "27730")] - pub unsafe fn as_mut_ptr(&self) -> *mut T { - self.as_ptr() - } } #[unstable(feature = "nonnull", issue = "27730")] -- cgit 1.4.1-3-g733a5 From 55c50cd8ac5ed5a799bc9f5aa1fe8fcfbb956706 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 22 Dec 2017 19:50:21 +0100 Subject: Stabilize std::ptr::NonNull --- src/liballoc/boxed.rs | 10 ++-------- src/liballoc/lib.rs | 1 - src/libcore/ptr.rs | 32 +++++++++++++++++--------------- src/libcore/tests/lib.rs | 1 - src/librustc_data_structures/lib.rs | 1 - src/libstd/lib.rs | 1 - src/libstd/panic.rs | 2 +- src/test/run-pass/issue-23433.rs | 2 -- 8 files changed, 20 insertions(+), 30 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 994466e2249..e7bc10dfaa9 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -288,16 +288,13 @@ impl Box { /// # Examples /// /// ``` - /// #![feature(nonnull)] - /// /// fn main() { /// let x = Box::new(5); /// let ptr = Box::into_nonnull_raw(x); /// let x = unsafe { Box::from_nonnull_raw(ptr) }; /// } /// ``` - #[unstable(feature = "nonnull", reason = "needs an RFC to flesh out design", - issue = "27730")] + #[stable(feature = "nonnull", since = "1.24.0")] #[inline] pub unsafe fn from_nonnull_raw(u: NonNull) -> Self { Box(u.into()) @@ -352,15 +349,12 @@ impl Box { /// # Examples /// /// ``` - /// #![feature(nonnull)] - /// /// fn main() { /// let x = Box::new(5); /// let ptr = Box::into_nonnull_raw(x); /// } /// ``` - #[unstable(feature = "nonnull", reason = "needs an RFC to flesh out design", - issue = "27730")] + #[stable(feature = "nonnull", since = "1.24.0")] #[inline] pub fn into_nonnull_raw(b: Box) -> NonNull { Box::into_unique(b).into() diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 07e4ccc45a9..f25b455f915 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -103,7 +103,6 @@ #![feature(iter_rfold)] #![feature(lang_items)] #![feature(needs_allocator)] -#![feature(nonnull)] #![feature(nonzero)] #![feature(offset_to)] #![feature(optin_builtin_traits)] diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 6cb84615d09..2e5f36ed71f 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2481,13 +2481,12 @@ pub type Shared = NonNull; /// Usually this won't be necessary; covariance is correct for most safe abstractions, /// such as Box, Rc, Arc, Vec, and LinkedList. This is the case because they /// provide a public API that follows the normal shared XOR mutable rules of Rust. -#[unstable(feature = "shared", reason = "needs an RFC to flesh out design", - issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] pub struct NonNull { pointer: NonZero<*const T>, } -#[unstable(feature = "shared", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl fmt::Debug for NonNull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:p}", self.as_ptr()) @@ -2496,20 +2495,20 @@ impl fmt::Debug for NonNull { /// `NonNull` pointers are not `Send` because the data they reference may be aliased. // NB: This impl is unnecessary, but should provide better error messages. -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl !Send for NonNull { } /// `NonNull` pointers are not `Sync` because the data they reference may be aliased. // NB: This impl is unnecessary, but should provide better error messages. -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl !Sync for NonNull { } -#[unstable(feature = "nonnull", issue = "27730")] impl NonNull { /// Creates a new `NonNull` that is dangling, but well-aligned. /// /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. + #[stable(feature = "nonnull", since = "1.24.0")] pub fn empty() -> Self { unsafe { let ptr = mem::align_of::() as *mut T; @@ -2518,24 +2517,25 @@ impl NonNull { } } -#[unstable(feature = "nonnull", issue = "27730")] impl NonNull { /// Creates a new `NonNull`. /// /// # Safety /// /// `ptr` must be non-null. - #[unstable(feature = "nonnull", issue = "27730")] + #[stable(feature = "nonnull", since = "1.24.0")] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { NonNull { pointer: NonZero::new_unchecked(ptr) } } /// Creates a new `NonNull` if `ptr` is non-null. + #[stable(feature = "nonnull", since = "1.24.0")] pub fn new(ptr: *mut T) -> Option { NonZero::new(ptr as *const T).map(|nz| NonNull { pointer: nz }) } /// Acquires the underlying `*mut` pointer. + #[stable(feature = "nonnull", since = "1.24.0")] pub fn as_ptr(self) -> *mut T { self.pointer.get() as *mut T } @@ -2545,6 +2545,7 @@ impl NonNull { /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer /// (unbound) lifetime is needed, use `&*my_ptr.ptr()`. + #[stable(feature = "nonnull", since = "1.24.0")] pub unsafe fn as_ref(&self) -> &T { &*self.as_ptr() } @@ -2554,46 +2555,47 @@ impl NonNull { /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer /// (unbound) lifetime is needed, use `&mut *my_ptr.ptr_mut()`. + #[stable(feature = "nonnull", since = "1.24.0")] pub unsafe fn as_mut(&mut self) -> &mut T { &mut *self.as_ptr() } } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl Clone for NonNull { fn clone(&self) -> Self { *self } } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl Copy for NonNull { } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl CoerceUnsized> for NonNull where T: Unsize { } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl fmt::Pointer for NonNull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&self.as_ptr(), f) } } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl From> for NonNull { fn from(unique: Unique) -> Self { NonNull { pointer: unique.pointer } } } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl<'a, T: ?Sized> From<&'a mut T> for NonNull { fn from(reference: &'a mut T) -> Self { NonNull { pointer: NonZero::from(reference) } } } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl<'a, T: ?Sized> From<&'a T> for NonNull { fn from(reference: &'a T) -> Self { NonNull { pointer: NonZero::from(reference) } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index bc7052d676d..1c32452f846 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -27,7 +27,6 @@ #![feature(iterator_try_fold)] #![feature(iter_rfind)] #![feature(iter_rfold)] -#![feature(nonnull)] #![feature(nonzero)] #![feature(pattern)] #![feature(raw)] diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 1d53825ac37..a35ef2f7ce7 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -22,7 +22,6 @@ #![deny(warnings)] #![feature(collections_range)] -#![feature(nonnull)] #![feature(nonzero)] #![feature(unboxed_closures)] #![feature(fn_traits)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 9f65d61658c..91cc6d25cce 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -283,7 +283,6 @@ #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] #![feature(never_type)] -#![feature(nonnull)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 6f7d8ddb770..560876006d3 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -198,7 +198,7 @@ impl UnwindSafe for *const T {} impl UnwindSafe for *mut T {} #[unstable(feature = "ptr_internals", issue = "0")] impl UnwindSafe for Unique {} -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl UnwindSafe for NonNull {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl UnwindSafe for Mutex {} diff --git a/src/test/run-pass/issue-23433.rs b/src/test/run-pass/issue-23433.rs index 37cc1b134c3..7af732f561d 100644 --- a/src/test/run-pass/issue-23433.rs +++ b/src/test/run-pass/issue-23433.rs @@ -10,8 +10,6 @@ // Don't fail if we encounter a NonZero<*T> where T is an unsized type -#![feature(nonnull)] - use std::ptr::NonNull; fn main() { -- cgit 1.4.1-3-g733a5 From 943a9e707c25380c48d2227224b89385b3004ef6 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 9 Jan 2018 11:25:22 +0100 Subject: Fix some doc-comment examples for earlier API refactor https://github.com/rust-lang/rust/pull/41064 --- src/libcore/ptr.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 2e5f36ed71f..4e9123fec97 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2403,7 +2403,7 @@ impl Unique { /// /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer - /// (unbound) lifetime is needed, use `&*my_ptr.ptr()`. + /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`. pub unsafe fn as_ref(&self) -> &T { &*self.as_ptr() } @@ -2412,7 +2412,7 @@ impl Unique { /// /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer - /// (unbound) lifetime is needed, use `&mut *my_ptr.ptr()`. + /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`. pub unsafe fn as_mut(&mut self) -> &mut T { &mut *self.as_ptr() } @@ -2544,7 +2544,7 @@ impl NonNull { /// /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer - /// (unbound) lifetime is needed, use `&*my_ptr.ptr()`. + /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`. #[stable(feature = "nonnull", since = "1.24.0")] pub unsafe fn as_ref(&self) -> &T { &*self.as_ptr() @@ -2554,7 +2554,7 @@ impl NonNull { /// /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer - /// (unbound) lifetime is needed, use `&mut *my_ptr.ptr_mut()`. + /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`. #[stable(feature = "nonnull", since = "1.24.0")] pub unsafe fn as_mut(&mut self) -> &mut T { &mut *self.as_ptr() -- cgit 1.4.1-3-g733a5 From a1db237cd48e9218f1ea5915c8fd2132dd72358e Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 10 Jan 2018 09:21:15 +0100 Subject: Preserve formatting options in Debug for NonNull/Unique --- src/libcore/ptr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 4e9123fec97..261291b747f 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2346,7 +2346,7 @@ pub struct Unique { #[unstable(feature = "ptr_internals", issue = "0")] impl fmt::Debug for Unique { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:p}", self.as_ptr()) + fmt::Pointer::fmt(&self.as_ptr(), f) } } @@ -2489,7 +2489,7 @@ pub struct NonNull { #[stable(feature = "nonnull", since = "1.24.0")] impl fmt::Debug for NonNull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:p}", self.as_ptr()) + fmt::Pointer::fmt(&self.as_ptr(), f) } } -- cgit 1.4.1-3-g733a5 From 76b686f78d97a90d9a563a0446de2d86b437e78e Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 10 Jan 2018 09:30:04 +0100 Subject: Rename NonNull::empty to dangling. --- src/libcore/ptr.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 261291b747f..fab5832d905 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2370,6 +2370,7 @@ impl Unique { /// /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. + // FIXME: rename to dangling() to match NonNull? pub fn empty() -> Self { unsafe { let ptr = mem::align_of::() as *mut T; @@ -2509,7 +2510,7 @@ impl NonNull { /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. #[stable(feature = "nonnull", since = "1.24.0")] - pub fn empty() -> Self { + pub fn dangling() -> Self { unsafe { let ptr = mem::align_of::() as *mut T; NonNull::new_unchecked(ptr) -- cgit 1.4.1-3-g733a5 From 3f557947abf99b262aab994e896522c76329d315 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sun, 21 Jan 2018 09:48:23 +0100 Subject: NonNull ended up landing in 1.25 --- src/libcore/ptr.rs | 36 ++++++++++++++++++------------------ src/libstd/panic.rs | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index fab5832d905..607e4a1a9fa 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2461,7 +2461,7 @@ impl<'a, T: ?Sized> From> for Unique { } /// Previous name of `NonNull`. -#[rustc_deprecated(since = "1.24", reason = "renamed to `NonNull`")] +#[rustc_deprecated(since = "1.25.0", reason = "renamed to `NonNull`")] #[unstable(feature = "shared", issue = "27730")] pub type Shared = NonNull; @@ -2482,12 +2482,12 @@ pub type Shared = NonNull; /// Usually this won't be necessary; covariance is correct for most safe abstractions, /// such as Box, Rc, Arc, Vec, and LinkedList. This is the case because they /// provide a public API that follows the normal shared XOR mutable rules of Rust. -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] pub struct NonNull { pointer: NonZero<*const T>, } -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl fmt::Debug for NonNull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&self.as_ptr(), f) @@ -2496,12 +2496,12 @@ impl fmt::Debug for NonNull { /// `NonNull` pointers are not `Send` because the data they reference may be aliased. // NB: This impl is unnecessary, but should provide better error messages. -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl !Send for NonNull { } /// `NonNull` pointers are not `Sync` because the data they reference may be aliased. // NB: This impl is unnecessary, but should provide better error messages. -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl !Sync for NonNull { } impl NonNull { @@ -2509,7 +2509,7 @@ impl NonNull { /// /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. - #[stable(feature = "nonnull", since = "1.24.0")] + #[stable(feature = "nonnull", since = "1.25.0")] pub fn dangling() -> Self { unsafe { let ptr = mem::align_of::() as *mut T; @@ -2524,19 +2524,19 @@ impl NonNull { /// # Safety /// /// `ptr` must be non-null. - #[stable(feature = "nonnull", since = "1.24.0")] + #[stable(feature = "nonnull", since = "1.25.0")] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { NonNull { pointer: NonZero::new_unchecked(ptr) } } /// Creates a new `NonNull` if `ptr` is non-null. - #[stable(feature = "nonnull", since = "1.24.0")] + #[stable(feature = "nonnull", since = "1.25.0")] pub fn new(ptr: *mut T) -> Option { NonZero::new(ptr as *const T).map(|nz| NonNull { pointer: nz }) } /// Acquires the underlying `*mut` pointer. - #[stable(feature = "nonnull", since = "1.24.0")] + #[stable(feature = "nonnull", since = "1.25.0")] pub fn as_ptr(self) -> *mut T { self.pointer.get() as *mut T } @@ -2546,7 +2546,7 @@ impl NonNull { /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`. - #[stable(feature = "nonnull", since = "1.24.0")] + #[stable(feature = "nonnull", since = "1.25.0")] pub unsafe fn as_ref(&self) -> &T { &*self.as_ptr() } @@ -2556,47 +2556,47 @@ impl NonNull { /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`. - #[stable(feature = "nonnull", since = "1.24.0")] + #[stable(feature = "nonnull", since = "1.25.0")] pub unsafe fn as_mut(&mut self) -> &mut T { &mut *self.as_ptr() } } -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl Clone for NonNull { fn clone(&self) -> Self { *self } } -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl Copy for NonNull { } -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl CoerceUnsized> for NonNull where T: Unsize { } -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl fmt::Pointer for NonNull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&self.as_ptr(), f) } } -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl From> for NonNull { fn from(unique: Unique) -> Self { NonNull { pointer: unique.pointer } } } -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl<'a, T: ?Sized> From<&'a mut T> for NonNull { fn from(reference: &'a mut T) -> Self { NonNull { pointer: NonZero::from(reference) } } } -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl<'a, T: ?Sized> From<&'a T> for NonNull { fn from(reference: &'a T) -> Self { NonNull { pointer: NonZero::from(reference) } diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 560876006d3..112e1106093 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -198,7 +198,7 @@ impl UnwindSafe for *const T {} impl UnwindSafe for *mut T {} #[unstable(feature = "ptr_internals", issue = "0")] impl UnwindSafe for Unique {} -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl UnwindSafe for NonNull {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl UnwindSafe for Mutex {} -- cgit 1.4.1-3-g733a5 From ad37e3fc01b533994dfb30f703c28ecdbf66fe10 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sun, 21 Jan 2018 09:48:58 +0100 Subject: Move Debug for NonNull impl closer to other trait impls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libcore/ptr.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 607e4a1a9fa..c3b7c4f5d22 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2487,13 +2487,6 @@ pub struct NonNull { pointer: NonZero<*const T>, } -#[stable(feature = "nonnull", since = "1.25.0")] -impl fmt::Debug for NonNull { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Pointer::fmt(&self.as_ptr(), f) - } -} - /// `NonNull` pointers are not `Send` because the data they reference may be aliased. // NB: This impl is unnecessary, but should provide better error messages. #[stable(feature = "nonnull", since = "1.25.0")] @@ -2575,6 +2568,13 @@ impl Copy for NonNull { } #[stable(feature = "nonnull", since = "1.25.0")] impl CoerceUnsized> for NonNull where T: Unsize { } +#[stable(feature = "nonnull", since = "1.25.0")] +impl fmt::Debug for NonNull { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Pointer::fmt(&self.as_ptr(), f) + } +} + #[stable(feature = "nonnull", since = "1.25.0")] impl fmt::Pointer for NonNull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -- cgit 1.4.1-3-g733a5 From 6461c9bdd35d6273b88f22fd5e8708eaf8949283 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sun, 21 Jan 2018 09:51:19 +0100 Subject: Implement Eq, PartialEq, Ord, PartialOrd, and Hash for NonNull<_> --- src/libcore/ptr.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index c3b7c4f5d22..a0d716fb574 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2582,6 +2582,37 @@ impl fmt::Pointer for NonNull { } } +#[stable(feature = "nonnull", since = "1.25.0")] +impl Eq for NonNull {} + +#[stable(feature = "nonnull", since = "1.25.0")] +impl PartialEq for NonNull { + fn eq(&self, other: &Self) -> bool { + self.as_ptr() == other.as_ptr() + } +} + +#[stable(feature = "nonnull", since = "1.25.0")] +impl Ord for NonNull { + fn cmp(&self, other: &Self) -> Ordering { + self.as_ptr().cmp(&other.as_ptr()) + } +} + +#[stable(feature = "nonnull", since = "1.25.0")] +impl PartialOrd for NonNull { + fn partial_cmp(&self, other: &Self) -> Option { + self.as_ptr().partial_cmp(&other.as_ptr()) + } +} + +#[stable(feature = "nonnull", since = "1.25.0")] +impl hash::Hash for NonNull { + fn hash(&self, state: &mut H) { + self.as_ptr().hash(state) + } +} + #[stable(feature = "nonnull", since = "1.25.0")] impl From> for NonNull { fn from(unique: Unique) -> Self { -- cgit 1.4.1-3-g733a5 From f129374d11d51ca23d85bc678fbc1ed4e7082ab1 Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 21 Jan 2018 19:45:27 +0000 Subject: Use repeat instead of RangeFrom --- src/libcore/iter/mod.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index d1fdedd1b23..4490f15f446 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -305,12 +305,10 @@ //! successfully for any infinite iterators. //! //! ```no_run -//! let positives = 1..; -//! let least = positives.min().unwrap(); // Oh no! An infinite loop! -//! // `positives.min` will either overflow and panic (in debug mode), -//! // or cause an infinite loop (in release mode), so we won't reach -//! // this point! -//! println!("The least positive number is {}.", least); +//! let ones = std::iter::repeat(1); +//! let least = ones.min().unwrap(); // Oh no! An infinite loop! +//! // `ones.min()` causes an infinite loop, so we won't reach this point! +//! println!("The smallest number one is {}.", least); //! ``` //! //! [`take`]: trait.Iterator.html#method.take -- cgit 1.4.1-3-g733a5 From b8ffc8a3d8c181e958d2ddf4f108f0cd3a108013 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sun, 21 Jan 2018 09:56:33 +0100 Subject: Add an unstable `cast() -> NonNull` method to `NonNull`. This is less verbose than going through raw pointers to cast with `as`. --- src/libcore/ptr.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index a0d716fb574..3d84e910fe6 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2553,6 +2553,14 @@ impl NonNull { pub unsafe fn as_mut(&mut self) -> &mut T { &mut *self.as_ptr() } + + /// Cast to a pointer of another type + #[unstable(feature = "nonnull_cast", issue = "47653")] + pub fn cast(self) -> NonNull { + unsafe { + NonNull::new_unchecked(self.as_ptr() as *mut U) + } + } } #[stable(feature = "nonnull", since = "1.25.0")] -- cgit 1.4.1-3-g733a5 From 2f98f4b12b8fd5d93ffff3d7b98931b3f1f2b07a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 23 Jan 2018 16:31:53 +0100 Subject: Move PanicInfo and Location to libcore Per https://rust-lang.github.io/rfcs/2070-panic-implementation.html --- src/libcore/lib.rs | 1 + src/libcore/panic.rs | 213 ++++++++++++++++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 1 + src/libstd/panic.rs | 5 +- src/libstd/panicking.rs | 200 +++------------------------------------------ 5 files changed, 230 insertions(+), 190 deletions(-) create mode 100644 src/libcore/panic.rs (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index d5190b65863..11476a05dd3 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -158,6 +158,7 @@ pub mod array; pub mod sync; pub mod cell; pub mod char; +pub mod panic; pub mod panicking; pub mod iter; pub mod option; diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs new file mode 100644 index 00000000000..dbfe531063b --- /dev/null +++ b/src/libcore/panic.rs @@ -0,0 +1,213 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Panic support in the standard library. + +#![unstable(feature = "core_panic_info", + reason = "newly available in libcore", + issue = "44489")] + +use any::Any; + +/// A struct providing information about a panic. +/// +/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`] +/// function. +/// +/// [`set_hook`]: ../../std/panic/fn.set_hook.html +/// +/// # Examples +/// +/// ```should_panic +/// use std::panic; +/// +/// panic::set_hook(Box::new(|panic_info| { +/// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); +/// })); +/// +/// panic!("Normal panic"); +/// ``` +#[stable(feature = "panic_hooks", since = "1.10.0")] +#[derive(Debug)] +pub struct PanicInfo<'a> { + payload: &'a (Any + Send), + location: Location<'a>, +} + +impl<'a> PanicInfo<'a> { + #![unstable(feature = "panic_internals", + reason = "internal details of the implementation of the `panic!` \ + and related macros", + issue = "0")] + #[doc(hidden)] + pub fn internal_constructor(payload: &'a (Any + Send), location: Location<'a>,) -> Self { + PanicInfo { payload, location } + } + + /// Returns the payload associated with the panic. + /// + /// This will commonly, but not always, be a `&'static str` or [`String`]. + /// + /// [`String`]: ../../std/string/struct.String.html + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[stable(feature = "panic_hooks", since = "1.10.0")] + pub fn payload(&self) -> &(Any + Send) { + self.payload + } + + /// Returns information about the location from which the panic originated, + /// if available. + /// + /// This method will currently always return [`Some`], but this may change + /// in future versions. + /// + /// [`Some`]: ../../std/option/enum.Option.html#variant.Some + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// if let Some(location) = panic_info.location() { + /// println!("panic occurred in file '{}' at line {}", location.file(), + /// location.line()); + /// } else { + /// println!("panic occurred but can't get location information..."); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[stable(feature = "panic_hooks", since = "1.10.0")] + pub fn location(&self) -> Option<&Location> { + // NOTE: If this is changed to sometimes return None, + // deal with that case in std::panicking::default_hook. + Some(&self.location) + } +} + +/// A struct containing information about the location of a panic. +/// +/// This structure is created by the [`location`] method of [`PanicInfo`]. +/// +/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location +/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html +/// +/// # Examples +/// +/// ```should_panic +/// use std::panic; +/// +/// panic::set_hook(Box::new(|panic_info| { +/// if let Some(location) = panic_info.location() { +/// println!("panic occurred in file '{}' at line {}", location.file(), location.line()); +/// } else { +/// println!("panic occurred but can't get location information..."); +/// } +/// })); +/// +/// panic!("Normal panic"); +/// ``` +#[derive(Debug)] +#[stable(feature = "panic_hooks", since = "1.10.0")] +pub struct Location<'a> { + file: &'a str, + line: u32, + col: u32, +} + +impl<'a> Location<'a> { + #![unstable(feature = "panic_internals", + reason = "internal details of the implementation of the `panic!` \ + and related macros", + issue = "0")] + #[doc(hidden)] + pub fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self { + Location { file, line, col } + } + + /// Returns the name of the source file from which the panic originated. + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// if let Some(location) = panic_info.location() { + /// println!("panic occurred in file '{}'", location.file()); + /// } else { + /// println!("panic occurred but can't get location information..."); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[stable(feature = "panic_hooks", since = "1.10.0")] + pub fn file(&self) -> &str { + self.file + } + + /// Returns the line number from which the panic originated. + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// if let Some(location) = panic_info.location() { + /// println!("panic occurred at line {}", location.line()); + /// } else { + /// println!("panic occurred but can't get location information..."); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[stable(feature = "panic_hooks", since = "1.10.0")] + pub fn line(&self) -> u32 { + self.line + } + + /// Returns the column from which the panic originated. + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// if let Some(location) = panic_info.location() { + /// println!("panic occurred at column {}", location.column()); + /// } else { + /// println!("panic occurred but can't get location information..."); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[stable(feature = "panic_col", since = "1.25")] + pub fn column(&self) -> u32 { + self.col + } +} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 91cc6d25cce..4b374dc1407 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -288,6 +288,7 @@ #![feature(on_unimplemented)] #![feature(oom)] #![feature(optin_builtin_traits)] +#![feature(panic_internals)] #![feature(panic_unwind)] #![feature(peek)] #![feature(placement_in_syntax)] diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 560876006d3..566ef16f295 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -23,7 +23,10 @@ use sync::{Arc, Mutex, RwLock, atomic}; use thread::Result; #[stable(feature = "panic_hooks", since = "1.10.0")] -pub use panicking::{take_hook, set_hook, PanicInfo, Location}; +pub use panicking::{take_hook, set_hook}; + +#[stable(feature = "panic_hooks", since = "1.10.0")] +pub use core::panic::{PanicInfo, Location}; /// A marker trait which represents "panic safe" types in Rust. /// diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index f91eaf433d7..a748c89f9d4 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -21,6 +21,7 @@ use io::prelude::*; use any::Any; use cell::RefCell; +use core::panic::{PanicInfo, Location}; use fmt; use intrinsics; use mem; @@ -158,182 +159,6 @@ pub fn take_hook() -> Box { } } -/// A struct providing information about a panic. -/// -/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`] -/// function. -/// -/// [`set_hook`]: ../../std/panic/fn.set_hook.html -/// -/// # Examples -/// -/// ```should_panic -/// use std::panic; -/// -/// panic::set_hook(Box::new(|panic_info| { -/// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); -/// })); -/// -/// panic!("Normal panic"); -/// ``` -#[stable(feature = "panic_hooks", since = "1.10.0")] -#[derive(Debug)] -pub struct PanicInfo<'a> { - payload: &'a (Any + Send), - location: Location<'a>, -} - -impl<'a> PanicInfo<'a> { - /// Returns the payload associated with the panic. - /// - /// This will commonly, but not always, be a `&'static str` or [`String`]. - /// - /// [`String`]: ../../std/string/struct.String.html - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn payload(&self) -> &(Any + Send) { - self.payload - } - - /// Returns information about the location from which the panic originated, - /// if available. - /// - /// This method will currently always return [`Some`], but this may change - /// in future versions. - /// - /// [`Some`]: ../../std/option/enum.Option.html#variant.Some - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// if let Some(location) = panic_info.location() { - /// println!("panic occurred in file '{}' at line {}", location.file(), - /// location.line()); - /// } else { - /// println!("panic occurred but can't get location information..."); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn location(&self) -> Option<&Location> { - Some(&self.location) - } -} - -/// A struct containing information about the location of a panic. -/// -/// This structure is created by the [`location`] method of [`PanicInfo`]. -/// -/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location -/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html -/// -/// # Examples -/// -/// ```should_panic -/// use std::panic; -/// -/// panic::set_hook(Box::new(|panic_info| { -/// if let Some(location) = panic_info.location() { -/// println!("panic occurred in file '{}' at line {}", location.file(), location.line()); -/// } else { -/// println!("panic occurred but can't get location information..."); -/// } -/// })); -/// -/// panic!("Normal panic"); -/// ``` -#[derive(Debug)] -#[stable(feature = "panic_hooks", since = "1.10.0")] -pub struct Location<'a> { - file: &'a str, - line: u32, - col: u32, -} - -impl<'a> Location<'a> { - /// Returns the name of the source file from which the panic originated. - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// if let Some(location) = panic_info.location() { - /// println!("panic occurred in file '{}'", location.file()); - /// } else { - /// println!("panic occurred but can't get location information..."); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn file(&self) -> &str { - self.file - } - - /// Returns the line number from which the panic originated. - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// if let Some(location) = panic_info.location() { - /// println!("panic occurred at line {}", location.line()); - /// } else { - /// println!("panic occurred but can't get location information..."); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn line(&self) -> u32 { - self.line - } - - /// Returns the column from which the panic originated. - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// if let Some(location) = panic_info.location() { - /// println!("panic occurred at column {}", location.column()); - /// } else { - /// println!("panic occurred but can't get location information..."); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_col", since = "1.25")] - pub fn column(&self) -> u32 { - self.col - } -} - fn default_hook(info: &PanicInfo) { #[cfg(feature = "backtrace")] use sys_common::backtrace; @@ -351,13 +176,14 @@ fn default_hook(info: &PanicInfo) { } }; - let file = info.location.file; - let line = info.location.line; - let col = info.location.col; + let location = info.location().unwrap(); // The current implementation always returns Some + let file = location.file(); + let line = location.line(); + let col = location.column(); - let msg = match info.payload.downcast_ref::<&'static str>() { + let msg = match info.payload().downcast_ref::<&'static str>() { Some(s) => *s, - None => match info.payload.downcast_ref::() { + None => match info.payload().downcast_ref::() { Some(s) => &s[..], None => "Box", } @@ -563,14 +389,10 @@ fn rust_panic_with_hook(msg: Box, } unsafe { - let info = PanicInfo { - payload: &*msg, - location: Location { - file, - line, - col, - }, - }; + let info = PanicInfo::internal_constructor( + &*msg, + Location::internal_constructor(file, line, col), + ); HOOK_LOCK.read(); match HOOK { Hook::Default => default_hook(&info), -- cgit 1.4.1-3-g733a5 From 9e96c1ef7fcac0ac85b3c9160f5486e91dd27dd2 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 23 Jan 2018 17:24:19 +0100 Subject: Add an unstable PanicInfo::message(&self) -> Option<&fmt::Arguments> method --- src/libcore/panic.rs | 19 +++++++++++++++++-- src/libstd/panicking.rs | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index dbfe531063b..2dfd950225c 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -15,6 +15,7 @@ issue = "44489")] use any::Any; +use fmt; /// A struct providing information about a panic. /// @@ -38,6 +39,7 @@ use any::Any; #[derive(Debug)] pub struct PanicInfo<'a> { payload: &'a (Any + Send), + message: Option<&'a fmt::Arguments<'a>>, location: Location<'a>, } @@ -47,8 +49,11 @@ impl<'a> PanicInfo<'a> { and related macros", issue = "0")] #[doc(hidden)] - pub fn internal_constructor(payload: &'a (Any + Send), location: Location<'a>,) -> Self { - PanicInfo { payload, location } + pub fn internal_constructor(payload: &'a (Any + Send), + message: Option<&'a fmt::Arguments<'a>>, + location: Location<'a>) + -> Self { + PanicInfo { payload, location, message } } /// Returns the payload associated with the panic. @@ -73,6 +78,16 @@ impl<'a> PanicInfo<'a> { self.payload } + /// If the `panic!` macro from the `core` crate (not from `std`) + /// was used with a formatting string and some additional arguments, + /// returns that message ready to be used for example with [`fmt::write`] + /// + /// [`fmt::write`]: ../fmt/fn.write.html + #[unstable(feature = "panic_info_message", issue = "44489")] + pub fn message(&self) -> Option<&fmt::Arguments> { + self.message + } + /// Returns information about the location from which the panic originated, /// if available. /// diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index a748c89f9d4..3f5523548ce 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -391,6 +391,7 @@ fn rust_panic_with_hook(msg: Box, unsafe { let info = PanicInfo::internal_constructor( &*msg, + None, Location::internal_constructor(file, line, col), ); HOOK_LOCK.read(); -- cgit 1.4.1-3-g733a5 From 0e60287b4136bcede0c5eae8ab4e5de8496a16f0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 23 Jan 2018 17:49:43 +0100 Subject: Implement Display for PanicInfo and Location MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Due to being in libcore, this impl cannot access PanicInfo::payload if it’s a String. --- src/libcore/panic.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 2dfd950225c..cf8ceff6cda 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -120,6 +120,23 @@ impl<'a> PanicInfo<'a> { } } +impl<'a> fmt::Display for PanicInfo<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("panicked at ")?; + if let Some(message) = self.message { + write!(formatter, "'{}', ", message)? + } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() { + write!(formatter, "'{}', ", payload)? + } + // NOTE: we cannot use downcast_ref::() here + // since String is not available in libcore! + // A String payload and no message is what we’d get from `std::panic!` + // called with multiple arguments. + + self.location.fmt(formatter) + } +} + /// A struct containing information about the location of a panic. /// /// This structure is created by the [`location`] method of [`PanicInfo`]. @@ -226,3 +243,9 @@ impl<'a> Location<'a> { self.col } } + +impl<'a> fmt::Display for Location<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "{}:{}:{}", self.file, self.line, self.col) + } +} -- cgit 1.4.1-3-g733a5 From f15c8169327244730f8e68598bf85d288e16fd70 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 23 Jan 2018 18:19:21 +0100 Subject: Make PanicInfo::message available for std::panic! with a formatting string. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables PanicInfo’s Display impl to show the panic message in those cases. --- src/libcore/panic.rs | 4 ++-- src/libstd/panicking.rs | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index cf8ceff6cda..14eb68d9b95 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -130,8 +130,8 @@ impl<'a> fmt::Display for PanicInfo<'a> { } // NOTE: we cannot use downcast_ref::() here // since String is not available in libcore! - // A String payload and no message is what we’d get from `std::panic!` - // called with multiple arguments. + // The payload is a String when `std::panic!` is called with multiple arguments, + // but in that case the message is also available. self.location.fmt(formatter) } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 3f5523548ce..161c3fc7113 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -344,7 +344,7 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, let mut s = String::new(); let _ = s.write_fmt(*msg); - begin_panic(s, file_line_col) + rust_panic_with_hook(Box::new(s), Some(msg), file_line_col) } /// This is the entry point of panicking for panic!() and assert!(). @@ -360,7 +360,7 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 // be performed in the parent of this thread instead of the thread that's // panicking. - rust_panic_with_hook(Box::new(msg), file_line_col) + rust_panic_with_hook(Box::new(msg), None, file_line_col) } /// Executes the primary logic for a panic, including checking for recursive @@ -371,7 +371,8 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 /// run panic hooks, and then delegate to the actual implementation of panics. #[inline(never)] #[cold] -fn rust_panic_with_hook(msg: Box, +fn rust_panic_with_hook(payload: Box, + message: Option<&fmt::Arguments>, file_line_col: &(&'static str, u32, u32)) -> ! { let (file, line, col) = *file_line_col; @@ -390,8 +391,8 @@ fn rust_panic_with_hook(msg: Box, unsafe { let info = PanicInfo::internal_constructor( - &*msg, - None, + &*payload, + message, Location::internal_constructor(file, line, col), ); HOOK_LOCK.read(); @@ -412,7 +413,7 @@ fn rust_panic_with_hook(msg: Box, unsafe { intrinsics::abort() } } - rust_panic(msg) + rust_panic(payload) } /// Shim around rust_panic. Called by resume_unwind. -- cgit 1.4.1-3-g733a5 From 399dcd112725a35352075262863781b3355452cd Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 24 Jan 2018 22:25:42 +0100 Subject: Add missing micro version number component in stability attributes. --- src/liballoc/heap.rs | 2 +- src/libcore/panic.rs | 2 +- src/libcore/ptr.rs | 2 +- src/libstd/net/mod.rs | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 37af9ea5295..372d606e457 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -232,7 +232,7 @@ unsafe impl Alloc for Heap { /// /// This preserves the non-null invariant for types like `Box`. The address /// may overlap with non-zero-size memory allocations. -#[rustc_deprecated(since = "1.19", reason = "Use Unique/NonNull::empty() instead")] +#[rustc_deprecated(since = "1.19.0", reason = "Use Unique/NonNull::empty() instead")] #[unstable(feature = "heap_api", issue = "27700")] pub const EMPTY: *mut () = 1 as *mut (); diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 14eb68d9b95..4e72eaa57c7 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -238,7 +238,7 @@ impl<'a> Location<'a> { /// /// panic!("Normal panic"); /// ``` - #[stable(feature = "panic_col", since = "1.25")] + #[stable(feature = "panic_col", since = "1.25.0")] pub fn column(&self) -> u32 { self.col } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index fab5832d905..2c1dfb13633 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2461,7 +2461,7 @@ impl<'a, T: ?Sized> From> for Unique { } /// Previous name of `NonNull`. -#[rustc_deprecated(since = "1.24", reason = "renamed to `NonNull`")] +#[rustc_deprecated(since = "1.25.0", reason = "renamed to `NonNull`")] #[unstable(feature = "shared", issue = "27730")] pub type Shared = NonNull; diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index eb0e2e13b4c..eef043683b0 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -134,14 +134,14 @@ fn each_addr(addr: A, mut f: F) -> io::Result iterator and returning socket \ addresses", issue = "27705")] -#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")] +#[rustc_deprecated(since = "1.25.0", reason = "Use the ToSocketAddrs trait instead")] pub struct LookupHost(net_imp::LookupHost); #[unstable(feature = "lookup_host", reason = "unsure about the returned \ iterator and returning socket \ addresses", issue = "27705")] -#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")] +#[rustc_deprecated(since = "1.25.0", reason = "Use the ToSocketAddrs trait instead")] #[allow(deprecated)] impl Iterator for LookupHost { type Item = SocketAddr; @@ -152,7 +152,7 @@ impl Iterator for LookupHost { iterator and returning socket \ addresses", issue = "27705")] -#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")] +#[rustc_deprecated(since = "1.25.0", reason = "Use the ToSocketAddrs trait instead")] #[allow(deprecated)] impl fmt::Debug for LookupHost { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -186,7 +186,7 @@ impl fmt::Debug for LookupHost { iterator and returning socket \ addresses", issue = "27705")] -#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")] +#[rustc_deprecated(since = "1.25.0", reason = "Use the ToSocketAddrs trait instead")] #[allow(deprecated)] pub fn lookup_host(host: &str) -> io::Result { net_imp::lookup_host(host).map(LookupHost) -- cgit 1.4.1-3-g733a5 From 4f7109a42482e266410b23fedc9643a6d76e5fa5 Mon Sep 17 00:00:00 2001 From: arthurprs Date: Fri, 26 Jan 2018 12:49:14 +0100 Subject: Use the slice length to hint the optimizer Using the len of the iterator doesn't give the same result. That's also why we can't generalize it to all TrustedLen iterators. --- src/libcore/slice/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index d088d4e6634..ac70ae583c7 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1223,7 +1223,8 @@ macro_rules! iterator { P: FnMut(Self::Item) -> bool, { // The addition might panic on overflow - let n = self.len(); + // Use the len of the slice to hint optimizer to remove result index bounds check. + let n = make_slice!(self.ptr, self.end).len(); self.try_fold(0, move |i, x| { if predicate(x) { Err(i) } else { Ok(i + 1) } @@ -1241,7 +1242,8 @@ macro_rules! iterator { { // No need for an overflow check here, because `ExactSizeIterator` // implies that the number of elements fits into a `usize`. - let n = self.len(); + // Use the len of the slice to hint optimizer to remove result index bounds check. + let n = make_slice!(self.ptr, self.end).len(); self.try_rfold(n, move |i, x| { let i = i - 1; if predicate(x) { Err(i) } -- cgit 1.4.1-3-g733a5 From 838ddbf908f63a0a3d8629d9dc16592a27a8ba30 Mon Sep 17 00:00:00 2001 From: tinaun Date: Fri, 26 Jan 2018 18:52:27 -0500 Subject: derive PartialEq and Eq for `ParseCharError` unlike the other Parse*Error types, ParseCharError didn't have these implemented for whatever reason --- src/libcore/char.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/char.rs b/src/libcore/char.rs index e8b81db0706..7215bd2a476 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -211,7 +211,7 @@ impl From for char { /// An error which can be returned when parsing a char. #[stable(feature = "char_from_str", since = "1.20.0")] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct ParseCharError { kind: CharErrorKind, } -- cgit 1.4.1-3-g733a5 From 81e49597bf3fe4fb2dfe9f60325079ff6bb916a0 Mon Sep 17 00:00:00 2001 From: penpalperson <16357077+penpalperson@users.noreply.github.com> Date: Sun, 28 Jan 2018 21:55:05 -0700 Subject: Added inline to fmt for debug implementations of primitives. --- src/libcore/array.rs | 1 + src/libcore/fmt/float.rs | 1 + src/libcore/fmt/mod.rs | 10 ++++++++++ src/libcore/fmt/num.rs | 1 + src/libcore/ptr.rs | 1 + 5 files changed, 14 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 3d24f8902bd..28f1da27bdb 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -185,6 +185,7 @@ macro_rules! array_impls { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for [T; $N] { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&&self[..], f) } diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs index 03e7a9a49d8..24ffe8c6888 100644 --- a/src/libcore/fmt/float.rs +++ b/src/libcore/fmt/float.rs @@ -125,6 +125,7 @@ macro_rules! floating { ($ty:ident) => ( #[stable(feature = "rust1", since = "1.0.0")] impl Debug for $ty { + #[inline] fn fmt(&self, fmt: &mut Formatter) -> Result { float_to_decimal_common(fmt, self, true, 1) } diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 65aacb23bd7..b4d23d153d8 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1558,10 +1558,12 @@ macro_rules! fmt_refs { $( #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized + $tr> $tr for &'a T { + #[inline] fn fmt(&self, f: &mut Formatter) -> Result { $tr::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized + $tr> $tr for &'a mut T { + #[inline] fn fmt(&self, f: &mut Formatter) -> Result { $tr::fmt(&**self, f) } } )* @@ -1586,6 +1588,7 @@ impl Display for ! { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for bool { + #[inline] fn fmt(&self, f: &mut Formatter) -> Result { Display::fmt(self, f) } @@ -1600,6 +1603,7 @@ impl Display for bool { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for str { + #[inline] fn fmt(&self, f: &mut Formatter) -> Result { f.write_char('"')?; let mut from = 0; @@ -1628,6 +1632,7 @@ impl Display for str { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for char { + #[inline] fn fmt(&self, f: &mut Formatter) -> Result { f.write_char('\'')?; for c in self.escape_debug() { @@ -1701,10 +1706,12 @@ impl<'a, T: ?Sized> Pointer for &'a mut T { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for *const T { + #[inline] fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) } } #[stable(feature = "rust1", since = "1.0.0")] impl Debug for *mut T { + #[inline] fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) } } @@ -1718,6 +1725,7 @@ macro_rules! tuple { #[stable(feature = "rust1", since = "1.0.0")] impl<$($name:Debug),*> Debug for ($($name,)*) where last_type!($($name,)+): ?Sized { #[allow(non_snake_case, unused_assignments, deprecated)] + #[inline] fn fmt(&self, f: &mut Formatter) -> Result { let mut builder = f.debug_tuple(""); let ($(ref $name,)*) = *self; @@ -1741,6 +1749,7 @@ tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } #[stable(feature = "rust1", since = "1.0.0")] impl Debug for [T] { + #[inline] fn fmt(&self, f: &mut Formatter) -> Result { f.debug_list().entries(self.iter()).finish() } @@ -1748,6 +1757,7 @@ impl Debug for [T] { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for () { + #[inline] fn fmt(&self, f: &mut Formatter) -> Result { f.pad("()") } diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index ee989854a37..2992e7cf8db 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -157,6 +157,7 @@ macro_rules! debug { ($T:ident) => { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for $T { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index fab5832d905..3e162afd649 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2202,6 +2202,7 @@ macro_rules! fnptr_impls_safety_abi { #[stable(feature = "fnptr_impls", since = "1.4.0")] impl fmt::Debug for $FnTy { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&(*self as *const ()), f) } -- cgit 1.4.1-3-g733a5 From aab712cbc8f657f3e87dacd762d23c80e589ac95 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Mon, 11 Dec 2017 13:42:01 -0500 Subject: Move time::Duration to libcore --- src/libcore/lib.rs | 1 + src/libcore/time.rs | 603 ++++++++++++++++++++++++++++++++++++++++++++ src/libstd/time.rs | 565 +++++++++++++++++++++++++++++++++++++++++ src/libstd/time/duration.rs | 590 ------------------------------------------- src/libstd/time/mod.rs | 567 ----------------------------------------- 5 files changed, 1169 insertions(+), 1157 deletions(-) create mode 100644 src/libcore/time.rs create mode 100644 src/libstd/time.rs delete mode 100644 src/libstd/time/duration.rs delete mode 100644 src/libstd/time/mod.rs (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index d5190b65863..2e1f925c49a 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -168,6 +168,7 @@ pub mod slice; pub mod str; pub mod hash; pub mod fmt; +pub mod time; // note: does not need to be public mod char_private; diff --git a/src/libcore/time.rs b/src/libcore/time.rs new file mode 100644 index 00000000000..1a0208d2f25 --- /dev/null +++ b/src/libcore/time.rs @@ -0,0 +1,603 @@ +// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![stable(feature = "duration_core", since = "1.24.0")] + +//! Temporal quantification. +//! +//! Example: +//! +//! ``` +//! use std::time::Duration; +//! +//! let five_seconds = Duration::new(5, 0); +//! // both declarations are equivalent +//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5)); +//! ``` + +use iter::Sum; +use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign}; + +const NANOS_PER_SEC: u32 = 1_000_000_000; +const NANOS_PER_MILLI: u32 = 1_000_000; +const NANOS_PER_MICRO: u32 = 1_000; +const MILLIS_PER_SEC: u64 = 1_000; +const MICROS_PER_SEC: u64 = 1_000_000; + +/// A `Duration` type to represent a span of time, typically used for system +/// timeouts. +/// +/// Each `Duration` is composed of a whole number of seconds and a fractional part +/// represented in nanoseconds. If the underlying system does not support +/// nanosecond-level precision, APIs binding a system timeout will typically round up +/// the number of nanoseconds. +/// +/// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other +/// [`ops`] traits. +/// +/// [`Add`]: ../../std/ops/trait.Add.html +/// [`Sub`]: ../../std/ops/trait.Sub.html +/// [`ops`]: ../../std/ops/index.html +/// +/// # Examples +/// +/// ``` +/// use std::time::Duration; +/// +/// let five_seconds = Duration::new(5, 0); +/// let five_seconds_and_five_nanos = five_seconds + Duration::new(0, 5); +/// +/// assert_eq!(five_seconds_and_five_nanos.as_secs(), 5); +/// assert_eq!(five_seconds_and_five_nanos.subsec_nanos(), 5); +/// +/// let ten_millis = Duration::from_millis(10); +/// ``` +#[stable(feature = "duration_core", since = "1.24.0")] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] +pub struct Duration { + secs: u64, + nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC +} + +impl Duration { + /// Creates a new `Duration` from the specified number of whole seconds and + /// additional nanoseconds. + /// + /// If the number of nanoseconds is greater than 1 billion (the number of + /// nanoseconds in a second), then it will carry over into the seconds provided. + /// + /// # Panics + /// + /// This constructor will panic if the carry from the nanoseconds overflows + /// the seconds counter. + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// + /// let five_seconds = Duration::new(5, 0); + /// ``` + #[stable(feature = "duration", since = "1.3.0")] + #[inline] + pub fn new(secs: u64, nanos: u32) -> Duration { + let secs = secs.checked_add((nanos / NANOS_PER_SEC) as u64) + .expect("overflow in Duration::new"); + let nanos = nanos % NANOS_PER_SEC; + Duration { secs: secs, nanos: nanos } + } + + /// Creates a new `Duration` from the specified number of whole seconds. + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// + /// let duration = Duration::from_secs(5); + /// + /// assert_eq!(5, duration.as_secs()); + /// assert_eq!(0, duration.subsec_nanos()); + /// ``` + #[stable(feature = "duration", since = "1.3.0")] + #[inline] + pub const fn from_secs(secs: u64) -> Duration { + Duration { secs: secs, nanos: 0 } + } + + /// Creates a new `Duration` from the specified number of milliseconds. + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// + /// let duration = Duration::from_millis(2569); + /// + /// assert_eq!(2, duration.as_secs()); + /// assert_eq!(569_000_000, duration.subsec_nanos()); + /// ``` + #[stable(feature = "duration", since = "1.3.0")] + #[inline] + pub const fn from_millis(millis: u64) -> Duration { + Duration { + secs: millis / MILLIS_PER_SEC, + nanos: ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI, + } + } + + /// Creates a new `Duration` from the specified number of microseconds. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_from_micros)] + /// use std::time::Duration; + /// + /// let duration = Duration::from_micros(1_000_002); + /// + /// assert_eq!(1, duration.as_secs()); + /// assert_eq!(2000, duration.subsec_nanos()); + /// ``` + #[unstable(feature = "duration_from_micros", issue = "44400")] + #[inline] + pub const fn from_micros(micros: u64) -> Duration { + Duration { + secs: micros / MICROS_PER_SEC, + nanos: ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO, + } + } + + /// Creates a new `Duration` from the specified number of nanoseconds. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_extras)] + /// use std::time::Duration; + /// + /// let duration = Duration::from_nanos(1_000_000_123); + /// + /// assert_eq!(1, duration.as_secs()); + /// assert_eq!(123, duration.subsec_nanos()); + /// ``` + #[unstable(feature = "duration_extras", issue = "46507")] + #[inline] + pub const fn from_nanos(nanos: u64) -> Duration { + Duration { + secs: nanos / (NANOS_PER_SEC as u64), + nanos: (nanos % (NANOS_PER_SEC as u64)) as u32, + } + } + + /// Returns the number of _whole_ seconds contained by this `Duration`. + /// + /// The returned value does not include the fractional (nanosecond) part of the + /// duration, which can be obtained using [`subsec_nanos`]. + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// + /// let duration = Duration::new(5, 730023852); + /// assert_eq!(duration.as_secs(), 5); + /// ``` + /// + /// To determine the total number of seconds represented by the `Duration`, + /// use `as_secs` in combination with [`subsec_nanos`]: + /// + /// ``` + /// use std::time::Duration; + /// + /// let duration = Duration::new(5, 730023852); + /// + /// assert_eq!(5.730023852, + /// duration.as_secs() as f64 + /// + duration.subsec_nanos() as f64 * 1e-9); + /// ``` + /// + /// [`subsec_nanos`]: #method.subsec_nanos + #[stable(feature = "duration", since = "1.3.0")] + #[inline] + pub fn as_secs(&self) -> u64 { self.secs } + + /// Returns the fractional part of this `Duration`, in milliseconds. + /// + /// This method does **not** return the length of the duration when + /// represented by milliseconds. The returned number always represents a + /// fractional portion of a second (i.e. it is less than one thousand). + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_extras)] + /// use std::time::Duration; + /// + /// let duration = Duration::from_millis(5432); + /// assert_eq!(duration.as_secs(), 5); + /// assert_eq!(duration.subsec_millis(), 432); + /// ``` + #[unstable(feature = "duration_extras", issue = "46507")] + #[inline] + pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI } + + /// Returns the fractional part of this `Duration`, in microseconds. + /// + /// This method does **not** return the length of the duration when + /// represented by microseconds. The returned number always represents a + /// fractional portion of a second (i.e. it is less than one million). + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_extras, duration_from_micros)] + /// use std::time::Duration; + /// + /// let duration = Duration::from_micros(1_234_567); + /// assert_eq!(duration.as_secs(), 1); + /// assert_eq!(duration.subsec_micros(), 234_567); + /// ``` + #[unstable(feature = "duration_extras", issue = "46507")] + #[inline] + pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO } + + /// Returns the fractional part of this `Duration`, in nanoseconds. + /// + /// This method does **not** return the length of the duration when + /// represented by nanoseconds. The returned number always represents a + /// fractional portion of a second (i.e. it is less than one billion). + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// + /// let duration = Duration::from_millis(5010); + /// assert_eq!(duration.as_secs(), 5); + /// assert_eq!(duration.subsec_nanos(), 10_000_000); + /// ``` + #[stable(feature = "duration", since = "1.3.0")] + #[inline] + pub fn subsec_nanos(&self) -> u32 { self.nanos } + + /// Checked `Duration` addition. Computes `self + other`, returning [`None`] + /// if overflow occurred. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); + /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None); + /// ``` + #[stable(feature = "duration_checked_ops", since = "1.16.0")] + #[inline] + pub fn checked_add(self, rhs: Duration) -> Option { + if let Some(mut secs) = self.secs.checked_add(rhs.secs) { + let mut nanos = self.nanos + rhs.nanos; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + if let Some(new_secs) = secs.checked_add(1) { + secs = new_secs; + } else { + return None; + } + } + debug_assert!(nanos < NANOS_PER_SEC); + Some(Duration { + secs, + nanos, + }) + } else { + None + } + } + + /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`] + /// if the result would be negative or if overflow occurred. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1))); + /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None); + /// ``` + #[stable(feature = "duration_checked_ops", since = "1.16.0")] + #[inline] + pub fn checked_sub(self, rhs: Duration) -> Option { + if let Some(mut secs) = self.secs.checked_sub(rhs.secs) { + let nanos = if self.nanos >= rhs.nanos { + self.nanos - rhs.nanos + } else { + if let Some(sub_secs) = secs.checked_sub(1) { + secs = sub_secs; + self.nanos + NANOS_PER_SEC - rhs.nanos + } else { + return None; + } + }; + debug_assert!(nanos < NANOS_PER_SEC); + Some(Duration { secs: secs, nanos: nanos }) + } else { + None + } + } + + /// Checked `Duration` multiplication. Computes `self * other`, returning + /// [`None`] if overflow occurred. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2))); + /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None); + /// ``` + #[stable(feature = "duration_checked_ops", since = "1.16.0")] + #[inline] + pub fn checked_mul(self, rhs: u32) -> Option { + // Multiply nanoseconds as u64, because it cannot overflow that way. + let total_nanos = self.nanos as u64 * rhs as u64; + let extra_secs = total_nanos / (NANOS_PER_SEC as u64); + let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32; + if let Some(secs) = self.secs + .checked_mul(rhs as u64) + .and_then(|s| s.checked_add(extra_secs)) { + debug_assert!(nanos < NANOS_PER_SEC); + Some(Duration { + secs, + nanos, + }) + } else { + None + } + } + + /// Checked `Duration` division. Computes `self / other`, returning [`None`] + /// if `other == 0`. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); + /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); + /// assert_eq!(Duration::new(2, 0).checked_div(0), None); + /// ``` + #[stable(feature = "duration_checked_ops", since = "1.16.0")] + #[inline] + pub fn checked_div(self, rhs: u32) -> Option { + if rhs != 0 { + let secs = self.secs / (rhs as u64); + let carry = self.secs - secs * (rhs as u64); + let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64); + let nanos = self.nanos / rhs + (extra_nanos as u32); + debug_assert!(nanos < NANOS_PER_SEC); + Some(Duration { secs: secs, nanos: nanos }) + } else { + None + } + } +} + +#[stable(feature = "duration", since = "1.3.0")] +impl Add for Duration { + type Output = Duration; + + fn add(self, rhs: Duration) -> Duration { + self.checked_add(rhs).expect("overflow when adding durations") + } +} + +#[stable(feature = "time_augmented_assignment", since = "1.9.0")] +impl AddAssign for Duration { + fn add_assign(&mut self, rhs: Duration) { + *self = *self + rhs; + } +} + +#[stable(feature = "duration", since = "1.3.0")] +impl Sub for Duration { + type Output = Duration; + + fn sub(self, rhs: Duration) -> Duration { + self.checked_sub(rhs).expect("overflow when subtracting durations") + } +} + +#[stable(feature = "time_augmented_assignment", since = "1.9.0")] +impl SubAssign for Duration { + fn sub_assign(&mut self, rhs: Duration) { + *self = *self - rhs; + } +} + +#[stable(feature = "duration", since = "1.3.0")] +impl Mul for Duration { + type Output = Duration; + + fn mul(self, rhs: u32) -> Duration { + self.checked_mul(rhs).expect("overflow when multiplying duration by scalar") + } +} + +#[stable(feature = "time_augmented_assignment", since = "1.9.0")] +impl MulAssign for Duration { + fn mul_assign(&mut self, rhs: u32) { + *self = *self * rhs; + } +} + +#[stable(feature = "duration", since = "1.3.0")] +impl Div for Duration { + type Output = Duration; + + fn div(self, rhs: u32) -> Duration { + self.checked_div(rhs).expect("divide by zero error when dividing duration by scalar") + } +} + +#[stable(feature = "time_augmented_assignment", since = "1.9.0")] +impl DivAssign for Duration { + fn div_assign(&mut self, rhs: u32) { + *self = *self / rhs; + } +} + +#[stable(feature = "duration_sum", since = "1.16.0")] +impl Sum for Duration { + fn sum>(iter: I) -> Duration { + iter.fold(Duration::new(0, 0), |a, b| a + b) + } +} + +#[stable(feature = "duration_sum", since = "1.16.0")] +impl<'a> Sum<&'a Duration> for Duration { + fn sum>(iter: I) -> Duration { + iter.fold(Duration::new(0, 0), |a, b| a + *b) + } +} + +#[cfg(test)] +mod tests { + use super::Duration; + + #[test] + fn creation() { + assert!(Duration::from_secs(1) != Duration::from_secs(0)); + assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), + Duration::from_secs(3)); + assert_eq!(Duration::from_millis(10) + Duration::from_secs(4), + Duration::new(4, 10 * 1_000_000)); + assert_eq!(Duration::from_millis(4000), Duration::new(4, 0)); + } + + #[test] + fn secs() { + assert_eq!(Duration::new(0, 0).as_secs(), 0); + assert_eq!(Duration::from_secs(1).as_secs(), 1); + assert_eq!(Duration::from_millis(999).as_secs(), 0); + assert_eq!(Duration::from_millis(1001).as_secs(), 1); + } + + #[test] + fn nanos() { + assert_eq!(Duration::new(0, 0).subsec_nanos(), 0); + assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); + assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); + assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); + assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000); + assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000); + } + + #[test] + fn add() { + assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), + Duration::new(0, 1)); + assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), + Duration::new(1, 1)); + } + + #[test] + fn checked_add() { + assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), + Some(Duration::new(0, 1))); + assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)), + Some(Duration::new(1, 1))); + assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None); + } + + #[test] + fn sub() { + assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), + Duration::new(0, 1)); + assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), + Duration::new(0, 1)); + assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), + Duration::new(0, 999_999_999)); + } + + #[test] + fn checked_sub() { + let zero = Duration::new(0, 0); + let one_nano = Duration::new(0, 1); + let one_sec = Duration::new(1, 0); + assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1))); + assert_eq!(one_sec.checked_sub(one_nano), + Some(Duration::new(0, 999_999_999))); + assert_eq!(zero.checked_sub(one_nano), None); + assert_eq!(zero.checked_sub(one_sec), None); + } + + #[test] #[should_panic] + fn sub_bad1() { + Duration::new(0, 0) - Duration::new(0, 1); + } + + #[test] #[should_panic] + fn sub_bad2() { + Duration::new(0, 0) - Duration::new(1, 0); + } + + #[test] + fn mul() { + assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2)); + assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3)); + assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4)); + assert_eq!(Duration::new(0, 500_000_001) * 4000, + Duration::new(2000, 4000)); + } + + #[test] + fn checked_mul() { + assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2))); + assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3))); + assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4))); + assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), + Some(Duration::new(2000, 4000))); + assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None); + } + + #[test] + fn div() { + assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); + assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); + assert_eq!(Duration::new(99, 999_999_000) / 100, + Duration::new(0, 999_999_990)); + } + + #[test] + fn checked_div() { + assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); + assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); + assert_eq!(Duration::new(2, 0).checked_div(0), None); + } +} diff --git a/src/libstd/time.rs b/src/libstd/time.rs new file mode 100644 index 00000000000..12f2a9bb85f --- /dev/null +++ b/src/libstd/time.rs @@ -0,0 +1,565 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Temporal quantification. +//! +//! Example: +//! +//! ``` +//! use std::time::Duration; +//! +//! let five_seconds = Duration::new(5, 0); +//! // both declarations are equivalent +//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5)); +//! ``` + +#![stable(feature = "time", since = "1.3.0")] + +use error::Error; +use fmt; +use ops::{Add, Sub, AddAssign, SubAssign}; +use sys::time; +use sys_common::FromInner; + +#[stable(feature = "time", since = "1.3.0")] +pub use core::time::Duration; + +/// A measurement of a monotonically nondecreasing clock. +/// Opaque and useful only with `Duration`. +/// +/// Instants are always guaranteed to be no less than any previously measured +/// instant when created, and are often useful for tasks such as measuring +/// benchmarks or timing how long an operation takes. +/// +/// Note, however, that instants are not guaranteed to be **steady**. In other +/// words, each tick of the underlying clock may not be the same length (e.g. +/// some seconds may be longer than others). An instant may jump forwards or +/// experience time dilation (slow down or speed up), but it will never go +/// backwards. +/// +/// Instants are opaque types that can only be compared to one another. There is +/// no method to get "the number of seconds" from an instant. Instead, it only +/// allows measuring the duration between two instants (or comparing two +/// instants). +/// +/// Example: +/// +/// ```no_run +/// use std::time::{Duration, Instant}; +/// use std::thread::sleep; +/// +/// fn main() { +/// let now = Instant::now(); +/// +/// // we sleep for 2 seconds +/// sleep(Duration::new(2, 0)); +/// // it prints '2' +/// println!("{}", now.elapsed().as_secs()); +/// } +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[stable(feature = "time2", since = "1.8.0")] +pub struct Instant(time::Instant); + +/// A measurement of the system clock, useful for talking to +/// external entities like the file system or other processes. +/// +/// Distinct from the [`Instant`] type, this time measurement **is not +/// monotonic**. This means that you can save a file to the file system, then +/// save another file to the file system, **and the second file has a +/// `SystemTime` measurement earlier than the first**. In other words, an +/// operation that happens after another operation in real time may have an +/// earlier `SystemTime`! +/// +/// Consequently, comparing two `SystemTime` instances to learn about the +/// duration between them returns a [`Result`] instead of an infallible [`Duration`] +/// to indicate that this sort of time drift may happen and needs to be handled. +/// +/// Although a `SystemTime` cannot be directly inspected, the [`UNIX_EPOCH`] +/// constant is provided in this module as an anchor in time to learn +/// information about a `SystemTime`. By calculating the duration from this +/// fixed point in time, a `SystemTime` can be converted to a human-readable time, +/// or perhaps some other string representation. +/// +/// [`Instant`]: ../../std/time/struct.Instant.html +/// [`Result`]: ../../std/result/enum.Result.html +/// [`Duration`]: ../../std/time/struct.Duration.html +/// [`UNIX_EPOCH`]: ../../std/time/constant.UNIX_EPOCH.html +/// +/// Example: +/// +/// ```no_run +/// use std::time::{Duration, SystemTime}; +/// use std::thread::sleep; +/// +/// fn main() { +/// let now = SystemTime::now(); +/// +/// // we sleep for 2 seconds +/// sleep(Duration::new(2, 0)); +/// match now.elapsed() { +/// Ok(elapsed) => { +/// // it prints '2' +/// println!("{}", elapsed.as_secs()); +/// } +/// Err(e) => { +/// // an error occurred! +/// println!("Error: {:?}", e); +/// } +/// } +/// } +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[stable(feature = "time2", since = "1.8.0")] +pub struct SystemTime(time::SystemTime); + +/// An error returned from the `duration_since` and `elapsed` methods on +/// `SystemTime`, used to learn how far in the opposite direction a system time +/// lies. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread::sleep; +/// use std::time::{Duration, SystemTime}; +/// +/// let sys_time = SystemTime::now(); +/// sleep(Duration::from_secs(1)); +/// let new_sys_time = SystemTime::now(); +/// match sys_time.duration_since(new_sys_time) { +/// Ok(_) => {} +/// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()), +/// } +/// ``` +#[derive(Clone, Debug)] +#[stable(feature = "time2", since = "1.8.0")] +pub struct SystemTimeError(Duration); + +impl Instant { + /// Returns an instant corresponding to "now". + /// + /// # Examples + /// + /// ``` + /// use std::time::Instant; + /// + /// let now = Instant::now(); + /// ``` + #[stable(feature = "time2", since = "1.8.0")] + pub fn now() -> Instant { + Instant(time::Instant::now()) + } + + /// Returns the amount of time elapsed from another instant to this one. + /// + /// # Panics + /// + /// This function will panic if `earlier` is later than `self`. + /// + /// # Examples + /// + /// ```no_run + /// use std::time::{Duration, Instant}; + /// use std::thread::sleep; + /// + /// let now = Instant::now(); + /// sleep(Duration::new(1, 0)); + /// let new_now = Instant::now(); + /// println!("{:?}", new_now.duration_since(now)); + /// ``` + #[stable(feature = "time2", since = "1.8.0")] + pub fn duration_since(&self, earlier: Instant) -> Duration { + self.0.sub_instant(&earlier.0) + } + + /// Returns the amount of time elapsed since this instant was created. + /// + /// # Panics + /// + /// This function may panic if the current time is earlier than this + /// instant, which is something that can happen if an `Instant` is + /// produced synthetically. + /// + /// # Examples + /// + /// ```no_run + /// use std::thread::sleep; + /// use std::time::{Duration, Instant}; + /// + /// let instant = Instant::now(); + /// let three_secs = Duration::from_secs(3); + /// sleep(three_secs); + /// assert!(instant.elapsed() >= three_secs); + /// ``` + #[stable(feature = "time2", since = "1.8.0")] + pub fn elapsed(&self) -> Duration { + Instant::now() - *self + } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl Add for Instant { + type Output = Instant; + + fn add(self, other: Duration) -> Instant { + Instant(self.0.add_duration(&other)) + } +} + +#[stable(feature = "time_augmented_assignment", since = "1.9.0")] +impl AddAssign for Instant { + fn add_assign(&mut self, other: Duration) { + *self = *self + other; + } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl Sub for Instant { + type Output = Instant; + + fn sub(self, other: Duration) -> Instant { + Instant(self.0.sub_duration(&other)) + } +} + +#[stable(feature = "time_augmented_assignment", since = "1.9.0")] +impl SubAssign for Instant { + fn sub_assign(&mut self, other: Duration) { + *self = *self - other; + } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl Sub for Instant { + type Output = Duration; + + fn sub(self, other: Instant) -> Duration { + self.duration_since(other) + } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl fmt::Debug for Instant { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl SystemTime { + /// Returns the system time corresponding to "now". + /// + /// # Examples + /// + /// ``` + /// use std::time::SystemTime; + /// + /// let sys_time = SystemTime::now(); + /// ``` + #[stable(feature = "time2", since = "1.8.0")] + pub fn now() -> SystemTime { + SystemTime(time::SystemTime::now()) + } + + /// Returns the amount of time elapsed from an earlier point in time. + /// + /// This function may fail because measurements taken earlier are not + /// guaranteed to always be before later measurements (due to anomalies such + /// as the system clock being adjusted either forwards or backwards). + /// + /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents + /// the amount of time elapsed from the specified measurement to this one. + /// + /// Returns an [`Err`] if `earlier` is later than `self`, and the error + /// contains how far from `self` the time is. + /// + /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok + /// [`Duration`]: ../../std/time/struct.Duration.html + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err + /// + /// # Examples + /// + /// ``` + /// use std::time::SystemTime; + /// + /// let sys_time = SystemTime::now(); + /// let difference = sys_time.duration_since(sys_time) + /// .expect("SystemTime::duration_since failed"); + /// println!("{:?}", difference); + /// ``` + #[stable(feature = "time2", since = "1.8.0")] + pub fn duration_since(&self, earlier: SystemTime) + -> Result { + self.0.sub_time(&earlier.0).map_err(SystemTimeError) + } + + /// Returns the amount of time elapsed since this system time was created. + /// + /// This function may fail as the underlying system clock is susceptible to + /// drift and updates (e.g. the system clock could go backwards), so this + /// function may not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is + /// returned where the duration represents the amount of time elapsed from + /// this time measurement to the current time. + /// + /// Returns an [`Err`] if `self` is later than the current system time, and + /// the error contains how far from the current system time `self` is. + /// + /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok + /// [`Duration`]: ../../std/time/struct.Duration.html + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err + /// + /// # Examples + /// + /// ```no_run + /// use std::thread::sleep; + /// use std::time::{Duration, SystemTime}; + /// + /// let sys_time = SystemTime::now(); + /// let one_sec = Duration::from_secs(1); + /// sleep(one_sec); + /// assert!(sys_time.elapsed().unwrap() >= one_sec); + /// ``` + #[stable(feature = "time2", since = "1.8.0")] + pub fn elapsed(&self) -> Result { + SystemTime::now().duration_since(*self) + } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl Add for SystemTime { + type Output = SystemTime; + + fn add(self, dur: Duration) -> SystemTime { + SystemTime(self.0.add_duration(&dur)) + } +} + +#[stable(feature = "time_augmented_assignment", since = "1.9.0")] +impl AddAssign for SystemTime { + fn add_assign(&mut self, other: Duration) { + *self = *self + other; + } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl Sub for SystemTime { + type Output = SystemTime; + + fn sub(self, dur: Duration) -> SystemTime { + SystemTime(self.0.sub_duration(&dur)) + } +} + +#[stable(feature = "time_augmented_assignment", since = "1.9.0")] +impl SubAssign for SystemTime { + fn sub_assign(&mut self, other: Duration) { + *self = *self - other; + } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl fmt::Debug for SystemTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +/// An anchor in time which can be used to create new `SystemTime` instances or +/// learn about where in time a `SystemTime` lies. +/// +/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with +/// respect to the system clock. Using `duration_since` on an existing +/// [`SystemTime`] instance can tell how far away from this point in time a +/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a +/// [`SystemTime`] instance to represent another fixed point in time. +/// +/// [`SystemTime`]: ../../std/time/struct.SystemTime.html +/// +/// # Examples +/// +/// ```no_run +/// use std::time::{SystemTime, UNIX_EPOCH}; +/// +/// match SystemTime::now().duration_since(UNIX_EPOCH) { +/// Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()), +/// Err(_) => panic!("SystemTime before UNIX EPOCH!"), +/// } +/// ``` +#[stable(feature = "time2", since = "1.8.0")] +pub const UNIX_EPOCH: SystemTime = SystemTime(time::UNIX_EPOCH); + +impl SystemTimeError { + /// Returns the positive duration which represents how far forward the + /// second system time was from the first. + /// + /// A `SystemTimeError` is returned from the [`duration_since`] and [`elapsed`] + /// methods of [`SystemTime`] whenever the second system time represents a point later + /// in time than the `self` of the method call. + /// + /// [`duration_since`]: ../../std/time/struct.SystemTime.html#method.duration_since + /// [`elapsed`]: ../../std/time/struct.SystemTime.html#method.elapsed + /// [`SystemTime`]: ../../std/time/struct.SystemTime.html + /// + /// # Examples + /// + /// ```no_run + /// use std::thread::sleep; + /// use std::time::{Duration, SystemTime}; + /// + /// let sys_time = SystemTime::now(); + /// sleep(Duration::from_secs(1)); + /// let new_sys_time = SystemTime::now(); + /// match sys_time.duration_since(new_sys_time) { + /// Ok(_) => {} + /// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()), + /// } + /// ``` + #[stable(feature = "time2", since = "1.8.0")] + pub fn duration(&self) -> Duration { + self.0 + } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl Error for SystemTimeError { + fn description(&self) -> &str { "other time was not earlier than self" } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl fmt::Display for SystemTimeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "second time provided was later than self") + } +} + +impl FromInner for SystemTime { + fn from_inner(time: time::SystemTime) -> SystemTime { + SystemTime(time) + } +} + +#[cfg(test)] +mod tests { + use super::{Instant, SystemTime, Duration, UNIX_EPOCH}; + + macro_rules! assert_almost_eq { + ($a:expr, $b:expr) => ({ + let (a, b) = ($a, $b); + if a != b { + let (a, b) = if a > b {(a, b)} else {(b, a)}; + assert!(a - Duration::new(0, 100) <= b); + } + }) + } + + #[test] + fn instant_monotonic() { + let a = Instant::now(); + let b = Instant::now(); + assert!(b >= a); + } + + #[test] + fn instant_elapsed() { + let a = Instant::now(); + a.elapsed(); + } + + #[test] + fn instant_math() { + let a = Instant::now(); + let b = Instant::now(); + let dur = b.duration_since(a); + assert_almost_eq!(b - dur, a); + assert_almost_eq!(a + dur, b); + + let second = Duration::new(1, 0); + assert_almost_eq!(a - second + second, a); + } + + #[test] + #[should_panic] + fn instant_duration_panic() { + let a = Instant::now(); + (a - Duration::new(1, 0)).duration_since(a); + } + + #[test] + fn system_time_math() { + let a = SystemTime::now(); + let b = SystemTime::now(); + match b.duration_since(a) { + Ok(dur) if dur == Duration::new(0, 0) => { + assert_almost_eq!(a, b); + } + Ok(dur) => { + assert!(b > a); + assert_almost_eq!(b - dur, a); + assert_almost_eq!(a + dur, b); + } + Err(dur) => { + let dur = dur.duration(); + assert!(a > b); + assert_almost_eq!(b + dur, a); + assert_almost_eq!(a - dur, b); + } + } + + let second = Duration::new(1, 0); + assert_almost_eq!(a.duration_since(a - second).unwrap(), second); + assert_almost_eq!(a.duration_since(a + second).unwrap_err() + .duration(), second); + + assert_almost_eq!(a - second + second, a); + + // A difference of 80 and 800 years cannot fit inside a 32-bit time_t + if !(cfg!(unix) && ::mem::size_of::<::libc::time_t>() <= 4) { + let eighty_years = second * 60 * 60 * 24 * 365 * 80; + assert_almost_eq!(a - eighty_years + eighty_years, a); + assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a); + } + + let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0); + let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000) + + Duration::new(0, 500_000_000); + assert_eq!(one_second_from_epoch, one_second_from_epoch2); + } + + #[test] + fn system_time_elapsed() { + let a = SystemTime::now(); + drop(a.elapsed()); + } + + #[test] + fn since_epoch() { + let ts = SystemTime::now(); + let a = ts.duration_since(UNIX_EPOCH).unwrap(); + let b = ts.duration_since(UNIX_EPOCH - Duration::new(1, 0)).unwrap(); + assert!(b > a); + assert_eq!(b - a, Duration::new(1, 0)); + + let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30; + + // Right now for CI this test is run in an emulator, and apparently the + // aarch64 emulator's sense of time is that we're still living in the + // 70s. + // + // Otherwise let's assume that we're all running computers later than + // 2000. + if !cfg!(target_arch = "aarch64") { + assert!(a > thirty_years); + } + + // let's assume that we're all running computers earlier than 2090. + // Should give us ~70 years to fix this! + let hundred_twenty_years = thirty_years * 4; + assert!(a < hundred_twenty_years); + } +} diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs deleted file mode 100644 index ee444830be4..00000000000 --- a/src/libstd/time/duration.rs +++ /dev/null @@ -1,590 +0,0 @@ -// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use iter::Sum; -use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign}; - -const NANOS_PER_SEC: u32 = 1_000_000_000; -const NANOS_PER_MILLI: u32 = 1_000_000; -const NANOS_PER_MICRO: u32 = 1_000; -const MILLIS_PER_SEC: u64 = 1_000; -const MICROS_PER_SEC: u64 = 1_000_000; - -/// A `Duration` type to represent a span of time, typically used for system -/// timeouts. -/// -/// Each `Duration` is composed of a whole number of seconds and a fractional part -/// represented in nanoseconds. If the underlying system does not support -/// nanosecond-level precision, APIs binding a system timeout will typically round up -/// the number of nanoseconds. -/// -/// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other -/// [`ops`] traits. -/// -/// [`Add`]: ../../std/ops/trait.Add.html -/// [`Sub`]: ../../std/ops/trait.Sub.html -/// [`ops`]: ../../std/ops/index.html -/// -/// # Examples -/// -/// ``` -/// use std::time::Duration; -/// -/// let five_seconds = Duration::new(5, 0); -/// let five_seconds_and_five_nanos = five_seconds + Duration::new(0, 5); -/// -/// assert_eq!(five_seconds_and_five_nanos.as_secs(), 5); -/// assert_eq!(five_seconds_and_five_nanos.subsec_nanos(), 5); -/// -/// let ten_millis = Duration::from_millis(10); -/// ``` -#[stable(feature = "duration", since = "1.3.0")] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] -pub struct Duration { - secs: u64, - nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC -} - -impl Duration { - /// Creates a new `Duration` from the specified number of whole seconds and - /// additional nanoseconds. - /// - /// If the number of nanoseconds is greater than 1 billion (the number of - /// nanoseconds in a second), then it will carry over into the seconds provided. - /// - /// # Panics - /// - /// This constructor will panic if the carry from the nanoseconds overflows - /// the seconds counter. - /// - /// # Examples - /// - /// ``` - /// use std::time::Duration; - /// - /// let five_seconds = Duration::new(5, 0); - /// ``` - #[stable(feature = "duration", since = "1.3.0")] - #[inline] - pub fn new(secs: u64, nanos: u32) -> Duration { - let secs = secs.checked_add((nanos / NANOS_PER_SEC) as u64) - .expect("overflow in Duration::new"); - let nanos = nanos % NANOS_PER_SEC; - Duration { secs: secs, nanos: nanos } - } - - /// Creates a new `Duration` from the specified number of whole seconds. - /// - /// # Examples - /// - /// ``` - /// use std::time::Duration; - /// - /// let duration = Duration::from_secs(5); - /// - /// assert_eq!(5, duration.as_secs()); - /// assert_eq!(0, duration.subsec_nanos()); - /// ``` - #[stable(feature = "duration", since = "1.3.0")] - #[inline] - pub const fn from_secs(secs: u64) -> Duration { - Duration { secs: secs, nanos: 0 } - } - - /// Creates a new `Duration` from the specified number of milliseconds. - /// - /// # Examples - /// - /// ``` - /// use std::time::Duration; - /// - /// let duration = Duration::from_millis(2569); - /// - /// assert_eq!(2, duration.as_secs()); - /// assert_eq!(569_000_000, duration.subsec_nanos()); - /// ``` - #[stable(feature = "duration", since = "1.3.0")] - #[inline] - pub const fn from_millis(millis: u64) -> Duration { - Duration { - secs: millis / MILLIS_PER_SEC, - nanos: ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI, - } - } - - /// Creates a new `Duration` from the specified number of microseconds. - /// - /// # Examples - /// - /// ``` - /// #![feature(duration_from_micros)] - /// use std::time::Duration; - /// - /// let duration = Duration::from_micros(1_000_002); - /// - /// assert_eq!(1, duration.as_secs()); - /// assert_eq!(2000, duration.subsec_nanos()); - /// ``` - #[unstable(feature = "duration_from_micros", issue = "44400")] - #[inline] - pub const fn from_micros(micros: u64) -> Duration { - Duration { - secs: micros / MICROS_PER_SEC, - nanos: ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO, - } - } - - /// Creates a new `Duration` from the specified number of nanoseconds. - /// - /// # Examples - /// - /// ``` - /// #![feature(duration_extras)] - /// use std::time::Duration; - /// - /// let duration = Duration::from_nanos(1_000_000_123); - /// - /// assert_eq!(1, duration.as_secs()); - /// assert_eq!(123, duration.subsec_nanos()); - /// ``` - #[unstable(feature = "duration_extras", issue = "46507")] - #[inline] - pub const fn from_nanos(nanos: u64) -> Duration { - Duration { - secs: nanos / (NANOS_PER_SEC as u64), - nanos: (nanos % (NANOS_PER_SEC as u64)) as u32, - } - } - - /// Returns the number of _whole_ seconds contained by this `Duration`. - /// - /// The returned value does not include the fractional (nanosecond) part of the - /// duration, which can be obtained using [`subsec_nanos`]. - /// - /// # Examples - /// - /// ``` - /// use std::time::Duration; - /// - /// let duration = Duration::new(5, 730023852); - /// assert_eq!(duration.as_secs(), 5); - /// ``` - /// - /// To determine the total number of seconds represented by the `Duration`, - /// use `as_secs` in combination with [`subsec_nanos`]: - /// - /// ``` - /// use std::time::Duration; - /// - /// let duration = Duration::new(5, 730023852); - /// - /// assert_eq!(5.730023852, - /// duration.as_secs() as f64 - /// + duration.subsec_nanos() as f64 * 1e-9); - /// ``` - /// - /// [`subsec_nanos`]: #method.subsec_nanos - #[stable(feature = "duration", since = "1.3.0")] - #[inline] - pub fn as_secs(&self) -> u64 { self.secs } - - /// Returns the fractional part of this `Duration`, in milliseconds. - /// - /// This method does **not** return the length of the duration when - /// represented by milliseconds. The returned number always represents a - /// fractional portion of a second (i.e. it is less than one thousand). - /// - /// # Examples - /// - /// ``` - /// #![feature(duration_extras)] - /// use std::time::Duration; - /// - /// let duration = Duration::from_millis(5432); - /// assert_eq!(duration.as_secs(), 5); - /// assert_eq!(duration.subsec_millis(), 432); - /// ``` - #[unstable(feature = "duration_extras", issue = "46507")] - #[inline] - pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI } - - /// Returns the fractional part of this `Duration`, in microseconds. - /// - /// This method does **not** return the length of the duration when - /// represented by microseconds. The returned number always represents a - /// fractional portion of a second (i.e. it is less than one million). - /// - /// # Examples - /// - /// ``` - /// #![feature(duration_extras, duration_from_micros)] - /// use std::time::Duration; - /// - /// let duration = Duration::from_micros(1_234_567); - /// assert_eq!(duration.as_secs(), 1); - /// assert_eq!(duration.subsec_micros(), 234_567); - /// ``` - #[unstable(feature = "duration_extras", issue = "46507")] - #[inline] - pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO } - - /// Returns the fractional part of this `Duration`, in nanoseconds. - /// - /// This method does **not** return the length of the duration when - /// represented by nanoseconds. The returned number always represents a - /// fractional portion of a second (i.e. it is less than one billion). - /// - /// # Examples - /// - /// ``` - /// use std::time::Duration; - /// - /// let duration = Duration::from_millis(5010); - /// assert_eq!(duration.as_secs(), 5); - /// assert_eq!(duration.subsec_nanos(), 10_000_000); - /// ``` - #[stable(feature = "duration", since = "1.3.0")] - #[inline] - pub fn subsec_nanos(&self) -> u32 { self.nanos } - - /// Checked `Duration` addition. Computes `self + other`, returning [`None`] - /// if overflow occurred. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::time::Duration; - /// - /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); - /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None); - /// ``` - #[stable(feature = "duration_checked_ops", since = "1.16.0")] - #[inline] - pub fn checked_add(self, rhs: Duration) -> Option { - if let Some(mut secs) = self.secs.checked_add(rhs.secs) { - let mut nanos = self.nanos + rhs.nanos; - if nanos >= NANOS_PER_SEC { - nanos -= NANOS_PER_SEC; - if let Some(new_secs) = secs.checked_add(1) { - secs = new_secs; - } else { - return None; - } - } - debug_assert!(nanos < NANOS_PER_SEC); - Some(Duration { - secs, - nanos, - }) - } else { - None - } - } - - /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`] - /// if the result would be negative or if overflow occurred. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::time::Duration; - /// - /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1))); - /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None); - /// ``` - #[stable(feature = "duration_checked_ops", since = "1.16.0")] - #[inline] - pub fn checked_sub(self, rhs: Duration) -> Option { - if let Some(mut secs) = self.secs.checked_sub(rhs.secs) { - let nanos = if self.nanos >= rhs.nanos { - self.nanos - rhs.nanos - } else { - if let Some(sub_secs) = secs.checked_sub(1) { - secs = sub_secs; - self.nanos + NANOS_PER_SEC - rhs.nanos - } else { - return None; - } - }; - debug_assert!(nanos < NANOS_PER_SEC); - Some(Duration { secs: secs, nanos: nanos }) - } else { - None - } - } - - /// Checked `Duration` multiplication. Computes `self * other`, returning - /// [`None`] if overflow occurred. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::time::Duration; - /// - /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2))); - /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None); - /// ``` - #[stable(feature = "duration_checked_ops", since = "1.16.0")] - #[inline] - pub fn checked_mul(self, rhs: u32) -> Option { - // Multiply nanoseconds as u64, because it cannot overflow that way. - let total_nanos = self.nanos as u64 * rhs as u64; - let extra_secs = total_nanos / (NANOS_PER_SEC as u64); - let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32; - if let Some(secs) = self.secs - .checked_mul(rhs as u64) - .and_then(|s| s.checked_add(extra_secs)) { - debug_assert!(nanos < NANOS_PER_SEC); - Some(Duration { - secs, - nanos, - }) - } else { - None - } - } - - /// Checked `Duration` division. Computes `self / other`, returning [`None`] - /// if `other == 0`. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::time::Duration; - /// - /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); - /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); - /// assert_eq!(Duration::new(2, 0).checked_div(0), None); - /// ``` - #[stable(feature = "duration_checked_ops", since = "1.16.0")] - #[inline] - pub fn checked_div(self, rhs: u32) -> Option { - if rhs != 0 { - let secs = self.secs / (rhs as u64); - let carry = self.secs - secs * (rhs as u64); - let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64); - let nanos = self.nanos / rhs + (extra_nanos as u32); - debug_assert!(nanos < NANOS_PER_SEC); - Some(Duration { secs: secs, nanos: nanos }) - } else { - None - } - } -} - -#[stable(feature = "duration", since = "1.3.0")] -impl Add for Duration { - type Output = Duration; - - fn add(self, rhs: Duration) -> Duration { - self.checked_add(rhs).expect("overflow when adding durations") - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl AddAssign for Duration { - fn add_assign(&mut self, rhs: Duration) { - *self = *self + rhs; - } -} - -#[stable(feature = "duration", since = "1.3.0")] -impl Sub for Duration { - type Output = Duration; - - fn sub(self, rhs: Duration) -> Duration { - self.checked_sub(rhs).expect("overflow when subtracting durations") - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl SubAssign for Duration { - fn sub_assign(&mut self, rhs: Duration) { - *self = *self - rhs; - } -} - -#[stable(feature = "duration", since = "1.3.0")] -impl Mul for Duration { - type Output = Duration; - - fn mul(self, rhs: u32) -> Duration { - self.checked_mul(rhs).expect("overflow when multiplying duration by scalar") - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl MulAssign for Duration { - fn mul_assign(&mut self, rhs: u32) { - *self = *self * rhs; - } -} - -#[stable(feature = "duration", since = "1.3.0")] -impl Div for Duration { - type Output = Duration; - - fn div(self, rhs: u32) -> Duration { - self.checked_div(rhs).expect("divide by zero error when dividing duration by scalar") - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl DivAssign for Duration { - fn div_assign(&mut self, rhs: u32) { - *self = *self / rhs; - } -} - -#[stable(feature = "duration_sum", since = "1.16.0")] -impl Sum for Duration { - fn sum>(iter: I) -> Duration { - iter.fold(Duration::new(0, 0), |a, b| a + b) - } -} - -#[stable(feature = "duration_sum", since = "1.16.0")] -impl<'a> Sum<&'a Duration> for Duration { - fn sum>(iter: I) -> Duration { - iter.fold(Duration::new(0, 0), |a, b| a + *b) - } -} - -#[cfg(test)] -mod tests { - use super::Duration; - - #[test] - fn creation() { - assert!(Duration::from_secs(1) != Duration::from_secs(0)); - assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), - Duration::from_secs(3)); - assert_eq!(Duration::from_millis(10) + Duration::from_secs(4), - Duration::new(4, 10 * 1_000_000)); - assert_eq!(Duration::from_millis(4000), Duration::new(4, 0)); - } - - #[test] - fn secs() { - assert_eq!(Duration::new(0, 0).as_secs(), 0); - assert_eq!(Duration::from_secs(1).as_secs(), 1); - assert_eq!(Duration::from_millis(999).as_secs(), 0); - assert_eq!(Duration::from_millis(1001).as_secs(), 1); - } - - #[test] - fn nanos() { - assert_eq!(Duration::new(0, 0).subsec_nanos(), 0); - assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); - assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); - assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); - assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000); - assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000); - } - - #[test] - fn add() { - assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), - Duration::new(0, 1)); - assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), - Duration::new(1, 1)); - } - - #[test] - fn checked_add() { - assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), - Some(Duration::new(0, 1))); - assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)), - Some(Duration::new(1, 1))); - assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None); - } - - #[test] - fn sub() { - assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), - Duration::new(0, 1)); - assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), - Duration::new(0, 1)); - assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), - Duration::new(0, 999_999_999)); - } - - #[test] - fn checked_sub() { - let zero = Duration::new(0, 0); - let one_nano = Duration::new(0, 1); - let one_sec = Duration::new(1, 0); - assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1))); - assert_eq!(one_sec.checked_sub(one_nano), - Some(Duration::new(0, 999_999_999))); - assert_eq!(zero.checked_sub(one_nano), None); - assert_eq!(zero.checked_sub(one_sec), None); - } - - #[test] #[should_panic] - fn sub_bad1() { - Duration::new(0, 0) - Duration::new(0, 1); - } - - #[test] #[should_panic] - fn sub_bad2() { - Duration::new(0, 0) - Duration::new(1, 0); - } - - #[test] - fn mul() { - assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2)); - assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3)); - assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4)); - assert_eq!(Duration::new(0, 500_000_001) * 4000, - Duration::new(2000, 4000)); - } - - #[test] - fn checked_mul() { - assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2))); - assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3))); - assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4))); - assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), - Some(Duration::new(2000, 4000))); - assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None); - } - - #[test] - fn div() { - assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); - assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); - assert_eq!(Duration::new(99, 999_999_000) / 100, - Duration::new(0, 999_999_990)); - } - - #[test] - fn checked_div() { - assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); - assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); - assert_eq!(Duration::new(2, 0).checked_div(0), None); - } -} diff --git a/src/libstd/time/mod.rs b/src/libstd/time/mod.rs deleted file mode 100644 index 6ce3b3e8a00..00000000000 --- a/src/libstd/time/mod.rs +++ /dev/null @@ -1,567 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Temporal quantification. -//! -//! Example: -//! -//! ``` -//! use std::time::Duration; -//! -//! let five_seconds = Duration::new(5, 0); -//! // both declarations are equivalent -//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5)); -//! ``` - -#![stable(feature = "time", since = "1.3.0")] - -use error::Error; -use fmt; -use ops::{Add, Sub, AddAssign, SubAssign}; -use sys::time; -use sys_common::FromInner; - -#[stable(feature = "time", since = "1.3.0")] -pub use self::duration::Duration; - -mod duration; - -/// A measurement of a monotonically nondecreasing clock. -/// Opaque and useful only with `Duration`. -/// -/// Instants are always guaranteed to be no less than any previously measured -/// instant when created, and are often useful for tasks such as measuring -/// benchmarks or timing how long an operation takes. -/// -/// Note, however, that instants are not guaranteed to be **steady**. In other -/// words, each tick of the underlying clock may not be the same length (e.g. -/// some seconds may be longer than others). An instant may jump forwards or -/// experience time dilation (slow down or speed up), but it will never go -/// backwards. -/// -/// Instants are opaque types that can only be compared to one another. There is -/// no method to get "the number of seconds" from an instant. Instead, it only -/// allows measuring the duration between two instants (or comparing two -/// instants). -/// -/// Example: -/// -/// ```no_run -/// use std::time::{Duration, Instant}; -/// use std::thread::sleep; -/// -/// fn main() { -/// let now = Instant::now(); -/// -/// // we sleep for 2 seconds -/// sleep(Duration::new(2, 0)); -/// // it prints '2' -/// println!("{}", now.elapsed().as_secs()); -/// } -/// ``` -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[stable(feature = "time2", since = "1.8.0")] -pub struct Instant(time::Instant); - -/// A measurement of the system clock, useful for talking to -/// external entities like the file system or other processes. -/// -/// Distinct from the [`Instant`] type, this time measurement **is not -/// monotonic**. This means that you can save a file to the file system, then -/// save another file to the file system, **and the second file has a -/// `SystemTime` measurement earlier than the first**. In other words, an -/// operation that happens after another operation in real time may have an -/// earlier `SystemTime`! -/// -/// Consequently, comparing two `SystemTime` instances to learn about the -/// duration between them returns a [`Result`] instead of an infallible [`Duration`] -/// to indicate that this sort of time drift may happen and needs to be handled. -/// -/// Although a `SystemTime` cannot be directly inspected, the [`UNIX_EPOCH`] -/// constant is provided in this module as an anchor in time to learn -/// information about a `SystemTime`. By calculating the duration from this -/// fixed point in time, a `SystemTime` can be converted to a human-readable time, -/// or perhaps some other string representation. -/// -/// [`Instant`]: ../../std/time/struct.Instant.html -/// [`Result`]: ../../std/result/enum.Result.html -/// [`Duration`]: ../../std/time/struct.Duration.html -/// [`UNIX_EPOCH`]: ../../std/time/constant.UNIX_EPOCH.html -/// -/// Example: -/// -/// ```no_run -/// use std::time::{Duration, SystemTime}; -/// use std::thread::sleep; -/// -/// fn main() { -/// let now = SystemTime::now(); -/// -/// // we sleep for 2 seconds -/// sleep(Duration::new(2, 0)); -/// match now.elapsed() { -/// Ok(elapsed) => { -/// // it prints '2' -/// println!("{}", elapsed.as_secs()); -/// } -/// Err(e) => { -/// // an error occurred! -/// println!("Error: {:?}", e); -/// } -/// } -/// } -/// ``` -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[stable(feature = "time2", since = "1.8.0")] -pub struct SystemTime(time::SystemTime); - -/// An error returned from the `duration_since` and `elapsed` methods on -/// `SystemTime`, used to learn how far in the opposite direction a system time -/// lies. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread::sleep; -/// use std::time::{Duration, SystemTime}; -/// -/// let sys_time = SystemTime::now(); -/// sleep(Duration::from_secs(1)); -/// let new_sys_time = SystemTime::now(); -/// match sys_time.duration_since(new_sys_time) { -/// Ok(_) => {} -/// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()), -/// } -/// ``` -#[derive(Clone, Debug)] -#[stable(feature = "time2", since = "1.8.0")] -pub struct SystemTimeError(Duration); - -impl Instant { - /// Returns an instant corresponding to "now". - /// - /// # Examples - /// - /// ``` - /// use std::time::Instant; - /// - /// let now = Instant::now(); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn now() -> Instant { - Instant(time::Instant::now()) - } - - /// Returns the amount of time elapsed from another instant to this one. - /// - /// # Panics - /// - /// This function will panic if `earlier` is later than `self`. - /// - /// # Examples - /// - /// ```no_run - /// use std::time::{Duration, Instant}; - /// use std::thread::sleep; - /// - /// let now = Instant::now(); - /// sleep(Duration::new(1, 0)); - /// let new_now = Instant::now(); - /// println!("{:?}", new_now.duration_since(now)); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn duration_since(&self, earlier: Instant) -> Duration { - self.0.sub_instant(&earlier.0) - } - - /// Returns the amount of time elapsed since this instant was created. - /// - /// # Panics - /// - /// This function may panic if the current time is earlier than this - /// instant, which is something that can happen if an `Instant` is - /// produced synthetically. - /// - /// # Examples - /// - /// ```no_run - /// use std::thread::sleep; - /// use std::time::{Duration, Instant}; - /// - /// let instant = Instant::now(); - /// let three_secs = Duration::from_secs(3); - /// sleep(three_secs); - /// assert!(instant.elapsed() >= three_secs); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn elapsed(&self) -> Duration { - Instant::now() - *self - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Add for Instant { - type Output = Instant; - - fn add(self, other: Duration) -> Instant { - Instant(self.0.add_duration(&other)) - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl AddAssign for Instant { - fn add_assign(&mut self, other: Duration) { - *self = *self + other; - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Sub for Instant { - type Output = Instant; - - fn sub(self, other: Duration) -> Instant { - Instant(self.0.sub_duration(&other)) - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl SubAssign for Instant { - fn sub_assign(&mut self, other: Duration) { - *self = *self - other; - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Sub for Instant { - type Output = Duration; - - fn sub(self, other: Instant) -> Duration { - self.duration_since(other) - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl fmt::Debug for Instant { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl SystemTime { - /// Returns the system time corresponding to "now". - /// - /// # Examples - /// - /// ``` - /// use std::time::SystemTime; - /// - /// let sys_time = SystemTime::now(); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn now() -> SystemTime { - SystemTime(time::SystemTime::now()) - } - - /// Returns the amount of time elapsed from an earlier point in time. - /// - /// This function may fail because measurements taken earlier are not - /// guaranteed to always be before later measurements (due to anomalies such - /// as the system clock being adjusted either forwards or backwards). - /// - /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents - /// the amount of time elapsed from the specified measurement to this one. - /// - /// Returns an [`Err`] if `earlier` is later than `self`, and the error - /// contains how far from `self` the time is. - /// - /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok - /// [`Duration`]: ../../std/time/struct.Duration.html - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// - /// # Examples - /// - /// ``` - /// use std::time::SystemTime; - /// - /// let sys_time = SystemTime::now(); - /// let difference = sys_time.duration_since(sys_time) - /// .expect("SystemTime::duration_since failed"); - /// println!("{:?}", difference); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn duration_since(&self, earlier: SystemTime) - -> Result { - self.0.sub_time(&earlier.0).map_err(SystemTimeError) - } - - /// Returns the amount of time elapsed since this system time was created. - /// - /// This function may fail as the underlying system clock is susceptible to - /// drift and updates (e.g. the system clock could go backwards), so this - /// function may not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is - /// returned where the duration represents the amount of time elapsed from - /// this time measurement to the current time. - /// - /// Returns an [`Err`] if `self` is later than the current system time, and - /// the error contains how far from the current system time `self` is. - /// - /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok - /// [`Duration`]: ../../std/time/struct.Duration.html - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// - /// # Examples - /// - /// ```no_run - /// use std::thread::sleep; - /// use std::time::{Duration, SystemTime}; - /// - /// let sys_time = SystemTime::now(); - /// let one_sec = Duration::from_secs(1); - /// sleep(one_sec); - /// assert!(sys_time.elapsed().unwrap() >= one_sec); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn elapsed(&self) -> Result { - SystemTime::now().duration_since(*self) - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Add for SystemTime { - type Output = SystemTime; - - fn add(self, dur: Duration) -> SystemTime { - SystemTime(self.0.add_duration(&dur)) - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl AddAssign for SystemTime { - fn add_assign(&mut self, other: Duration) { - *self = *self + other; - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Sub for SystemTime { - type Output = SystemTime; - - fn sub(self, dur: Duration) -> SystemTime { - SystemTime(self.0.sub_duration(&dur)) - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl SubAssign for SystemTime { - fn sub_assign(&mut self, other: Duration) { - *self = *self - other; - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -/// An anchor in time which can be used to create new `SystemTime` instances or -/// learn about where in time a `SystemTime` lies. -/// -/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with -/// respect to the system clock. Using `duration_since` on an existing -/// [`SystemTime`] instance can tell how far away from this point in time a -/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a -/// [`SystemTime`] instance to represent another fixed point in time. -/// -/// [`SystemTime`]: ../../std/time/struct.SystemTime.html -/// -/// # Examples -/// -/// ```no_run -/// use std::time::{SystemTime, UNIX_EPOCH}; -/// -/// match SystemTime::now().duration_since(UNIX_EPOCH) { -/// Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()), -/// Err(_) => panic!("SystemTime before UNIX EPOCH!"), -/// } -/// ``` -#[stable(feature = "time2", since = "1.8.0")] -pub const UNIX_EPOCH: SystemTime = SystemTime(time::UNIX_EPOCH); - -impl SystemTimeError { - /// Returns the positive duration which represents how far forward the - /// second system time was from the first. - /// - /// A `SystemTimeError` is returned from the [`duration_since`] and [`elapsed`] - /// methods of [`SystemTime`] whenever the second system time represents a point later - /// in time than the `self` of the method call. - /// - /// [`duration_since`]: ../../std/time/struct.SystemTime.html#method.duration_since - /// [`elapsed`]: ../../std/time/struct.SystemTime.html#method.elapsed - /// [`SystemTime`]: ../../std/time/struct.SystemTime.html - /// - /// # Examples - /// - /// ```no_run - /// use std::thread::sleep; - /// use std::time::{Duration, SystemTime}; - /// - /// let sys_time = SystemTime::now(); - /// sleep(Duration::from_secs(1)); - /// let new_sys_time = SystemTime::now(); - /// match sys_time.duration_since(new_sys_time) { - /// Ok(_) => {} - /// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()), - /// } - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn duration(&self) -> Duration { - self.0 - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Error for SystemTimeError { - fn description(&self) -> &str { "other time was not earlier than self" } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl fmt::Display for SystemTimeError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "second time provided was later than self") - } -} - -impl FromInner for SystemTime { - fn from_inner(time: time::SystemTime) -> SystemTime { - SystemTime(time) - } -} - -#[cfg(test)] -mod tests { - use super::{Instant, SystemTime, Duration, UNIX_EPOCH}; - - macro_rules! assert_almost_eq { - ($a:expr, $b:expr) => ({ - let (a, b) = ($a, $b); - if a != b { - let (a, b) = if a > b {(a, b)} else {(b, a)}; - assert!(a - Duration::new(0, 100) <= b); - } - }) - } - - #[test] - fn instant_monotonic() { - let a = Instant::now(); - let b = Instant::now(); - assert!(b >= a); - } - - #[test] - fn instant_elapsed() { - let a = Instant::now(); - a.elapsed(); - } - - #[test] - fn instant_math() { - let a = Instant::now(); - let b = Instant::now(); - let dur = b.duration_since(a); - assert_almost_eq!(b - dur, a); - assert_almost_eq!(a + dur, b); - - let second = Duration::new(1, 0); - assert_almost_eq!(a - second + second, a); - } - - #[test] - #[should_panic] - fn instant_duration_panic() { - let a = Instant::now(); - (a - Duration::new(1, 0)).duration_since(a); - } - - #[test] - fn system_time_math() { - let a = SystemTime::now(); - let b = SystemTime::now(); - match b.duration_since(a) { - Ok(dur) if dur == Duration::new(0, 0) => { - assert_almost_eq!(a, b); - } - Ok(dur) => { - assert!(b > a); - assert_almost_eq!(b - dur, a); - assert_almost_eq!(a + dur, b); - } - Err(dur) => { - let dur = dur.duration(); - assert!(a > b); - assert_almost_eq!(b + dur, a); - assert_almost_eq!(a - dur, b); - } - } - - let second = Duration::new(1, 0); - assert_almost_eq!(a.duration_since(a - second).unwrap(), second); - assert_almost_eq!(a.duration_since(a + second).unwrap_err() - .duration(), second); - - assert_almost_eq!(a - second + second, a); - - // A difference of 80 and 800 years cannot fit inside a 32-bit time_t - if !(cfg!(unix) && ::mem::size_of::<::libc::time_t>() <= 4) { - let eighty_years = second * 60 * 60 * 24 * 365 * 80; - assert_almost_eq!(a - eighty_years + eighty_years, a); - assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a); - } - - let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0); - let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000) - + Duration::new(0, 500_000_000); - assert_eq!(one_second_from_epoch, one_second_from_epoch2); - } - - #[test] - fn system_time_elapsed() { - let a = SystemTime::now(); - drop(a.elapsed()); - } - - #[test] - fn since_epoch() { - let ts = SystemTime::now(); - let a = ts.duration_since(UNIX_EPOCH).unwrap(); - let b = ts.duration_since(UNIX_EPOCH - Duration::new(1, 0)).unwrap(); - assert!(b > a); - assert_eq!(b - a, Duration::new(1, 0)); - - let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30; - - // Right now for CI this test is run in an emulator, and apparently the - // aarch64 emulator's sense of time is that we're still living in the - // 70s. - // - // Otherwise let's assume that we're all running computers later than - // 2000. - if !cfg!(target_arch = "aarch64") { - assert!(a > thirty_years); - } - - // let's assume that we're all running computers earlier than 2090. - // Should give us ~70 years to fix this! - let hundred_twenty_years = thirty_years * 4; - assert!(a < hundred_twenty_years); - } -} -- cgit 1.4.1-3-g733a5 From deba3890c59a3122acb6373fc09a68d84240d471 Mon Sep 17 00:00:00 2001 From: penpalperson <16357077+penpalperson@users.noreply.github.com> Date: Tue, 30 Jan 2018 05:31:38 -0700 Subject: Changed back inline markings. --- src/libcore/array.rs | 1 - src/libcore/fmt/float.rs | 1 - src/libcore/fmt/mod.rs | 8 -------- src/libcore/ptr.rs | 1 - 4 files changed, 11 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 28f1da27bdb..3d24f8902bd 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -185,7 +185,6 @@ macro_rules! array_impls { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for [T; $N] { - #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&&self[..], f) } diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs index 24ffe8c6888..03e7a9a49d8 100644 --- a/src/libcore/fmt/float.rs +++ b/src/libcore/fmt/float.rs @@ -125,7 +125,6 @@ macro_rules! floating { ($ty:ident) => ( #[stable(feature = "rust1", since = "1.0.0")] impl Debug for $ty { - #[inline] fn fmt(&self, fmt: &mut Formatter) -> Result { float_to_decimal_common(fmt, self, true, 1) } diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index b4d23d153d8..6c8a1c3062b 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1558,12 +1558,10 @@ macro_rules! fmt_refs { $( #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized + $tr> $tr for &'a T { - #[inline] fn fmt(&self, f: &mut Formatter) -> Result { $tr::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized + $tr> $tr for &'a mut T { - #[inline] fn fmt(&self, f: &mut Formatter) -> Result { $tr::fmt(&**self, f) } } )* @@ -1603,7 +1601,6 @@ impl Display for bool { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for str { - #[inline] fn fmt(&self, f: &mut Formatter) -> Result { f.write_char('"')?; let mut from = 0; @@ -1632,7 +1629,6 @@ impl Display for str { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for char { - #[inline] fn fmt(&self, f: &mut Formatter) -> Result { f.write_char('\'')?; for c in self.escape_debug() { @@ -1706,12 +1702,10 @@ impl<'a, T: ?Sized> Pointer for &'a mut T { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for *const T { - #[inline] fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) } } #[stable(feature = "rust1", since = "1.0.0")] impl Debug for *mut T { - #[inline] fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) } } @@ -1725,7 +1719,6 @@ macro_rules! tuple { #[stable(feature = "rust1", since = "1.0.0")] impl<$($name:Debug),*> Debug for ($($name,)*) where last_type!($($name,)+): ?Sized { #[allow(non_snake_case, unused_assignments, deprecated)] - #[inline] fn fmt(&self, f: &mut Formatter) -> Result { let mut builder = f.debug_tuple(""); let ($(ref $name,)*) = *self; @@ -1749,7 +1742,6 @@ tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } #[stable(feature = "rust1", since = "1.0.0")] impl Debug for [T] { - #[inline] fn fmt(&self, f: &mut Formatter) -> Result { f.debug_list().entries(self.iter()).finish() } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 3e162afd649..fab5832d905 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2202,7 +2202,6 @@ macro_rules! fnptr_impls_safety_abi { #[stable(feature = "fnptr_impls", since = "1.4.0")] impl fmt::Debug for $FnTy { - #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&(*self as *const ()), f) } -- cgit 1.4.1-3-g733a5 From e34c31bf02eb0f0ff4dd43ae72e0eae53f2ac519 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 1 Feb 2018 18:35:51 +0000 Subject: Use constant for 180/π in to_degrees MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current `f32|f64.to_degrees` implementation uses a division to calculate 180/π, which causes a loss of precision. Using a constant is still not perfect (implementing a maximally-precise algorithm would come with a high performance cost), but improves precision with a minimal change. --- src/libcore/num/f32.rs | 4 +++- src/libcore/num/f64.rs | 3 +++ src/libstd/f32.rs | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 207df84d080..3586fa5442f 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -239,7 +239,9 @@ impl Float for f32 { /// Converts to degrees, assuming the number is in radians. #[inline] fn to_degrees(self) -> f32 { - self * (180.0f32 / consts::PI) + // Use a constant for better precision. + const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32; + self * PIS_IN_180 } /// Converts to radians, assuming the number is in degrees. diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 9206132e8b4..64c0d508b38 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -237,6 +237,9 @@ impl Float for f64 { /// Converts to degrees, assuming the number is in radians. #[inline] fn to_degrees(self) -> f64 { + // The division here is correctly rounded with respect to the true + // value of 180/π. (This differs from f32, where a constant must be + // used to ensure a correctly rounded result.) self * (180.0f64 / consts::PI) } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 9810dede618..ecf68f29d6f 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1531,6 +1531,7 @@ mod tests { assert!(nan.to_degrees().is_nan()); assert_eq!(inf.to_degrees(), inf); assert_eq!(neg_inf.to_degrees(), neg_inf); + assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703); } #[test] -- cgit 1.4.1-3-g733a5 From 196fad0d00bddd11074b5da32af2393abaac9a26 Mon Sep 17 00:00:00 2001 From: Badel2 <2badel2@gmail.com> Date: Tue, 30 Jan 2018 21:33:33 +0100 Subject: Turn `type_id` into a constant intrinsic Add rustc_const_unstable attribute for `any::TypeId::of` Add test for `const fn TypeId::of` --- src/libcore/any.rs | 27 +++++++++++++++++ src/libcore/lib.rs | 1 + src/librustc_const_eval/eval.rs | 4 +++ src/librustc_mir/interpret/const_eval.rs | 6 ++++ src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_trans/mir/constant.rs | 5 ++++ src/test/compile-fail/const-typeid-of.rs | 18 ++++++++++++ src/test/run-pass/const-typeid-of.rs | 43 ++++++++++++++++++++++++++++ 8 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/const-typeid-of.rs create mode 100644 src/test/run-pass/const-typeid-of.rs (limited to 'src/libcore') diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 338e5c7fd95..566bfe2a3fb 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -367,9 +367,36 @@ impl TypeId { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] pub fn of() -> TypeId { TypeId { t: unsafe { intrinsics::type_id::() }, } } + + /// Returns the `TypeId` of the type this generic function has been + /// instantiated with. + /// + /// # Examples + /// + /// ``` + /// use std::any::{Any, TypeId}; + /// + /// fn is_string(_s: &T) -> bool { + /// TypeId::of::() == TypeId::of::() + /// } + /// + /// fn main() { + /// assert_eq!(is_string(&0), false); + /// assert_eq!(is_string(&"cookie monster".to_string()), true); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature="const_type_id")] + #[cfg(not(stage0))] + pub const fn of() -> TypeId { + TypeId { + t: unsafe { intrinsics::type_id::() }, + } + } } diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index d5190b65863..7f094e580ab 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -91,6 +91,7 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(doc_spotlight)] +#![feature(rustc_const_unstable)] #[prelude_import] #[allow(unused)] diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 418bd4b5eff..17a9454e9d4 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -328,6 +328,10 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, return Ok(mk_const(Integral(Usize(ConstUsize::new(align, tcx.sess.target.usize_ty).unwrap())))); } + "type_id" => { + let type_id = tcx.type_id_hash(substs.type_at(0)); + return Ok(mk_const(Integral(U64(type_id)))); + } _ => signal!(e, TypeckError) } } diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 2913f72460e..d3b084fde6a 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -243,6 +243,12 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { ecx.write_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?; } + "type_id" => { + let ty = substs.type_at(0); + let type_id = ecx.tcx.type_id_hash(ty) as u128; + ecx.write_primval(dest, PrimVal::from_u128(type_id), dest_layout.ty)?; + } + name => return Err(ConstEvalError::NeedsRfc(format!("calling intrinsic `{}`", name)).into()), } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index b896e6ca853..da76adfd48f 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -737,7 +737,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { Abi::PlatformIntrinsic => { assert!(!self.tcx.is_const_fn(def_id)); match &self.tcx.item_name(def_id)[..] { - "size_of" | "min_align_of" => is_const_fn = Some(def_id), + "size_of" | "min_align_of" | "type_id" => is_const_fn = Some(def_id), name if name.starts_with("simd_shuffle") => { is_shuffle = true; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index a3e55205dd8..cd1975488a2 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -411,6 +411,11 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { self.cx.align_of(substs.type_at(0)).abi()); Ok(Const::new(llval, tcx.types.usize)) } + "type_id" => { + let llval = C_u64(self.cx, + self.cx.tcx.type_id_hash(substs.type_at(0))); + Ok(Const::new(llval, tcx.types.u64)) + } _ => span_bug!(span, "{:?} in constant", terminator.kind) } } else if let Some((op, is_checked)) = self.is_binop_lang_item(def_id) { diff --git a/src/test/compile-fail/const-typeid-of.rs b/src/test/compile-fail/const-typeid-of.rs new file mode 100644 index 00000000000..401125cef09 --- /dev/null +++ b/src/test/compile-fail/const-typeid-of.rs @@ -0,0 +1,18 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::any::TypeId; + +struct A; + +fn main() { + const A_ID: TypeId = TypeId::of::(); + //~^ ERROR `std::any::TypeId::of` is not yet stable as a const fn +} diff --git a/src/test/run-pass/const-typeid-of.rs b/src/test/run-pass/const-typeid-of.rs new file mode 100644 index 00000000000..ce29e55c6d7 --- /dev/null +++ b/src/test/run-pass/const-typeid-of.rs @@ -0,0 +1,43 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(core_intrinsics)] +#![feature(const_type_id)] + +use std::any::TypeId; + +struct A; + +static ID_ISIZE: TypeId = TypeId::of::(); + +pub fn main() { + assert_eq!(ID_ISIZE, TypeId::of::()); + + // sanity test of TypeId + const T: (TypeId, TypeId, TypeId) = (TypeId::of::(), + TypeId::of::<&'static str>(), + TypeId::of::()); + let (d, e, f) = (TypeId::of::(), TypeId::of::<&'static str>(), + TypeId::of::()); + + assert!(T.0 != T.1); + assert!(T.0 != T.2); + assert!(T.1 != T.2); + + assert_eq!(T.0, d); + assert_eq!(T.1, e); + assert_eq!(T.2, f); + + // Check fn pointer against collisions + const F: (TypeId, TypeId) = (TypeId::of:: A) -> A>(), + TypeId::of:: A, A) -> A>()); + + assert!(F.0 != F.1); +} -- cgit 1.4.1-3-g733a5 From c1383e4dc4bd6598f5d73d2d6b1054f61b2b99d4 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Fri, 19 Jan 2018 19:57:10 -0800 Subject: Add filtering options to `rustc_on_unimplemented` - filter error on the evaluated value of `Self` - filter error on the evaluated value of the type arguments - add argument to include custom note in diagnostic - allow the parser to parse `Self` when processing attributes - add custom message to binops --- src/libcore/ops/arith.rs | 115 +++++++++++++++++++-- src/libcore/ops/bit.rs | 30 ++++-- src/librustc/traits/error_reporting.rs | 32 ++++-- src/librustc/traits/on_unimplemented.rs | 34 ++++-- src/libsyntax/parse/attr.rs | 2 +- src/libsyntax/parse/parser.rs | 16 ++- .../ui/anonymous-higher-ranked-lifetime.stderr | 66 ++---------- .../issue-39802-show-5-trait-impls.stderr | 18 +--- src/test/ui/did_you_mean/recursion_limit.stderr | 6 +- src/test/ui/feature-gate-abi_unadjusted.stderr | 2 +- src/test/ui/feature-gate-catch_expr.stderr | 2 +- src/test/ui/feature-gate-i128_type2.stderr | 10 +- src/test/ui/feature-gate-intrinsics.stderr | 4 +- src/test/ui/feature-gate-non_ascii_idents.stderr | 26 ++--- src/test/ui/feature-gate-repr128.stderr | 2 +- src/test/ui/feature-gate-unboxed-closures.stderr | 2 +- src/test/ui/feature-gate-untagged_unions.stderr | 6 +- src/test/ui/fmt/send-sync.stderr | 12 +-- src/test/ui/generator/not-send-sync.stderr | 6 +- src/test/ui/impl-trait/auto-trait-leak.stderr | 12 +-- src/test/ui/impl-trait/equality.stderr | 2 +- src/test/ui/issue-24424.stderr | 6 +- src/test/ui/lint/suggestions.stderr | 32 ++---- src/test/ui/lint/use_suggestion_json.stderr | 67 +----------- src/test/ui/macros/format-foreign.stderr | 10 +- src/test/ui/macros/format-unused-lables.stderr | 52 +++++----- src/test/ui/mismatched_types/E0631.stderr | 24 +---- src/test/ui/mismatched_types/binops.stderr | 8 +- .../ui/mismatched_types/closure-arg-count.stderr | 6 +- .../closure-arg-type-mismatch.stderr | 12 +-- .../ui/mismatched_types/closure-mismatch.stderr | 12 +-- src/test/ui/mismatched_types/fn-variance-1.stderr | 12 +-- .../unboxed-closures-vtable-mismatch.stderr | 13 +-- src/test/ui/on-unimplemented/multiple-impls.stderr | 18 +--- src/test/ui/on-unimplemented/on-impl.stderr | 6 +- src/test/ui/on-unimplemented/on-trait.stderr | 12 +-- src/test/ui/span/issue-29595.stderr | 6 +- src/test/ui/span/multiline-span-simple.stderr | 2 +- .../ui/suggestions/try-operator-on-main.stderr | 6 +- src/test/ui/type-check/issue-40294.stderr | 6 +- 40 files changed, 312 insertions(+), 403 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs index 8b3d662a6db..59a18d6cb75 100644 --- a/src/libcore/ops/arith.rs +++ b/src/libcore/ops/arith.rs @@ -75,7 +75,93 @@ /// ``` #[lang = "add"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} + {RHS}`"] +#[rustc_on_unimplemented( + on( + any( + all(_Self="i128", RHS="i64"), + all(_Self="i128", RHS="i32"), + all(_Self="i128", RHS="i16"), + all(_Self="i128", RHS="i8"), + all(_Self="i64", RHS="i32"), + all(_Self="i64", RHS="i16"), + all(_Self="i64", RHS="i8"), + all(_Self="i32", RHS="i16"), + all(_Self="i32", RHS="i8"), + all(_Self="i16", RHS="i8"), + all(_Self="u128", RHS="u64"), + all(_Self="u128", RHS="u32"), + all(_Self="u128", RHS="u16"), + all(_Self="u128", RHS="u8"), + all(_Self="u64", RHS="u32"), + all(_Self="u64", RHS="u16"), + all(_Self="u64", RHS="u8"), + all(_Self="u32", RHS="u16"), + all(_Self="u32", RHS="u8"), + all(_Self="u16", RHS="u8"), + all(_Self="f64", RHS="i32"), + all(_Self="f64", RHS="i16"), + all(_Self="f64", RHS="i8"), + all(_Self="f64", RHS="u32"), + all(_Self="f64", RHS="u16"), + all(_Self="f64", RHS="u8"), + all(_Self="f32", RHS="i16"), + all(_Self="f32", RHS="i8"), + all(_Self="f32", RHS="u16"), + all(_Self="f32", RHS="u8"), + ), + message="cannot add `{RHS}` to `{Self}`", + label="no implementation for `{Self} + {RHS}`, but you can safely cast \ + `{RHS}` into `{Self}` using `as {Self}`", + ), + on( + any( + all(RHS="i128", _Self="i64"), + all(RHS="i128", _Self="i32"), + all(RHS="i128", _Self="i16"), + all(RHS="i128", _Self="i8"), + all(RHS="i64", _Self="i32"), + all(RHS="i64", _Self="i16"), + all(RHS="i64", _Self="i8"), + all(RHS="i32", _Self="i16"), + all(RHS="i32", _Self="i8"), + all(RHS="i16", _Self="i8"), + all(RHS="u128", _Self="u64"), + all(RHS="u128", _Self="u32"), + all(RHS="u128", _Self="u16"), + all(RHS="u128", _Self="u8"), + all(RHS="u64", _Self="u32"), + all(RHS="u64", _Self="u16"), + all(RHS="u64", _Self="u8"), + all(RHS="u32", _Self="u16"), + all(RHS="u32", _Self="u8"), + all(RHS="u16", _Self="u8"), + all(RHS="f64", _Self="i32"), + all(RHS="f64", _Self="i16"), + all(RHS="f64", _Self="i8"), + all(RHS="f64", _Self="u32"), + all(RHS="f64", _Self="u16"), + all(RHS="f64", _Self="u8"), + all(RHS="f32", _Self="i16"), + all(RHS="f32", _Self="i8"), + all(RHS="f32", _Self="u16"), + all(RHS="f32", _Self="u8"), + ), + message="cannot add `{RHS}` to `{Self}`", + label="no implementation for `{Self} + {RHS}`, but you can safely turn \ + `{Self}` into `{RHS}` using `as {RHS}`", + ), + on( + all(_Self="{integer}", RHS="{float}"), + message="cannot add a float to an integer", + label="no implementation for `{Self} + {RHS}`", + ), + on( + all(_Self="{float}", RHS="{integer}"), + message="cannot add an integer to a float", + label="no implementation for `{Self} + {RHS}`", + ), + message="cannot add `{RHS}` to `{Self}`", + label="no implementation for `{Self} + {RHS}`")] pub trait Add { /// The resulting type after applying the `+` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -170,7 +256,8 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "sub"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} - {RHS}`"] +#[rustc_on_unimplemented(message="cannot substract `{RHS}` from `{Self}`", + label="no implementation for `{Self} - {RHS}`")] pub trait Sub { /// The resulting type after applying the `-` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -287,7 +374,8 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "mul"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} * {RHS}`"] +#[rustc_on_unimplemented(message="cannot multiply `{RHS}` to `{Self}`", + label="no implementation for `{Self} * {RHS}`")] pub trait Mul { /// The resulting type after applying the `*` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -408,7 +496,8 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "div"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} / {RHS}`"] +#[rustc_on_unimplemented(message="cannot divide `{Self}` by `{RHS}`", + label="no implementation for `{Self} / {RHS}`")] pub trait Div { /// The resulting type after applying the `/` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -490,7 +579,8 @@ div_impl_float! { f32 f64 } /// ``` #[lang = "rem"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} % {RHS}`"] +#[rustc_on_unimplemented(message="cannot mod `{Self}` by `{RHS}`", + label="no implementation for `{Self} % {RHS}`")] pub trait Rem { /// The resulting type after applying the `%` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -647,7 +737,8 @@ neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "add_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} += {Rhs}`"] +#[rustc_on_unimplemented(message="cannot add-assign `{Rhs}` to `{Self}`", + label="no implementation for `{Self} += {Rhs}`")] pub trait AddAssign { /// Performs the `+=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -700,7 +791,8 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "sub_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} -= {Rhs}`"] +#[rustc_on_unimplemented(message="cannot substract-assign `{Rhs}` from `{Self}`", + label="no implementation for `{Self} -= {Rhs}`")] pub trait SubAssign { /// Performs the `-=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -744,7 +836,8 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "mul_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} *= {Rhs}`"] +#[rustc_on_unimplemented(message="cannot multiply-assign `{Rhs}` to `{Self}`", + label="no implementation for `{Self} *= {Rhs}`")] pub trait MulAssign { /// Performs the `*=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -788,7 +881,8 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "div_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} /= {Rhs}`"] +#[rustc_on_unimplemented(message="cannot divide-assign `{Self}` by `{Rhs}`", + label="no implementation for `{Self} /= {Rhs}`")] pub trait DivAssign { /// Performs the `/=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -835,7 +929,8 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "rem_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} %= {Rhs}`"] +#[rustc_on_unimplemented(message="cannot mod-assign `{Self}` by `{Rhs}``", + label="no implementation for `{Self} %= {Rhs}`")] pub trait RemAssign { /// Performs the `%=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] diff --git a/src/libcore/ops/bit.rs b/src/libcore/ops/bit.rs index 7ac5fc4debf..a0ecd6cf75c 100644 --- a/src/libcore/ops/bit.rs +++ b/src/libcore/ops/bit.rs @@ -120,7 +120,8 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "bitand"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} & {RHS}`"] +#[rustc_on_unimplemented(message="no implementation for `{Self} & {RHS}`", + label="no implementation for `{Self} & {RHS}`")] pub trait BitAnd { /// The resulting type after applying the `&` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -201,7 +202,8 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "bitor"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} | {RHS}`"] +#[rustc_on_unimplemented(message="no implementation for `{Self} | {RHS}`", + label="no implementation for `{Self} | {RHS}`")] pub trait BitOr { /// The resulting type after applying the `|` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -285,7 +287,8 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "bitxor"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} ^ {RHS}`"] +#[rustc_on_unimplemented(message="no implementation for `{Self} ^ {RHS}`", + label="no implementation for `{Self} ^ {RHS}`")] pub trait BitXor { /// The resulting type after applying the `^` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -365,7 +368,8 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "shl"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} << {RHS}`"] +#[rustc_on_unimplemented(message="no implementation for `{Self} << {RHS}`", + label="no implementation for `{Self} << {RHS}`")] pub trait Shl { /// The resulting type after applying the `<<` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -466,7 +470,8 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// ``` #[lang = "shr"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} >> {RHS}`"] +#[rustc_on_unimplemented(message="no implementation for `{Self} >> {RHS}`", + label="no implementation for `{Self} >> {RHS}`")] pub trait Shr { /// The resulting type after applying the `>>` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -579,7 +584,8 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// ``` #[lang = "bitand_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} &= {Rhs}`"] +#[rustc_on_unimplemented(message="no implementation for `{Self} &= {Rhs}`", + label="no implementation for `{Self} &= {Rhs}`")] pub trait BitAndAssign { /// Performs the `&=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -626,7 +632,8 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "bitor_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} |= {Rhs}`"] +#[rustc_on_unimplemented(message="no implementation for `{Self} |= {Rhs}`", + label="no implementation for `{Self} |= {Rhs}`")] pub trait BitOrAssign { /// Performs the `|=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -673,7 +680,8 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "bitxor_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} ^= {Rhs}`"] +#[rustc_on_unimplemented(message="no implementation for `{Self} ^= {Rhs}`", + label="no implementation for `{Self} ^= {Rhs}`")] pub trait BitXorAssign { /// Performs the `^=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -718,7 +726,8 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "shl_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} <<= {Rhs}`"] +#[rustc_on_unimplemented(message="no implementation for `{Self} <<= {Rhs}`", + label="no implementation for `{Self} <<= {Rhs}`")] pub trait ShlAssign { /// Performs the `<<=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -784,7 +793,8 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// ``` #[lang = "shr_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented = "no implementation for `{Self} >>= {Rhs}`"] +#[rustc_on_unimplemented(message="no implementation for `{Self} >>= {Rhs}`", + label="no implementation for `{Self} >>= {Rhs}`")] pub trait ShrAssign { /// Performs the `>>=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index d65becb912a..f5ff1226685 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -348,7 +348,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if direct { // this is a "direct", user-specified, rather than derived, // obligation. - flags.push(("direct", None)); + flags.push(("direct".to_string(), None)); } if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code { @@ -359,21 +359,35 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Currently I'm leaving it for what I need for `try`. if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) { method = self.tcx.item_name(item); - flags.push(("from_method", None)); - flags.push(("from_method", Some(&*method))); + flags.push(("from_method".to_string(), None)); + flags.push(("from_method".to_string(), Some(method.to_string()))); } } if let Some(k) = obligation.cause.span.compiler_desugaring_kind() { desugaring = k.as_symbol().as_str(); - flags.push(("from_desugaring", None)); - flags.push(("from_desugaring", Some(&*desugaring))); + flags.push(("from_desugaring".to_string(), None)); + flags.push(("from_desugaring".to_string(), Some(desugaring.to_string()))); + } + let generics = self.tcx.generics_of(def_id); + let self_ty = trait_ref.self_ty(); + let self_ty_str = self_ty.to_string(); + // FIXME: remove once `Self` is accepted by the compiler + flags.push(("_Self".to_string(), Some(self_ty_str.clone()))); + flags.push(("Self".to_string(), Some(self_ty_str.clone()))); + + for param in generics.types.iter() { + let name = param.name.as_str().to_string(); + let ty = trait_ref.substs.type_for_def(param); + let ty_str = ty.to_string(); + flags.push((name.clone(), + Some(ty_str.clone()))); } if let Ok(Some(command)) = OnUnimplementedDirective::of_item( self.tcx, trait_ref.def_id, def_id ) { - command.evaluate(self.tcx, trait_ref, &flags) + command.evaluate(self.tcx, trait_ref, &flags[..]) } else { OnUnimplementedNote::empty() } @@ -549,7 +563,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t))) .unwrap_or((String::new(), String::new())); - let OnUnimplementedNote { message, label } + let OnUnimplementedNote { message, label, note } = self.on_unimplemented_note(trait_ref, obligation); let have_alt_message = message.is_some() || label.is_some(); @@ -578,6 +592,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { trait_ref, trait_ref.self_ty())); } + if let Some(ref s) = note { + // If it has a custom "#[rustc_on_unimplemented]" note, let's display it + err.note(s.as_str()); + } self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err); diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index 757b078086d..a493b7f0bb6 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -29,16 +29,18 @@ pub struct OnUnimplementedDirective { pub subcommands: Vec, pub message: Option, pub label: Option, + pub note: Option, } pub struct OnUnimplementedNote { pub message: Option, pub label: Option, + pub note: Option, } impl OnUnimplementedNote { pub fn empty() -> Self { - OnUnimplementedNote { message: None, label: None } + OnUnimplementedNote { message: None, label: None, note: None } } } @@ -89,6 +91,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { let mut message = None; let mut label = None; + let mut note = None; let mut subcommands = vec![]; for item in item_iter { if item.check_name("message") && message.is_none() { @@ -103,8 +106,14 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { tcx, trait_def_id, label_.as_str(), span)?); continue; } + } else if item.check_name("note") && note.is_none() { + if let Some(note_) = item.value_str() { + note = Some(OnUnimplementedFormatString::try_parse( + tcx, trait_def_id, note_.as_str(), span)?); + continue; + } } else if item.check_name("on") && is_root && - message.is_none() && label.is_none() + message.is_none() && label.is_none() && note.is_none() { if let Some(items) = item.meta_item_list() { if let Ok(subcommand) = @@ -128,7 +137,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { if errored { Err(ErrorReported) } else { - Ok(OnUnimplementedDirective { condition, message, label, subcommands }) + Ok(OnUnimplementedDirective { condition, message, label, subcommands, note }) } } @@ -154,7 +163,8 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { message: None, subcommands: vec![], label: Some(OnUnimplementedFormatString::try_parse( - tcx, trait_def_id, value.as_str(), attr.span)?) + tcx, trait_def_id, value.as_str(), attr.span)?), + note: None, })) } else { return Err(parse_error(tcx, attr.span, @@ -169,20 +179,21 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { pub fn evaluate(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, trait_ref: ty::TraitRef<'tcx>, - options: &[(&str, Option<&str>)]) + options: &[(String, Option)]) -> OnUnimplementedNote { let mut message = None; let mut label = None; + let mut note = None; info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options); for command in self.subcommands.iter().chain(Some(self)).rev() { if let Some(ref condition) = command.condition { if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| { - options.contains(&(&c.name().as_str(), - match c.value_str().map(|s| s.as_str()) { - Some(ref s) => Some(s), + options.contains(&(c.name().as_str().to_string(), + match c.value_str().map(|s| s.as_str().to_string()) { + Some(s) => Some(s), None => None })) }) { @@ -198,11 +209,16 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { if let Some(ref label_) = command.label { label = Some(label_.clone()); } + + if let Some(ref note_) = command.note { + note = Some(note_.clone()); + } } OnUnimplementedNote { label: label.map(|l| l.format(tcx, trait_ref)), - message: message.map(|m| m.format(tcx, trait_ref)) + message: message.map(|m| m.format(tcx, trait_ref)), + note: note.map(|n| n.format(tcx, trait_ref)), } } } diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 053746b579d..b01f479895b 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -235,7 +235,7 @@ impl<'a> Parser<'a> { } let lo = self.span; - let ident = self.parse_ident()?; + let ident = self.parse_ident_attr()?; let node = self.parse_meta_item_kind()?; Ok(ast::MetaItem { name: ident.name, node: node, span: lo.to(self.prev_span) }) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b3c485a85c0..9e8c4d3de22 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -762,13 +762,19 @@ impl<'a> Parser<'a> { } pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> { - self.parse_ident_common(true) + self.parse_ident_common(true, false) } - fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, ast::Ident> { + pub fn parse_ident_attr(&mut self) -> PResult<'a, ast::Ident> { + self.parse_ident_common(true, true) + } + + fn parse_ident_common(&mut self, recover: bool, accept_self: bool) -> PResult<'a, ast::Ident> { match self.token { token::Ident(i) => { - if self.token.is_reserved_ident() { + if self.token.is_reserved_ident() + && !(accept_self && i.name == keywords::SelfType.name()) + { let mut err = self.struct_span_err(self.span, &format!("expected identifier, found {}", self.this_token_descr())); @@ -2111,7 +2117,7 @@ impl<'a> Parser<'a> { self.bump(); Ok(Ident::with_empty_ctxt(name)) } else { - self.parse_ident_common(false) + self.parse_ident_common(false, false) } } @@ -2128,7 +2134,7 @@ impl<'a> Parser<'a> { hi = self.prev_span; (fieldname, self.parse_expr()?, false) } else { - let fieldname = self.parse_ident_common(false)?; + let fieldname = self.parse_ident_common(false, false)?; hi = self.prev_span; // Mimic `x: x` for the `x` field shorthand. diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.stderr b/src/test/ui/anonymous-higher-ranked-lifetime.stderr index 4bd3b684b7b..e364a4d8b14 100644 --- a/src/test/ui/anonymous-higher-ranked-lifetime.stderr +++ b/src/test/ui/anonymous-higher-ranked-lifetime.stderr @@ -6,11 +6,7 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'r, 's> fn(&'r (), &'s ()) -> _` | -note: required by `f1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:26:1 - | -26 | fn f1(_: F) where F: Fn(&(), &()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `f1` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:13:5 @@ -20,11 +16,7 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'a, 'r> fn(&'a (), &'r ()) -> _` | -note: required by `f2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:27:1 - | -27 | fn f2(_: F) where F: for<'a> Fn(&'a (), &()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `f2` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5 @@ -34,11 +26,7 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'r> fn(&(), &'r ()) -> _` | -note: required by `f3` - --> $DIR/anonymous-higher-ranked-lifetime.rs:28:1 - | -28 | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `f3` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:15:5 @@ -48,11 +36,7 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'s, 'r> fn(&'s (), &'r ()) -> _` | -note: required by `f4` - --> $DIR/anonymous-higher-ranked-lifetime.rs:29:1 - | -29 | fn f4(_: F) where F: for<'r> Fn(&(), &'r ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `f4` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5 @@ -62,11 +46,7 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'r> fn(&'r (), &'r ()) -> _` | -note: required by `f5` - --> $DIR/anonymous-higher-ranked-lifetime.rs:30:1 - | -30 | fn f5(_: F) where F: for<'r> Fn(&'r (), &'r ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `f5` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:17:5 @@ -76,11 +56,7 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'r> fn(&'r (), std::boxed::Box std::ops::Fn(&'s ()) + 'static>) -> _` | -note: required by `g1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:33:1 - | -33 | fn g1(_: F) where F: Fn(&(), Box) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `g1` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5 @@ -90,11 +66,7 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'r> fn(&'r (), for<'s> fn(&'s ())) -> _` | -note: required by `g2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:34:1 - | -34 | fn g2(_: F) where F: Fn(&(), fn(&())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `g2` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:19:5 @@ -104,11 +76,7 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'s> fn(&'s (), std::boxed::Box std::ops::Fn(&'r ()) + 'static>) -> _` | -note: required by `g3` - --> $DIR/anonymous-higher-ranked-lifetime.rs:35:1 - | -35 | fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `g3` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5 @@ -118,11 +86,7 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'s> fn(&'s (), for<'r> fn(&'r ())) -> _` | -note: required by `g4` - --> $DIR/anonymous-higher-ranked-lifetime.rs:36:1 - | -36 | fn g4(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `g4` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:21:5 @@ -132,11 +96,7 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'r, 's> fn(&'r (), std::boxed::Box std::ops::Fn(&'t0 ()) + 'static>, &'s (), for<'t0, 't1> fn(&'t0 (), &'t1 ())) -> _` | -note: required by `h1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:39:1 - | -39 | fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `h1` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5 @@ -146,11 +106,7 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'r, 't0> fn(&'r (), std::boxed::Box std::ops::Fn(&'s ()) + 'static>, &'t0 (), for<'s, 't1> fn(&'s (), &'t1 ())) -> _` | -note: required by `h2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:40:1 - | -40 | fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), &())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `h2` error: aborting due to 11 previous errors diff --git a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr index 7ca3e8728fd..d5c4add34b5 100644 --- a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr +++ b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr @@ -10,11 +10,7 @@ error[E0277]: the trait bound `i8: Foo` is not satisfied > > > -note: required by `Foo::bar` - --> $DIR/issue-39802-show-5-trait-impls.rs:12:5 - | -12 | fn bar(&self){} - | ^^^^^^^^^^^^^ + = note: required by `Foo::bar` error[E0277]: the trait bound `u8: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:35:5 @@ -27,11 +23,7 @@ error[E0277]: the trait bound `u8: Foo` is not satisfied > > > -note: required by `Foo::bar` - --> $DIR/issue-39802-show-5-trait-impls.rs:12:5 - | -12 | fn bar(&self){} - | ^^^^^^^^^^^^^ + = note: required by `Foo::bar` error[E0277]: the trait bound `bool: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:36:5 @@ -45,11 +37,7 @@ error[E0277]: the trait bound `bool: Foo` is not satisfied > > and 2 others -note: required by `Foo::bar` - --> $DIR/issue-39802-show-5-trait-impls.rs:12:5 - | -12 | fn bar(&self){} - | ^^^^^^^^^^^^^ + = note: required by `Foo::bar` error: aborting due to 3 previous errors diff --git a/src/test/ui/did_you_mean/recursion_limit.stderr b/src/test/ui/did_you_mean/recursion_limit.stderr index 2bc7e9e46e7..7fac604ba49 100644 --- a/src/test/ui/did_you_mean/recursion_limit.stderr +++ b/src/test/ui/did_you_mean/recursion_limit.stderr @@ -15,11 +15,7 @@ error[E0275]: overflow evaluating the requirement `K: std::marker::Send` = note: required because it appears within the type `C` = note: required because it appears within the type `B` = note: required because it appears within the type `A` -note: required by `is_send` - --> $DIR/recursion_limit.rs:41:1 - | -41 | fn is_send() { } - | ^^^^^^^^^^^^^^^^^^^^ + = note: required by `is_send` error: aborting due to previous error diff --git a/src/test/ui/feature-gate-abi_unadjusted.stderr b/src/test/ui/feature-gate-abi_unadjusted.stderr index b3f7cd218d3..3cc43847156 100644 --- a/src/test/ui/feature-gate-abi_unadjusted.stderr +++ b/src/test/ui/feature-gate-abi_unadjusted.stderr @@ -1,4 +1,4 @@ -error[E0658]: unadjusted ABI is an implementation detail and perma-unstable +error: unadjusted ABI is an implementation detail and perma-unstable --> $DIR/feature-gate-abi_unadjusted.rs:11:1 | 11 | / extern "unadjusted" fn foo() { diff --git a/src/test/ui/feature-gate-catch_expr.stderr b/src/test/ui/feature-gate-catch_expr.stderr index 4b3bfbbe27a..f486373d225 100644 --- a/src/test/ui/feature-gate-catch_expr.stderr +++ b/src/test/ui/feature-gate-catch_expr.stderr @@ -1,4 +1,4 @@ -error[E0658]: `catch` expression is experimental (see issue #31436) +error: `catch` expression is experimental (see issue #31436) --> $DIR/feature-gate-catch_expr.rs:12:24 | 12 | let catch_result = do catch { //~ ERROR `catch` expression is experimental diff --git a/src/test/ui/feature-gate-i128_type2.stderr b/src/test/ui/feature-gate-i128_type2.stderr index ee81a269214..26653a5739b 100644 --- a/src/test/ui/feature-gate-i128_type2.stderr +++ b/src/test/ui/feature-gate-i128_type2.stderr @@ -1,4 +1,4 @@ -error[E0658]: 128-bit type is unstable (see issue #35118) +error: 128-bit type is unstable (see issue #35118) --> $DIR/feature-gate-i128_type2.rs:13:15 | 13 | fn test1() -> i128 { //~ ERROR 128-bit type is unstable @@ -6,7 +6,7 @@ error[E0658]: 128-bit type is unstable (see issue #35118) | = help: add #![feature(i128_type)] to the crate attributes to enable -error[E0658]: 128-bit type is unstable (see issue #35118) +error: 128-bit type is unstable (see issue #35118) --> $DIR/feature-gate-i128_type2.rs:17:17 | 17 | fn test1_2() -> u128 { //~ ERROR 128-bit type is unstable @@ -14,7 +14,7 @@ error[E0658]: 128-bit type is unstable (see issue #35118) | = help: add #![feature(i128_type)] to the crate attributes to enable -error[E0658]: 128-bit type is unstable (see issue #35118) +error: 128-bit type is unstable (see issue #35118) --> $DIR/feature-gate-i128_type2.rs:22:12 | 22 | let x: i128 = 0; //~ ERROR 128-bit type is unstable @@ -22,7 +22,7 @@ error[E0658]: 128-bit type is unstable (see issue #35118) | = help: add #![feature(i128_type)] to the crate attributes to enable -error[E0658]: 128-bit type is unstable (see issue #35118) +error: 128-bit type is unstable (see issue #35118) --> $DIR/feature-gate-i128_type2.rs:26:12 | 26 | let x: u128 = 0; //~ ERROR 128-bit type is unstable @@ -32,7 +32,7 @@ error[E0658]: 128-bit type is unstable (see issue #35118) error[E0601]: main function not found -error[E0658]: repr with 128-bit type is unstable (see issue #35118) +error: repr with 128-bit type is unstable (see issue #35118) --> $DIR/feature-gate-i128_type2.rs:30:1 | 30 | / enum A { //~ ERROR 128-bit type is unstable diff --git a/src/test/ui/feature-gate-intrinsics.stderr b/src/test/ui/feature-gate-intrinsics.stderr index 918c749504a..5382122e30e 100644 --- a/src/test/ui/feature-gate-intrinsics.stderr +++ b/src/test/ui/feature-gate-intrinsics.stderr @@ -1,4 +1,4 @@ -error[E0658]: intrinsics are subject to change +error: intrinsics are subject to change --> $DIR/feature-gate-intrinsics.rs:11:1 | 11 | / extern "rust-intrinsic" { //~ ERROR intrinsics are subject to change @@ -8,7 +8,7 @@ error[E0658]: intrinsics are subject to change | = help: add #![feature(intrinsics)] to the crate attributes to enable -error[E0658]: intrinsics are subject to change +error: intrinsics are subject to change --> $DIR/feature-gate-intrinsics.rs:15:1 | 15 | / extern "rust-intrinsic" fn baz() { //~ ERROR intrinsics are subject to change diff --git a/src/test/ui/feature-gate-non_ascii_idents.stderr b/src/test/ui/feature-gate-non_ascii_idents.stderr index deb707752b0..90d0b8daee7 100644 --- a/src/test/ui/feature-gate-non_ascii_idents.stderr +++ b/src/test/ui/feature-gate-non_ascii_idents.stderr @@ -1,4 +1,4 @@ -error[E0658]: non-ascii idents are not fully supported. (see issue #28979) +error: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:11:1 | 11 | extern crate core as bäz; //~ ERROR non-ascii idents @@ -6,7 +6,7 @@ error[E0658]: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #28979) +error: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:13:5 | 13 | use föö::bar; //~ ERROR non-ascii idents @@ -14,7 +14,7 @@ error[E0658]: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #28979) +error: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:15:1 | 15 | mod föö { //~ ERROR non-ascii idents @@ -22,7 +22,7 @@ error[E0658]: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #28979) +error: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:19:1 | 19 | / fn bär( //~ ERROR non-ascii idents @@ -36,7 +36,7 @@ error[E0658]: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #28979) +error: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:20:5 | 20 | bäz: isize //~ ERROR non-ascii idents @@ -44,7 +44,7 @@ error[E0658]: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #28979) +error: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:22:9 | 22 | let _ö: isize; //~ ERROR non-ascii idents @@ -52,7 +52,7 @@ error[E0658]: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #28979) +error: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:25:10 | 25 | (_ä, _) => {} //~ ERROR non-ascii idents @@ -60,7 +60,7 @@ error[E0658]: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #28979) +error: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:29:1 | 29 | struct Föö { //~ ERROR non-ascii idents @@ -68,7 +68,7 @@ error[E0658]: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #28979) +error: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:30:5 | 30 | föö: isize //~ ERROR non-ascii idents @@ -76,7 +76,7 @@ error[E0658]: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #28979) +error: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:33:1 | 33 | enum Bär { //~ ERROR non-ascii idents @@ -84,7 +84,7 @@ error[E0658]: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #28979) +error: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:34:5 | 34 | Bäz { //~ ERROR non-ascii idents @@ -92,7 +92,7 @@ error[E0658]: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #28979) +error: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:35:9 | 35 | qüx: isize //~ ERROR non-ascii idents @@ -100,7 +100,7 @@ error[E0658]: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #28979) +error: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:40:5 | 40 | fn qüx(); //~ ERROR non-ascii idents diff --git a/src/test/ui/feature-gate-repr128.stderr b/src/test/ui/feature-gate-repr128.stderr index 982ebb01016..c59964887b5 100644 --- a/src/test/ui/feature-gate-repr128.stderr +++ b/src/test/ui/feature-gate-repr128.stderr @@ -1,4 +1,4 @@ -error[E0658]: repr with 128-bit type is unstable (see issue #35118) +error: repr with 128-bit type is unstable (see issue #35118) --> $DIR/feature-gate-repr128.rs:12:1 | 12 | / enum A { //~ ERROR repr with 128-bit type is unstable diff --git a/src/test/ui/feature-gate-unboxed-closures.stderr b/src/test/ui/feature-gate-unboxed-closures.stderr index ca8a5924946..b79165147e5 100644 --- a/src/test/ui/feature-gate-unboxed-closures.stderr +++ b/src/test/ui/feature-gate-unboxed-closures.stderr @@ -1,4 +1,4 @@ -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error: rust-call ABI is subject to change (see issue #29625) --> $DIR/feature-gate-unboxed-closures.rs:16:5 | 16 | / extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 { diff --git a/src/test/ui/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gate-untagged_unions.stderr index 14b66cb5c81..26b698912bc 100644 --- a/src/test/ui/feature-gate-untagged_unions.stderr +++ b/src/test/ui/feature-gate-untagged_unions.stderr @@ -1,4 +1,4 @@ -error[E0658]: unions with non-`Copy` fields are unstable (see issue #32836) +error: unions with non-`Copy` fields are unstable (see issue #32836) --> $DIR/feature-gate-untagged_unions.rs:19:1 | 19 | / union U3 { //~ ERROR unions with non-`Copy` fields are unstable @@ -8,7 +8,7 @@ error[E0658]: unions with non-`Copy` fields are unstable (see issue #32836) | = help: add #![feature(untagged_unions)] to the crate attributes to enable -error[E0658]: unions with non-`Copy` fields are unstable (see issue #32836) +error: unions with non-`Copy` fields are unstable (see issue #32836) --> $DIR/feature-gate-untagged_unions.rs:23:1 | 23 | / union U4 { //~ ERROR unions with non-`Copy` fields are unstable @@ -18,7 +18,7 @@ error[E0658]: unions with non-`Copy` fields are unstable (see issue #32836) | = help: add #![feature(untagged_unions)] to the crate attributes to enable -error[E0658]: unions with `Drop` implementations are unstable (see issue #32836) +error: unions with `Drop` implementations are unstable (see issue #32836) --> $DIR/feature-gate-untagged_unions.rs:27:1 | 27 | / union U5 { //~ ERROR unions with `Drop` implementations are unstable diff --git a/src/test/ui/fmt/send-sync.stderr b/src/test/ui/fmt/send-sync.stderr index 4ec5c9ebd27..9e0e563c35f 100644 --- a/src/test/ui/fmt/send-sync.stderr +++ b/src/test/ui/fmt/send-sync.stderr @@ -12,11 +12,7 @@ error[E0277]: the trait bound `*mut std::ops::Fn() + 'static: std::marker::Sync` = 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<'_>` -note: required by `send` - --> $DIR/send-sync.rs:11:1 - | -11 | fn send(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `send` error[E0277]: the trait bound `*mut std::ops::Fn() + 'static: std::marker::Sync` is not satisfied in `std::fmt::Arguments<'_>` --> $DIR/send-sync.rs:19:5 @@ -32,11 +28,7 @@ error[E0277]: the trait bound `*mut std::ops::Fn() + 'static: std::marker::Sync` = 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::Arguments<'_>` -note: required by `sync` - --> $DIR/send-sync.rs:12:1 - | -12 | fn sync(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `sync` error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr index e65c8f1546e..fd8f3b8e646 100644 --- a/src/test/ui/generator/not-send-sync.stderr +++ b/src/test/ui/generator/not-send-sync.stderr @@ -7,11 +7,7 @@ error[E0277]: the trait bound `std::cell::Cell: std::marker::Sync` is not s = help: the trait `std::marker::Sync` is not implemented for `std::cell::Cell` = note: required because of the requirements on the impl of `std::marker::Send` for `&std::cell::Cell` = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:26:17: 30:6 a:&std::cell::Cell _]` -note: required by `main::assert_send` - --> $DIR/not-send-sync.rs:17:5 - | -17 | fn assert_send(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `main::assert_send` error[E0277]: the trait bound `std::cell::Cell: std::marker::Sync` is not satisfied in `[generator@$DIR/not-send-sync.rs:19:17: 23:6 {std::cell::Cell, ()}]` --> $DIR/not-send-sync.rs:19:5 diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 838a3002e3a..ffd6a3fe4ff 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -7,11 +7,7 @@ error[E0277]: the trait bound `std::rc::Rc>: std::marker::S = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` = note: required because it appears within the type `[closure@$DIR/auto-trait-leak.rs:21:5: 21:22 p:std::rc::Rc>]` = note: required because it appears within the type `impl std::ops::Fn<(i32,)>` -note: required by `send` - --> $DIR/auto-trait-leak.rs:24:1 - | -24 | fn send(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `send` error[E0277]: the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied in `impl std::ops::Fn<(i32,)>` --> $DIR/auto-trait-leak.rs:30:5 @@ -22,11 +18,7 @@ error[E0277]: the trait bound `std::rc::Rc>: std::marker::S = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` = note: required because it appears within the type `[closure@$DIR/auto-trait-leak.rs:38:5: 38:22 p:std::rc::Rc>]` = note: required because it appears within the type `impl std::ops::Fn<(i32,)>` -note: required by `send` - --> $DIR/auto-trait-leak.rs:24:1 - | -24 | fn send(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `send` error[E0391]: unsupported cyclic reference between types/traits detected --> $DIR/auto-trait-leak.rs:44:1 diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr index 3fc08a0900f..8ec81903803 100644 --- a/src/test/ui/impl-trait/equality.stderr +++ b/src/test/ui/impl-trait/equality.stderr @@ -7,7 +7,7 @@ error[E0308]: mismatched types = note: expected type `i32` found type `u32` -error[E0277]: the trait bound `u32: std::ops::Add` is not satisfied +error[E0277]: cannot add `impl Foo` to `u32` --> $DIR/equality.rs:34:11 | 34 | n + sum_to(n - 1) diff --git a/src/test/ui/issue-24424.stderr b/src/test/ui/issue-24424.stderr index 55af26dd91e..acdf348791b 100644 --- a/src/test/ui/issue-24424.stderr +++ b/src/test/ui/issue-24424.stderr @@ -4,11 +4,7 @@ error[E0283]: type annotations required: cannot resolve `T0: Trait0<'l0>` 14 | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: required by `Trait0` - --> $DIR/issue-24424.rs:12:1 - | -12 | trait Trait0<'l0> {} - | ^^^^^^^^^^^^^^^^^ + = note: required by `Trait0` error: aborting due to previous error diff --git a/src/test/ui/lint/suggestions.stderr b/src/test/ui/lint/suggestions.stderr index 8b30f552d37..701a9522218 100644 --- a/src/test/ui/lint/suggestions.stderr +++ b/src/test/ui/lint/suggestions.stderr @@ -1,7 +1,7 @@ warning: unnecessary parentheses around assigned value - --> $DIR/suggestions.rs:46:21 + --> $DIR/suggestions.rs:36:21 | -46 | let mut a = (1); // should suggest no `mut`, no parens +36 | let mut a = (1); // should suggest no `mut`, no parens | ^^^ help: remove these parentheses | note: lint level defined here @@ -11,17 +11,17 @@ note: lint level defined here | ^^^^^^^^^^^^^ warning: use of deprecated attribute `no_debug`: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand. See https://github.com/rust-lang/rust/issues/29721 - --> $DIR/suggestions.rs:41:1 + --> $DIR/suggestions.rs:31:1 | -41 | #[no_debug] // should suggest removal of deprecated attribute +31 | #[no_debug] // should suggest removal of deprecated attribute | ^^^^^^^^^^^ help: remove this attribute | = note: #[warn(deprecated)] on by default warning: variable does not need to be mutable - --> $DIR/suggestions.rs:46:13 + --> $DIR/suggestions.rs:36:13 | -46 | let mut a = (1); // should suggest no `mut`, no parens +36 | let mut a = (1); // should suggest no `mut`, no parens | ---^^ | | | help: remove this `mut` @@ -72,30 +72,18 @@ warning: function is marked #[no_mangle], but not exported | = note: #[warn(private_no_mangle_fns)] on by default -warning: static is marked #[no_mangle], but not exported - --> $DIR/suggestions.rs:31:18 - | -31 | #[no_mangle] pub static DAUNTLESS: bool = true; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: function is marked #[no_mangle], but not exported - --> $DIR/suggestions.rs:33:18 - | -33 | #[no_mangle] pub fn val_jean() {} - | ^^^^^^^^^^^^^^^^^^^^ - warning: denote infinite loops with `loop { ... }` - --> $DIR/suggestions.rs:44:5 + --> $DIR/suggestions.rs:34:5 | -44 | while true { // should suggest `loop` +34 | while true { // should suggest `loop` | ^^^^^^^^^^ help: use `loop` | = note: #[warn(while_true)] on by default warning: the `warp_factor:` in this pattern is redundant - --> $DIR/suggestions.rs:51:23 + --> $DIR/suggestions.rs:41:23 | -51 | Equinox { warp_factor: warp_factor } => {} // should suggest shorthand +41 | Equinox { warp_factor: warp_factor } => {} // should suggest shorthand | ------------^^^^^^^^^^^^ | | | help: remove this diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr index 86c2ad4c0e7..abbf3da513a 100644 --- a/src/test/ui/lint/use_suggestion_json.stderr +++ b/src/test/ui/lint/use_suggestion_json.stderr @@ -2,72 +2,7 @@ "message": "cannot find type `Iter` in this scope", "code": { "code": "E0412", - "explanation": " -The type name used is not in scope. - -Erroneous code examples: - -```compile_fail,E0412 -impl Something {} // error: type name `Something` is not in scope - -// or: - -trait Foo { - fn bar(N); // error: type name `N` is not in scope -} - -// or: - -fn foo(x: T) {} // type name `T` is not in scope -``` - -To fix this error, please verify you didn't misspell the type name, you did -declare it or imported it into the scope. Examples: - -``` -struct Something; - -impl Something {} // ok! - -// or: - -trait Foo { - type N; - - fn bar(_: Self::N); // ok! -} - -// or: - -fn foo(x: T) {} // ok! -``` - -Another case that causes this error is when a type is imported into a parent -module. To fix this, you can follow the suggestion and use File directly or -`use super::File;` which will import the types from the parent namespace. An -example that causes this error is below: - -```compile_fail,E0412 -use std::fs::File; - -mod foo { - fn some_function(f: File) {} -} -``` - -``` -use std::fs::File; - -mod foo { - // either - use super::File; - // or - // use std::fs::File; - fn foo(f: File) {} -} -# fn main() {} // don't insert it for us; that'll break imports -``` -" + "explanation": null }, "level": "error", "spans": [ diff --git a/src/test/ui/macros/format-foreign.stderr b/src/test/ui/macros/format-foreign.stderr index f9852c54773..d0229957b68 100644 --- a/src/test/ui/macros/format-foreign.stderr +++ b/src/test/ui/macros/format-foreign.stderr @@ -1,8 +1,12 @@ error: multiple unused formatting arguments - --> $DIR/format-foreign.rs:12:30 + --> $DIR/format-foreign.rs:12:5 | -12 | println!("%.*3$s %s!/n", "Hello,", "World", 4); //~ ERROR multiple unused formatting arguments - | -------------------------^^^^^^^^--^^^^^^^--^-- multiple unused arguments in this statement +12 | println!("%.*3$s %s!/n", "Hello,", "World", 4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^--------^^-------^^-^^ + | | | | + | | | unused + | | unused + | unused | = help: `%.*3$s` should be written as `{:.2$}` = help: `%s` should be written as `{}` diff --git a/src/test/ui/macros/format-unused-lables.stderr b/src/test/ui/macros/format-unused-lables.stderr index 64ea5626c1d..9efdca12dea 100644 --- a/src/test/ui/macros/format-unused-lables.stderr +++ b/src/test/ui/macros/format-unused-lables.stderr @@ -1,43 +1,49 @@ error: multiple unused formatting arguments - --> $DIR/format-unused-lables.rs:12:22 + --> $DIR/format-unused-lables.rs:12:5 | 12 | println!("Test", 123, 456, 789); - | -----------------^^^--^^^--^^^-- multiple unused arguments in this statement + | ^^^^^^^^^^^^^^^^^---^^---^^---^^ + | | | | + | | | unused + | | unused + | unused | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: multiple unused formatting arguments - --> $DIR/format-unused-lables.rs:16:9 + --> $DIR/format-unused-lables.rs:14:5 | -15 | / println!("Test2", -16 | | 123, //~ ERROR multiple unused formatting arguments - | | ^^^ -17 | | 456, - | | ^^^ -18 | | 789 - | | ^^^ -19 | | ); - | |______- multiple unused arguments in this statement +14 | / println!("Test2", +15 | | 123, + | | --- unused +16 | | 456, + | | --- unused +17 | | 789 + | | --- unused +18 | | ); + | |______^ | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: named argument never used - --> $DIR/format-unused-lables.rs:21:35 + --> $DIR/format-unused-lables.rs:20:35 | -21 | println!("Some stuff", UNUSED="args"); //~ ERROR named argument never used +20 | println!("Some stuff", UNUSED="args"); //~ ERROR named argument never used | ^^^^^^ error: multiple unused formatting arguments - --> $DIR/format-unused-lables.rs:24:9 + --> $DIR/format-unused-lables.rs:22:5 | -23 | / println!("Some more $STUFF", -24 | | "woo!", //~ ERROR multiple unused formatting arguments - | | ^^^^^^ -25 | | STUFF= -26 | | "things" - | | ^^^^^^^^ -27 | | , UNUSED="args"); - | |_______________________^^^^^^_- multiple unused arguments in this statement +22 | / println!("Some more $STUFF", +23 | | "woo!", + | | ------ unused +24 | | STUFF= +25 | | "things" + | | -------- unused +26 | | , UNUSED="args"); + | |_______________________------_^ + | | + | unused | = help: `$STUFF` should be written as `{STUFF}` = note: shell formatting not supported; see the documentation for `std::fmt` diff --git a/src/test/ui/mismatched_types/E0631.stderr b/src/test/ui/mismatched_types/E0631.stderr index 53f2f54325d..442900e0a83 100644 --- a/src/test/ui/mismatched_types/E0631.stderr +++ b/src/test/ui/mismatched_types/E0631.stderr @@ -6,11 +6,7 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `fn(usize) -> _` | -note: required by `foo` - --> $DIR/E0631.rs:13:1 - | -13 | fn foo(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `foo` error[E0631]: type mismatch in closure arguments --> $DIR/E0631.rs:18:5 @@ -20,11 +16,7 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `fn(usize) -> _` | -note: required by `bar` - --> $DIR/E0631.rs:14:1 - | -14 | fn bar>(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `bar` error[E0631]: type mismatch in function arguments --> $DIR/E0631.rs:19:5 @@ -35,11 +27,7 @@ error[E0631]: type mismatch in function arguments 19 | foo(f); //~ ERROR type mismatch | ^^^ expected signature of `fn(usize) -> _` | -note: required by `foo` - --> $DIR/E0631.rs:13:1 - | -13 | fn foo(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `foo` error[E0631]: type mismatch in function arguments --> $DIR/E0631.rs:20:5 @@ -50,11 +38,7 @@ error[E0631]: type mismatch in function arguments 20 | bar(f); //~ ERROR type mismatch | ^^^ expected signature of `fn(usize) -> _` | -note: required by `bar` - --> $DIR/E0631.rs:14:1 - | -14 | fn bar>(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `bar` error: aborting due to 4 previous errors diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr index 8541ad52e01..57e66794a58 100644 --- a/src/test/ui/mismatched_types/binops.stderr +++ b/src/test/ui/mismatched_types/binops.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `{integer}: std::ops::Add>` is not satisfied +error[E0277]: cannot add `std::option::Option<{integer}>` to `{integer}` --> $DIR/binops.rs:12:7 | 12 | 1 + Some(1); //~ ERROR is not satisfied @@ -6,7 +6,7 @@ error[E0277]: the trait bound `{integer}: std::ops::Add>` is not implemented for `{integer}` -error[E0277]: the trait bound `usize: std::ops::Sub>` is not satisfied +error[E0277]: cannot substract `std::option::Option<{integer}>` from `usize` --> $DIR/binops.rs:13:16 | 13 | 2 as usize - Some(1); //~ ERROR is not satisfied @@ -14,7 +14,7 @@ error[E0277]: the trait bound `usize: std::ops::Sub>` is not implemented for `usize` -error[E0277]: the trait bound `{integer}: std::ops::Mul<()>` is not satisfied +error[E0277]: cannot multiply `()` to `{integer}` --> $DIR/binops.rs:14:7 | 14 | 3 * (); //~ ERROR is not satisfied @@ -22,7 +22,7 @@ error[E0277]: the trait bound `{integer}: std::ops::Mul<()>` is not satisfied | = help: the trait `std::ops::Mul<()>` is not implemented for `{integer}` -error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied +error[E0277]: cannot divide `{integer}` by `&str` --> $DIR/binops.rs:15:7 | 15 | 4 / ""; //~ ERROR is not satisfied diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr index be00ee4d74e..d904831ba4e 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.stderr +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -46,11 +46,7 @@ error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments | | | expected closure that takes 1 argument | -note: required by `f` - --> $DIR/closure-arg-count.rs:13:1 - | -13 | fn f>(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `f` error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments --> $DIR/closure-arg-count.rs:26:53 diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr index dfd02fe23b6..77d3a332767 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -31,11 +31,7 @@ error[E0631]: type mismatch in function arguments | expected signature of `for<'r> fn(*mut &'r u32) -> _` | found signature of `fn(*mut &'a u32) -> _` | -note: required by `baz` - --> $DIR/closure-arg-type-mismatch.rs:18:1 - | -18 | fn baz(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `baz` error[E0271]: type mismatch resolving `for<'r> >::Output == ()` --> $DIR/closure-arg-type-mismatch.rs:20:5 @@ -43,11 +39,7 @@ error[E0271]: type mismatch resolving `for<'r> $DIR/closure-arg-type-mismatch.rs:18:1 - | -18 | fn baz(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `baz` error: aborting due to 5 previous errors diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr index 01de7e07495..99767ba1afa 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -5,11 +5,7 @@ error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.r | ^^^ expected bound lifetime parameter, found concrete lifetime | = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:18:9: 18:15]` -note: required by `baz` - --> $DIR/closure-mismatch.rs:15:1 - | -15 | fn baz(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^ + = note: required by `baz` error[E0631]: type mismatch in closure arguments --> $DIR/closure-mismatch.rs:18:5 @@ -20,11 +16,7 @@ error[E0631]: type mismatch in closure arguments | expected signature of `for<'r> fn(&'r ()) -> _` | = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:18:9: 18:15]` -note: required by `baz` - --> $DIR/closure-mismatch.rs:15:1 - | -15 | fn baz(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^ + = note: required by `baz` error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/fn-variance-1.stderr b/src/test/ui/mismatched_types/fn-variance-1.stderr index 64c260c30ed..2a27ffd1062 100644 --- a/src/test/ui/mismatched_types/fn-variance-1.stderr +++ b/src/test/ui/mismatched_types/fn-variance-1.stderr @@ -7,11 +7,7 @@ error[E0631]: type mismatch in function arguments 21 | apply(&3, takes_mut); | ^^^^^ expected signature of `fn(&{integer}) -> _` | -note: required by `apply` - --> $DIR/fn-variance-1.rs:15:1 - | -15 | fn apply(t: T, f: F) where F: FnOnce(T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `apply` error[E0631]: type mismatch in function arguments --> $DIR/fn-variance-1.rs:25:5 @@ -22,11 +18,7 @@ error[E0631]: type mismatch in function arguments 25 | apply(&mut 3, takes_imm); | ^^^^^ expected signature of `fn(&mut {integer}) -> _` | -note: required by `apply` - --> $DIR/fn-variance-1.rs:15:1 - | -15 | fn apply(t: T, f: F) where F: FnOnce(T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `apply` error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr index 9c9bbd19c75..8539c8818c0 100644 --- a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr +++ b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr @@ -1,17 +1,12 @@ error[E0631]: type mismatch in closure arguments - --> $DIR/unboxed-closures-vtable-mismatch.rs:25:13 + --> $DIR/unboxed-closures-vtable-mismatch.rs:23:13 | -23 | let f = to_fn_mut(|x: usize, y: isize| -> isize { (x as isize) + y }); +22 | let f = to_fn_mut(|x: usize, y: isize| -> isize { (x as isize) + y }); | ----------------------------- found signature of `fn(usize, isize) -> _` -24 | //~^ NOTE found signature of `fn(usize, isize) -> _` -25 | let z = call_it(3, f); +23 | let z = call_it(3, f); | ^^^^^^^ expected signature of `fn(isize, isize) -> _` | -note: required by `call_it` - --> $DIR/unboxed-closures-vtable-mismatch.rs:17:1 - | -17 | fn call_itisize>(y: isize, mut f: F) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `call_it` error: aborting due to previous error diff --git a/src/test/ui/on-unimplemented/multiple-impls.stderr b/src/test/ui/on-unimplemented/multiple-impls.stderr index cfac3981be2..1f71be446ef 100644 --- a/src/test/ui/on-unimplemented/multiple-impls.stderr +++ b/src/test/ui/on-unimplemented/multiple-impls.stderr @@ -5,11 +5,7 @@ error[E0277]: the trait bound `[i32]: Index` is not satisfied | ^^^^^^^^^^^^ trait message | = help: the trait `Index` is not implemented for `[i32]` -note: required by `Index::index` - --> $DIR/multiple-impls.rs:22:5 - | -22 | fn index(&self, index: Idx) -> &Self::Output; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `Index::index` error[E0277]: the trait bound `[i32]: Index` is not satisfied --> $DIR/multiple-impls.rs:43:5 @@ -26,11 +22,7 @@ error[E0277]: the trait bound `[i32]: Index>` is not satisfied | ^^^^^^^^^^^^ on impl for Foo | = help: the trait `Index>` is not implemented for `[i32]` -note: required by `Index::index` - --> $DIR/multiple-impls.rs:22:5 - | -22 | fn index(&self, index: Idx) -> &Self::Output; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `Index::index` error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:46:5 @@ -47,11 +39,7 @@ error[E0277]: the trait bound `[i32]: Index>` is not satisfied | ^^^^^^^^^^^^ on impl for Bar | = help: the trait `Index>` is not implemented for `[i32]` -note: required by `Index::index` - --> $DIR/multiple-impls.rs:22:5 - | -22 | fn index(&self, index: Idx) -> &Self::Output; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `Index::index` error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:49:5 diff --git a/src/test/ui/on-unimplemented/on-impl.stderr b/src/test/ui/on-unimplemented/on-impl.stderr index ed2da68f081..c8c06bf44fd 100644 --- a/src/test/ui/on-unimplemented/on-impl.stderr +++ b/src/test/ui/on-unimplemented/on-impl.stderr @@ -5,11 +5,7 @@ error[E0277]: the trait bound `[i32]: Index` is not satisfied | ^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice | = help: the trait `Index` is not implemented for `[i32]` -note: required by `Index::index` - --> $DIR/on-impl.rs:19:5 - | -19 | fn index(&self, index: Idx) -> &Self::Output; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `Index::index` error[E0277]: the trait bound `[i32]: Index` is not satisfied --> $DIR/on-impl.rs:32:5 diff --git a/src/test/ui/on-unimplemented/on-trait.stderr b/src/test/ui/on-unimplemented/on-trait.stderr index 028200a5558..cde56022fae 100644 --- a/src/test/ui/on-unimplemented/on-trait.stderr +++ b/src/test/ui/on-unimplemented/on-trait.stderr @@ -5,11 +5,7 @@ error[E0277]: the trait bound `std::option::Option>: MyFromIte | ^^^^^^^ a collection of type `std::option::Option>` cannot be built from an iterator over elements of type `&u8` | = help: the trait `MyFromIterator<&u8>` is not implemented for `std::option::Option>` -note: required by `collect` - --> $DIR/on-trait.rs:31:1 - | -31 | fn collect, B: MyFromIterator>(it: I) -> B { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `collect` error[E0277]: the trait bound `std::string::String: Bar::Foo` is not satisfied --> $DIR/on-trait.rs:40:21 @@ -18,11 +14,7 @@ error[E0277]: the trait bound `std::string::String: Bar::Foo` is not | ^^^^^^ test error `std::string::String` with `u8` `_` `u32` in `Bar::Foo` | = help: the trait `Bar::Foo` is not implemented for `std::string::String` -note: required by `foobar` - --> $DIR/on-trait.rs:21:1 - | -21 | fn foobar>() -> T { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `foobar` error: aborting due to 2 previous errors diff --git a/src/test/ui/span/issue-29595.stderr b/src/test/ui/span/issue-29595.stderr index 9046b90f0e9..81ba0057d71 100644 --- a/src/test/ui/span/issue-29595.stderr +++ b/src/test/ui/span/issue-29595.stderr @@ -4,11 +4,7 @@ error[E0277]: the trait bound `u8: Tr` is not satisfied 17 | let a: u8 = Tr::C; //~ ERROR the trait bound `u8: Tr` is not satisfied | ^^^^^ the trait `Tr` is not implemented for `u8` | -note: required by `Tr::C` - --> $DIR/issue-29595.rs:13:5 - | -13 | const C: Self; - | ^^^^^^^^^^^^^^ + = note: required by `Tr::C` error: aborting due to previous error diff --git a/src/test/ui/span/multiline-span-simple.stderr b/src/test/ui/span/multiline-span-simple.stderr index b068798630e..b6182825fc2 100644 --- a/src/test/ui/span/multiline-span-simple.stderr +++ b/src/test/ui/span/multiline-span-simple.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied +error[E0277]: cannot add `()` to `u32` --> $DIR/multiline-span-simple.rs:23:18 | 23 | foo(1 as u32 + //~ ERROR not satisfied diff --git a/src/test/ui/suggestions/try-operator-on-main.stderr b/src/test/ui/suggestions/try-operator-on-main.stderr index e97823a3d5d..36cdd558b0f 100644 --- a/src/test/ui/suggestions/try-operator-on-main.stderr +++ b/src/test/ui/suggestions/try-operator-on-main.stderr @@ -22,11 +22,7 @@ error[E0277]: the trait bound `(): std::ops::Try` is not satisfied 25 | try_trait_generic::<()>(); //~ ERROR the trait bound | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Try` is not implemented for `()` | -note: required by `try_trait_generic` - --> $DIR/try-operator-on-main.rs:30:1 - | -30 | fn try_trait_generic() -> T { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: required by `try_trait_generic` error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` --> $DIR/try-operator-on-main.rs:32:5 diff --git a/src/test/ui/type-check/issue-40294.stderr b/src/test/ui/type-check/issue-40294.stderr index cf270afdeb1..2ca97aa3ef0 100644 --- a/src/test/ui/type-check/issue-40294.stderr +++ b/src/test/ui/type-check/issue-40294.stderr @@ -10,11 +10,7 @@ error[E0283]: type annotations required: cannot resolve `&'a T: Foo` 21 | | } | |_^ | -note: required by `Foo` - --> $DIR/issue-40294.rs:11:1 - | -11 | trait Foo: Sized { - | ^^^^^^^^^^^^^^^^ + = note: required by `Foo` error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 4c92a02b64e5cb8cfb9b885638e1dfa2067cacd9 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Fri, 19 Jan 2018 20:28:09 -0800 Subject: Change rustc_on_unimplemented for Iterator and binops --- src/libcore/ops/arith.rs | 9 +-- .../ui/anonymous-higher-ranked-lifetime.stderr | 66 ++++++++++++++++++---- .../issue-39802-show-5-trait-impls.stderr | 18 +++++- src/test/ui/did_you_mean/recursion_limit.stderr | 6 +- src/test/ui/feature-gate-abi_unadjusted.stderr | 2 +- src/test/ui/feature-gate-catch_expr.stderr | 2 +- src/test/ui/feature-gate-i128_type2.stderr | 10 ++-- src/test/ui/feature-gate-intrinsics.stderr | 4 +- src/test/ui/feature-gate-non_ascii_idents.stderr | 26 ++++----- src/test/ui/feature-gate-repr128.stderr | 2 +- src/test/ui/feature-gate-unboxed-closures.stderr | 2 +- src/test/ui/feature-gate-untagged_unions.stderr | 6 +- src/test/ui/fmt/send-sync.stderr | 12 +++- src/test/ui/generator/not-send-sync.stderr | 6 +- src/test/ui/impl-trait/auto-trait-leak.stderr | 12 +++- src/test/ui/issue-24424.stderr | 6 +- src/test/ui/lint/suggestions.stderr | 32 +++++++---- src/test/ui/macros/format-foreign.stderr | 10 +--- src/test/ui/macros/format-unused-lables.stderr | 52 ++++++++--------- src/test/ui/mismatched_types/E0631.stderr | 24 ++++++-- .../ui/mismatched_types/closure-arg-count.stderr | 56 +++++++++--------- .../closure-arg-type-mismatch.stderr | 12 +++- .../ui/mismatched_types/closure-mismatch.stderr | 12 +++- src/test/ui/mismatched_types/fn-variance-1.stderr | 12 +++- .../unboxed-closures-vtable-mismatch.stderr | 13 +++-- .../multiple-impls-complex-filtering.rs | 61 ++++++++++++++++++++ .../multiple-impls-complex-filtering.stderr | 44 +++++++++++++++ src/test/ui/on-unimplemented/multiple-impls.stderr | 18 +++++- src/test/ui/on-unimplemented/on-impl.stderr | 6 +- src/test/ui/on-unimplemented/on-trait.stderr | 12 +++- src/test/ui/span/issue-29595.stderr | 6 +- .../ui/suggestions/try-operator-on-main.stderr | 6 +- src/test/ui/type-check/issue-40294.stderr | 6 +- 33 files changed, 418 insertions(+), 153 deletions(-) create mode 100644 src/test/ui/on-unimplemented/multiple-impls-complex-filtering.rs create mode 100644 src/test/ui/on-unimplemented/multiple-impls-complex-filtering.stderr (limited to 'src/libcore') diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs index 59a18d6cb75..47617b22dd3 100644 --- a/src/libcore/ops/arith.rs +++ b/src/libcore/ops/arith.rs @@ -109,7 +109,6 @@ all(_Self="f32", RHS="u16"), all(_Self="f32", RHS="u8"), ), - message="cannot add `{RHS}` to `{Self}`", label="no implementation for `{Self} + {RHS}`, but you can safely cast \ `{RHS}` into `{Self}` using `as {Self}`", ), @@ -146,22 +145,20 @@ all(RHS="f32", _Self="u16"), all(RHS="f32", _Self="u8"), ), - message="cannot add `{RHS}` to `{Self}`", - label="no implementation for `{Self} + {RHS}`, but you can safely turn \ + label="no implementation for `{Self} + {RHS}`, but you can safely cast \ `{Self}` into `{RHS}` using `as {RHS}`", ), on( all(_Self="{integer}", RHS="{float}"), message="cannot add a float to an integer", - label="no implementation for `{Self} + {RHS}`", ), on( all(_Self="{float}", RHS="{integer}"), message="cannot add an integer to a float", - label="no implementation for `{Self} + {RHS}`", ), message="cannot add `{RHS}` to `{Self}`", - label="no implementation for `{Self} + {RHS}`")] + label="no implementation for `{Self} + {RHS}`", +)] pub trait Add { /// The resulting type after applying the `+` operator. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.stderr b/src/test/ui/anonymous-higher-ranked-lifetime.stderr index e364a4d8b14..4bd3b684b7b 100644 --- a/src/test/ui/anonymous-higher-ranked-lifetime.stderr +++ b/src/test/ui/anonymous-higher-ranked-lifetime.stderr @@ -6,7 +6,11 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'r, 's> fn(&'r (), &'s ()) -> _` | - = note: required by `f1` +note: required by `f1` + --> $DIR/anonymous-higher-ranked-lifetime.rs:26:1 + | +26 | fn f1(_: F) where F: Fn(&(), &()) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:13:5 @@ -16,7 +20,11 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'a, 'r> fn(&'a (), &'r ()) -> _` | - = note: required by `f2` +note: required by `f2` + --> $DIR/anonymous-higher-ranked-lifetime.rs:27:1 + | +27 | fn f2(_: F) where F: for<'a> Fn(&'a (), &()) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5 @@ -26,7 +34,11 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'r> fn(&(), &'r ()) -> _` | - = note: required by `f3` +note: required by `f3` + --> $DIR/anonymous-higher-ranked-lifetime.rs:28:1 + | +28 | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:15:5 @@ -36,7 +48,11 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'s, 'r> fn(&'s (), &'r ()) -> _` | - = note: required by `f4` +note: required by `f4` + --> $DIR/anonymous-higher-ranked-lifetime.rs:29:1 + | +29 | fn f4(_: F) where F: for<'r> Fn(&(), &'r ()) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5 @@ -46,7 +62,11 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'r> fn(&'r (), &'r ()) -> _` | - = note: required by `f5` +note: required by `f5` + --> $DIR/anonymous-higher-ranked-lifetime.rs:30:1 + | +30 | fn f5(_: F) where F: for<'r> Fn(&'r (), &'r ()) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:17:5 @@ -56,7 +76,11 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'r> fn(&'r (), std::boxed::Box std::ops::Fn(&'s ()) + 'static>) -> _` | - = note: required by `g1` +note: required by `g1` + --> $DIR/anonymous-higher-ranked-lifetime.rs:33:1 + | +33 | fn g1(_: F) where F: Fn(&(), Box) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5 @@ -66,7 +90,11 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'r> fn(&'r (), for<'s> fn(&'s ())) -> _` | - = note: required by `g2` +note: required by `g2` + --> $DIR/anonymous-higher-ranked-lifetime.rs:34:1 + | +34 | fn g2(_: F) where F: Fn(&(), fn(&())) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:19:5 @@ -76,7 +104,11 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'s> fn(&'s (), std::boxed::Box std::ops::Fn(&'r ()) + 'static>) -> _` | - = note: required by `g3` +note: required by `g3` + --> $DIR/anonymous-higher-ranked-lifetime.rs:35:1 + | +35 | fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5 @@ -86,7 +118,11 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'s> fn(&'s (), for<'r> fn(&'r ())) -> _` | - = note: required by `g4` +note: required by `g4` + --> $DIR/anonymous-higher-ranked-lifetime.rs:36:1 + | +36 | fn g4(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:21:5 @@ -96,7 +132,11 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'r, 's> fn(&'r (), std::boxed::Box std::ops::Fn(&'t0 ()) + 'static>, &'s (), for<'t0, 't1> fn(&'t0 (), &'t1 ())) -> _` | - = note: required by `h1` +note: required by `h1` + --> $DIR/anonymous-higher-ranked-lifetime.rs:39:1 + | +39 | fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5 @@ -106,7 +146,11 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `for<'r, 't0> fn(&'r (), std::boxed::Box std::ops::Fn(&'s ()) + 'static>, &'t0 (), for<'s, 't1> fn(&'s (), &'t1 ())) -> _` | - = note: required by `h2` +note: required by `h2` + --> $DIR/anonymous-higher-ranked-lifetime.rs:40:1 + | +40 | fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), &())) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 11 previous errors diff --git a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr index d5c4add34b5..7ca3e8728fd 100644 --- a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr +++ b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr @@ -10,7 +10,11 @@ error[E0277]: the trait bound `i8: Foo` is not satisfied > > > - = note: required by `Foo::bar` +note: required by `Foo::bar` + --> $DIR/issue-39802-show-5-trait-impls.rs:12:5 + | +12 | fn bar(&self){} + | ^^^^^^^^^^^^^ error[E0277]: the trait bound `u8: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:35:5 @@ -23,7 +27,11 @@ error[E0277]: the trait bound `u8: Foo` is not satisfied > > > - = note: required by `Foo::bar` +note: required by `Foo::bar` + --> $DIR/issue-39802-show-5-trait-impls.rs:12:5 + | +12 | fn bar(&self){} + | ^^^^^^^^^^^^^ error[E0277]: the trait bound `bool: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:36:5 @@ -37,7 +45,11 @@ error[E0277]: the trait bound `bool: Foo` is not satisfied > > and 2 others - = note: required by `Foo::bar` +note: required by `Foo::bar` + --> $DIR/issue-39802-show-5-trait-impls.rs:12:5 + | +12 | fn bar(&self){} + | ^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/did_you_mean/recursion_limit.stderr b/src/test/ui/did_you_mean/recursion_limit.stderr index 7fac604ba49..2bc7e9e46e7 100644 --- a/src/test/ui/did_you_mean/recursion_limit.stderr +++ b/src/test/ui/did_you_mean/recursion_limit.stderr @@ -15,7 +15,11 @@ error[E0275]: overflow evaluating the requirement `K: std::marker::Send` = note: required because it appears within the type `C` = note: required because it appears within the type `B` = note: required because it appears within the type `A` - = note: required by `is_send` +note: required by `is_send` + --> $DIR/recursion_limit.rs:41:1 + | +41 | fn is_send() { } + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/feature-gate-abi_unadjusted.stderr b/src/test/ui/feature-gate-abi_unadjusted.stderr index 3cc43847156..b3f7cd218d3 100644 --- a/src/test/ui/feature-gate-abi_unadjusted.stderr +++ b/src/test/ui/feature-gate-abi_unadjusted.stderr @@ -1,4 +1,4 @@ -error: unadjusted ABI is an implementation detail and perma-unstable +error[E0658]: unadjusted ABI is an implementation detail and perma-unstable --> $DIR/feature-gate-abi_unadjusted.rs:11:1 | 11 | / extern "unadjusted" fn foo() { diff --git a/src/test/ui/feature-gate-catch_expr.stderr b/src/test/ui/feature-gate-catch_expr.stderr index f486373d225..4b3bfbbe27a 100644 --- a/src/test/ui/feature-gate-catch_expr.stderr +++ b/src/test/ui/feature-gate-catch_expr.stderr @@ -1,4 +1,4 @@ -error: `catch` expression is experimental (see issue #31436) +error[E0658]: `catch` expression is experimental (see issue #31436) --> $DIR/feature-gate-catch_expr.rs:12:24 | 12 | let catch_result = do catch { //~ ERROR `catch` expression is experimental diff --git a/src/test/ui/feature-gate-i128_type2.stderr b/src/test/ui/feature-gate-i128_type2.stderr index 26653a5739b..ee81a269214 100644 --- a/src/test/ui/feature-gate-i128_type2.stderr +++ b/src/test/ui/feature-gate-i128_type2.stderr @@ -1,4 +1,4 @@ -error: 128-bit type is unstable (see issue #35118) +error[E0658]: 128-bit type is unstable (see issue #35118) --> $DIR/feature-gate-i128_type2.rs:13:15 | 13 | fn test1() -> i128 { //~ ERROR 128-bit type is unstable @@ -6,7 +6,7 @@ error: 128-bit type is unstable (see issue #35118) | = help: add #![feature(i128_type)] to the crate attributes to enable -error: 128-bit type is unstable (see issue #35118) +error[E0658]: 128-bit type is unstable (see issue #35118) --> $DIR/feature-gate-i128_type2.rs:17:17 | 17 | fn test1_2() -> u128 { //~ ERROR 128-bit type is unstable @@ -14,7 +14,7 @@ error: 128-bit type is unstable (see issue #35118) | = help: add #![feature(i128_type)] to the crate attributes to enable -error: 128-bit type is unstable (see issue #35118) +error[E0658]: 128-bit type is unstable (see issue #35118) --> $DIR/feature-gate-i128_type2.rs:22:12 | 22 | let x: i128 = 0; //~ ERROR 128-bit type is unstable @@ -22,7 +22,7 @@ error: 128-bit type is unstable (see issue #35118) | = help: add #![feature(i128_type)] to the crate attributes to enable -error: 128-bit type is unstable (see issue #35118) +error[E0658]: 128-bit type is unstable (see issue #35118) --> $DIR/feature-gate-i128_type2.rs:26:12 | 26 | let x: u128 = 0; //~ ERROR 128-bit type is unstable @@ -32,7 +32,7 @@ error: 128-bit type is unstable (see issue #35118) error[E0601]: main function not found -error: repr with 128-bit type is unstable (see issue #35118) +error[E0658]: repr with 128-bit type is unstable (see issue #35118) --> $DIR/feature-gate-i128_type2.rs:30:1 | 30 | / enum A { //~ ERROR 128-bit type is unstable diff --git a/src/test/ui/feature-gate-intrinsics.stderr b/src/test/ui/feature-gate-intrinsics.stderr index 5382122e30e..918c749504a 100644 --- a/src/test/ui/feature-gate-intrinsics.stderr +++ b/src/test/ui/feature-gate-intrinsics.stderr @@ -1,4 +1,4 @@ -error: intrinsics are subject to change +error[E0658]: intrinsics are subject to change --> $DIR/feature-gate-intrinsics.rs:11:1 | 11 | / extern "rust-intrinsic" { //~ ERROR intrinsics are subject to change @@ -8,7 +8,7 @@ error: intrinsics are subject to change | = help: add #![feature(intrinsics)] to the crate attributes to enable -error: intrinsics are subject to change +error[E0658]: intrinsics are subject to change --> $DIR/feature-gate-intrinsics.rs:15:1 | 15 | / extern "rust-intrinsic" fn baz() { //~ ERROR intrinsics are subject to change diff --git a/src/test/ui/feature-gate-non_ascii_idents.stderr b/src/test/ui/feature-gate-non_ascii_idents.stderr index 90d0b8daee7..deb707752b0 100644 --- a/src/test/ui/feature-gate-non_ascii_idents.stderr +++ b/src/test/ui/feature-gate-non_ascii_idents.stderr @@ -1,4 +1,4 @@ -error: non-ascii idents are not fully supported. (see issue #28979) +error[E0658]: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:11:1 | 11 | extern crate core as bäz; //~ ERROR non-ascii idents @@ -6,7 +6,7 @@ error: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error: non-ascii idents are not fully supported. (see issue #28979) +error[E0658]: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:13:5 | 13 | use föö::bar; //~ ERROR non-ascii idents @@ -14,7 +14,7 @@ error: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error: non-ascii idents are not fully supported. (see issue #28979) +error[E0658]: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:15:1 | 15 | mod föö { //~ ERROR non-ascii idents @@ -22,7 +22,7 @@ error: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error: non-ascii idents are not fully supported. (see issue #28979) +error[E0658]: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:19:1 | 19 | / fn bär( //~ ERROR non-ascii idents @@ -36,7 +36,7 @@ error: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error: non-ascii idents are not fully supported. (see issue #28979) +error[E0658]: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:20:5 | 20 | bäz: isize //~ ERROR non-ascii idents @@ -44,7 +44,7 @@ error: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error: non-ascii idents are not fully supported. (see issue #28979) +error[E0658]: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:22:9 | 22 | let _ö: isize; //~ ERROR non-ascii idents @@ -52,7 +52,7 @@ error: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error: non-ascii idents are not fully supported. (see issue #28979) +error[E0658]: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:25:10 | 25 | (_ä, _) => {} //~ ERROR non-ascii idents @@ -60,7 +60,7 @@ error: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error: non-ascii idents are not fully supported. (see issue #28979) +error[E0658]: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:29:1 | 29 | struct Föö { //~ ERROR non-ascii idents @@ -68,7 +68,7 @@ error: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error: non-ascii idents are not fully supported. (see issue #28979) +error[E0658]: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:30:5 | 30 | föö: isize //~ ERROR non-ascii idents @@ -76,7 +76,7 @@ error: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error: non-ascii idents are not fully supported. (see issue #28979) +error[E0658]: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:33:1 | 33 | enum Bär { //~ ERROR non-ascii idents @@ -84,7 +84,7 @@ error: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error: non-ascii idents are not fully supported. (see issue #28979) +error[E0658]: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:34:5 | 34 | Bäz { //~ ERROR non-ascii idents @@ -92,7 +92,7 @@ error: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error: non-ascii idents are not fully supported. (see issue #28979) +error[E0658]: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:35:9 | 35 | qüx: isize //~ ERROR non-ascii idents @@ -100,7 +100,7 @@ error: non-ascii idents are not fully supported. (see issue #28979) | = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error: non-ascii idents are not fully supported. (see issue #28979) +error[E0658]: non-ascii idents are not fully supported. (see issue #28979) --> $DIR/feature-gate-non_ascii_idents.rs:40:5 | 40 | fn qüx(); //~ ERROR non-ascii idents diff --git a/src/test/ui/feature-gate-repr128.stderr b/src/test/ui/feature-gate-repr128.stderr index c59964887b5..982ebb01016 100644 --- a/src/test/ui/feature-gate-repr128.stderr +++ b/src/test/ui/feature-gate-repr128.stderr @@ -1,4 +1,4 @@ -error: repr with 128-bit type is unstable (see issue #35118) +error[E0658]: repr with 128-bit type is unstable (see issue #35118) --> $DIR/feature-gate-repr128.rs:12:1 | 12 | / enum A { //~ ERROR repr with 128-bit type is unstable diff --git a/src/test/ui/feature-gate-unboxed-closures.stderr b/src/test/ui/feature-gate-unboxed-closures.stderr index b79165147e5..ca8a5924946 100644 --- a/src/test/ui/feature-gate-unboxed-closures.stderr +++ b/src/test/ui/feature-gate-unboxed-closures.stderr @@ -1,4 +1,4 @@ -error: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change (see issue #29625) --> $DIR/feature-gate-unboxed-closures.rs:16:5 | 16 | / extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 { diff --git a/src/test/ui/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gate-untagged_unions.stderr index 26b698912bc..14b66cb5c81 100644 --- a/src/test/ui/feature-gate-untagged_unions.stderr +++ b/src/test/ui/feature-gate-untagged_unions.stderr @@ -1,4 +1,4 @@ -error: unions with non-`Copy` fields are unstable (see issue #32836) +error[E0658]: unions with non-`Copy` fields are unstable (see issue #32836) --> $DIR/feature-gate-untagged_unions.rs:19:1 | 19 | / union U3 { //~ ERROR unions with non-`Copy` fields are unstable @@ -8,7 +8,7 @@ error: unions with non-`Copy` fields are unstable (see issue #32836) | = help: add #![feature(untagged_unions)] to the crate attributes to enable -error: unions with non-`Copy` fields are unstable (see issue #32836) +error[E0658]: unions with non-`Copy` fields are unstable (see issue #32836) --> $DIR/feature-gate-untagged_unions.rs:23:1 | 23 | / union U4 { //~ ERROR unions with non-`Copy` fields are unstable @@ -18,7 +18,7 @@ error: unions with non-`Copy` fields are unstable (see issue #32836) | = help: add #![feature(untagged_unions)] to the crate attributes to enable -error: unions with `Drop` implementations are unstable (see issue #32836) +error[E0658]: unions with `Drop` implementations are unstable (see issue #32836) --> $DIR/feature-gate-untagged_unions.rs:27:1 | 27 | / union U5 { //~ ERROR unions with `Drop` implementations are unstable diff --git a/src/test/ui/fmt/send-sync.stderr b/src/test/ui/fmt/send-sync.stderr index 9e0e563c35f..4ec5c9ebd27 100644 --- a/src/test/ui/fmt/send-sync.stderr +++ b/src/test/ui/fmt/send-sync.stderr @@ -12,7 +12,11 @@ error[E0277]: the trait bound `*mut std::ops::Fn() + 'static: std::marker::Sync` = 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<'_>` - = note: required by `send` +note: required by `send` + --> $DIR/send-sync.rs:11:1 + | +11 | fn send(_: T) {} + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `*mut std::ops::Fn() + 'static: std::marker::Sync` is not satisfied in `std::fmt::Arguments<'_>` --> $DIR/send-sync.rs:19:5 @@ -28,7 +32,11 @@ error[E0277]: the trait bound `*mut std::ops::Fn() + 'static: std::marker::Sync` = 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::Arguments<'_>` - = note: required by `sync` +note: required by `sync` + --> $DIR/send-sync.rs:12:1 + | +12 | fn sync(_: T) {} + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr index fd8f3b8e646..e65c8f1546e 100644 --- a/src/test/ui/generator/not-send-sync.stderr +++ b/src/test/ui/generator/not-send-sync.stderr @@ -7,7 +7,11 @@ error[E0277]: the trait bound `std::cell::Cell: std::marker::Sync` is not s = help: the trait `std::marker::Sync` is not implemented for `std::cell::Cell` = note: required because of the requirements on the impl of `std::marker::Send` for `&std::cell::Cell` = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:26:17: 30:6 a:&std::cell::Cell _]` - = note: required by `main::assert_send` +note: required by `main::assert_send` + --> $DIR/not-send-sync.rs:17:5 + | +17 | fn assert_send(_: T) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::cell::Cell: std::marker::Sync` is not satisfied in `[generator@$DIR/not-send-sync.rs:19:17: 23:6 {std::cell::Cell, ()}]` --> $DIR/not-send-sync.rs:19:5 diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index ffd6a3fe4ff..838a3002e3a 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -7,7 +7,11 @@ error[E0277]: the trait bound `std::rc::Rc>: std::marker::S = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` = note: required because it appears within the type `[closure@$DIR/auto-trait-leak.rs:21:5: 21:22 p:std::rc::Rc>]` = note: required because it appears within the type `impl std::ops::Fn<(i32,)>` - = note: required by `send` +note: required by `send` + --> $DIR/auto-trait-leak.rs:24:1 + | +24 | fn send(_: T) {} + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied in `impl std::ops::Fn<(i32,)>` --> $DIR/auto-trait-leak.rs:30:5 @@ -18,7 +22,11 @@ error[E0277]: the trait bound `std::rc::Rc>: std::marker::S = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` = note: required because it appears within the type `[closure@$DIR/auto-trait-leak.rs:38:5: 38:22 p:std::rc::Rc>]` = note: required because it appears within the type `impl std::ops::Fn<(i32,)>` - = note: required by `send` +note: required by `send` + --> $DIR/auto-trait-leak.rs:24:1 + | +24 | fn send(_: T) {} + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0391]: unsupported cyclic reference between types/traits detected --> $DIR/auto-trait-leak.rs:44:1 diff --git a/src/test/ui/issue-24424.stderr b/src/test/ui/issue-24424.stderr index acdf348791b..55af26dd91e 100644 --- a/src/test/ui/issue-24424.stderr +++ b/src/test/ui/issue-24424.stderr @@ -4,7 +4,11 @@ error[E0283]: type annotations required: cannot resolve `T0: Trait0<'l0>` 14 | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: required by `Trait0` +note: required by `Trait0` + --> $DIR/issue-24424.rs:12:1 + | +12 | trait Trait0<'l0> {} + | ^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/lint/suggestions.stderr b/src/test/ui/lint/suggestions.stderr index 701a9522218..8b30f552d37 100644 --- a/src/test/ui/lint/suggestions.stderr +++ b/src/test/ui/lint/suggestions.stderr @@ -1,7 +1,7 @@ warning: unnecessary parentheses around assigned value - --> $DIR/suggestions.rs:36:21 + --> $DIR/suggestions.rs:46:21 | -36 | let mut a = (1); // should suggest no `mut`, no parens +46 | let mut a = (1); // should suggest no `mut`, no parens | ^^^ help: remove these parentheses | note: lint level defined here @@ -11,17 +11,17 @@ note: lint level defined here | ^^^^^^^^^^^^^ warning: use of deprecated attribute `no_debug`: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand. See https://github.com/rust-lang/rust/issues/29721 - --> $DIR/suggestions.rs:31:1 + --> $DIR/suggestions.rs:41:1 | -31 | #[no_debug] // should suggest removal of deprecated attribute +41 | #[no_debug] // should suggest removal of deprecated attribute | ^^^^^^^^^^^ help: remove this attribute | = note: #[warn(deprecated)] on by default warning: variable does not need to be mutable - --> $DIR/suggestions.rs:36:13 + --> $DIR/suggestions.rs:46:13 | -36 | let mut a = (1); // should suggest no `mut`, no parens +46 | let mut a = (1); // should suggest no `mut`, no parens | ---^^ | | | help: remove this `mut` @@ -72,18 +72,30 @@ warning: function is marked #[no_mangle], but not exported | = note: #[warn(private_no_mangle_fns)] on by default +warning: static is marked #[no_mangle], but not exported + --> $DIR/suggestions.rs:31:18 + | +31 | #[no_mangle] pub static DAUNTLESS: bool = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: function is marked #[no_mangle], but not exported + --> $DIR/suggestions.rs:33:18 + | +33 | #[no_mangle] pub fn val_jean() {} + | ^^^^^^^^^^^^^^^^^^^^ + warning: denote infinite loops with `loop { ... }` - --> $DIR/suggestions.rs:34:5 + --> $DIR/suggestions.rs:44:5 | -34 | while true { // should suggest `loop` +44 | while true { // should suggest `loop` | ^^^^^^^^^^ help: use `loop` | = note: #[warn(while_true)] on by default warning: the `warp_factor:` in this pattern is redundant - --> $DIR/suggestions.rs:41:23 + --> $DIR/suggestions.rs:51:23 | -41 | Equinox { warp_factor: warp_factor } => {} // should suggest shorthand +51 | Equinox { warp_factor: warp_factor } => {} // should suggest shorthand | ------------^^^^^^^^^^^^ | | | help: remove this diff --git a/src/test/ui/macros/format-foreign.stderr b/src/test/ui/macros/format-foreign.stderr index d0229957b68..f9852c54773 100644 --- a/src/test/ui/macros/format-foreign.stderr +++ b/src/test/ui/macros/format-foreign.stderr @@ -1,12 +1,8 @@ error: multiple unused formatting arguments - --> $DIR/format-foreign.rs:12:5 + --> $DIR/format-foreign.rs:12:30 | -12 | println!("%.*3$s %s!/n", "Hello,", "World", 4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^--------^^-------^^-^^ - | | | | - | | | unused - | | unused - | unused +12 | println!("%.*3$s %s!/n", "Hello,", "World", 4); //~ ERROR multiple unused formatting arguments + | -------------------------^^^^^^^^--^^^^^^^--^-- multiple unused arguments in this statement | = help: `%.*3$s` should be written as `{:.2$}` = help: `%s` should be written as `{}` diff --git a/src/test/ui/macros/format-unused-lables.stderr b/src/test/ui/macros/format-unused-lables.stderr index 9efdca12dea..64ea5626c1d 100644 --- a/src/test/ui/macros/format-unused-lables.stderr +++ b/src/test/ui/macros/format-unused-lables.stderr @@ -1,49 +1,43 @@ error: multiple unused formatting arguments - --> $DIR/format-unused-lables.rs:12:5 + --> $DIR/format-unused-lables.rs:12:22 | 12 | println!("Test", 123, 456, 789); - | ^^^^^^^^^^^^^^^^^---^^---^^---^^ - | | | | - | | | unused - | | unused - | unused + | -----------------^^^--^^^--^^^-- multiple unused arguments in this statement | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: multiple unused formatting arguments - --> $DIR/format-unused-lables.rs:14:5 + --> $DIR/format-unused-lables.rs:16:9 | -14 | / println!("Test2", -15 | | 123, - | | --- unused -16 | | 456, - | | --- unused -17 | | 789 - | | --- unused -18 | | ); - | |______^ +15 | / println!("Test2", +16 | | 123, //~ ERROR multiple unused formatting arguments + | | ^^^ +17 | | 456, + | | ^^^ +18 | | 789 + | | ^^^ +19 | | ); + | |______- multiple unused arguments in this statement | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: named argument never used - --> $DIR/format-unused-lables.rs:20:35 + --> $DIR/format-unused-lables.rs:21:35 | -20 | println!("Some stuff", UNUSED="args"); //~ ERROR named argument never used +21 | println!("Some stuff", UNUSED="args"); //~ ERROR named argument never used | ^^^^^^ error: multiple unused formatting arguments - --> $DIR/format-unused-lables.rs:22:5 + --> $DIR/format-unused-lables.rs:24:9 | -22 | / println!("Some more $STUFF", -23 | | "woo!", - | | ------ unused -24 | | STUFF= -25 | | "things" - | | -------- unused -26 | | , UNUSED="args"); - | |_______________________------_^ - | | - | unused +23 | / println!("Some more $STUFF", +24 | | "woo!", //~ ERROR multiple unused formatting arguments + | | ^^^^^^ +25 | | STUFF= +26 | | "things" + | | ^^^^^^^^ +27 | | , UNUSED="args"); + | |_______________________^^^^^^_- multiple unused arguments in this statement | = help: `$STUFF` should be written as `{STUFF}` = note: shell formatting not supported; see the documentation for `std::fmt` diff --git a/src/test/ui/mismatched_types/E0631.stderr b/src/test/ui/mismatched_types/E0631.stderr index 442900e0a83..53f2f54325d 100644 --- a/src/test/ui/mismatched_types/E0631.stderr +++ b/src/test/ui/mismatched_types/E0631.stderr @@ -6,7 +6,11 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `fn(usize) -> _` | - = note: required by `foo` +note: required by `foo` + --> $DIR/E0631.rs:13:1 + | +13 | fn foo(_: F) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/E0631.rs:18:5 @@ -16,7 +20,11 @@ error[E0631]: type mismatch in closure arguments | | | expected signature of `fn(usize) -> _` | - = note: required by `bar` +note: required by `bar` + --> $DIR/E0631.rs:14:1 + | +14 | fn bar>(_: F) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in function arguments --> $DIR/E0631.rs:19:5 @@ -27,7 +35,11 @@ error[E0631]: type mismatch in function arguments 19 | foo(f); //~ ERROR type mismatch | ^^^ expected signature of `fn(usize) -> _` | - = note: required by `foo` +note: required by `foo` + --> $DIR/E0631.rs:13:1 + | +13 | fn foo(_: F) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in function arguments --> $DIR/E0631.rs:20:5 @@ -38,7 +50,11 @@ error[E0631]: type mismatch in function arguments 20 | bar(f); //~ ERROR type mismatch | ^^^ expected signature of `fn(usize) -> _` | - = note: required by `bar` +note: required by `bar` + --> $DIR/E0631.rs:14:1 + | +14 | fn bar>(_: F) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr index d904831ba4e..4e1523c79d2 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.stderr +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -14,7 +14,7 @@ error[E0593]: closure is expected to take 2 arguments, but it takes 1 argument | | | expected closure that takes 2 arguments -error[E0593]: closure is expected to take 2 distinct arguments, but it takes a single 2-tuple as argument +error[E0593]: closure is expected to take 2 arguments, but it takes 1 argument --> $DIR/closure-arg-count.rs:19:15 | 19 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); @@ -39,62 +39,58 @@ help: change the closure to take multiple arguments instead of a single tuple | ^^^^^^^^^^^^^^^ error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments - --> $DIR/closure-arg-count.rs:23:5 + --> $DIR/closure-arg-count.rs:21:5 | -23 | f(|| panic!()); +21 | f(|| panic!()); | ^ -- takes 0 arguments | | | expected closure that takes 1 argument | - = note: required by `f` +note: required by `f` + --> $DIR/closure-arg-count.rs:13:1 + | +13 | fn f>(_: F) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments - --> $DIR/closure-arg-count.rs:26:53 +error[E0593]: closure is expected to take a single tuple as argument, but it takes 2 distinct arguments + --> $DIR/closure-arg-count.rs:24:53 | -26 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i); - | ^^^ ------ takes 2 distinct arguments +24 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i); + | ^^^ ------ help: consider changing the closure to accept a tuple: `|(i, x)|` | | - | expected closure that takes a single 2-tuple as argument -help: change the closure to accept a tuple instead of individual arguments - | -26 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|(i, x)| i); - | ^^^^^^^^ + | expected closure that takes a single tuple as argument -error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments - --> $DIR/closure-arg-count.rs:28:53 +error[E0593]: closure is expected to take a single tuple as argument, but it takes 2 distinct arguments + --> $DIR/closure-arg-count.rs:26:53 | -28 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i: usize, x| i); - | ^^^ ------------- takes 2 distinct arguments +26 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i: usize, x| i); + | ^^^ ------------- help: consider changing the closure to accept a tuple: `|(i, x): (usize, _)|` | | - | expected closure that takes a single 2-tuple as argument -help: change the closure to accept a tuple instead of individual arguments - | -28 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|(i, x)| i); - | ^^^^^^^^ + | expected closure that takes a single tuple as argument error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 3 distinct arguments - --> $DIR/closure-arg-count.rs:30:53 + --> $DIR/closure-arg-count.rs:28:53 | -30 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x, y| i); +28 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x, y| i); | ^^^ --------- takes 3 distinct arguments | | | expected closure that takes a single 2-tuple as argument error[E0593]: function is expected to take a single 2-tuple as argument, but it takes 0 arguments - --> $DIR/closure-arg-count.rs:32:53 + --> $DIR/closure-arg-count.rs:30:53 | -32 | let _it = vec![1, 2, 3].into_iter().enumerate().map(foo); +30 | let _it = vec![1, 2, 3].into_iter().enumerate().map(foo); | ^^^ expected function that takes a single 2-tuple as argument ... -41 | fn foo() {} +37 | fn foo() {} | -------- takes 0 arguments error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 3 distinct arguments - --> $DIR/closure-arg-count.rs:35:53 + --> $DIR/closure-arg-count.rs:33:53 | -34 | let bar = |i, x, y| i; +32 | let bar = |i, x, y| i; | --------- takes 3 distinct arguments -35 | let _it = vec![1, 2, 3].into_iter().enumerate().map(bar); +33 | let _it = vec![1, 2, 3].into_iter().enumerate().map(bar); | ^^^ expected closure that takes a single 2-tuple as argument error[E0593]: function is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr index 77d3a332767..dfd02fe23b6 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -31,7 +31,11 @@ error[E0631]: type mismatch in function arguments | expected signature of `for<'r> fn(*mut &'r u32) -> _` | found signature of `fn(*mut &'a u32) -> _` | - = note: required by `baz` +note: required by `baz` + --> $DIR/closure-arg-type-mismatch.rs:18:1 + | +18 | fn baz(_: F) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0271]: type mismatch resolving `for<'r> >::Output == ()` --> $DIR/closure-arg-type-mismatch.rs:20:5 @@ -39,7 +43,11 @@ error[E0271]: type mismatch resolving `for<'r> $DIR/closure-arg-type-mismatch.rs:18:1 + | +18 | fn baz(_: F) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr index 99767ba1afa..01de7e07495 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -5,7 +5,11 @@ error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.r | ^^^ expected bound lifetime parameter, found concrete lifetime | = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:18:9: 18:15]` - = note: required by `baz` +note: required by `baz` + --> $DIR/closure-mismatch.rs:15:1 + | +15 | fn baz(_: T) {} + | ^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/closure-mismatch.rs:18:5 @@ -16,7 +20,11 @@ error[E0631]: type mismatch in closure arguments | expected signature of `for<'r> fn(&'r ()) -> _` | = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:18:9: 18:15]` - = note: required by `baz` +note: required by `baz` + --> $DIR/closure-mismatch.rs:15:1 + | +15 | fn baz(_: T) {} + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/fn-variance-1.stderr b/src/test/ui/mismatched_types/fn-variance-1.stderr index 2a27ffd1062..64c260c30ed 100644 --- a/src/test/ui/mismatched_types/fn-variance-1.stderr +++ b/src/test/ui/mismatched_types/fn-variance-1.stderr @@ -7,7 +7,11 @@ error[E0631]: type mismatch in function arguments 21 | apply(&3, takes_mut); | ^^^^^ expected signature of `fn(&{integer}) -> _` | - = note: required by `apply` +note: required by `apply` + --> $DIR/fn-variance-1.rs:15:1 + | +15 | fn apply(t: T, f: F) where F: FnOnce(T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in function arguments --> $DIR/fn-variance-1.rs:25:5 @@ -18,7 +22,11 @@ error[E0631]: type mismatch in function arguments 25 | apply(&mut 3, takes_imm); | ^^^^^ expected signature of `fn(&mut {integer}) -> _` | - = note: required by `apply` +note: required by `apply` + --> $DIR/fn-variance-1.rs:15:1 + | +15 | fn apply(t: T, f: F) where F: FnOnce(T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr index 8539c8818c0..9c9bbd19c75 100644 --- a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr +++ b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr @@ -1,12 +1,17 @@ error[E0631]: type mismatch in closure arguments - --> $DIR/unboxed-closures-vtable-mismatch.rs:23:13 + --> $DIR/unboxed-closures-vtable-mismatch.rs:25:13 | -22 | let f = to_fn_mut(|x: usize, y: isize| -> isize { (x as isize) + y }); +23 | let f = to_fn_mut(|x: usize, y: isize| -> isize { (x as isize) + y }); | ----------------------------- found signature of `fn(usize, isize) -> _` -23 | let z = call_it(3, f); +24 | //~^ NOTE found signature of `fn(usize, isize) -> _` +25 | let z = call_it(3, f); | ^^^^^^^ expected signature of `fn(isize, isize) -> _` | - = note: required by `call_it` +note: required by `call_it` + --> $DIR/unboxed-closures-vtable-mismatch.rs:17:1 + | +17 | fn call_itisize>(y: isize, mut f: F) -> isize { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/on-unimplemented/multiple-impls-complex-filtering.rs b/src/test/ui/on-unimplemented/multiple-impls-complex-filtering.rs new file mode 100644 index 00000000000..b48b08daa19 --- /dev/null +++ b/src/test/ui/on-unimplemented/multiple-impls-complex-filtering.rs @@ -0,0 +1,61 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test if the on_unimplemented message override works + +#![feature(on_unimplemented)] +#![feature(rustc_attrs)] + +struct Foo(T); +struct Bar(T); + +#[rustc_on_unimplemented( + on(_Self="[i32]", label="trait label if i32"), + label="trait label", + message="trait message", +)] +trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +#[rustc_on_unimplemented( + label="impl foo {Self} {Idx} {Index}", +)] +impl Index> for [i32] { + type Output = i32; + fn index(&self, _index: Foo) -> &i32 { + loop {} + } +} + +#[rustc_on_unimplemented = "on impl for Bar"] +impl Index> for [i32] { + type Output = i32; + fn index(&self, _index: Bar) -> &i32 { + loop {} + } +} + +#[rustc_error] +fn main() { + Index::index(&[] as &[i32], 2usize); + Index::index(&[] as &[i32], 2u32); + Index::index(&[] as &[u32], 2u32); + //~^ ERROR E0277 + //~| ERROR E0277 + Index::index(&[] as &[i32], Foo(2usize)); + Index::index(&[] as &[i32], Foo(2u32)); + //~^ ERROR E0277 + //~| ERROR E0277 + Index::index(&[] as &[i32], Bar(2u32)); + //~^ ERROR E0277 + //~| ERROR E0277 +} diff --git a/src/test/ui/on-unimplemented/multiple-impls-complex-filtering.stderr b/src/test/ui/on-unimplemented/multiple-impls-complex-filtering.stderr new file mode 100644 index 00000000000..2ea9b67f260 --- /dev/null +++ b/src/test/ui/on-unimplemented/multiple-impls-complex-filtering.stderr @@ -0,0 +1,44 @@ +error[E0277]: trait message `[i32]` + --> $DIR/multiple-impls-complex-filtering.rs:46:5 + | +46 | Index::index(&[] as &[i32], 2usize); + | ^^^^^^^^^^^^ u32 message + | + = help: the trait `Index<_>` is not implemented for `[i32]` +note: required by `Index::index` + --> $DIR/multiple-impls-complex-filtering.rs:25:5 + | +25 | fn index(&self, index: Idx) -> &Self::Output; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: trait message `[i32]` + --> $DIR/multiple-impls-complex-filtering.rs:46:5 + | +46 | Index::index(&[] as &[i32], 2usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ u32 message + | + = help: the trait `Index<_>` is not implemented for `[i32]` + +error[E0277]: trait message `[i32]` + --> $DIR/multiple-impls-complex-filtering.rs:47:5 + | +47 | Index::index(&[] as &[i32], 2u32); + | ^^^^^^^^^^^^ u32 message + | + = help: the trait `Index<_>` is not implemented for `[i32]` +note: required by `Index::index` + --> $DIR/multiple-impls-complex-filtering.rs:25:5 + | +25 | fn index(&self, index: Idx) -> &Self::Output; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: trait message `[i32]` + --> $DIR/multiple-impls-complex-filtering.rs:47:5 + | +47 | Index::index(&[] as &[i32], 2u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ u32 message + | + = help: the trait `Index<_>` is not implemented for `[i32]` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/on-unimplemented/multiple-impls.stderr b/src/test/ui/on-unimplemented/multiple-impls.stderr index 1f71be446ef..cfac3981be2 100644 --- a/src/test/ui/on-unimplemented/multiple-impls.stderr +++ b/src/test/ui/on-unimplemented/multiple-impls.stderr @@ -5,7 +5,11 @@ error[E0277]: the trait bound `[i32]: Index` is not satisfied | ^^^^^^^^^^^^ trait message | = help: the trait `Index` is not implemented for `[i32]` - = note: required by `Index::index` +note: required by `Index::index` + --> $DIR/multiple-impls.rs:22:5 + | +22 | fn index(&self, index: Idx) -> &Self::Output; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `[i32]: Index` is not satisfied --> $DIR/multiple-impls.rs:43:5 @@ -22,7 +26,11 @@ error[E0277]: the trait bound `[i32]: Index>` is not satisfied | ^^^^^^^^^^^^ on impl for Foo | = help: the trait `Index>` is not implemented for `[i32]` - = note: required by `Index::index` +note: required by `Index::index` + --> $DIR/multiple-impls.rs:22:5 + | +22 | fn index(&self, index: Idx) -> &Self::Output; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:46:5 @@ -39,7 +47,11 @@ error[E0277]: the trait bound `[i32]: Index>` is not satisfied | ^^^^^^^^^^^^ on impl for Bar | = help: the trait `Index>` is not implemented for `[i32]` - = note: required by `Index::index` +note: required by `Index::index` + --> $DIR/multiple-impls.rs:22:5 + | +22 | fn index(&self, index: Idx) -> &Self::Output; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:49:5 diff --git a/src/test/ui/on-unimplemented/on-impl.stderr b/src/test/ui/on-unimplemented/on-impl.stderr index c8c06bf44fd..ed2da68f081 100644 --- a/src/test/ui/on-unimplemented/on-impl.stderr +++ b/src/test/ui/on-unimplemented/on-impl.stderr @@ -5,7 +5,11 @@ error[E0277]: the trait bound `[i32]: Index` is not satisfied | ^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice | = help: the trait `Index` is not implemented for `[i32]` - = note: required by `Index::index` +note: required by `Index::index` + --> $DIR/on-impl.rs:19:5 + | +19 | fn index(&self, index: Idx) -> &Self::Output; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `[i32]: Index` is not satisfied --> $DIR/on-impl.rs:32:5 diff --git a/src/test/ui/on-unimplemented/on-trait.stderr b/src/test/ui/on-unimplemented/on-trait.stderr index cde56022fae..028200a5558 100644 --- a/src/test/ui/on-unimplemented/on-trait.stderr +++ b/src/test/ui/on-unimplemented/on-trait.stderr @@ -5,7 +5,11 @@ error[E0277]: the trait bound `std::option::Option>: MyFromIte | ^^^^^^^ a collection of type `std::option::Option>` cannot be built from an iterator over elements of type `&u8` | = help: the trait `MyFromIterator<&u8>` is not implemented for `std::option::Option>` - = note: required by `collect` +note: required by `collect` + --> $DIR/on-trait.rs:31:1 + | +31 | fn collect, B: MyFromIterator>(it: I) -> B { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::string::String: Bar::Foo` is not satisfied --> $DIR/on-trait.rs:40:21 @@ -14,7 +18,11 @@ error[E0277]: the trait bound `std::string::String: Bar::Foo` is not | ^^^^^^ test error `std::string::String` with `u8` `_` `u32` in `Bar::Foo` | = help: the trait `Bar::Foo` is not implemented for `std::string::String` - = note: required by `foobar` +note: required by `foobar` + --> $DIR/on-trait.rs:21:1 + | +21 | fn foobar>() -> T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/span/issue-29595.stderr b/src/test/ui/span/issue-29595.stderr index 81ba0057d71..9046b90f0e9 100644 --- a/src/test/ui/span/issue-29595.stderr +++ b/src/test/ui/span/issue-29595.stderr @@ -4,7 +4,11 @@ error[E0277]: the trait bound `u8: Tr` is not satisfied 17 | let a: u8 = Tr::C; //~ ERROR the trait bound `u8: Tr` is not satisfied | ^^^^^ the trait `Tr` is not implemented for `u8` | - = note: required by `Tr::C` +note: required by `Tr::C` + --> $DIR/issue-29595.rs:13:5 + | +13 | const C: Self; + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/suggestions/try-operator-on-main.stderr b/src/test/ui/suggestions/try-operator-on-main.stderr index 36cdd558b0f..e97823a3d5d 100644 --- a/src/test/ui/suggestions/try-operator-on-main.stderr +++ b/src/test/ui/suggestions/try-operator-on-main.stderr @@ -22,7 +22,11 @@ error[E0277]: the trait bound `(): std::ops::Try` is not satisfied 25 | try_trait_generic::<()>(); //~ ERROR the trait bound | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Try` is not implemented for `()` | - = note: required by `try_trait_generic` +note: required by `try_trait_generic` + --> $DIR/try-operator-on-main.rs:30:1 + | +30 | fn try_trait_generic() -> T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` --> $DIR/try-operator-on-main.rs:32:5 diff --git a/src/test/ui/type-check/issue-40294.stderr b/src/test/ui/type-check/issue-40294.stderr index 2ca97aa3ef0..cf270afdeb1 100644 --- a/src/test/ui/type-check/issue-40294.stderr +++ b/src/test/ui/type-check/issue-40294.stderr @@ -10,7 +10,11 @@ error[E0283]: type annotations required: cannot resolve `&'a T: Foo` 21 | | } | |_^ | - = note: required by `Foo` +note: required by `Foo` + --> $DIR/issue-40294.rs:11:1 + | +11 | trait Foo: Sized { + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 621e61bff92554d784aab13a507afcc0acdde53b Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sat, 20 Jan 2018 01:33:39 -0800 Subject: Add filter to detect local crates for rustc_on_unimplemented --- src/libcore/fmt/mod.rs | 17 ++-- src/libcore/iter/iterator.rs | 9 +- src/librustc/traits/error_reporting.rs | 4 + src/librustc/traits/on_unimplemented.rs | 3 +- src/test/ui/impl-trait/equality.rs | 2 +- src/test/ui/lint/use_suggestion_json.stderr | 67 +++++++++++- src/test/ui/mismatched_types/binops.rs | 8 +- src/test/ui/mismatched_types/binops.stderr | 8 +- src/test/ui/on-unimplemented/auxiliary/no_debug.rs | 14 +++ .../multiple-impls-complex-filtering.stderr | 113 ++++++++++++++++----- src/test/ui/on-unimplemented/no-debug.rs | 27 +++++ src/test/ui/on-unimplemented/no-debug.stderr | 38 +++++++ src/test/ui/span/multiline-span-simple.rs | 2 +- src/test/ui/span/multiline-span-simple.stderr | 2 +- src/test/ui/suggestions/iterate-str.rs | 19 ++++ src/test/ui/suggestions/iterate-str.stderr | 13 +++ 16 files changed, 299 insertions(+), 47 deletions(-) create mode 100644 src/test/ui/on-unimplemented/auxiliary/no_debug.rs create mode 100644 src/test/ui/on-unimplemented/no-debug.rs create mode 100644 src/test/ui/on-unimplemented/no-debug.stderr create mode 100644 src/test/ui/suggestions/iterate-str.rs create mode 100644 src/test/ui/suggestions/iterate-str.stderr (limited to 'src/libcore') diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 6c8a1c3062b..8ad5a9861a0 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -530,9 +530,12 @@ impl<'a> Display for Arguments<'a> { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "`{Self}` cannot be formatted using `:?`; if it is \ - defined in your crate, add `#[derive(Debug)]` or \ - manually implement it"] +#[rustc_on_unimplemented( + on(crate_local, label="`{Self}` cannot be formatted using `:?`; \ + add `#[derive(Debug)]` or manually implement `{Debug}`"), + message="`{Self}` doesn't implement `{Debug}`", + label="`{Self}` cannot be formatted using `:?` because it doesn't implement `{Debug}`", +)] #[lang = "debug_trait"] pub trait Debug { /// Formats the value using the given formatter. @@ -593,9 +596,11 @@ pub trait Debug { /// /// println!("The origin is: {}", origin); /// ``` -#[rustc_on_unimplemented = "`{Self}` cannot be formatted with the default \ - formatter; try using `:?` instead if you are using \ - a format string"] +#[rustc_on_unimplemented( + message="`{Self}` doesn't implement `{Display}`", + label="`{Self}` cannot be formatted with the default formatter; \ + try using `:?` instead if you are using a format string", +)] #[stable(feature = "rust1", since = "1.0.0")] pub trait Display { /// Formats the value using the given formatter. diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 35cd7441c66..296fb8733ba 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -28,8 +28,13 @@ fn _assert_is_object_safe(_: &Iterator) {} /// [module-level documentation]: index.html /// [impl]: index.html#implementing-iterator #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "`{Self}` is not an iterator; maybe try calling \ - `.iter()` or a similar method"] +#[rustc_on_unimplemented( + on( + _Self="&str", + label="`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`" + ), + label="`{Self}` is not an iterator; maybe try calling `.iter()` or a similar method" +)] #[doc(spotlight)] pub trait Iterator { /// The type of the elements being iterated over. diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index f5ff1226685..be7ecbce8af 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -384,6 +384,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { Some(ty_str.clone()))); } + if let Some(true) = self_ty.ty_to_def_id().map(|def_id| def_id.is_local()) { + flags.push(("crate_local".to_string(), None)); + } + if let Ok(Some(command)) = OnUnimplementedDirective::of_item( self.tcx, trait_ref.def_id, def_id ) { diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index a493b7f0bb6..8c2c1cfa454 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -185,8 +185,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { let mut message = None; let mut label = None; let mut note = None; - info!("evaluate({:?}, trait_ref={:?}, options={:?})", - self, trait_ref, options); + info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options); for command in self.subcommands.iter().chain(Some(self)).rev() { if let Some(ref condition) = command.condition { diff --git a/src/test/ui/impl-trait/equality.rs b/src/test/ui/impl-trait/equality.rs index 36df4f0eb4d..9d9d4cef311 100644 --- a/src/test/ui/impl-trait/equality.rs +++ b/src/test/ui/impl-trait/equality.rs @@ -32,7 +32,7 @@ fn sum_to(n: u32) -> impl Foo { 0 } else { n + sum_to(n - 1) - //~^ ERROR the trait bound `u32: std::ops::Add` is not satisfied + //~^ ERROR cannot add `impl Foo` to `u32` } } diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr index abbf3da513a..86c2ad4c0e7 100644 --- a/src/test/ui/lint/use_suggestion_json.stderr +++ b/src/test/ui/lint/use_suggestion_json.stderr @@ -2,7 +2,72 @@ "message": "cannot find type `Iter` in this scope", "code": { "code": "E0412", - "explanation": null + "explanation": " +The type name used is not in scope. + +Erroneous code examples: + +```compile_fail,E0412 +impl Something {} // error: type name `Something` is not in scope + +// or: + +trait Foo { + fn bar(N); // error: type name `N` is not in scope +} + +// or: + +fn foo(x: T) {} // type name `T` is not in scope +``` + +To fix this error, please verify you didn't misspell the type name, you did +declare it or imported it into the scope. Examples: + +``` +struct Something; + +impl Something {} // ok! + +// or: + +trait Foo { + type N; + + fn bar(_: Self::N); // ok! +} + +// or: + +fn foo(x: T) {} // ok! +``` + +Another case that causes this error is when a type is imported into a parent +module. To fix this, you can follow the suggestion and use File directly or +`use super::File;` which will import the types from the parent namespace. An +example that causes this error is below: + +```compile_fail,E0412 +use std::fs::File; + +mod foo { + fn some_function(f: File) {} +} +``` + +``` +use std::fs::File; + +mod foo { + // either + use super::File; + // or + // use std::fs::File; + fn foo(f: File) {} +} +# fn main() {} // don't insert it for us; that'll break imports +``` +" }, "level": "error", "spans": [ diff --git a/src/test/ui/mismatched_types/binops.rs b/src/test/ui/mismatched_types/binops.rs index e45616cd67a..5144b59955c 100644 --- a/src/test/ui/mismatched_types/binops.rs +++ b/src/test/ui/mismatched_types/binops.rs @@ -9,10 +9,10 @@ // except according to those terms. fn main() { - 1 + Some(1); //~ ERROR is not satisfied - 2 as usize - Some(1); //~ ERROR is not satisfied - 3 * (); //~ ERROR is not satisfied - 4 / ""; //~ ERROR is not satisfied + 1 + Some(1); //~ ERROR cannot add `std::option::Option<{integer}>` to `{integer}` + 2 as usize - Some(1); //~ ERROR cannot substract `std::option::Option<{integer}>` from `usize` + 3 * (); //~ ERROR cannot multiply `()` to `{integer}` + 4 / ""; //~ ERROR cannot divide `{integer}` by `&str` 5 < String::new(); //~ ERROR is not satisfied 6 == Ok(1); //~ ERROR is not satisfied } diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr index 57e66794a58..1b7fba05063 100644 --- a/src/test/ui/mismatched_types/binops.stderr +++ b/src/test/ui/mismatched_types/binops.stderr @@ -1,7 +1,7 @@ error[E0277]: cannot add `std::option::Option<{integer}>` to `{integer}` --> $DIR/binops.rs:12:7 | -12 | 1 + Some(1); //~ ERROR is not satisfied +12 | 1 + Some(1); //~ ERROR cannot add `std::option::Option<{integer}>` to `{integer}` | ^ no implementation for `{integer} + std::option::Option<{integer}>` | = help: the trait `std::ops::Add>` is not implemented for `{integer}` @@ -9,7 +9,7 @@ error[E0277]: cannot add `std::option::Option<{integer}>` to `{integer}` error[E0277]: cannot substract `std::option::Option<{integer}>` from `usize` --> $DIR/binops.rs:13:16 | -13 | 2 as usize - Some(1); //~ ERROR is not satisfied +13 | 2 as usize - Some(1); //~ ERROR cannot substract `std::option::Option<{integer}>` from `usize` | ^ no implementation for `usize - std::option::Option<{integer}>` | = help: the trait `std::ops::Sub>` is not implemented for `usize` @@ -17,7 +17,7 @@ error[E0277]: cannot substract `std::option::Option<{integer}>` from `usize` error[E0277]: cannot multiply `()` to `{integer}` --> $DIR/binops.rs:14:7 | -14 | 3 * (); //~ ERROR is not satisfied +14 | 3 * (); //~ ERROR cannot multiply `()` to `{integer}` | ^ no implementation for `{integer} * ()` | = help: the trait `std::ops::Mul<()>` is not implemented for `{integer}` @@ -25,7 +25,7 @@ error[E0277]: cannot multiply `()` to `{integer}` error[E0277]: cannot divide `{integer}` by `&str` --> $DIR/binops.rs:15:7 | -15 | 4 / ""; //~ ERROR is not satisfied +15 | 4 / ""; //~ ERROR cannot divide `{integer}` by `&str` | ^ no implementation for `{integer} / &str` | = help: the trait `std::ops::Div<&str>` is not implemented for `{integer}` diff --git a/src/test/ui/on-unimplemented/auxiliary/no_debug.rs b/src/test/ui/on-unimplemented/auxiliary/no_debug.rs new file mode 100644 index 00000000000..0f833c62637 --- /dev/null +++ b/src/test/ui/on-unimplemented/auxiliary/no_debug.rs @@ -0,0 +1,14 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// ignore-tidy-linelength + +#![crate_type = "lib"] + +pub struct Bar; diff --git a/src/test/ui/on-unimplemented/multiple-impls-complex-filtering.stderr b/src/test/ui/on-unimplemented/multiple-impls-complex-filtering.stderr index 2ea9b67f260..c4bac12eebd 100644 --- a/src/test/ui/on-unimplemented/multiple-impls-complex-filtering.stderr +++ b/src/test/ui/on-unimplemented/multiple-impls-complex-filtering.stderr @@ -1,44 +1,107 @@ -error[E0277]: trait message `[i32]` - --> $DIR/multiple-impls-complex-filtering.rs:46:5 +error[E0277]: trait message + --> $DIR/multiple-impls-complex-filtering.rs:49:5 | -46 | Index::index(&[] as &[i32], 2usize); - | ^^^^^^^^^^^^ u32 message +49 | Index::index(&[] as &[i32], 2usize); + | ^^^^^^^^^^^^ trait label if i32 | - = help: the trait `Index<_>` is not implemented for `[i32]` + = help: the trait `Index` is not implemented for `[i32]` note: required by `Index::index` - --> $DIR/multiple-impls-complex-filtering.rs:25:5 + --> $DIR/multiple-impls-complex-filtering.rs:26:5 | -25 | fn index(&self, index: Idx) -> &Self::Output; +26 | fn index(&self, index: Idx) -> &Self::Output; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: trait message `[i32]` - --> $DIR/multiple-impls-complex-filtering.rs:46:5 +error[E0277]: trait message + --> $DIR/multiple-impls-complex-filtering.rs:49:5 | -46 | Index::index(&[] as &[i32], 2usize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ u32 message +49 | Index::index(&[] as &[i32], 2usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait label if i32 | - = help: the trait `Index<_>` is not implemented for `[i32]` + = help: the trait `Index` is not implemented for `[i32]` -error[E0277]: trait message `[i32]` - --> $DIR/multiple-impls-complex-filtering.rs:47:5 +error[E0277]: trait message + --> $DIR/multiple-impls-complex-filtering.rs:50:5 | -47 | Index::index(&[] as &[i32], 2u32); - | ^^^^^^^^^^^^ u32 message +50 | Index::index(&[] as &[i32], 2u32); + | ^^^^^^^^^^^^ trait label if i32 | - = help: the trait `Index<_>` is not implemented for `[i32]` + = help: the trait `Index` is not implemented for `[i32]` note: required by `Index::index` - --> $DIR/multiple-impls-complex-filtering.rs:25:5 + --> $DIR/multiple-impls-complex-filtering.rs:26:5 | -25 | fn index(&self, index: Idx) -> &Self::Output; +26 | fn index(&self, index: Idx) -> &Self::Output; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: trait message `[i32]` - --> $DIR/multiple-impls-complex-filtering.rs:47:5 +error[E0277]: trait message + --> $DIR/multiple-impls-complex-filtering.rs:50:5 | -47 | Index::index(&[] as &[i32], 2u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ u32 message +50 | Index::index(&[] as &[i32], 2u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait label if i32 | - = help: the trait `Index<_>` is not implemented for `[i32]` + = help: the trait `Index` is not implemented for `[i32]` -error: aborting due to 4 previous errors +error[E0277]: trait message + --> $DIR/multiple-impls-complex-filtering.rs:51:5 + | +51 | Index::index(&[] as &[u32], 2u32); + | ^^^^^^^^^^^^ trait label + | + = help: the trait `Index<_>` is not implemented for `[u32]` +note: required by `Index::index` + --> $DIR/multiple-impls-complex-filtering.rs:26:5 + | +26 | fn index(&self, index: Idx) -> &Self::Output; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: trait message + --> $DIR/multiple-impls-complex-filtering.rs:51:5 + | +51 | Index::index(&[] as &[u32], 2u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait label + | + = help: the trait `Index<_>` is not implemented for `[u32]` + +error[E0277]: the trait bound `[i32]: Index>` is not satisfied + --> $DIR/multiple-impls-complex-filtering.rs:55:5 + | +55 | Index::index(&[] as &[i32], Foo(2u32)); + | ^^^^^^^^^^^^ impl foo [i32] Foo Index + | + = help: the trait `Index>` is not implemented for `[i32]` +note: required by `Index::index` + --> $DIR/multiple-impls-complex-filtering.rs:26:5 + | +26 | fn index(&self, index: Idx) -> &Self::Output; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `[i32]: Index>` is not satisfied + --> $DIR/multiple-impls-complex-filtering.rs:55:5 + | +55 | Index::index(&[] as &[i32], Foo(2u32)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl foo [i32] Foo Index + | + = help: the trait `Index>` is not implemented for `[i32]` + +error[E0277]: the trait bound `[i32]: Index>` is not satisfied + --> $DIR/multiple-impls-complex-filtering.rs:58:5 + | +58 | Index::index(&[] as &[i32], Bar(2u32)); + | ^^^^^^^^^^^^ on impl for Bar + | + = help: the trait `Index>` is not implemented for `[i32]` +note: required by `Index::index` + --> $DIR/multiple-impls-complex-filtering.rs:26:5 + | +26 | fn index(&self, index: Idx) -> &Self::Output; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `[i32]: Index>` is not satisfied + --> $DIR/multiple-impls-complex-filtering.rs:58:5 + | +58 | Index::index(&[] as &[i32], Bar(2u32)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Bar + | + = help: the trait `Index>` is not implemented for `[i32]` + +error: aborting due to 10 previous errors diff --git a/src/test/ui/on-unimplemented/no-debug.rs b/src/test/ui/on-unimplemented/no-debug.rs new file mode 100644 index 00000000000..fff6122c6b3 --- /dev/null +++ b/src/test/ui/on-unimplemented/no-debug.rs @@ -0,0 +1,27 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:no_debug.rs + +extern crate no_debug; + +use no_debug::Bar; + +struct Foo; + +fn main() { + println!("{:?} {:?}", Foo, Bar); + println!("{} {}", Foo, Bar); +} +//~^^^ ERROR `Foo` doesn't implement `std::fmt::Debug` +//~| ERROR `no_debug::Bar` doesn't implement `std::fmt::Debug` +//~^^^^ ERROR `Foo` doesn't implement `std::fmt::Display` +//~| ERROR `no_debug::Bar` doesn't implement `std::fmt::Display` + diff --git a/src/test/ui/on-unimplemented/no-debug.stderr b/src/test/ui/on-unimplemented/no-debug.stderr new file mode 100644 index 00000000000..af5b1e91211 --- /dev/null +++ b/src/test/ui/on-unimplemented/no-debug.stderr @@ -0,0 +1,38 @@ +error[E0277]: `Foo` doesn't implement `std::fmt::Debug` + --> $DIR/no-debug.rs:20:27 + | +20 | println!("{:?} {:?}", Foo, Bar); + | ^^^ `Foo` cannot be formatted using `:?`; add `#[derive(Debug)]` or manually implement `std::fmt::Debug` + | + = help: the trait `std::fmt::Debug` is not implemented for `Foo` + = note: required by `std::fmt::Debug::fmt` + +error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Debug` + --> $DIR/no-debug.rs:20:32 + | +20 | println!("{:?} {:?}", Foo, Bar); + | ^^^ `no_debug::Bar` cannot be formatted using `:?` because it doesn't implement `std::fmt::Debug` + | + = help: the trait `std::fmt::Debug` is not implemented for `no_debug::Bar` + = note: required by `std::fmt::Debug::fmt` + +error[E0277]: `Foo` doesn't implement `std::fmt::Display` + --> $DIR/no-debug.rs:21:23 + | +21 | println!("{} {}", Foo, Bar); + | ^^^ `Foo` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string + | + = help: the trait `std::fmt::Display` is not implemented for `Foo` + = note: required by `std::fmt::Display::fmt` + +error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Display` + --> $DIR/no-debug.rs:21:28 + | +21 | println!("{} {}", Foo, Bar); + | ^^^ `no_debug::Bar` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string + | + = help: the trait `std::fmt::Display` is not implemented for `no_debug::Bar` + = note: required by `std::fmt::Display::fmt` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/span/multiline-span-simple.rs b/src/test/ui/span/multiline-span-simple.rs index f8e4cbcbf19..dd09534480e 100644 --- a/src/test/ui/span/multiline-span-simple.rs +++ b/src/test/ui/span/multiline-span-simple.rs @@ -20,7 +20,7 @@ fn main() { let x = 1; let y = 2; let z = 3; - foo(1 as u32 + //~ ERROR not satisfied + foo(1 as u32 + //~ ERROR cannot add `()` to `u32` bar(x, diff --git a/src/test/ui/span/multiline-span-simple.stderr b/src/test/ui/span/multiline-span-simple.stderr index b6182825fc2..a18dfeb31d9 100644 --- a/src/test/ui/span/multiline-span-simple.stderr +++ b/src/test/ui/span/multiline-span-simple.stderr @@ -1,7 +1,7 @@ error[E0277]: cannot add `()` to `u32` --> $DIR/multiline-span-simple.rs:23:18 | -23 | foo(1 as u32 + //~ ERROR not satisfied +23 | foo(1 as u32 + //~ ERROR cannot add `()` to `u32` | ^ no implementation for `u32 + ()` | = help: the trait `std::ops::Add<()>` is not implemented for `u32` diff --git a/src/test/ui/suggestions/iterate-str.rs b/src/test/ui/suggestions/iterate-str.rs new file mode 100644 index 00000000000..1022491b84a --- /dev/null +++ b/src/test/ui/suggestions/iterate-str.rs @@ -0,0 +1,19 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + for c in "foobarbaz" { + println!("{}", c); + } + //~^^^ ERROR the trait bound `&str: std::iter::Iterator` is not satisfied + //~| NOTE `&str` is not an iterator; try calling `.chars()` or `.bytes()` + //~| HELP the trait `std::iter::Iterator` is not implemented for `&str` + //~| NOTE required by `std::iter::IntoIterator::into_iter` +} diff --git a/src/test/ui/suggestions/iterate-str.stderr b/src/test/ui/suggestions/iterate-str.stderr new file mode 100644 index 00000000000..59da6d70c02 --- /dev/null +++ b/src/test/ui/suggestions/iterate-str.stderr @@ -0,0 +1,13 @@ +error[E0277]: the trait bound `&str: std::iter::Iterator` is not satisfied + --> $DIR/iterate-str.rs:12:5 + | +12 | / for c in "foobarbaz" { +13 | | println!("{}", c); +14 | | } + | |_____^ `&str` is not an iterator; try calling `.chars()` or `.bytes()` + | + = help: the trait `std::iter::Iterator` is not implemented for `&str` + = note: required by `std::iter::IntoIterator::into_iter` + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 2dee07b12a2dd08a281a84146dc7085299389add Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sat, 20 Jan 2018 02:36:39 -0800 Subject: Remove cast suggestions --- src/libcore/ops/arith.rs | 72 -------------- .../multiple-impls-complex-filtering.rs | 61 ------------ .../multiple-impls-complex-filtering.stderr | 107 --------------------- 3 files changed, 240 deletions(-) delete mode 100644 src/test/ui/on-unimplemented/multiple-impls-complex-filtering.rs delete mode 100644 src/test/ui/on-unimplemented/multiple-impls-complex-filtering.stderr (limited to 'src/libcore') diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs index 47617b22dd3..d0d0c09869e 100644 --- a/src/libcore/ops/arith.rs +++ b/src/libcore/ops/arith.rs @@ -76,78 +76,6 @@ #[lang = "add"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( - on( - any( - all(_Self="i128", RHS="i64"), - all(_Self="i128", RHS="i32"), - all(_Self="i128", RHS="i16"), - all(_Self="i128", RHS="i8"), - all(_Self="i64", RHS="i32"), - all(_Self="i64", RHS="i16"), - all(_Self="i64", RHS="i8"), - all(_Self="i32", RHS="i16"), - all(_Self="i32", RHS="i8"), - all(_Self="i16", RHS="i8"), - all(_Self="u128", RHS="u64"), - all(_Self="u128", RHS="u32"), - all(_Self="u128", RHS="u16"), - all(_Self="u128", RHS="u8"), - all(_Self="u64", RHS="u32"), - all(_Self="u64", RHS="u16"), - all(_Self="u64", RHS="u8"), - all(_Self="u32", RHS="u16"), - all(_Self="u32", RHS="u8"), - all(_Self="u16", RHS="u8"), - all(_Self="f64", RHS="i32"), - all(_Self="f64", RHS="i16"), - all(_Self="f64", RHS="i8"), - all(_Self="f64", RHS="u32"), - all(_Self="f64", RHS="u16"), - all(_Self="f64", RHS="u8"), - all(_Self="f32", RHS="i16"), - all(_Self="f32", RHS="i8"), - all(_Self="f32", RHS="u16"), - all(_Self="f32", RHS="u8"), - ), - label="no implementation for `{Self} + {RHS}`, but you can safely cast \ - `{RHS}` into `{Self}` using `as {Self}`", - ), - on( - any( - all(RHS="i128", _Self="i64"), - all(RHS="i128", _Self="i32"), - all(RHS="i128", _Self="i16"), - all(RHS="i128", _Self="i8"), - all(RHS="i64", _Self="i32"), - all(RHS="i64", _Self="i16"), - all(RHS="i64", _Self="i8"), - all(RHS="i32", _Self="i16"), - all(RHS="i32", _Self="i8"), - all(RHS="i16", _Self="i8"), - all(RHS="u128", _Self="u64"), - all(RHS="u128", _Self="u32"), - all(RHS="u128", _Self="u16"), - all(RHS="u128", _Self="u8"), - all(RHS="u64", _Self="u32"), - all(RHS="u64", _Self="u16"), - all(RHS="u64", _Self="u8"), - all(RHS="u32", _Self="u16"), - all(RHS="u32", _Self="u8"), - all(RHS="u16", _Self="u8"), - all(RHS="f64", _Self="i32"), - all(RHS="f64", _Self="i16"), - all(RHS="f64", _Self="i8"), - all(RHS="f64", _Self="u32"), - all(RHS="f64", _Self="u16"), - all(RHS="f64", _Self="u8"), - all(RHS="f32", _Self="i16"), - all(RHS="f32", _Self="i8"), - all(RHS="f32", _Self="u16"), - all(RHS="f32", _Self="u8"), - ), - label="no implementation for `{Self} + {RHS}`, but you can safely cast \ - `{Self}` into `{RHS}` using `as {RHS}`", - ), on( all(_Self="{integer}", RHS="{float}"), message="cannot add a float to an integer", diff --git a/src/test/ui/on-unimplemented/multiple-impls-complex-filtering.rs b/src/test/ui/on-unimplemented/multiple-impls-complex-filtering.rs deleted file mode 100644 index b48b08daa19..00000000000 --- a/src/test/ui/on-unimplemented/multiple-impls-complex-filtering.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test if the on_unimplemented message override works - -#![feature(on_unimplemented)] -#![feature(rustc_attrs)] - -struct Foo(T); -struct Bar(T); - -#[rustc_on_unimplemented( - on(_Self="[i32]", label="trait label if i32"), - label="trait label", - message="trait message", -)] -trait Index { - type Output: ?Sized; - fn index(&self, index: Idx) -> &Self::Output; -} - -#[rustc_on_unimplemented( - label="impl foo {Self} {Idx} {Index}", -)] -impl Index> for [i32] { - type Output = i32; - fn index(&self, _index: Foo) -> &i32 { - loop {} - } -} - -#[rustc_on_unimplemented = "on impl for Bar"] -impl Index> for [i32] { - type Output = i32; - fn index(&self, _index: Bar) -> &i32 { - loop {} - } -} - -#[rustc_error] -fn main() { - Index::index(&[] as &[i32], 2usize); - Index::index(&[] as &[i32], 2u32); - Index::index(&[] as &[u32], 2u32); - //~^ ERROR E0277 - //~| ERROR E0277 - Index::index(&[] as &[i32], Foo(2usize)); - Index::index(&[] as &[i32], Foo(2u32)); - //~^ ERROR E0277 - //~| ERROR E0277 - Index::index(&[] as &[i32], Bar(2u32)); - //~^ ERROR E0277 - //~| ERROR E0277 -} diff --git a/src/test/ui/on-unimplemented/multiple-impls-complex-filtering.stderr b/src/test/ui/on-unimplemented/multiple-impls-complex-filtering.stderr deleted file mode 100644 index c4bac12eebd..00000000000 --- a/src/test/ui/on-unimplemented/multiple-impls-complex-filtering.stderr +++ /dev/null @@ -1,107 +0,0 @@ -error[E0277]: trait message - --> $DIR/multiple-impls-complex-filtering.rs:49:5 - | -49 | Index::index(&[] as &[i32], 2usize); - | ^^^^^^^^^^^^ trait label if i32 - | - = help: the trait `Index` is not implemented for `[i32]` -note: required by `Index::index` - --> $DIR/multiple-impls-complex-filtering.rs:26:5 - | -26 | fn index(&self, index: Idx) -> &Self::Output; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: trait message - --> $DIR/multiple-impls-complex-filtering.rs:49:5 - | -49 | Index::index(&[] as &[i32], 2usize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait label if i32 - | - = help: the trait `Index` is not implemented for `[i32]` - -error[E0277]: trait message - --> $DIR/multiple-impls-complex-filtering.rs:50:5 - | -50 | Index::index(&[] as &[i32], 2u32); - | ^^^^^^^^^^^^ trait label if i32 - | - = help: the trait `Index` is not implemented for `[i32]` -note: required by `Index::index` - --> $DIR/multiple-impls-complex-filtering.rs:26:5 - | -26 | fn index(&self, index: Idx) -> &Self::Output; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: trait message - --> $DIR/multiple-impls-complex-filtering.rs:50:5 - | -50 | Index::index(&[] as &[i32], 2u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait label if i32 - | - = help: the trait `Index` is not implemented for `[i32]` - -error[E0277]: trait message - --> $DIR/multiple-impls-complex-filtering.rs:51:5 - | -51 | Index::index(&[] as &[u32], 2u32); - | ^^^^^^^^^^^^ trait label - | - = help: the trait `Index<_>` is not implemented for `[u32]` -note: required by `Index::index` - --> $DIR/multiple-impls-complex-filtering.rs:26:5 - | -26 | fn index(&self, index: Idx) -> &Self::Output; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: trait message - --> $DIR/multiple-impls-complex-filtering.rs:51:5 - | -51 | Index::index(&[] as &[u32], 2u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait label - | - = help: the trait `Index<_>` is not implemented for `[u32]` - -error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls-complex-filtering.rs:55:5 - | -55 | Index::index(&[] as &[i32], Foo(2u32)); - | ^^^^^^^^^^^^ impl foo [i32] Foo Index - | - = help: the trait `Index>` is not implemented for `[i32]` -note: required by `Index::index` - --> $DIR/multiple-impls-complex-filtering.rs:26:5 - | -26 | fn index(&self, index: Idx) -> &Self::Output; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls-complex-filtering.rs:55:5 - | -55 | Index::index(&[] as &[i32], Foo(2u32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl foo [i32] Foo Index - | - = help: the trait `Index>` is not implemented for `[i32]` - -error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls-complex-filtering.rs:58:5 - | -58 | Index::index(&[] as &[i32], Bar(2u32)); - | ^^^^^^^^^^^^ on impl for Bar - | - = help: the trait `Index>` is not implemented for `[i32]` -note: required by `Index::index` - --> $DIR/multiple-impls-complex-filtering.rs:26:5 - | -26 | fn index(&self, index: Idx) -> &Self::Output; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls-complex-filtering.rs:58:5 - | -58 | Index::index(&[] as &[i32], Bar(2u32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Bar - | - = help: the trait `Index>` is not implemented for `[i32]` - -error: aborting due to 10 previous errors - -- cgit 1.4.1-3-g733a5 From 321e429b9f9318dccd93f0bb637be3a6c926daef Mon Sep 17 00:00:00 2001 From: Per Lundberg Date: Fri, 2 Feb 2018 22:44:14 +0200 Subject: copy_nonoverlapping example: Fixed typo The comment referred to a variable using an incorrect name. (it has probably been renamed since the comment was written, or the comment was copied elsewhere - I noted the example in libcore has the `tmp` name for the temporary variable.) --- src/libcore/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index a611dc02469..a05d67a304f 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -992,7 +992,7 @@ extern "rust-intrinsic" { /// ptr::copy_nonoverlapping(y, x, 1); /// ptr::copy_nonoverlapping(&t, y, 1); /// - /// // y and t now point to the same thing, but we need to completely forget `tmp` + /// // y and t now point to the same thing, but we need to completely forget `t` /// // because it's no longer relevant. /// mem::forget(t); /// } -- cgit 1.4.1-3-g733a5 From a1809d57840a19e28e93b437a7d029be3656acb8 Mon Sep 17 00:00:00 2001 From: oberien Date: Thu, 18 Jan 2018 18:40:08 +0100 Subject: Implement TrustedLen for Take and Take --- src/libcore/iter/mod.rs | 3 +++ src/libcore/iter/range.rs | 3 +++ src/libcore/iter/sources.rs | 3 +++ 3 files changed, 9 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 7314fac282b..bf8367d85fd 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -2322,6 +2322,9 @@ impl ExactSizeIterator for Take where I: ExactSizeIterator {} #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for Take where I: FusedIterator {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Take {} + /// An iterator to maintain state while iterating another iterator. /// /// This `struct` is created by the [`scan`] method on [`Iterator`]. See its diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 66a76a24df4..5af6df3e1cb 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -325,6 +325,9 @@ impl Iterator for ops::RangeFrom { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for ops::RangeFrom {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ops::RangeFrom {} + #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] impl Iterator for ops::RangeInclusive { type Item = A; diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index b405f35d5e4..b05a893e661 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -44,6 +44,9 @@ impl DoubleEndedIterator for Repeat { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for Repeat {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Repeat {} + /// Creates a new iterator that endlessly repeats a single element. /// /// The `repeat()` function repeats a single value over and over and over and -- cgit 1.4.1-3-g733a5 From 75474ff1323c2968bb2dafc8b8f0af4817a89d01 Mon Sep 17 00:00:00 2001 From: oberien Date: Fri, 2 Feb 2018 09:31:56 +0100 Subject: TrustedLen for Repeat / RangeFrom test cases --- src/libcore/tests/iter.rs | 43 ++++++++++++++++++++++++++++++++++ src/test/codegen/repeat-trusted-len.rs | 23 ++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 src/test/codegen/repeat-trusted-len.rs (limited to 'src/libcore') diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index e52e119ff59..f6b12fbb2dd 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1371,6 +1371,29 @@ fn test_range_from_nth() { assert_eq!(r, 16..); assert_eq!(r.nth(10), Some(26)); assert_eq!(r, 27..); + + assert_eq!((0..).size_hint(), (usize::MAX, None)); +} + +fn is_trusted_len(_: I) {} + +#[test] +fn test_range_from_take() { + let mut it = (0..).take(3); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next(), Some(1)); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.next(), None); + is_trusted_len((0..).take(3)); + assert_eq!((0..).take(3).size_hint(), (3, Some(3))); + assert_eq!((0..).take(0).size_hint(), (0, Some(0))); + assert_eq!((0..).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); +} + +#[test] +fn test_range_from_take_collect() { + let v: Vec<_> = (0..).take(3).collect(); + assert_eq!(v, vec![0, 1, 2]); } #[test] @@ -1465,6 +1488,26 @@ fn test_repeat() { assert_eq!(it.next(), Some(42)); assert_eq!(it.next(), Some(42)); assert_eq!(it.next(), Some(42)); + assert_eq!(repeat(42).size_hint(), (usize::MAX, None)); +} + +#[test] +fn test_repeat_take() { + let mut it = repeat(42).take(3); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), None); + is_trusted_len(repeat(42).take(3)); + assert_eq!(repeat(42).take(3).size_hint(), (3, Some(3))); + assert_eq!(repeat(42).take(0).size_hint(), (0, Some(0))); + assert_eq!(repeat(42).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); +} + +#[test] +fn test_repeat_take_collect() { + let v: Vec<_> = repeat(42).take(3).collect(); + assert_eq!(v, vec![42, 42, 42]); } #[test] diff --git a/src/test/codegen/repeat-trusted-len.rs b/src/test/codegen/repeat-trusted-len.rs new file mode 100644 index 00000000000..43872f15d51 --- /dev/null +++ b/src/test/codegen/repeat-trusted-len.rs @@ -0,0 +1,23 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -O +// ignore-tidy-linelength + +#![crate_type = "lib"] + +use std::iter; + +// CHECK-LABEL: @repeat_take_collect +#[no_mangle] +pub fn repeat_take_collect() -> Vec { +// CHECK: call void @llvm.memset.p0i8 + iter::repeat(42).take(100000).collect() +} -- cgit 1.4.1-3-g733a5 From 6caec2c0494a173f696e5a63583ff35d1bd106aa Mon Sep 17 00:00:00 2001 From: oberien Date: Sun, 4 Feb 2018 16:04:06 +0100 Subject: Document TrustedLen guarantees more explicitly --- src/libcore/iter/traits.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 11e668d228c..be4889f2487 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -970,9 +970,11 @@ impl<'a, I: FusedIterator + ?Sized> FusedIterator for &'a mut I {} /// The iterator reports a size hint where it is either exact /// (lower bound is equal to upper bound), or the upper bound is [`None`]. /// The upper bound must only be [`None`] if the actual iterator length is -/// larger than [`usize::MAX`]. +/// larger than [`usize::MAX`]. In that case, the lower bound must be +/// [`usize::MAX`], resulting in a [`.size_hint`] of `(usize::MAX, None)`. /// -/// The iterator must produce exactly the number of elements it reported. +/// The iterator must produce exactly the number of elements it reported +/// or diverge before reaching the end. /// /// # Safety /// -- cgit 1.4.1-3-g733a5 From f243f9239d2e2e5c0d21aa45f4d8bfd3cdcd3367 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Sun, 4 Feb 2018 11:57:36 -0800 Subject: Fix info about generic impls in AsMut docs This text was copy-pasted from the `AsRef` docs to `AsMut`, but needed some additional adjustments for correctness. --- src/libcore/convert.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index e815d72d366..d3a83dc795c 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -141,9 +141,9 @@ pub trait AsRef { /// /// # Generic Implementations /// -/// - `AsMut` auto-dereferences if the inner type is a reference or a mutable -/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type -/// `&mut Foo` or `&&mut Foo`) +/// - `AsMut` auto-dereferences if the inner type is a mutable reference +/// (e.g.: `foo.as_mut()` will work the same if `foo` has type `&mut Foo` +/// or `&mut &mut Foo`) /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 1b1e887f4d40e5800a8d5ae81f8574806e7ba21a Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 4 Feb 2018 23:48:40 -0800 Subject: Override try_[r]fold for RangeInclusive Because the last item needs special handling, it seems that LLVM has trouble canonicalizing the loops in external iteration. With the override, it becomes obvious that the start==end case exits the loop (as opposed to the one *after* that exiting the loop in external iteration). --- src/libcore/iter/range.rs | 46 +++++++++++++++++++++++++++++++++++++++++++++- src/libcore/tests/iter.rs | 20 ++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 66a76a24df4..3b034efcce1 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -10,7 +10,7 @@ use convert::TryFrom; use mem; -use ops::{self, Add, Sub}; +use ops::{self, Add, Sub, Try}; use usize; use super::{FusedIterator, TrustedLen}; @@ -397,6 +397,28 @@ impl Iterator for ops::RangeInclusive { fn max(mut self) -> Option { self.next_back() } + + #[inline] + fn try_fold(&mut self, init: B, mut f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try + { + let mut accum = init; + if self.start <= self.end { + loop { + let (x, done) = + if self.start < self.end { + let n = self.start.add_one(); + (mem::replace(&mut self.start, n), false) + } else { + self.end.replace_zero(); + (self.start.replace_one(), true) + }; + accum = f(accum, x)?; + if done { break } + } + } + Try::from_ok(accum) + } } #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] @@ -418,6 +440,28 @@ impl DoubleEndedIterator for ops::RangeInclusive { _ => None, } } + + #[inline] + fn try_rfold(&mut self, init: B, mut f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try + { + let mut accum = init; + if self.start <= self.end { + loop { + let (x, done) = + if self.start < self.end { + let n = self.end.sub_one(); + (mem::replace(&mut self.end, n), false) + } else { + self.start.replace_one(); + (self.end.replace_zero(), true) + }; + accum = f(accum, x)?; + if done { break } + } + } + Try::from_ok(accum) + } } #[unstable(feature = "fused", issue = "35602")] diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 8997cf9c6bf..e33a0b6224e 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1397,6 +1397,26 @@ fn test_range_inclusive_min() { assert_eq!(r.min(), None); } +#[test] +fn test_range_inclusive_folds() { + assert_eq!((1..=10).sum::(), 55); + assert_eq!((1..=10).rev().sum::(), 55); + + let mut it = 40..=50; + assert_eq!(it.try_fold(0, i8::checked_add), None); + assert_eq!(it, 44..=50); + assert_eq!(it.try_rfold(0, i8::checked_add), None); + assert_eq!(it, 44..=47); + + let mut it = 10..=20; + assert_eq!(it.try_fold(0, |a,b| Some(a+b)), Some(165)); + assert_eq!(it, 1..=0); + + let mut it = 10..=20; + assert_eq!(it.try_rfold(0, |a,b| Some(a+b)), Some(165)); + assert_eq!(it, 1..=0); +} + #[test] fn test_repeat() { let mut it = repeat(42); -- cgit 1.4.1-3-g733a5 From 96eed862a08f0ee1d234f4f83419dd46fe58ccef Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 7 Feb 2018 09:31:22 -0500 Subject: libcore/libstd: fix commas in macro_rules! macros BREAKING CHANGE: (or perhaps, *bugfix*) In #![no_std] applications, the following calls to `panic!` used to behave differently; they now behave the same. Old behavior: panic!("{{"); // panics with "{{" panic!("{{",); // panics with "{" New behavior: panic!("{{"); // panics with "{{" panic!("{{",); // panics with "{{" This only affects calls to `panic!` (and by proxy `assert` and `debug_assert`) with a single string literal followed by a trailing comma, and only in `#![no_std]` applications. --- src/libcore/macros.rs | 17 +++++++++++++++-- src/libstd/macros.rs | 3 +++ 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index f00128a8147..c12edaf0b29 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -19,7 +19,10 @@ macro_rules! panic { ($msg:expr) => ({ $crate::panicking::panic(&($msg, file!(), line!(), __rust_unstable_column!())) }); - ($fmt:expr, $($arg:tt)*) => ({ + ($msg:expr,) => ( + panic!($msg) + ); + ($fmt:expr, $($arg:tt)+) => ({ $crate::panicking::panic_fmt(format_args!($fmt, $($arg)*), &(file!(), line!(), __rust_unstable_column!())) }); @@ -79,6 +82,9 @@ macro_rules! assert { panic!(concat!("assertion failed: ", stringify!($cond))) } ); + ($cond:expr,) => ( + assert!($cond) + ); ($cond:expr, $($arg:tt)+) => ( if !$cond { panic!($($arg)+) @@ -359,7 +365,8 @@ macro_rules! try { $crate::result::Result::Err(err) => { return $crate::result::Result::Err($crate::convert::From::from(err)) } - }) + }); + ($expr:expr,) => (try!($expr)); } /// Write formatted data into a buffer. @@ -456,6 +463,9 @@ macro_rules! writeln { ($dst:expr) => ( write!($dst, "\n") ); + ($dst:expr,) => ( + writeln!($dst) + ); ($dst:expr, $fmt:expr) => ( write!($dst, concat!($fmt, "\n")) ); @@ -524,6 +534,9 @@ macro_rules! unreachable { ($msg:expr) => ({ unreachable!("{}", $msg) }); + ($msg:expr,) => ({ + unreachable!($msg) + }); ($fmt:expr, $($arg:tt)*) => ({ panic!(concat!("internal error: entered unreachable code: ", $fmt), $($arg)*) }); diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index f058b1caef5..5a01674a3d0 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -68,6 +68,9 @@ macro_rules! panic { ($msg:expr) => ({ $crate::rt::begin_panic($msg, &(file!(), line!(), __rust_unstable_column!())) }); + ($msg:expr,) => ({ + panic!($msg) + }); ($fmt:expr, $($arg:tt)+) => ({ $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+), &(file!(), line!(), __rust_unstable_column!())) -- cgit 1.4.1-3-g733a5 From b7c6dc6c0600eaee4d149c63dd3cf1faa00a098f Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 7 Feb 2018 10:24:34 -0500 Subject: update the builtin macro doc stubs --- src/libcore/macros.rs | 25 ++++++++++++++++++++----- src/libstd/macros.rs | 25 ++++++++++++++++++++----- 2 files changed, 40 insertions(+), 10 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index c12edaf0b29..19bbf85cadb 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -616,7 +616,10 @@ mod builtin { #[stable(feature = "compile_error_macro", since = "1.20.0")] #[macro_export] #[cfg(dox)] - macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }) } + macro_rules! compile_error { + ($msg:expr) => ({ /* compiler built-in */ }); + ($msg:expr,) => ({ /* compiler built-in */ }); + } /// The core macro for formatted string creation & output. /// @@ -652,7 +655,10 @@ mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] #[cfg(dox)] - macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }) } + macro_rules! option_env { + ($name:expr) => ({ /* compiler built-in */ }); + ($name:expr,) => ({ /* compiler built-in */ }); + } /// Concatenate identifiers into one identifier. /// @@ -728,7 +734,10 @@ mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] #[cfg(dox)] - macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include_str { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Includes a file as a reference to a byte array. /// @@ -738,7 +747,10 @@ mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] #[cfg(dox)] - macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include_bytes { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Expands to a string that represents the current module path. /// @@ -768,5 +780,8 @@ mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] #[cfg(dox)] - macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } } diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 5a01674a3d0..a18c811d196 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -315,7 +315,10 @@ pub mod builtin { /// ``` #[stable(feature = "compile_error_macro", since = "1.20.0")] #[macro_export] - macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }) } + macro_rules! compile_error { + ($msg:expr) => ({ /* compiler built-in */ }); + ($msg:expr,) => ({ /* compiler built-in */ }); + } /// The core macro for formatted string creation & output. /// @@ -403,7 +406,10 @@ pub mod builtin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] - macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }) } + macro_rules! option_env { + ($name:expr) => ({ /* compiler built-in */ }); + ($name:expr,) => ({ /* compiler built-in */ }); + } /// Concatenate identifiers into one identifier. /// @@ -583,7 +589,10 @@ pub mod builtin { /// Compiling 'main.rs' and running the resulting binary will print "adiós". #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] - macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include_str { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Includes a file as a reference to a byte array. /// @@ -617,7 +626,10 @@ pub mod builtin { /// Compiling 'main.rs' and running the resulting binary will print "adiós". #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] - macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include_bytes { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Expands to a string that represents the current module path. /// @@ -703,7 +715,10 @@ pub mod builtin { /// "🙈🙊🙉🙈🙊🙉". #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] - macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } } /// A macro for defining #[cfg] if-else statements. -- cgit 1.4.1-3-g733a5 From 27d4d51670710aa44a73baf04130bc262b8de244 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 7 Feb 2018 11:11:54 -0800 Subject: Simplify RangeInclusive::next[_back] `match`ing on an `Option` seems cause some confusion for LLVM; switching to just using comparison operators removes a few jumps from the simple `for` loops I was trying. --- src/libcore/iter/range.rs | 28 ++++++++++++---------------- src/libcore/tests/iter.rs | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+), 16 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 3b034efcce1..6d582b9a721 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -331,19 +331,17 @@ impl Iterator for ops::RangeInclusive { #[inline] fn next(&mut self) -> Option { - use cmp::Ordering::*; - - match self.start.partial_cmp(&self.end) { - Some(Less) => { + if self.start <= self.end { + if self.start < self.end { let n = self.start.add_one(); Some(mem::replace(&mut self.start, n)) - }, - Some(Equal) => { + } else { let last = self.start.replace_one(); self.end.replace_zero(); Some(last) - }, - _ => None, + } + } else { + None } } @@ -425,19 +423,17 @@ impl Iterator for ops::RangeInclusive { impl DoubleEndedIterator for ops::RangeInclusive { #[inline] fn next_back(&mut self) -> Option { - use cmp::Ordering::*; - - match self.start.partial_cmp(&self.end) { - Some(Less) => { + if self.start <= self.end { + if self.start < self.end { let n = self.end.sub_one(); Some(mem::replace(&mut self.end, n)) - }, - Some(Equal) => { + } else { let last = self.end.replace_zero(); self.start.replace_one(); Some(last) - }, - _ => None, + } + } else { + None } } diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index dc866d180bf..c742a1d8048 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1332,6 +1332,18 @@ fn test_range_inclusive_exhaustion() { assert_eq!(r.next_back(), Some(10)); assert_eq!(r, 1..=0); + let mut r = 10..=12; + assert_eq!(r.next(), Some(10)); + assert_eq!(r.next(), Some(11)); + assert_eq!(r.next(), Some(12)); + assert_eq!(r, 1..=0); + + let mut r = 10..=12; + assert_eq!(r.next_back(), Some(12)); + assert_eq!(r.next_back(), Some(11)); + assert_eq!(r.next_back(), Some(10)); + assert_eq!(r, 1..=0); + let mut r = 10..=12; assert_eq!(r.nth(2), Some(12)); assert_eq!(r, 1..=0); @@ -1340,6 +1352,13 @@ fn test_range_inclusive_exhaustion() { assert_eq!(r.nth(5), None); assert_eq!(r, 1..=0); + let mut r = 100..=10; + assert_eq!(r.next(), None); + assert_eq!(r, 100..=10); + + let mut r = 100..=10; + assert_eq!(r.next_back(), None); + assert_eq!(r, 100..=10); } #[test] -- cgit 1.4.1-3-g733a5 From 7ae7e5393367cdc9a630cd56911ab42f499c091f Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 8 Feb 2018 11:07:05 +0100 Subject: New introduction and revised hash map explanation. --- src/libcore/borrow.rs | 74 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 30 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 33e4c8780d6..1f692d019c3 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -14,19 +14,28 @@ /// A trait identifying how borrowed data behaves. /// -/// If a type implements this trait, it signals that a reference to it behaves -/// exactly like a reference to `Borrowed`. As a consequence, if a trait is -/// implemented both by `Self` and `Borrowed`, all trait methods that -/// take a `&self` argument must produce the same result in both -/// implementations. -/// -/// As a consequence, this trait should only be implemented for types managing -/// a value of another type without modifying its behavior. Examples are -/// smart pointers such as [`Box`] or [`Rc`] as well the owned version -/// of slices such as [`Vec`]. -/// -/// A relaxed version that allows converting a reference to some other type -/// without any further promises is available through [`AsRef`]. +/// In Rust, it is common to provide different representations of a type for +/// different use cases. For instance, storage location and management for a +/// value can be specifically chosen as appropriate for a particular use via +/// pointer types such as [`Box`] or [`Rc`] or one can opt into +/// concurrency via synchronization types such as [`Mutex`], avoiding the +/// associated cost when in parallel doesn’t happen. Beyond these generic +/// wrappers that can be used with any type, some types provide optional +/// facets providing potentially costly functionality. An example for such a +/// type is [`String`] which adds the ability to extend a string to the basic +/// [`str`]. This requires keeping additional information unnecessary for a +/// simple, imutable string. +/// +/// These types signal that they are a specialized representation of a basic +/// type `T` by implementing `Borrow`. The method `borrow` provides a way +/// to convert a reference to the type into a reference to the underlying +/// basic type. +/// +/// If a type implementing `Borrow` implements other traits also +/// implemented by `T`, these implementations behave identically if the trait +/// is concerned with the data rather than its representation. For instance, +/// the comparison traits such as `PartialEq` or `PartialOrd` must behave +/// identical for `T` and any type implemeting `Borrow`. /// /// When writing generic code, a use of `Borrow` should always be justified /// by additional trait bounds, making it clear that the two types need to @@ -37,11 +46,13 @@ /// The companion trait [`BorrowMut`] provides the same guarantees for /// mutable references. /// -/// [`Box`]: ../../std/boxed/struct.Box.html -/// [`Rc`]: ../../std/rc/struct.Rc.html -/// [`Vec`]: ../../std/vec/struct.Vec.html /// [`AsRef`]: ../../std/convert/trait.AsRef.html /// [`BorrowMut`]: trait.BorrowMut.html +/// [`Box`]: ../../std/boxed/struct.Box.html +/// [`Mutex`]: ../../std/sync/struct.Mutex.html +/// [`Rc`]: ../../std/rc/struct.Rc.html +/// [`str`]: ../../std/primitive.str.html +/// [`String`]: ../../std/string/struct.String.html /// /// # Examples /// @@ -85,30 +96,34 @@ /// ``` /// /// The entire hash map is generic over a key type `K`. Because these keys -/// are stored by with the hash map, this type as to own the key’s data. +/// are stored with the hash map, this type has to own the key’s data. /// When inserting a key-value pair, the map is given such a `K` and needs /// to find the correct hash bucket and check if the key is already present /// based on that `K`. It therefore requires `K: Hash + Eq`. /// -/// In order to search for a value based on the key’s data, the `get` method -/// is generic over some type `Q`. Technically, it needs to convert that `Q` -/// into a `K` in order to use `K`’s [`Hash`] implementation to be able to -/// arrive at the same hash value as during insertion in order to look into -/// the right hash bucket. Since `K` is some kind of owned value, this likely -/// would involve cloning and isn’t really practical. +/// When searching for a value in the map, however, having to provide a +/// reference to a `K` as the key to search for would require to always +/// create such an owned value. For string keys, this would mean a `String` +/// value needs to be created just for the search for cases where only a +/// `str` is available. /// -/// Instead, `get` relies on `Q`’s implementation of `Hash` and uses `Borrow` -/// to indicate that `K`’s implementation of `Hash` must produce the same -/// result as `Q`’s by demanding that `K: Borrow`. +/// Instead, the `get` method is generic over the type of the underlying key +/// data, called `Q` in the method signature above. It states that `K` is a +/// representation of `Q` by requiring that `K: Borrow`. By additionally +/// requiring `Q: Hash + Eq`, it demands that `K` and `Q` have +/// implementations of the `Hash` and `Eq` traits that procude identical +/// results. +/// +/// The implementation of `get` relies in particular on identical +/// implementations of `Hash` by determining the key’s hash bucket by calling +/// `Hash::hash` on the `Q` value even though it inserted the key based on +/// the hash value calculated from the `K` value. /// /// As a consequence, the hash map breaks if a `K` wrapping a `Q` value /// produces a different hash than `Q`. For instance, imagine you have a /// type that wraps a string but compares ASCII letters ignoring their case: /// /// ``` -/// # #[allow(unused_imports)] -/// use std::ascii::AsciiExt; -/// /// pub struct CIString(String); /// /// impl PartialEq for CIString { @@ -124,7 +139,6 @@ /// implementation of `Hash` needs to reflect that, too: /// /// ``` -/// # #[allow(unused_imports)] use std::ascii::AsciiExt; /// # use std::hash::{Hash, Hasher}; /// # pub struct CIString(String); /// impl Hash for CIString { -- cgit 1.4.1-3-g733a5 From 4f8049a2b00c46cb1ac77cabaaf716895f185afe Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 9 Feb 2018 01:47:18 -0800 Subject: Add Range[Inclusive]::is_empty During the RFC, it was discussed that figuring out whether a range is empty was subtle, and thus there should be a clear and obvious way to do it. It can't just be ExactSizeIterator::is_empty (also unstable) because not all ranges are ExactSize -- not even Range or RangeInclusive. --- src/libcore/iter/traits.rs | 2 +- src/libcore/ops/range.rs | 36 ++++++++++++++++++++++++++++++++++-- src/libcore/tests/iter.rs | 4 ++-- src/libcore/tests/lib.rs | 1 + src/libcore/tests/ops.rs | 24 ++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index be4889f2487..860742d9eab 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -706,7 +706,7 @@ pub trait ExactSizeIterator: Iterator { /// ``` /// #![feature(exact_size_is_empty)] /// - /// let mut one_element = 0..1; + /// let mut one_element = std::iter::once(0); /// assert!(!one_element.is_empty()); /// /// assert_eq!(one_element.next(), Some(0)); diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 3f573f7c7eb..102e08362cb 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -92,7 +92,6 @@ impl fmt::Debug for Range { } } -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> Range { /// Returns `true` if `item` is contained in the range. /// @@ -109,9 +108,26 @@ impl> Range { /// assert!(!(3..3).contains(3)); /// assert!(!(3..2).contains(3)); /// ``` + #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: Idx) -> bool { (self.start <= item) && (item < self.end) } + + /// Returns `true` if the range contains no items. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_is_empty)] + /// + /// assert!(!(3..5).is_empty()); + /// assert!( (3..3).is_empty()); + /// assert!( (3..2).is_empty()); + /// ``` + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] + pub fn is_empty(&self) -> bool { + !(self.start < self.end) + } } /// A range only bounded inclusively below (`start..`). @@ -280,7 +296,6 @@ impl fmt::Debug for RangeInclusive { } } -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> RangeInclusive { /// Returns `true` if `item` is contained in the range. /// @@ -298,9 +313,26 @@ impl> RangeInclusive { /// assert!( (3..=3).contains(3)); /// assert!(!(3..=2).contains(3)); /// ``` + #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: Idx) -> bool { self.start <= item && item <= self.end } + + /// Returns `true` if the range contains no items. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// assert!(!(3..=5).is_empty()); + /// assert!(!(3..=3).is_empty()); + /// assert!( (3..=2).is_empty()); + /// ``` + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] + pub fn is_empty(&self) -> bool { + !(self.start <= self.end) + } } /// A range only bounded inclusively above (`..=end`). diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index b2a5243d5e6..062b6d4126e 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1427,9 +1427,9 @@ fn test_range_inclusive_nth() { assert_eq!(r, 13..=20); assert_eq!(r.nth(2), Some(15)); assert_eq!(r, 16..=20); - assert_eq!(r.is_empty(), false); + assert_eq!(ExactSizeIterator::is_empty(&r), false); assert_eq!(r.nth(10), None); - assert_eq!(r.is_empty(), true); + assert_eq!(ExactSizeIterator::is_empty(&r), true); assert_eq!(r, 1..=0); // We may not want to document/promise this detail } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 1c32452f846..91b4f02594b 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -29,6 +29,7 @@ #![feature(iter_rfold)] #![feature(nonzero)] #![feature(pattern)] +#![feature(range_is_empty)] #![feature(raw)] #![feature(refcell_replace_swap)] #![feature(sip_hash_13)] diff --git a/src/libcore/tests/ops.rs b/src/libcore/tests/ops.rs index 9d2fa1abff6..68a692b24a3 100644 --- a/src/libcore/tests/ops.rs +++ b/src/libcore/tests/ops.rs @@ -68,3 +68,27 @@ fn test_range_inclusive() { assert_eq!(r.size_hint(), (0, Some(0))); assert_eq!(r.next(), None); } + + +#[test] +fn test_range_is_empty() { + use core::f32::*; + + assert!(!(0.0 .. 10.0).is_empty()); + assert!( (-0.0 .. 0.0).is_empty()); + assert!( (10.0 .. 0.0).is_empty()); + + assert!(!(NEG_INFINITY .. INFINITY).is_empty()); + assert!( (EPSILON .. NAN).is_empty()); + assert!( (NAN .. EPSILON).is_empty()); + assert!( (NAN .. NAN).is_empty()); + + assert!(!(0.0 ..= 10.0).is_empty()); + assert!(!(-0.0 ..= 0.0).is_empty()); + assert!( (10.0 ..= 0.0).is_empty()); + + assert!(!(NEG_INFINITY ..= INFINITY).is_empty()); + assert!( (EPSILON ..= NAN).is_empty()); + assert!( (NAN ..= EPSILON).is_empty()); + assert!( (NAN ..= NAN).is_empty()); +} \ No newline at end of file -- cgit 1.4.1-3-g733a5 From 7fe182fdfe01e01dd899962cc8dbaea63f422c9c Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 9 Feb 2018 02:11:04 -0800 Subject: Fix tidy --- src/libcore/tests/ops.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/ops.rs b/src/libcore/tests/ops.rs index 68a692b24a3..bed08f86d72 100644 --- a/src/libcore/tests/ops.rs +++ b/src/libcore/tests/ops.rs @@ -91,4 +91,4 @@ fn test_range_is_empty() { assert!( (EPSILON ..= NAN).is_empty()); assert!( (NAN ..= EPSILON).is_empty()); assert!( (NAN ..= NAN).is_empty()); -} \ No newline at end of file +} -- cgit 1.4.1-3-g733a5 From 1335b3da5a80fa4b74b25642e1bb651388bac3a8 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Fri, 9 Feb 2018 11:19:52 -0700 Subject: Add fetch_nand. cc #13226 (the tracking issue) --- src/libcore/sync/atomic.rs | 46 +++++++++++++++++++++++++++++++++++++++++++++ src/libcore/tests/atomic.rs | 14 ++++++++++++++ src/libcore/tests/lib.rs | 1 + 3 files changed, 61 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 8b47143f63c..f22862ae701 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -945,6 +945,7 @@ macro_rules! atomic_int { $stable_debug:meta, $stable_access:meta, $stable_from:meta, + $stable_nand:meta, $s_int_type:expr, $int_ref:expr, $int_type:ident $atomic_type:ident $atomic_init:ident) => { /// An integer type which can be safely shared between threads. @@ -1325,6 +1326,29 @@ macro_rules! atomic_int { unsafe { atomic_and(self.v.get(), val, order) } } + /// Bitwise "nand" with the current value. + /// + /// Performs a bitwise "nand" operation on the current value and the argument `val`, and + /// sets the new value to the result. + /// + /// Returns the previous value. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_nand)] + /// + /// use std::sync::atomic::{AtomicIsize, Ordering}; + /// + /// let foo = AtomicIsize::new(0xf731); + /// assert_eq!(foo.fetch_nand(0x137f, Ordering::SeqCst), 0xf731); + /// assert_eq!(foo.load(Ordering::SeqCst), !(0xf731 & 0x137f)); + #[inline] + #[$stable_nand] + pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { atomic_nand(self.v.get(), val, order) } + } + /// Bitwise "or" with the current value. /// /// Performs a bitwise "or" operation on the current value and the argument `val`, and @@ -1377,6 +1401,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "atomic_nand", issue = "13226"), "i8", "../../../std/primitive.i8.html", i8 AtomicI8 ATOMIC_I8_INIT } @@ -1387,6 +1412,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "atomic_nand", issue = "13226"), "u8", "../../../std/primitive.u8.html", u8 AtomicU8 ATOMIC_U8_INIT } @@ -1397,6 +1423,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "atomic_nand", issue = "13226"), "i16", "../../../std/primitive.i16.html", i16 AtomicI16 ATOMIC_I16_INIT } @@ -1407,6 +1434,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "atomic_nand", issue = "13226"), "u16", "../../../std/primitive.u16.html", u16 AtomicU16 ATOMIC_U16_INIT } @@ -1417,6 +1445,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "atomic_nand", issue = "13226"), "i32", "../../../std/primitive.i32.html", i32 AtomicI32 ATOMIC_I32_INIT } @@ -1427,6 +1456,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "atomic_nand", issue = "13226"), "u32", "../../../std/primitive.u32.html", u32 AtomicU32 ATOMIC_U32_INIT } @@ -1437,6 +1467,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "atomic_nand", issue = "13226"), "i64", "../../../std/primitive.i64.html", i64 AtomicI64 ATOMIC_I64_INIT } @@ -1447,6 +1478,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "atomic_nand", issue = "13226"), "u64", "../../../std/primitive.u64.html", u64 AtomicU64 ATOMIC_U64_INIT } @@ -1457,6 +1489,7 @@ atomic_int!{ stable(feature = "atomic_debug", since = "1.3.0"), stable(feature = "atomic_access", since = "1.15.0"), stable(feature = "atomic_from", since = "1.23.0"), + unstable(feature = "atomic_nand", issue = "13226"), "isize", "../../../std/primitive.isize.html", isize AtomicIsize ATOMIC_ISIZE_INIT } @@ -1467,6 +1500,7 @@ atomic_int!{ stable(feature = "atomic_debug", since = "1.3.0"), stable(feature = "atomic_access", since = "1.15.0"), stable(feature = "atomic_from", since = "1.23.0"), + unstable(feature = "atomic_nand", issue = "13226"), "usize", "../../../std/primitive.usize.html", usize AtomicUsize ATOMIC_USIZE_INIT } @@ -1609,6 +1643,18 @@ unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { } } +#[inline] +unsafe fn atomic_nand(dst: *mut T, val: T, order: Ordering) -> T { + match order { + Acquire => intrinsics::atomic_nand_acq(dst, val), + Release => intrinsics::atomic_nand_rel(dst, val), + AcqRel => intrinsics::atomic_nand_acqrel(dst, val), + Relaxed => intrinsics::atomic_nand_relaxed(dst, val), + SeqCst => intrinsics::atomic_nand(dst, val), + __Nonexhaustive => panic!("invalid memory ordering"), + } +} + #[inline] unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { match order { diff --git a/src/libcore/tests/atomic.rs b/src/libcore/tests/atomic.rs index 9babe24a985..f634fabe503 100644 --- a/src/libcore/tests/atomic.rs +++ b/src/libcore/tests/atomic.rs @@ -48,6 +48,13 @@ fn uint_and() { assert_eq!(x.load(SeqCst), 0xf731 & 0x137f); } +#[test] +fn uint_nand() { + let x = AtomicUsize::new(0xf731); + assert_eq!(x.fetch_nand(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), !(0xf731 & 0x137f)); +} + #[test] fn uint_or() { let x = AtomicUsize::new(0xf731); @@ -69,6 +76,13 @@ fn int_and() { assert_eq!(x.load(SeqCst), 0xf731 & 0x137f); } +#[test] +fn int_nand() { + let x = AtomicIsize::new(0xf731); + assert_eq!(x.fetch_nand(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), !(0xf731 & 0x137f)); +} + #[test] fn int_or() { let x = AtomicIsize::new(0xf731); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 1c32452f846..9e90313bc0e 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -42,6 +42,7 @@ #![feature(try_from)] #![feature(try_trait)] #![feature(exact_chunks)] +#![feature(atomic_nand)] extern crate core; extern crate test; -- cgit 1.4.1-3-g733a5 From e6f910e31e578301cc8608f049f1763172569ca8 Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Fri, 9 Feb 2018 22:18:06 +0100 Subject: fix typo: substract -> subtract. --- src/libcore/ops/arith.rs | 4 ++-- src/test/ui/mismatched_types/binops.rs | 2 +- src/test/ui/mismatched_types/binops.stderr | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs index d0d0c09869e..88db019b02f 100644 --- a/src/libcore/ops/arith.rs +++ b/src/libcore/ops/arith.rs @@ -181,7 +181,7 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "sub"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented(message="cannot substract `{RHS}` from `{Self}`", +#[rustc_on_unimplemented(message="cannot subtract `{RHS}` from `{Self}`", label="no implementation for `{Self} - {RHS}`")] pub trait Sub { /// The resulting type after applying the `-` operator. @@ -716,7 +716,7 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "sub_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] -#[rustc_on_unimplemented(message="cannot substract-assign `{Rhs}` from `{Self}`", +#[rustc_on_unimplemented(message="cannot subtract-assign `{Rhs}` from `{Self}`", label="no implementation for `{Self} -= {Rhs}`")] pub trait SubAssign { /// Performs the `-=` operation. diff --git a/src/test/ui/mismatched_types/binops.rs b/src/test/ui/mismatched_types/binops.rs index 5144b59955c..3f2cb59b11d 100644 --- a/src/test/ui/mismatched_types/binops.rs +++ b/src/test/ui/mismatched_types/binops.rs @@ -10,7 +10,7 @@ fn main() { 1 + Some(1); //~ ERROR cannot add `std::option::Option<{integer}>` to `{integer}` - 2 as usize - Some(1); //~ ERROR cannot substract `std::option::Option<{integer}>` from `usize` + 2 as usize - Some(1); //~ ERROR cannot subtract `std::option::Option<{integer}>` from `usize` 3 * (); //~ ERROR cannot multiply `()` to `{integer}` 4 / ""; //~ ERROR cannot divide `{integer}` by `&str` 5 < String::new(); //~ ERROR is not satisfied diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr index 1b7fba05063..828cf636951 100644 --- a/src/test/ui/mismatched_types/binops.stderr +++ b/src/test/ui/mismatched_types/binops.stderr @@ -6,10 +6,10 @@ error[E0277]: cannot add `std::option::Option<{integer}>` to `{integer}` | = help: the trait `std::ops::Add>` is not implemented for `{integer}` -error[E0277]: cannot substract `std::option::Option<{integer}>` from `usize` +error[E0277]: cannot subtract `std::option::Option<{integer}>` from `usize` --> $DIR/binops.rs:13:16 | -13 | 2 as usize - Some(1); //~ ERROR cannot substract `std::option::Option<{integer}>` from `usize` +13 | 2 as usize - Some(1); //~ ERROR cannot subtract `std::option::Option<{integer}>` from `usize` | ^ no implementation for `usize - std::option::Option<{integer}>` | = help: the trait `std::ops::Sub>` is not implemented for `usize` -- cgit 1.4.1-3-g733a5 From b5cb393cf5b4a65fb99d8b1e43450fb87567788b Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 9 Feb 2018 17:54:27 -0800 Subject: Use is_empty in range iteration exhaustion tests --- src/libcore/ops/range.rs | 18 ++++++++++++++ src/libcore/tests/iter.rs | 61 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 70 insertions(+), 9 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 102e08362cb..cce593ee208 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -262,6 +262,13 @@ impl> RangeTo { /// The `RangeInclusive` `start..=end` contains all values with `x >= start` /// and `x <= end`. /// +/// This iterator is [fused], but the specific values of `start` and `end` after +/// iteration has finished are **unspecified** other than that [`.is_empty()`] +/// will return `true` once no more values will be produced. +/// +/// [fused]: ../iter/trait.FusedIterator.html +/// [`.is_empty()`]: #method.is_empty +/// /// # Examples /// /// ``` @@ -329,6 +336,17 @@ impl> RangeInclusive { /// assert!(!(3..=3).is_empty()); /// assert!( (3..=2).is_empty()); /// ``` + /// + /// This method returns `true` after iteration has finished: + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// let mut r = 3..=5; + /// for _ in r.by_ref() {} + /// // Precise field values are unspecified here + /// assert!(r.is_empty()); + /// ``` #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] pub fn is_empty(&self) -> bool { !(self.start <= self.end) diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 062b6d4126e..d8c9dcd8664 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1322,42 +1322,84 @@ fn test_range() { (isize::MAX as usize + 2, Some(isize::MAX as usize + 2))); } +#[test] +fn test_range_exhaustion() { + let mut r = 10..10; + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next_back(), None); + assert_eq!(r, 10..10); + + let mut r = 10..12; + assert_eq!(r.next(), Some(10)); + assert_eq!(r.next(), Some(11)); + assert!(r.is_empty()); + assert_eq!(r, 12..12); + assert_eq!(r.next(), None); + + let mut r = 10..12; + assert_eq!(r.next_back(), Some(11)); + assert_eq!(r.next_back(), Some(10)); + assert!(r.is_empty()); + assert_eq!(r, 10..10); + assert_eq!(r.next_back(), None); + + let mut r = 100..10; + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next_back(), None); + assert_eq!(r, 100..10); +} + #[test] fn test_range_inclusive_exhaustion() { let mut r = 10..=10; assert_eq!(r.next(), Some(10)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next(), None); let mut r = 10..=10; assert_eq!(r.next_back(), Some(10)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); let mut r = 10..=12; assert_eq!(r.next(), Some(10)); assert_eq!(r.next(), Some(11)); assert_eq!(r.next(), Some(12)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); let mut r = 10..=12; assert_eq!(r.next_back(), Some(12)); assert_eq!(r.next_back(), Some(11)); assert_eq!(r.next_back(), Some(10)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); let mut r = 10..=12; assert_eq!(r.nth(2), Some(12)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); let mut r = 10..=12; assert_eq!(r.nth(5), None); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); let mut r = 100..=10; assert_eq!(r.next(), None); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next(), None); assert_eq!(r, 100..=10); let mut r = 100..=10; assert_eq!(r.next_back(), None); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); + assert_eq!(r.next_back(), None); assert_eq!(r, 100..=10); } @@ -1427,10 +1469,11 @@ fn test_range_inclusive_nth() { assert_eq!(r, 13..=20); assert_eq!(r.nth(2), Some(15)); assert_eq!(r, 16..=20); + assert_eq!(r.is_empty(), false); assert_eq!(ExactSizeIterator::is_empty(&r), false); assert_eq!(r.nth(10), None); + assert_eq!(r.is_empty(), true); assert_eq!(ExactSizeIterator::is_empty(&r), true); - assert_eq!(r, 1..=0); // We may not want to document/promise this detail } #[test] @@ -1514,11 +1557,11 @@ fn test_range_inclusive_folds() { let mut it = 10..=20; assert_eq!(it.try_fold(0, |a,b| Some(a+b)), Some(165)); - assert_eq!(it, 1..=0); + assert!(it.is_empty()); let mut it = 10..=20; assert_eq!(it.try_rfold(0, |a,b| Some(a+b)), Some(165)); - assert_eq!(it, 1..=0); + assert!(it.is_empty()); } #[test] -- cgit 1.4.1-3-g733a5 From 6f70a11a831992fe86a935a0d649d3aa6b16dc50 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 9 Feb 2018 18:01:12 -0800 Subject: range_is_empty tracking issue is #48111 --- src/libcore/ops/range.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index cce593ee208..4e4d3347523 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -124,7 +124,7 @@ impl> Range { /// assert!( (3..3).is_empty()); /// assert!( (3..2).is_empty()); /// ``` - #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] pub fn is_empty(&self) -> bool { !(self.start < self.end) } @@ -347,7 +347,7 @@ impl> RangeInclusive { /// // Precise field values are unspecified here /// assert!(r.is_empty()); /// ``` - #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] pub fn is_empty(&self) -> bool { !(self.start <= self.end) } -- cgit 1.4.1-3-g733a5 From 7ee3e39f640a9532842e1441bf6bc98893b6a3ba Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Sat, 10 Feb 2018 12:22:57 +0100 Subject: fix typos in src/{bootstrap,ci,etc,lib{backtrace,core,fmt_macros}} --- src/bootstrap/builder.rs | 2 +- src/bootstrap/lib.rs | 2 +- src/bootstrap/test.rs | 2 +- src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh | 2 +- src/etc/installer/msi/rust.wxs | 4 ++-- src/etc/platform-intrinsics/generator.py | 2 +- src/etc/test-float-parse/runtests.py | 2 +- src/libbacktrace/ltmain.sh | 2 +- src/libbacktrace/macho.c | 2 +- src/libcore/macros.rs | 2 +- src/libfmt_macros/lib.rs | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src/libcore') diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 6c68ee18506..03630dfbed3 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -570,7 +570,7 @@ impl<'a> Builder<'a> { // build scripts in that situation. // // If LLVM support is disabled we need to use the snapshot compiler to compile - // build scripts, as the new compiler doesnt support executables. + // build scripts, as the new compiler doesn't support executables. if mode == Mode::Libstd || !self.build.config.llvm_enabled { cargo.env("RUSTC_SNAPSHOT", &self.initial_rustc) .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir()); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index a84a6a8990b..83c270865c0 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -666,7 +666,7 @@ impl Build { } } - /// Returns the path to the linker for the given target if it needs to be overriden. + /// Returns the path to the linker for the given target if it needs to be overridden. fn linker(&self, target: Interned) -> Option<&Path> { if let Some(linker) = self.config.target_config.get(&target) .and_then(|c| c.linker.as_ref()) { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index eae8ec1311d..f6b95f0bf97 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -902,7 +902,7 @@ impl Step for Compiletest { } } if suite == "run-make" && !build.config.llvm_enabled { - println!("Ignoring run-make test suite as they generally dont work without LLVM"); + println!("Ignoring run-make test suite as they generally don't work without LLVM"); return; } diff --git a/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh index 5b4314d57e6..e730dd86087 100755 --- a/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh +++ b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh @@ -54,7 +54,7 @@ cd usr/src # The options, in order, do the following # * this is an unprivileged build # * output to a predictable location -# * disable various uneeded stuff +# * disable various unneeded stuff MKUNPRIVED=yes TOOLDIR=/x-tools/x86_64-unknown-netbsd \ MKSHARE=no MKDOC=no MKHTML=no MKINFO=no MKKMOD=no MKLINT=no MKMAN=no MKNLS=no MKPROFILE=no \ hide_output ./build.sh -j10 -m amd64 tools diff --git a/src/etc/installer/msi/rust.wxs b/src/etc/installer/msi/rust.wxs index d95b096d732..a471ccc6f5b 100644 --- a/src/etc/installer/msi/rust.wxs +++ b/src/etc/installer/msi/rust.wxs @@ -18,7 +18,7 @@ - + @@ -129,7 +129,7 @@ - + diff --git a/src/etc/platform-intrinsics/generator.py b/src/etc/platform-intrinsics/generator.py index e9cf71c32fe..d9f78978a25 100644 --- a/src/etc/platform-intrinsics/generator.py +++ b/src/etc/platform-intrinsics/generator.py @@ -591,7 +591,7 @@ def parse_args(): The X86 architecture is specified as multiple files (for the different instruction sets that x86 supports). To generate the compiler definitions one needs to pass the script a "platform information file" - (with the -i flag) next to the files of the different intruction sets. + (with the -i flag) next to the files of the different instruction sets. For example, to generate the X86 compiler-definitions for SSE4.2, just: python generator.py --format compiler-defs -i x86/info.json sse42.json diff --git a/src/etc/test-float-parse/runtests.py b/src/etc/test-float-parse/runtests.py index d520c9bd5c3..e9f5bba2312 100644 --- a/src/etc/test-float-parse/runtests.py +++ b/src/etc/test-float-parse/runtests.py @@ -41,7 +41,7 @@ Instead, we take the input and compute the true value with bignum arithmetic (as a fraction, using the ``fractions`` module). Given an input string and the corresponding float computed via Rust, simply -decode the float into f * 2^k (for intergers f, k) and the ULP. +decode the float into f * 2^k (for integers f, k) and the ULP. We can now easily compute the error and check if it is within 0.5 ULP as it should be. Zero and infinites are handled similarly: diff --git a/src/libbacktrace/ltmain.sh b/src/libbacktrace/ltmain.sh index eff9e62be8a..fd23815fc61 100644 --- a/src/libbacktrace/ltmain.sh +++ b/src/libbacktrace/ltmain.sh @@ -487,7 +487,7 @@ func_mkdir_p () # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited - # list incase some portion of path contains whitespace. + # list in case some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done diff --git a/src/libbacktrace/macho.c b/src/libbacktrace/macho.c index 9af14e724b4..ba7f94c079f 100644 --- a/src/libbacktrace/macho.c +++ b/src/libbacktrace/macho.c @@ -327,7 +327,7 @@ macho_get_commands (struct backtrace_state *state, int descriptor, goto end; file_header_view_valid = 1; - // The endianess of the slice may be different than the fat image + // The endianness of the slice may be different than the fat image switch (*(uint32_t *) file_header_view.data) { case MH_MAGIC: diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index f00128a8147..cc5cf6523a9 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -327,7 +327,7 @@ macro_rules! debug_assert_ne { /// } /// } /// -/// // The prefered method of quick returning Errors +/// // The preferred method of quick returning Errors /// fn write_to_file_question() -> Result<(), MyError> { /// let mut file = File::create("my_best_friends.txt")?; /// file.write_all(b"This is a list of my best friends.")?; diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 44cdb5e8a36..71519ab21fe 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -73,7 +73,7 @@ pub struct FormatSpec<'a> { /// Enum describing where an argument for a format can be located. #[derive(Copy, Clone, PartialEq)] pub enum Position<'a> { - /// The arugment is implied to be located at an index + /// The argument is implied to be located at an index ArgumentImplicitlyIs(usize), /// The argument is located at a specific index given in the format ArgumentIs(usize), -- cgit 1.4.1-3-g733a5 From 45d5a420ada9c11f61347fd4c63c7f0234adaea7 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sat, 10 Feb 2018 21:20:42 +0000 Subject: Correct a few stability attributes --- src/libcore/num/mod.rs | 6 +++--- src/libcore/ptr.rs | 4 ++-- src/libcore/time.rs | 4 ++-- src/libstd/io/cursor.rs | 2 +- src/libstd/path.rs | 2 +- src/libsyntax/feature_gate.rs | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 1fae88b9c77..21d4a486b98 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2881,7 +2881,7 @@ pub enum FpCategory { issue = "32110")] pub trait Float: Sized { /// Type used by `to_bits` and `from_bits`. - #[stable(feature = "core_float_bits", since = "1.24.0")] + #[stable(feature = "core_float_bits", since = "1.25.0")] type Bits; /// Returns `true` if this value is NaN and false otherwise. @@ -2947,10 +2947,10 @@ pub trait Float: Sized { fn min(self, other: Self) -> Self; /// Raw transmutation to integer. - #[stable(feature = "core_float_bits", since="1.24.0")] + #[stable(feature = "core_float_bits", since="1.25.0")] fn to_bits(self) -> Self::Bits; /// Raw transmutation from integer. - #[stable(feature = "core_float_bits", since="1.24.0")] + #[stable(feature = "core_float_bits", since="1.25.0")] fn from_bits(v: Self::Bits) -> Self; } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 3d84e910fe6..b266771b818 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2573,7 +2573,7 @@ impl Clone for NonNull { #[stable(feature = "nonnull", since = "1.25.0")] impl Copy for NonNull { } -#[stable(feature = "nonnull", since = "1.25.0")] +#[unstable(feature = "coerce_unsized", issue = "27732")] impl CoerceUnsized> for NonNull where T: Unsize { } #[stable(feature = "nonnull", since = "1.25.0")] @@ -2621,7 +2621,7 @@ impl hash::Hash for NonNull { } } -#[stable(feature = "nonnull", since = "1.25.0")] +#[unstable(feature = "ptr_internals", issue = "0")] impl From> for NonNull { fn from(unique: Unique) -> Self { NonNull { pointer: unique.pointer } diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 1a0208d2f25..b8d0719b9b9 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![stable(feature = "duration_core", since = "1.24.0")] +#![stable(feature = "duration_core", since = "1.25.0")] //! Temporal quantification. //! @@ -58,7 +58,7 @@ const MICROS_PER_SEC: u64 = 1_000_000; /// /// let ten_millis = Duration::from_millis(10); /// ``` -#[stable(feature = "duration_core", since = "1.24.0")] +#[stable(feature = "duration", since = "1.3.0")] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] pub struct Duration { secs: u64, diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index c8447707d5b..76bcb5fedc9 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -296,7 +296,7 @@ impl<'a> Write for Cursor<&'a mut [u8]> { fn flush(&mut self) -> io::Result<()> { Ok(()) } } -#[unstable(feature = "cursor_mut_vec", issue = "30132")] +#[stable(feature = "cursor_mut_vec", since = "1.25.0")] impl<'a> Write for Cursor<&'a mut Vec> { fn write(&mut self, buf: &[u8]) -> io::Result { vec_write(&mut self.pos, self.inner, buf) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index ed102c2949e..e03a182653e 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -576,7 +576,7 @@ impl<'a> AsRef for Component<'a> { } } -#[stable(feature = "path_component_asref", since = "1.24.0")] +#[stable(feature = "path_component_asref", since = "1.25.0")] impl<'a> AsRef for Component<'a> { fn as_ref(&self) -> &Path { self.as_os_str().as_ref() diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9c6520cd874..f8dbc4d0f45 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -538,7 +538,7 @@ declare_features! ( // instead of just the platforms on which it is the C ABI (accepted, abi_sysv64, "1.24.0", Some(36167)), // Allows `repr(align(16))` struct attribute (RFC 1358) - (accepted, repr_align, "1.24.0", Some(33626)), + (accepted, repr_align, "1.25.0", Some(33626)), // allow '|' at beginning of match arms (RFC 1925) (accepted, match_beginning_vert, "1.25.0", Some(44101)), // Nested groups in `use` (RFC 2128) -- cgit 1.4.1-3-g733a5 From 22b0489f80dae5242f19c4ce892b50d3685dbf82 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 10 Feb 2018 16:32:05 -0800 Subject: Add the emptiness condition to the docs; add a PartialOrd example with NAN --- src/libcore/ops/range.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 4e4d3347523..8a45444f1ab 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -60,7 +60,7 @@ impl fmt::Debug for RangeFull { /// (`start..end`). /// /// The `Range` `start..end` contains all values with `x >= start` and -/// `x < end`. +/// `x < end`. It is empty unless `start < end`. /// /// # Examples /// @@ -124,6 +124,17 @@ impl> Range { /// assert!( (3..3).is_empty()); /// assert!( (3..2).is_empty()); /// ``` + /// + /// The range is empty if either side is incomparable: + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// use std::f32::NAN; + /// assert!(!(3.0..5.0).is_empty()); + /// assert!( (3.0..NAN).is_empty()); + /// assert!( (NAN..5.0).is_empty()); + /// ``` #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] pub fn is_empty(&self) -> bool { !(self.start < self.end) @@ -260,7 +271,7 @@ impl> RangeTo { /// An range bounded inclusively below and above (`start..=end`). /// /// The `RangeInclusive` `start..=end` contains all values with `x >= start` -/// and `x <= end`. +/// and `x <= end`. It is empty unless `start <= end`. /// /// This iterator is [fused], but the specific values of `start` and `end` after /// iteration has finished are **unspecified** other than that [`.is_empty()`] @@ -337,6 +348,17 @@ impl> RangeInclusive { /// assert!( (3..=2).is_empty()); /// ``` /// + /// The range is empty if either side is incomparable: + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// use std::f32::NAN; + /// assert!(!(3.0..=5.0).is_empty()); + /// assert!( (3.0..=NAN).is_empty()); + /// assert!( (NAN..=5.0).is_empty()); + /// ``` + /// /// This method returns `true` after iteration has finished: /// /// ``` -- cgit 1.4.1-3-g733a5 From bd426f1d69ec8371d86e06382e96e9ed842f3933 Mon Sep 17 00:00:00 2001 From: Jason Schein Date: Sun, 11 Feb 2018 17:54:44 -0800 Subject: Update ops range example to avoid confusion between indexes and values. --- src/libcore/ops/range.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 3f573f7c7eb..a80699c0f5a 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -68,11 +68,11 @@ impl fmt::Debug for RangeFull { /// assert_eq!((3..5), std::ops::Range { start: 3, end: 5 }); /// assert_eq!(3 + 4 + 5, (3..6).sum()); /// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); -/// assert_eq!(arr[ ..3], [0,1,2 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3]); -/// assert_eq!(arr[1..3], [ 1,2 ]); // Range +/// let arr = ['a', 'b', 'c', 'd']; +/// assert_eq!(arr[ .. ], ['a', 'b', 'c', 'd']); +/// assert_eq!(arr[ ..3], ['a', 'b', 'c', ]); +/// assert_eq!(arr[1.. ], [ 'b', 'c', 'd']); +/// assert_eq!(arr[1..3], [ 'b', 'c' ]); // Range /// ``` #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] -- cgit 1.4.1-3-g733a5 From 9931583468c197fe8b3c9e15abb793457134757f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 11 Feb 2018 22:08:32 +0100 Subject: Make primitive types docs relevant --- src/libcore/num/mod.rs | 1955 ++++++++++++++++++++++-------------------- src/libstd/primitive_docs.rs | 48 -- 2 files changed, 1017 insertions(+), 986 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 1fae88b9c77..3ad52370526 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -96,132 +96,151 @@ pub mod dec2flt; pub mod bignum; pub mod diy_float; +macro_rules! doc_comment { + ($x:expr, $($tt:tt)*) => { + #[doc = $x] + $($tt)* + }; +} + // `Int` + `SignedInt` implemented for signed integers macro_rules! int_impl { - ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr) => { - /// Returns the smallest value that can be represented by this integer type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(i8::min_value(), -128); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub const fn min_value() -> Self { - !0 ^ ((!0 as $UnsignedT) >> 1) as Self + ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr) => { + doc_comment! { + concat!("Returns the smallest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +assert_eq!(", stringify!($SelfT), "::min_value(), ", stringify!($Min), "); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub const fn min_value() -> Self { + !0 ^ ((!0 as $UnsignedT) >> 1) as Self + } } - /// Returns the largest value that can be represented by this integer type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(i8::max_value(), 127); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub const fn max_value() -> Self { - !Self::min_value() + doc_comment! { + concat!("Returns the largest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +assert_eq!(", stringify!($SelfT), "::max_value(), ", stringify!($Max), "); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub const fn max_value() -> Self { + !Self::min_value() + } } - /// Converts a string slice in a given base to an integer. - /// - /// The string is expected to be an optional `+` or `-` sign - /// followed by digits. - /// Leading and trailing whitespace represent an error. - /// Digits are a subset of these characters, depending on `radix`: - /// - /// * `0-9` - /// * `a-z` - /// * `A-Z` - /// - /// # Panics - /// - /// This function panics if `radix` is not in the range from 2 to 36. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(i32::from_str_radix("A", 16), Ok(10)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_str_radix(src: &str, radix: u32) -> Result { - from_str_radix(src, radix) + doc_comment! { + concat!("Converts a string slice in a given base to an integer. + +The string is expected to be an optional `+` or `-` sign followed by digits. +Leading and trailing whitespace represent an error. Digits are a subset of these characters, +depending on `radix`: + + * `0-9` + * `a-z` + * `a-z` + +# Panics + +This function panics if `radix` is not in the range from 2 to 36. + +# Examples + +Basic usage: + +``` +assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10)); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + pub fn from_str_radix(src: &str, radix: u32) -> Result { + from_str_radix(src, radix) + } } - /// Returns the number of ones in the binary representation of `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = -0b1000_0000i8; - /// - /// assert_eq!(n.count_ones(), 1); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } + doc_comment! { + concat!("Returns the number of ones in the binary representation of `self`. - /// Returns the number of zeros in the binary representation of `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = -0b1000_0000i8; - /// - /// assert_eq!(n.count_zeros(), 7); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn count_zeros(self) -> u32 { - (!self).count_ones() +# Examples + +Basic usage: + +``` +let n = -0b1000_0000", stringify!($SelfT), "; + +assert_eq!(n.count_ones(), 1); +``` +"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } } - /// Returns the number of leading zeros in the binary representation - /// of `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = -1i16; - /// - /// assert_eq!(n.leading_zeros(), 0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn leading_zeros(self) -> u32 { - (self as $UnsignedT).leading_zeros() + doc_comment! { + concat!("Returns the number of zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +let n = -0b1000_0000", stringify!($SelfT), "; + +assert_eq!(n.count_zeros(), 7); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn count_zeros(self) -> u32 { + (!self).count_ones() + } } - /// Returns the number of trailing zeros in the binary representation - /// of `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = -4i8; - /// - /// assert_eq!(n.trailing_zeros(), 2); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn trailing_zeros(self) -> u32 { - (self as $UnsignedT).trailing_zeros() + doc_comment! { + concat!("Returns the number of leading zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +let n = -1", stringify!($SelfT), "; + +assert_eq!(n.leading_zeros(), 0); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn leading_zeros(self) -> u32 { + (self as $UnsignedT).leading_zeros() + } + } + + doc_comment! { + concat!("Returns the number of trailing zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +let n = -4", stringify!($SelfT), "; + +assert_eq!(n.trailing_zeros(), 2); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn trailing_zeros(self) -> u32 { + (self as $UnsignedT).trailing_zeros() + } } /// Shifts the bits to the left by a specified amount, `n`, @@ -288,947 +307,1007 @@ macro_rules! int_impl { (self as $UnsignedT).swap_bytes() as Self } - /// Converts an integer from big endian to the target's endianness. - /// - /// On big endian this is a no-op. On little endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 0x0123456789ABCDEFi64; - /// - /// if cfg!(target_endian = "big") { - /// assert_eq!(i64::from_be(n), n) - /// } else { - /// assert_eq!(i64::from_be(n), n.swap_bytes()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn from_be(x: Self) -> Self { - if cfg!(target_endian = "big") { x } else { x.swap_bytes() } + doc_comment! { + concat!("Converts an integer from big endian to the target's endianness. + +On big endian this is a no-op. On little endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +let n = 0xA1", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(", stringify!($SelfT), "::from_be(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) +} +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn from_be(x: Self) -> Self { + if cfg!(target_endian = "big") { x } else { x.swap_bytes() } + } } - /// Converts an integer from little endian to the target's endianness. - /// - /// On little endian this is a no-op. On big endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 0x0123456789ABCDEFi64; - /// - /// if cfg!(target_endian = "little") { - /// assert_eq!(i64::from_le(n), n) - /// } else { - /// assert_eq!(i64::from_le(n), n.swap_bytes()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn from_le(x: Self) -> Self { - if cfg!(target_endian = "little") { x } else { x.swap_bytes() } + doc_comment! { + concat!("Converts an integer from little endian to the target's endianness. + +On little endian this is a no-op. On big endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +let n = 0xA1", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(", stringify!($SelfT), "::from_le(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes()) +} +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn from_le(x: Self) -> Self { + if cfg!(target_endian = "little") { x } else { x.swap_bytes() } + } } - /// Converts `self` to big endian from the target's endianness. - /// - /// On big endian this is a no-op. On little endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 0x0123456789ABCDEFi64; - /// - /// if cfg!(target_endian = "big") { - /// assert_eq!(n.to_be(), n) - /// } else { - /// assert_eq!(n.to_be(), n.swap_bytes()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_be(self) -> Self { // or not to be? - if cfg!(target_endian = "big") { self } else { self.swap_bytes() } + doc_comment! { + concat!("Converts `self` to big endian from the target's endianness. + +On big endian this is a no-op. On little endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +let n = 0xA1", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(n.to_be(), n) +} else { + assert_eq!(n.to_be(), n.swap_bytes()) +} +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_be(self) -> Self { // or not to be? + if cfg!(target_endian = "big") { self } else { self.swap_bytes() } + } } - /// Converts `self` to little endian from the target's endianness. - /// - /// On little endian this is a no-op. On big endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 0x0123456789ABCDEFi64; - /// - /// if cfg!(target_endian = "little") { - /// assert_eq!(n.to_le(), n) - /// } else { - /// assert_eq!(n.to_le(), n.swap_bytes()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_le(self) -> Self { - if cfg!(target_endian = "little") { self } else { self.swap_bytes() } + doc_comment! { + concat!("Converts `self` to little endian from the target's endianness. + +On little endian this is a no-op. On big endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +let n = 0xA1", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(n.to_le(), n) +} else { + assert_eq!(n.to_le(), n.swap_bytes()) +} +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_le(self) -> Self { + if cfg!(target_endian = "little") { self } else { self.swap_bytes() } + } } - /// Checked integer addition. Computes `self + rhs`, returning `None` - /// if overflow occurred. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(7i16.checked_add(32760), Some(32767)); - /// assert_eq!(8i16.checked_add(32760), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn checked_add(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_add(rhs); - if b {None} else {Some(a)} - } + doc_comment! { + concat!("Checked integer addition. Computes `self + rhs`, returning `None` +if overflow occurred. - /// Checked integer subtraction. Computes `self - rhs`, returning - /// `None` if overflow occurred. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!((-127i8).checked_sub(1), Some(-128)); - /// assert_eq!((-128i8).checked_sub(1), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn checked_sub(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_sub(rhs); - if b {None} else {Some(a)} - } +# Examples - /// Checked integer multiplication. Computes `self * rhs`, returning - /// `None` if overflow occurred. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(6i8.checked_mul(21), Some(126)); - /// assert_eq!(6i8.checked_mul(22), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn checked_mul(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_mul(rhs); - if b {None} else {Some(a)} - } +Basic usage: - /// Checked integer division. Computes `self / rhs`, returning `None` - /// if `rhs == 0` or the division results in overflow. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!((-127i8).checked_div(-1), Some(127)); - /// assert_eq!((-128i8).checked_div(-1), None); - /// assert_eq!((1i8).checked_div(0), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn checked_div(self, rhs: Self) -> Option { - if rhs == 0 || (self == Self::min_value() && rhs == -1) { - None - } else { - Some(unsafe { intrinsics::unchecked_div(self, rhs) }) +``` +assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(1), Some(", +stringify!($SelfT), "::max_value() - 1)); +assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3), None); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn checked_add(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_add(rhs); + if b {None} else {Some(a)} } } - /// Checked integer remainder. Computes `self % rhs`, returning `None` - /// if `rhs == 0` or the division results in overflow. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!(5i32.checked_rem(2), Some(1)); - /// assert_eq!(5i32.checked_rem(0), None); - /// assert_eq!(i32::MIN.checked_rem(-1), None); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[inline] - pub fn checked_rem(self, rhs: Self) -> Option { - if rhs == 0 || (self == Self::min_value() && rhs == -1) { - None - } else { - Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) + doc_comment! { + concat!("Checked integer subtraction. Computes `self - rhs`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +assert_eq!((", stringify!($SelfT), "::min_value() + 2).checked_sub(1), Some(", +stringify!($SelfT), "::min_value() + 1)); +assert_eq!((", stringify!($SelfT), "::min_value() + 2).checked_sub(3), None); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn checked_sub(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_sub(rhs); + if b {None} else {Some(a)} } } - /// Checked negation. Computes `-self`, returning `None` if `self == - /// MIN`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!(5i32.checked_neg(), Some(-5)); - /// assert_eq!(i32::MIN.checked_neg(), None); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[inline] - pub fn checked_neg(self) -> Option { - let (a, b) = self.overflowing_neg(); - if b {None} else {Some(a)} + doc_comment! { + concat!("Checked integer multiplication. Computes `self * rhs`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +assert_eq!(", stringify!($SelfT), "::max_value().checked_mul(1), Some(", stringify!($SelfT), +"::max_value())); +assert_eq!(", stringify!($SelfT), "::max_value().checked_mul(2), None); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn checked_mul(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_mul(rhs); + if b {None} else {Some(a)} + } } - /// Checked shift left. Computes `self << rhs`, returning `None` - /// if `rhs` is larger than or equal to the number of bits in `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(0x10i32.checked_shl(4), Some(0x100)); - /// assert_eq!(0x10i32.checked_shl(33), None); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[inline] - pub fn checked_shl(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shl(rhs); - if b {None} else {Some(a)} + doc_comment! { + concat!("Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0` +or the division results in overflow. + +# Examples + +Basic usage: + +``` +assert_eq!((", stringify!($SelfT), "::min_value() + 1).checked_div(-1), Some(", +stringify!($Max), ")); +assert_eq!(", stringify!($SelfT), "::min_value().checked_div(-1), None); +assert_eq!((1", stringify!($SelfT), ").checked_div(0), None); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn checked_div(self, rhs: Self) -> Option { + if rhs == 0 || (self == Self::min_value() && rhs == -1) { + None + } else { + Some(unsafe { intrinsics::unchecked_div(self, rhs) }) + } + } } - /// Checked shift right. Computes `self >> rhs`, returning `None` - /// if `rhs` is larger than or equal to the number of bits in `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(0x10i32.checked_shr(4), Some(0x1)); - /// assert_eq!(0x10i32.checked_shr(33), None); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[inline] - pub fn checked_shr(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shr(rhs); - if b {None} else {Some(a)} + doc_comment! { + concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if +`rhs == 0` or the division results in overflow. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None); +assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None); +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[inline] + pub fn checked_rem(self, rhs: Self) -> Option { + if rhs == 0 || (self == Self::min_value() && rhs == -1) { + None + } else { + Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) + } + } } - /// Checked absolute value. Computes `self.abs()`, returning `None` if - /// `self == MIN`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!((-5i32).checked_abs(), Some(5)); - /// assert_eq!(i32::MIN.checked_abs(), None); - /// ``` - #[stable(feature = "no_panic_abs", since = "1.13.0")] - #[inline] - pub fn checked_abs(self) -> Option { - if self.is_negative() { - self.checked_neg() - } else { - Some(self) + doc_comment! { + concat!("Checked negation. Computes `-self`, returning `None` if `self == MIN`. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5)); +assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None); +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[inline] + pub fn checked_neg(self) -> Option { + let (a, b) = self.overflowing_neg(); + if b {None} else {Some(a)} } } - /// Saturating integer addition. Computes `self + rhs`, saturating at - /// the numeric bounds instead of overflowing. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100i8.saturating_add(1), 101); - /// assert_eq!(100i8.saturating_add(127), 127); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn saturating_add(self, rhs: Self) -> Self { - match self.checked_add(rhs) { - Some(x) => x, - None if rhs >= 0 => Self::max_value(), - None => Self::min_value(), + doc_comment! { + concat!("Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger +than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); +assert_eq!(0x1", stringify!($SelfT), ".checked_shl(70), None); +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[inline] + pub fn checked_shl(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shl(rhs); + if b {None} else {Some(a)} } } - /// Saturating integer subtraction. Computes `self - rhs`, saturating - /// at the numeric bounds instead of overflowing. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100i8.saturating_sub(127), -27); - /// assert_eq!((-100i8).saturating_sub(127), -128); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn saturating_sub(self, rhs: Self) -> Self { - match self.checked_sub(rhs) { - Some(x) => x, - None if rhs >= 0 => Self::min_value(), - None => Self::max_value(), + doc_comment! { + concat!("Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is +larger than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); +assert_eq!(0x10", stringify!($SelfT), ".checked_shr(70), None); +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[inline] + pub fn checked_shr(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shr(rhs); + if b {None} else {Some(a)} } } - /// Saturating integer multiplication. Computes `self * rhs`, - /// saturating at the numeric bounds instead of overflowing. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!(100i32.saturating_mul(127), 12700); - /// assert_eq!((1i32 << 23).saturating_mul(1 << 23), i32::MAX); - /// assert_eq!((-1i32 << 23).saturating_mul(1 << 23), i32::MIN); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[inline] - pub fn saturating_mul(self, rhs: Self) -> Self { - self.checked_mul(rhs).unwrap_or_else(|| { - if (self < 0 && rhs < 0) || (self > 0 && rhs > 0) { - Self::max_value() + doc_comment! { + concat!("Checked absolute value. Computes `self.abs()`, returning `None` if +`self == MIN`. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5)); +assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None); +```"), + #[stable(feature = "no_panic_abs", since = "1.13.0")] + #[inline] + pub fn checked_abs(self) -> Option { + if self.is_negative() { + self.checked_neg() } else { - Self::min_value() + Some(self) } - }) + } } - /// Wrapping (modular) addition. Computes `self + rhs`, - /// wrapping around at the boundary of the type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100i8.wrapping_add(27), 127); - /// assert_eq!(100i8.wrapping_add(127), -29); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn wrapping_add(self, rhs: Self) -> Self { - unsafe { - intrinsics::overflowing_add(self, rhs) + doc_comment! { + concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric +bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); +assert_eq!(", stringify!($SelfT), "::max_value().saturating_add(100), ", stringify!($SelfT), +"::max_value()); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn saturating_add(self, rhs: Self) -> Self { + match self.checked_add(rhs) { + Some(x) => x, + None if rhs >= 0 => Self::max_value(), + None => Self::min_value(), + } } } - /// Wrapping (modular) subtraction. Computes `self - rhs`, - /// wrapping around at the boundary of the type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(0i8.wrapping_sub(127), -127); - /// assert_eq!((-2i8).wrapping_sub(127), 127); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn wrapping_sub(self, rhs: Self) -> Self { - unsafe { - intrinsics::overflowing_sub(self, rhs) + doc_comment! { + concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the +numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27); +assert_eq!(", stringify!($SelfT), "::min_value().saturating_sub(100), ", stringify!($SelfT), +"::min_value()); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn saturating_sub(self, rhs: Self) -> Self { + match self.checked_sub(rhs) { + Some(x) => x, + None if rhs >= 0 => Self::min_value(), + None => Self::max_value(), + } } } - /// Wrapping (modular) multiplication. Computes `self * - /// rhs`, wrapping around at the boundary of the type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(10i8.wrapping_mul(12), 120); - /// assert_eq!(11i8.wrapping_mul(12), -124); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn wrapping_mul(self, rhs: Self) -> Self { - unsafe { - intrinsics::overflowing_mul(self, rhs) + doc_comment! { + concat!("Saturating integer multiplication. Computes `self * rhs`, saturating at the +numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(11 << 23), ", stringify!($SelfT), "::MAX); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(1 << 23), ", stringify!($SelfT), "::MIN); +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[inline] + pub fn saturating_mul(self, rhs: Self) -> Self { + self.checked_mul(rhs).unwrap_or_else(|| { + if (self < 0 && rhs < 0) || (self > 0 && rhs > 0) { + Self::max_value() + } else { + Self::min_value() + } + }) } } - /// Wrapping (modular) division. Computes `self / rhs`, - /// wrapping around at the boundary of the type. - /// - /// The only case where such wrapping can occur is when one - /// divides `MIN / -1` on a signed type (where `MIN` is the - /// negative minimal value for the type); this is equivalent - /// to `-MIN`, a positive value that is too large to represent - /// in the type. In such a case, this function returns `MIN` - /// itself. - /// - /// # Panics - /// - /// This function will panic if `rhs` is 0. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100u8.wrapping_div(10), 10); - /// assert_eq!((-128i8).wrapping_div(-1), -128); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline] - pub fn wrapping_div(self, rhs: Self) -> Self { - self.overflowing_div(rhs).0 - } + doc_comment! { + concat!("Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the +boundary of the type. - /// Wrapping (modular) remainder. Computes `self % rhs`, - /// wrapping around at the boundary of the type. - /// - /// Such wrap-around never actually occurs mathematically; - /// implementation artifacts make `x % y` invalid for `MIN / - /// -1` on a signed type (where `MIN` is the negative - /// minimal value). In such a case, this function returns `0`. - /// - /// # Panics - /// - /// This function will panic if `rhs` is 0. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100i8.wrapping_rem(10), 0); - /// assert_eq!((-128i8).wrapping_rem(-1), 0); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline] - pub fn wrapping_rem(self, rhs: Self) -> Self { - self.overflowing_rem(rhs).0 +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127); +assert_eq!(", stringify!($SelfT), "::max_value().wrapping_add(2), ", stringify!($SelfT), +"::min_value() + 1); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn wrapping_add(self, rhs: Self) -> Self { + unsafe { + intrinsics::overflowing_add(self, rhs) + } + } } - /// Wrapping (modular) negation. Computes `-self`, - /// wrapping around at the boundary of the type. - /// - /// The only case where such wrapping can occur is when one - /// negates `MIN` on a signed type (where `MIN` is the - /// negative minimal value for the type); this is a positive - /// value that is too large to represent in the type. In such - /// a case, this function returns `MIN` itself. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100i8.wrapping_neg(), -100); - /// assert_eq!((-128i8).wrapping_neg(), -128); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline] - pub fn wrapping_neg(self) -> Self { - self.overflowing_neg().0 + doc_comment! { + concat!("Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the +boundary of the type. + +# Examples + +Basic usage: + +``` +assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127); +assert_eq!((-2i8).wrapping_sub(", stringify!($SelfT), "::max_value()), ", +stringify!($SelfT), "::max_value()); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn wrapping_sub(self, rhs: Self) -> Self { + unsafe { + intrinsics::overflowing_sub(self, rhs) + } + } } - /// Panic-free bitwise shift-left; yields `self << mask(rhs)`, - /// where `mask` removes any high-order bits of `rhs` that - /// would cause the shift to exceed the bitwidth of the type. - /// - /// Note that this is *not* the same as a rotate-left; the - /// RHS of a wrapping shift-left is restricted to the range - /// of the type, rather than the bits shifted out of the LHS - /// being returned to the other end. The primitive integer - /// types all implement a `rotate_left` function, which may - /// be what you want instead. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!((-1i8).wrapping_shl(7), -128); - /// assert_eq!((-1i8).wrapping_shl(8), -1); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline] - pub fn wrapping_shl(self, rhs: u32) -> Self { - unsafe { - intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) + doc_comment! { + concat!("Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at +the boundary of the type. + +# Examples + +Basic usage: + +``` +assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120); +assert_eq!(11i8.wrapping_mul(12), -124); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn wrapping_mul(self, rhs: Self) -> Self { + unsafe { + intrinsics::overflowing_mul(self, rhs) + } } } - /// Panic-free bitwise shift-right; yields `self >> mask(rhs)`, - /// where `mask` removes any high-order bits of `rhs` that - /// would cause the shift to exceed the bitwidth of the type. - /// - /// Note that this is *not* the same as a rotate-right; the - /// RHS of a wrapping shift-right is restricted to the range - /// of the type, rather than the bits shifted out of the LHS - /// being returned to the other end. The primitive integer - /// types all implement a `rotate_right` function, which may - /// be what you want instead. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!((-128i8).wrapping_shr(7), -1); - /// assert_eq!((-128i8).wrapping_shr(8), -128); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline] - pub fn wrapping_shr(self, rhs: u32) -> Self { - unsafe { - intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) + doc_comment! { + concat!("Wrapping (modular) division. Computes `self / rhs`, wrapping around at the +boundary of the type. + +The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where +`MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value +that is too large to represent in the type. In such a case, this function returns `MIN` itself. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10); +assert_eq!((-128i8).wrapping_div(-1), -128); +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline] + pub fn wrapping_div(self, rhs: Self) -> Self { + self.overflowing_div(rhs).0 } } - /// Wrapping (modular) absolute value. Computes `self.abs()`, - /// wrapping around at the boundary of the type. - /// - /// The only case where such wrapping can occur is when one takes - /// the absolute value of the negative minimal value for the type - /// this is a positive value that is too large to represent in the - /// type. In such a case, this function returns `MIN` itself. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100i8.wrapping_abs(), 100); - /// assert_eq!((-100i8).wrapping_abs(), 100); - /// assert_eq!((-128i8).wrapping_abs(), -128); - /// assert_eq!((-128i8).wrapping_abs() as u8, 128); - /// ``` - #[stable(feature = "no_panic_abs", since = "1.13.0")] - #[inline] - pub fn wrapping_abs(self) -> Self { - if self.is_negative() { - self.wrapping_neg() - } else { - self + doc_comment! { + concat!("Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the +boundary of the type. + +Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y` +invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case, +this function returns `0`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0); +assert_eq!((-128i8).wrapping_rem(-1), 0); +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline] + pub fn wrapping_rem(self, rhs: Self) -> Self { + self.overflowing_rem(rhs).0 } } - /// Calculates `self` + `rhs` - /// - /// Returns a tuple of the addition along with a boolean indicating - /// whether an arithmetic overflow would occur. If an overflow would - /// have occurred then the wrapped value is returned. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!(5i32.overflowing_add(2), (7, false)); - /// assert_eq!(i32::MAX.overflowing_add(1), (i32::MIN, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_add(self, rhs: Self) -> (Self, bool) { - let (a, b) = unsafe { - intrinsics::add_with_overflow(self as $ActualT, - rhs as $ActualT) - }; - (a as Self, b) + doc_comment! { + concat!("Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary +of the type. + +The only case where such wrapping can occur is when one negates `MIN` on a signed type (where `MIN` +is the negative minimal value for the type); this is a positive value that is too large to represent +in the type. In such a case, this function returns `MIN` itself. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100); +assert_eq!(", stringify!($SelfT), "::min_value().wrapping_neg(), ", stringify!($SelfT), +"::min_value()); +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline] + pub fn wrapping_neg(self) -> Self { + self.overflowing_neg().0 + } } - /// Calculates `self` - `rhs` - /// - /// Returns a tuple of the subtraction along with a boolean indicating - /// whether an arithmetic overflow would occur. If an overflow would - /// have occurred then the wrapped value is returned. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!(5i32.overflowing_sub(2), (3, false)); - /// assert_eq!(i32::MIN.overflowing_sub(1), (i32::MAX, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) { - let (a, b) = unsafe { - intrinsics::sub_with_overflow(self as $ActualT, - rhs as $ActualT) - }; - (a as Self, b) + doc_comment! { + concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes +any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to +the range of the type, rather than the bits shifted out of the LHS being returned to the other end. +The primitive integer types all implement a `rotate_left` function, which may be what you want +instead. + +# Examples + +Basic usage: + +``` +assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128); +assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(64), -1); +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline] + pub fn wrapping_shl(self, rhs: u32) -> Self { + unsafe { + intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) + } + } } - /// Calculates the multiplication of `self` and `rhs`. - /// - /// Returns a tuple of the multiplication along with a boolean - /// indicating whether an arithmetic overflow would occur. If an - /// overflow would have occurred then the wrapped value is returned. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// assert_eq!(5i32.overflowing_mul(2), (10, false)); - /// assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) { - let (a, b) = unsafe { - intrinsics::mul_with_overflow(self as $ActualT, - rhs as $ActualT) - }; - (a as Self, b) + doc_comment! { + concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask` +removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted +to the range of the type, rather than the bits shifted out of the LHS being returned to the other +end. The primitive integer types all implement a `rotate_right` function, which may be what you want +instead. + +# Examples + +Basic usage: + +``` +assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1); +assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(64), -128); +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline] + pub fn wrapping_shr(self, rhs: u32) -> Self { + unsafe { + intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) + } + } } - /// Calculates the divisor when `self` is divided by `rhs`. - /// - /// Returns a tuple of the divisor along with a boolean indicating - /// whether an arithmetic overflow would occur. If an overflow would - /// occur then self is returned. - /// - /// # Panics - /// - /// This function will panic if `rhs` is 0. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!(5i32.overflowing_div(2), (2, false)); - /// assert_eq!(i32::MIN.overflowing_div(-1), (i32::MIN, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_div(self, rhs: Self) -> (Self, bool) { - if self == Self::min_value() && rhs == -1 { - (self, true) - } else { - (self / rhs, false) + doc_comment! { + concat!("Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at +the boundary of the type. + +The only case where such wrapping can occur is when one takes the absolute value of the negative +minimal value for the type this is a positive value that is too large to represent in the type. In +such a case, this function returns `MIN` itself. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100); +assert_eq!((-100", stringify!($SelfT), ").wrapping_abs(), 100); +assert_eq!(", stringify!($SelfT), "::min_value().wrapping_abs(), ", stringify!($SelfT), +"::min_value()); +assert_eq!((-128i8).wrapping_abs() as u8, 128); +```"), + #[stable(feature = "no_panic_abs", since = "1.13.0")] + #[inline] + pub fn wrapping_abs(self) -> Self { + if self.is_negative() { + self.wrapping_neg() + } else { + self + } } } - /// Calculates the remainder when `self` is divided by `rhs`. - /// - /// Returns a tuple of the remainder after dividing along with a boolean - /// indicating whether an arithmetic overflow would occur. If an - /// overflow would occur then 0 is returned. - /// - /// # Panics - /// - /// This function will panic if `rhs` is 0. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!(5i32.overflowing_rem(2), (1, false)); - /// assert_eq!(i32::MIN.overflowing_rem(-1), (0, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_rem(self, rhs: Self) -> (Self, bool) { - if self == Self::min_value() && rhs == -1 { - (0, true) - } else { - (self % rhs, false) + doc_comment! { + concat!("Calculates `self` + `rhs` + +Returns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would +occur. If an overflow would have occurred then the wrapped value is returned. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); +assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT), "::MIN, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_add(self, rhs: Self) -> (Self, bool) { + let (a, b) = unsafe { + intrinsics::add_with_overflow(self as $ActualT, + rhs as $ActualT) + }; + (a as Self, b) } } - /// Negates self, overflowing if this is equal to the minimum value. - /// - /// Returns a tuple of the negated version of self along with a boolean - /// indicating whether an overflow happened. If `self` is the minimum - /// value (e.g. `i32::MIN` for values of type `i32`), then the minimum - /// value will be returned again and `true` will be returned for an - /// overflow happening. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!(2i32.overflowing_neg(), (-2, false)); - /// assert_eq!(i32::MIN.overflowing_neg(), (i32::MIN, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_neg(self) -> (Self, bool) { - if self == Self::min_value() { - (Self::min_value(), true) - } else { - (-self, false) + doc_comment! { + concat!("Calculates `self` - `rhs` + +Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow +would occur. If an overflow would have occurred then the wrapped value is returned. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT), "::MAX, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + let (a, b) = unsafe { + intrinsics::sub_with_overflow(self as $ActualT, + rhs as $ActualT) + }; + (a as Self, b) } } - /// Shifts self left by `rhs` bits. - /// - /// Returns a tuple of the shifted version of self along with a boolean - /// indicating whether the shift value was larger than or equal to the - /// number of bits. If the shift value is too large, then value is - /// masked (N-1) where N is the number of bits, and this value is then - /// used to perform the shift. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// assert_eq!(0x10i32.overflowing_shl(4), (0x100, false)); - /// assert_eq!(0x10i32.overflowing_shl(36), (0x100, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) + doc_comment! { + concat!("Calculates the multiplication of `self` and `rhs`. + +Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow +would occur. If an overflow would have occurred then the wrapped value is returned. + +# Examples + +Basic usage: + +``` +assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false)); +assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) { + let (a, b) = unsafe { + intrinsics::mul_with_overflow(self as $ActualT, + rhs as $ActualT) + }; + (a as Self, b) + } } - /// Shifts self right by `rhs` bits. - /// - /// Returns a tuple of the shifted version of self along with a boolean - /// indicating whether the shift value was larger than or equal to the - /// number of bits. If the shift value is too large, then value is - /// masked (N-1) where N is the number of bits, and this value is then - /// used to perform the shift. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// assert_eq!(0x10i32.overflowing_shr(4), (0x1, false)); - /// assert_eq!(0x10i32.overflowing_shr(36), (0x1, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) + doc_comment! { + concat!("Calculates the divisor when `self` is divided by `rhs`. + +Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would +occur. If an overflow would occur then self is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false)); +assert_eq!(i", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT), +"::MIN, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_div(self, rhs: Self) -> (Self, bool) { + if self == Self::min_value() && rhs == -1 { + (self, true) + } else { + (self / rhs, false) + } + } } - /// Computes the absolute value of `self`. - /// - /// Returns a tuple of the absolute version of self along with a - /// boolean indicating whether an overflow happened. If self is the - /// minimum value (e.g. i32::MIN for values of type i32), then the - /// minimum value will be returned again and true will be returned for - /// an overflow happening. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(10i8.overflowing_abs(), (10,false)); - /// assert_eq!((-10i8).overflowing_abs(), (10,false)); - /// assert_eq!((-128i8).overflowing_abs(), (-128,true)); - /// ``` - #[stable(feature = "no_panic_abs", since = "1.13.0")] - #[inline] - pub fn overflowing_abs(self) -> (Self, bool) { - if self.is_negative() { - self.overflowing_neg() - } else { - (self, false) + doc_comment! { + concat!("Calculates the remainder when `self` is divided by `rhs`. + +Returns a tuple of the remainder after dividing along with a boolean indicating whether an +arithmetic overflow would occur. If an overflow would occur then 0 is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_rem(self, rhs: Self) -> (Self, bool) { + if self == Self::min_value() && rhs == -1 { + (0, true) + } else { + (self % rhs, false) + } } } - /// Raises self to the power of `exp`, using exponentiation by squaring. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let x: i32 = 2; // or any other integer type - /// - /// assert_eq!(x.pow(4), 16); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - #[rustc_inherit_overflow_checks] - pub fn pow(self, mut exp: u32) -> Self { - let mut base = self; - let mut acc = 1; + doc_comment! { + concat!("Negates self, overflowing if this is equal to the minimum value. - while exp > 1 { - if (exp & 1) == 1 { - acc = acc * base; +Returns a tuple of the negated version of self along with a boolean indicating whether an overflow +happened. If `self` is the minimum value (e.g. `i32::MIN` for values of type `i32`), then the +minimum value will be returned again and `true` will be returned for an overflow happening. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT), "::MIN, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_neg(self) -> (Self, bool) { + if self == Self::min_value() { + (Self::min_value(), true) + } else { + (-self, false) } - exp /= 2; - base = base * base; } + } - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - if exp == 1 { - acc = acc * base; + doc_comment! { + concat!("Shifts self left by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean indicating whether the shift +value was larger than or equal to the number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then used to perform the shift. + +# Examples + +Basic usage: + +``` +assert_eq!(0x10", stringify!($SelfT), ".overflowing_shl(4), (0x100, false)); +assert_eq!(0x10i32.overflowing_shl(36), (0x100, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) } + } - acc + doc_comment! { + concat!("Shifts self right by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean indicating whether the shift +value was larger than or equal to the number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then used to perform the shift. + +# Examples + +Basic usage: + +``` +assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); +assert_eq!(0x10i32.overflowing_shr(36), (0x1, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) + } } - /// Computes the absolute value of `self`. - /// - /// # Overflow behavior - /// - /// The absolute value of `i32::min_value()` cannot be represented as an - /// `i32`, and attempting to calculate it will cause an overflow. This - /// means that code in debug mode will trigger a panic on this case and - /// optimized code will return `i32::min_value()` without a panic. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(10i8.abs(), 10); - /// assert_eq!((-10i8).abs(), 10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - #[rustc_inherit_overflow_checks] - pub fn abs(self) -> Self { - if self.is_negative() { - // Note that the #[inline] above means that the overflow - // semantics of this negation depend on the crate we're being - // inlined into. - -self - } else { - self + doc_comment! { + concat!("Computes the absolute value of `self`. + +Returns a tuple of the absolute version of self along with a boolean indicating whether an overflow +happened. If self is the minimum value (e.g. ", stringify!($SelfT), "::MIN for values of type +", stringify!($SelfT), "), then the minimum value will be returned again and true will be returned +for an overflow happening. + +# Examples + +Basic usage: + +``` +assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false)); +assert_eq!((-10", stringify!($SelfT), ").overflowing_abs(), (10, false)); +assert_eq!((", stringify!($SelfT), "::min_value()).overflowing_abs(), (-", stringify!($SelfT), +"::min_value(), true)); +```"), + #[stable(feature = "no_panic_abs", since = "1.13.0")] + #[inline] + pub fn overflowing_abs(self) -> (Self, bool) { + if self.is_negative() { + self.overflowing_neg() + } else { + (self, false) + } } } - /// Returns a number representing sign of `self`. - /// - /// - `0` if the number is zero - /// - `1` if the number is positive - /// - `-1` if the number is negative - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(10i8.signum(), 1); - /// assert_eq!(0i8.signum(), 0); - /// assert_eq!((-10i8).signum(), -1); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn signum(self) -> Self { - match self { - n if n > 0 => 1, - 0 => 0, - _ => -1, + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +# Examples + +Basic usage: + +``` +let x: ", stringify!($SelfT), " = 2; // or any other integer type + +assert_eq!(x.pow(4), 16); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[rustc_inherit_overflow_checks] + pub fn pow(self, mut exp: u32) -> Self { + let mut base = self; + let mut acc = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc * base; + } + exp /= 2; + base = base * base; + } + + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + if exp == 1 { + acc = acc * base; + } + + acc } } - /// Returns `true` if `self` is positive and `false` if the number - /// is zero or negative. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!(10i8.is_positive()); - /// assert!(!(-10i8).is_positive()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_positive(self) -> bool { self > 0 } + doc_comment! { + concat!("Computes the absolute value of `self`. - /// Returns `true` if `self` is negative and `false` if the number - /// is zero or positive. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!((-10i8).is_negative()); - /// assert!(!10i8.is_negative()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_negative(self) -> bool { self < 0 } +# Overflow behavior + +The absolute value of `", stringify!($SelfT), "::min_value()` cannot be represented as an +`", stringify!($SelfT), "`, and attempting to calculate it will cause an overflow. This means that +code in debug mode will trigger a panic on this case and optimized code will return `", +stringify!($SelfT), "::min_value()` without a panic. + +# Examples + +Basic usage: + +``` +assert_eq!(10", stringify!($SelfT), ".abs(), 10); +assert_eq!((-10", stringify!($SelfT), ").abs(), 10); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[rustc_inherit_overflow_checks] + pub fn abs(self) -> Self { + if self.is_negative() { + // Note that the #[inline] above means that the overflow + // semantics of this negation depend on the crate we're being + // inlined into. + -self + } else { + self + } + } + } + + doc_comment! { + concat!("Returns a number representing sign of `self`. + + - `0` if the number is zero + - `1` if the number is positive + - `-1` if the number is negative + +# Examples + +Basic usage: + +``` +assert_eq!(10", stringify!($SelfT), ".signum(), 1); +assert_eq!(0", stringify!($SelfT), ".signum(), 0); +assert_eq!((-10", stringify!($SelfT), ").signum(), -1); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn signum(self) -> Self { + match self { + n if n > 0 => 1, + 0 => 0, + _ => -1, + } + } + } + + doc_comment! { + concat!("Returns `true` if `self` is positive and `false` if the number is zero or +negative. + +# Examples + +Basic usage: + +``` +assert!(10", stringify!($SelfT), ".is_positive()); +assert!(!(-10", stringify!($SelfT), ").is_positive()); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_positive(self) -> bool { self > 0 } + } + + doc_comment! { + concat!("Returns `true` if `self` is negative and `false` if the number is zero or +positive. + +# Examples + +Basic usage: + +``` +assert!((-10", stringify!($SelfT), ").is_negative()); +assert!(!10", stringify!($SelfT), ".is_negative()); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_negative(self) -> bool { self < 0 } + } } } #[lang = "i8"] impl i8 { - int_impl! { i8, i8, u8, 8 } + int_impl! { i8, i8, u8, 8, -128, 127 } } #[lang = "i16"] impl i16 { - int_impl! { i16, i16, u16, 16 } + int_impl! { i16, i16, u16, 16, -32768, 32767 } } #[lang = "i32"] impl i32 { - int_impl! { i32, i32, u32, 32 } + int_impl! { i32, i32, u32, 32, -2147483648, 2147483647 } } #[lang = "i64"] impl i64 { - int_impl! { i64, i64, u64, 64 } + int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807 } } #[lang = "i128"] impl i128 { - int_impl! { i128, i128, u128, 128 } + int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, 170141183460469231731687303715884105727 } } #[cfg(target_pointer_width = "16")] @@ -1246,7 +1325,7 @@ impl isize { #[cfg(target_pointer_width = "64")] #[lang = "isize"] impl isize { - int_impl! { isize, i64, u64, 64 } + int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807 } } // `Int` + `UnsignedInt` implemented for unsigned integers diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index a2caf47e8cc..358aa2c37df 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -720,10 +720,6 @@ mod prim_f64 { } /// The 8-bit signed integer type. /// /// *[See also the `std::i8` module](i8/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `i64` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_i8 { } @@ -732,10 +728,6 @@ mod prim_i8 { } /// The 16-bit signed integer type. /// /// *[See also the `std::i16` module](i16/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `i32` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_i16 { } @@ -744,10 +736,6 @@ mod prim_i16 { } /// The 32-bit signed integer type. /// /// *[See also the `std::i32` module](i32/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `i16` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_i32 { } @@ -756,10 +744,6 @@ mod prim_i32 { } /// The 64-bit signed integer type. /// /// *[See also the `std::i64` module](i64/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `i8` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_i64 { } @@ -768,10 +752,6 @@ mod prim_i64 { } /// The 128-bit signed integer type. /// /// *[See also the `std::i128` module](i128/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `i8` in there. -/// #[unstable(feature = "i128", issue="35118")] mod prim_i128 { } @@ -780,10 +760,6 @@ mod prim_i128 { } /// The 8-bit unsigned integer type. /// /// *[See also the `std::u8` module](u8/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `u64` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_u8 { } @@ -792,10 +768,6 @@ mod prim_u8 { } /// The 16-bit unsigned integer type. /// /// *[See also the `std::u16` module](u16/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `u32` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_u16 { } @@ -804,10 +776,6 @@ mod prim_u16 { } /// The 32-bit unsigned integer type. /// /// *[See also the `std::u32` module](u32/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `u16` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_u32 { } @@ -816,10 +784,6 @@ mod prim_u32 { } /// The 64-bit unsigned integer type. /// /// *[See also the `std::u64` module](u64/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `u8` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_u64 { } @@ -828,10 +792,6 @@ mod prim_u64 { } /// The 128-bit unsigned integer type. /// /// *[See also the `std::u128` module](u128/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `u8` in there. -/// #[unstable(feature = "i128", issue="35118")] mod prim_u128 { } @@ -844,10 +804,6 @@ mod prim_u128 { } /// and on a 64 bit target, this is 8 bytes. /// /// *[See also the `std::isize` module](isize/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `usize` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_isize { } @@ -860,10 +816,6 @@ mod prim_isize { } /// and on a 64 bit target, this is 8 bytes. /// /// *[See also the `std::usize` module](usize/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `isize` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_usize { } -- cgit 1.4.1-3-g733a5 From 56e15de9f9c15d967d5a538b8dc37710354ae893 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 11 Feb 2018 18:13:12 -0500 Subject: Make primitive types docs relevant (unsigned) --- src/libcore/num/mod.rs | 1562 +++++++++++++++++++++++++----------------------- 1 file changed, 821 insertions(+), 741 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 3ad52370526..da46eeb44bf 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1330,92 +1330,102 @@ impl isize { // `Int` + `UnsignedInt` implemented for unsigned integers macro_rules! uint_impl { - ($SelfT:ty, $ActualT:ty, $BITS:expr) => { - /// Returns the smallest value that can be represented by this integer type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(u8::min_value(), 0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub const fn min_value() -> Self { 0 } + ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr) => { + doc_comment! { + concat!("Returns the smallest value that can be represented by this integer type. - /// Returns the largest value that can be represented by this integer type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(u8::max_value(), 255); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub const fn max_value() -> Self { !0 } +# Examples - /// Converts a string slice in a given base to an integer. - /// - /// The string is expected to be an optional `+` sign - /// followed by digits. - /// Leading and trailing whitespace represent an error. - /// Digits are a subset of these characters, depending on `radix`: - /// - /// * `0-9` - /// * `a-z` - /// * `A-Z` - /// - /// # Panics - /// - /// This function panics if `radix` is not in the range from 2 to 36. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(u32::from_str_radix("A", 16), Ok(10)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_str_radix(src: &str, radix: u32) -> Result { - from_str_radix(src, radix) +Basic usage: + +``` +assert_eq!(", stringify!($SelfT), "::min_value(), 0); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub const fn min_value() -> Self { 0 } } - /// Returns the number of ones in the binary representation of `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 0b01001100u8; - /// - /// assert_eq!(n.count_ones(), 3); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn count_ones(self) -> u32 { - unsafe { intrinsics::ctpop(self as $ActualT) as u32 } + doc_comment! { + concat!("Returns the largest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +assert_eq!(", stringify!($SelfT), "::max_value(), ", stringify!($MaxV), "); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub const fn max_value() -> Self { !0 } } - /// Returns the number of zeros in the binary representation of `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 0b01001100u8; - /// - /// assert_eq!(n.count_zeros(), 5); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn count_zeros(self) -> u32 { - (!self).count_ones() + doc_comment! { + concat!("Converts a string slice in a given base to an integer. + +The string is expected to be an optional `+` sign +followed by digits. +Leading and trailing whitespace represent an error. +Digits are a subset of these characters, depending on `radix`: + +* `0-9` +* `a-z` +* `A-Z` + +# Panics + +This function panics if `radix` is not in the range from 2 to 36. + +# Examples + +Basic usage: + +``` +assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10)); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + pub fn from_str_radix(src: &str, radix: u32) -> Result { + from_str_radix(src, radix) + } + } + + doc_comment! { + concat!("Returns the number of ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +let n = 0b01001100", stringify!($SelfT), "; + +assert_eq!(n.count_ones(), 3); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn count_ones(self) -> u32 { + unsafe { intrinsics::ctpop(self as $ActualT) as u32 } + } + } + + doc_comment! { + concat!("Returns the number of zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +let n = 0b01001100", stringify!($SelfT), "; + +assert_eq!(n.count_zeros(), 5); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn count_zeros(self) -> u32 { + (!self).count_ones() + } } /// Returns the number of leading zeros in the binary representation @@ -1436,33 +1446,35 @@ macro_rules! uint_impl { unsafe { intrinsics::ctlz(self as $ActualT) as u32 } } - /// Returns the number of trailing zeros in the binary representation - /// of `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 0b0101000u16; - /// - /// assert_eq!(n.trailing_zeros(), 3); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn trailing_zeros(self) -> u32 { - // As of LLVM 3.6 the codegen for the zero-safe cttz8 intrinsic - // emits two conditional moves on x86_64. By promoting the value to - // u16 and setting bit 8, we get better code without any conditional - // operations. - // FIXME: There's a LLVM patch (http://reviews.llvm.org/D9284) - // pending, remove this workaround once LLVM generates better code - // for cttz8. - unsafe { - if $BITS == 8 { - intrinsics::cttz(self as u16 | 0x100) as u32 - } else { - intrinsics::cttz(self) as u32 + doc_comment! { + concat!("Returns the number of trailing zeros in the binary representation +of `self`. + +# Examples + +Basic usage: + +``` +let n = 0b0101000", stringify!($SelfT), "; + +assert_eq!(n.trailing_zeros(), 3); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn trailing_zeros(self) -> u32 { + // As of LLVM 3.6 the codegen for the zero-safe cttz8 intrinsic + // emits two conditional moves on x86_64. By promoting the value to + // u16 and setting bit 8, we get better code without any conditional + // operations. + // FIXME: There's a LLVM patch (http://reviews.llvm.org/D9284) + // pending, remove this workaround once LLVM generates better code + // for cttz8. + unsafe { + if $BITS == 8 { + intrinsics::cttz(self as u16 | 0x100) as u32 + } else { + intrinsics::cttz(self) as u32 + } } } } @@ -1535,347 +1547,382 @@ macro_rules! uint_impl { unsafe { intrinsics::bswap(self as $ActualT) as Self } } - /// Converts an integer from big endian to the target's endianness. - /// - /// On big endian this is a no-op. On little endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 0x0123456789ABCDEFu64; - /// - /// if cfg!(target_endian = "big") { - /// assert_eq!(u64::from_be(n), n) - /// } else { - /// assert_eq!(u64::from_be(n), n.swap_bytes()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn from_be(x: Self) -> Self { - if cfg!(target_endian = "big") { x } else { x.swap_bytes() } - } + doc_comment! { + concat!("Converts an integer from big endian to the target's endianness. - /// Converts an integer from little endian to the target's endianness. - /// - /// On little endian this is a no-op. On big endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 0x0123456789ABCDEFu64; - /// - /// if cfg!(target_endian = "little") { - /// assert_eq!(u64::from_le(n), n) - /// } else { - /// assert_eq!(u64::from_le(n), n.swap_bytes()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn from_le(x: Self) -> Self { - if cfg!(target_endian = "little") { x } else { x.swap_bytes() } - } +On big endian this is a no-op. On little endian the bytes are +swapped. - /// Converts `self` to big endian from the target's endianness. - /// - /// On big endian this is a no-op. On little endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 0x0123456789ABCDEFu64; - /// - /// if cfg!(target_endian = "big") { - /// assert_eq!(n.to_be(), n) - /// } else { - /// assert_eq!(n.to_be(), n.swap_bytes()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_be(self) -> Self { // or not to be? - if cfg!(target_endian = "big") { self } else { self.swap_bytes() } - } +# Examples - /// Converts `self` to little endian from the target's endianness. - /// - /// On little endian this is a no-op. On big endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 0x0123456789ABCDEFu64; - /// - /// if cfg!(target_endian = "little") { - /// assert_eq!(n.to_le(), n) - /// } else { - /// assert_eq!(n.to_le(), n.swap_bytes()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_le(self) -> Self { - if cfg!(target_endian = "little") { self } else { self.swap_bytes() } - } +Basic usage: - /// Checked integer addition. Computes `self + rhs`, returning `None` - /// if overflow occurred. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(5u16.checked_add(65530), Some(65535)); - /// assert_eq!(6u16.checked_add(65530), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn checked_add(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_add(rhs); - if b {None} else {Some(a)} - } +``` +let n = 0xA1", stringify!($SelfT), "; - /// Checked integer subtraction. Computes `self - rhs`, returning - /// `None` if overflow occurred. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(1u8.checked_sub(1), Some(0)); - /// assert_eq!(0u8.checked_sub(1), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn checked_sub(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_sub(rhs); - if b {None} else {Some(a)} +if cfg!(target_endian = \"big\") { + assert_eq!(", stringify!($SelfT), "::from_be(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) +} +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn from_be(x: Self) -> Self { + if cfg!(target_endian = "big") { x } else { x.swap_bytes() } + } } - /// Checked integer multiplication. Computes `self * rhs`, returning - /// `None` if overflow occurred. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(5u8.checked_mul(51), Some(255)); - /// assert_eq!(5u8.checked_mul(52), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn checked_mul(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_mul(rhs); - if b {None} else {Some(a)} - } + doc_comment! { + concat!("Converts an integer from little endian to the target's endianness. - /// Checked integer division. Computes `self / rhs`, returning `None` - /// if `rhs == 0`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(128u8.checked_div(2), Some(64)); - /// assert_eq!(1u8.checked_div(0), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn checked_div(self, rhs: Self) -> Option { - match rhs { - 0 => None, - rhs => Some(unsafe { intrinsics::unchecked_div(self, rhs) }), +On little endian this is a no-op. On big endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +let n = 0xA1", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(u64::from_le(n), n) +} else { + assert_eq!(u64::from_le(n), n.swap_bytes()) +} +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn from_le(x: Self) -> Self { + if cfg!(target_endian = "little") { x } else { x.swap_bytes() } } } - /// Checked integer remainder. Computes `self % rhs`, returning `None` - /// if `rhs == 0`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(5u32.checked_rem(2), Some(1)); - /// assert_eq!(5u32.checked_rem(0), None); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[inline] - pub fn checked_rem(self, rhs: Self) -> Option { - if rhs == 0 { - None - } else { - Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) + doc_comment! { + concat!("Converts `self` to big endian from the target's endianness. + +On big endian this is a no-op. On little endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +let n = 0xA1", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(n.to_be(), n) +} else { + assert_eq!(n.to_be(), n.swap_bytes()) +} +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_be(self) -> Self { // or not to be? + if cfg!(target_endian = "big") { self } else { self.swap_bytes() } } } - /// Checked negation. Computes `-self`, returning `None` unless `self == - /// 0`. - /// - /// Note that negating any positive integer will overflow. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(0u32.checked_neg(), Some(0)); - /// assert_eq!(1u32.checked_neg(), None); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[inline] - pub fn checked_neg(self) -> Option { - let (a, b) = self.overflowing_neg(); - if b {None} else {Some(a)} + doc_comment! { + concat!("Converts `self` to little endian from the target's endianness. + +On little endian this is a no-op. On big endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +let n = 0xA1", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(n.to_le(), n) +} else { + assert_eq!(n.to_le(), n.swap_bytes()) +} +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_le(self) -> Self { + if cfg!(target_endian = "little") { self } else { self.swap_bytes() } + } } - /// Checked shift left. Computes `self << rhs`, returning `None` - /// if `rhs` is larger than or equal to the number of bits in `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(0x10u32.checked_shl(4), Some(0x100)); - /// assert_eq!(0x10u32.checked_shl(33), None); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[inline] - pub fn checked_shl(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shl(rhs); - if b {None} else {Some(a)} + doc_comment! { + concat!("Checked integer addition. Computes `self + rhs`, returning `None` +if overflow occurred. + +# Examples + +Basic usage: + +``` +assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(1), ", +"Some(", stringify!($SelfT), "::max_value() - 1)); +assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3),None); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn checked_add(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_add(rhs); + if b {None} else {Some(a)} + } } - /// Checked shift right. Computes `self >> rhs`, returning `None` - /// if `rhs` is larger than or equal to the number of bits in `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(0x10u32.checked_shr(4), Some(0x1)); - /// assert_eq!(0x10u32.checked_shr(33), None); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[inline] - pub fn checked_shr(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shr(rhs); - if b {None} else {Some(a)} + doc_comment! { + concat!("Checked integer subtraction. Computes `self - rhs`, returning +`None` if overflow occurred. + +# Examples + +Basic usage: + +``` +assert_eq!(1", stringify!($SelfT), ".checked_sub(1), Some(0)); +assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn checked_sub(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_sub(rhs); + if b {None} else {Some(a)} + } } - /// Saturating integer addition. Computes `self + rhs`, saturating at - /// the numeric bounds instead of overflowing. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100u8.saturating_add(1), 101); - /// assert_eq!(200u8.saturating_add(127), 255); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn saturating_add(self, rhs: Self) -> Self { - match self.checked_add(rhs) { - Some(x) => x, - None => Self::max_value(), + doc_comment! { + concat!("Checked integer multiplication. Computes `self * rhs`, returning +`None` if overflow occurred. + +# Examples + +Basic usage: + +``` +assert_eq!(5", stringify!($SelfT), ".checked_mul(1), Some(5)); +assert_eq!(5", stringify!($SelfT), ".checked_mul(2), None); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn checked_mul(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_mul(rhs); + if b {None} else {Some(a)} } } - /// Saturating integer subtraction. Computes `self - rhs`, saturating - /// at the numeric bounds instead of overflowing. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100u8.saturating_sub(27), 73); - /// assert_eq!(13u8.saturating_sub(127), 0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn saturating_sub(self, rhs: Self) -> Self { - match self.checked_sub(rhs) { - Some(x) => x, - None => Self::min_value(), + doc_comment! { + concat!("Checked integer division. Computes `self / rhs`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64)); +assert_eq!(1", stringify!($SelfT), ".checked_div(0), None); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn checked_div(self, rhs: Self) -> Option { + match rhs { + 0 => None, + rhs => Some(unsafe { intrinsics::unchecked_div(self, rhs) }), + } } } - /// Saturating integer multiplication. Computes `self * rhs`, - /// saturating at the numeric bounds instead of overflowing. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::u32; - /// - /// assert_eq!(100u32.saturating_mul(127), 12700); - /// assert_eq!((1u32 << 23).saturating_mul(1 << 23), u32::MAX); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[inline] - pub fn saturating_mul(self, rhs: Self) -> Self { - self.checked_mul(rhs).unwrap_or(Self::max_value()) + doc_comment! { + concat!("Checked integer remainder. Computes `self % rhs`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None); +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[inline] + pub fn checked_rem(self, rhs: Self) -> Option { + if rhs == 0 { + None + } else { + Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) + } + } } - /// Wrapping (modular) addition. Computes `self + rhs`, - /// wrapping around at the boundary of the type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(200u8.wrapping_add(55), 255); - /// assert_eq!(200u8.wrapping_add(155), 99); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn wrapping_add(self, rhs: Self) -> Self { - unsafe { - intrinsics::overflowing_add(self, rhs) + doc_comment! { + concat!("Checked negation. Computes `-self`, returning `None` unless `self == +0`. + +Note that negating any positive integer will overflow. + +# Examples + +Basic usage: + +``` +assert_eq!(0", stringify!($SelfT), ".checked_neg(), Some(0)); +assert_eq!(1", stringify!($SelfT), ".checked_neg(), None); +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[inline] + pub fn checked_neg(self) -> Option { + let (a, b) = self.overflowing_neg(); + if b {None} else {Some(a)} } } - /// Wrapping (modular) subtraction. Computes `self - rhs`, - /// wrapping around at the boundary of the type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100u8.wrapping_sub(100), 0); - /// assert_eq!(100u8.wrapping_sub(155), 201); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn wrapping_sub(self, rhs: Self) -> Self { - unsafe { - intrinsics::overflowing_sub(self, rhs) + doc_comment! { + concat!("Checked shift left. Computes `self << rhs`, returning `None` +if `rhs` is larger than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +assert_eq!(0x10", stringify!($SelfT), ".checked_shl(4), Some(0x100)); +assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None); +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[inline] + pub fn checked_shl(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shl(rhs); + if b {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked shift right. Computes `self >> rhs`, returning `None` +if `rhs` is larger than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); +assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None); +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[inline] + pub fn checked_shr(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shr(rhs); + if b {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Saturating integer addition. Computes `self + rhs`, saturating at +the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); +assert_eq!(200", stringify!($SelfT), ".saturating_add(127), 255); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn saturating_add(self, rhs: Self) -> Self { + match self.checked_add(rhs) { + Some(x) => x, + None => Self::max_value(), + } + } + } + + doc_comment! { + concat!("Saturating integer subtraction. Computes `self - rhs`, saturating +at the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73); +assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn saturating_sub(self, rhs: Self) -> Self { + match self.checked_sub(rhs) { + Some(x) => x, + None => Self::min_value(), + } + } + } + + doc_comment! { + concat!("Saturating integer multiplication. Computes `self * rhs`, +saturating at the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(100", stringify!($SelfT), ".saturating_mul(127), 12700); +assert_eq!((1", stringify!($SelfT), " << 23).saturating_mul(1 << 23), ", stringify!($SelfT), "::MAX); +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[inline] + pub fn saturating_mul(self, rhs: Self) -> Self { + self.checked_mul(rhs).unwrap_or(Self::max_value()) + } + } + + doc_comment! { + concat!("Wrapping (modular) addition. Computes `self + rhs`, +wrapping around at the boundary of the type. + +# Examples + +Basic usage: + +``` +assert_eq!(200", stringify!($SelfT), ".wrapping_add(55), 255); +assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::max_value()), 199); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn wrapping_add(self, rhs: Self) -> Self { + unsafe { + intrinsics::overflowing_add(self, rhs) + } + } + } + + doc_comment! { + concat!("Wrapping (modular) subtraction. Computes `self - rhs`, +wrapping around at the boundary of the type. + +# Examples + +Basic usage: + +``` +assert_eq!(100u8.wrapping_sub(100), 0); +assert_eq!(100u8.wrapping_sub(", stringify!($SelfT), "::max_value()), 101); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn wrapping_sub(self, rhs: Self) -> Self { + unsafe { + intrinsics::overflowing_sub(self, rhs) + } } } @@ -1898,175 +1945,190 @@ macro_rules! uint_impl { } } - /// Wrapping (modular) division. Computes `self / rhs`. - /// Wrapped division on unsigned types is just normal division. - /// There's no way wrapping could ever happen. - /// This function exists, so that all operations - /// are accounted for in the wrapping operations. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100u8.wrapping_div(10), 10); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline] - pub fn wrapping_div(self, rhs: Self) -> Self { - self / rhs + doc_comment! { + concat!("Wrapping (modular) division. Computes `self / rhs`. +Wrapped division on unsigned types is just normal division. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10); +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline] + pub fn wrapping_div(self, rhs: Self) -> Self { + self / rhs + } } - /// Wrapping (modular) remainder. Computes `self % rhs`. - /// Wrapped remainder calculation on unsigned types is - /// just the regular remainder calculation. - /// There's no way wrapping could ever happen. - /// This function exists, so that all operations - /// are accounted for in the wrapping operations. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100u8.wrapping_rem(10), 0); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline] - pub fn wrapping_rem(self, rhs: Self) -> Self { - self % rhs + doc_comment! { + concat!("Wrapping (modular) remainder. Computes `self % rhs`. +Wrapped remainder calculation on unsigned types is +just the regular remainder calculation. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0); +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline] + pub fn wrapping_rem(self, rhs: Self) -> Self { + self % rhs + } } - /// Wrapping (modular) negation. Computes `-self`, - /// wrapping around at the boundary of the type. - /// - /// Since unsigned types do not have negative equivalents - /// all applications of this function will wrap (except for `-0`). - /// For values smaller than the corresponding signed type's maximum - /// the result is the same as casting the corresponding signed value. - /// Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where - /// `MAX` is the corresponding signed type's maximum. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100u8.wrapping_neg(), 156); - /// assert_eq!(0u8.wrapping_neg(), 0); - /// assert_eq!(180u8.wrapping_neg(), 76); - /// assert_eq!(180u8.wrapping_neg(), (127 + 1) - (180u8 - (127 + 1))); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline] - pub fn wrapping_neg(self) -> Self { - self.overflowing_neg().0 + doc_comment! { + concat!("Wrapping (modular) negation. Computes `-self`, +wrapping around at the boundary of the type. + +Since unsigned types do not have negative equivalents +all applications of this function will wrap (except for `-0`). +For values smaller than the corresponding signed type's maximum +the result is the same as casting the corresponding signed value. +Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where +`MAX` is the corresponding signed type's maximum. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), ", stringify!($SelfT), "::max_value() - 100 + 1); +assert_eq!(0", stringify!($SelfT), ".wrapping_neg(), 0); +assert_eq!(180", stringify!($SelfT), ".wrapping_neg(), ", stringify!($SelfT), "::max_value() - 180 + 1); +assert_eq!(180", stringify!($SelfT), ".wrapping_neg(), (", stringify!($SelfT), "::max_value() / 2", +"+ 1) - (180", stringify!($SelfT), " - (", stringify!($SelfT), "::max_value() / 2 + 1))); +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline] + pub fn wrapping_neg(self) -> Self { + self.overflowing_neg().0 + } } - /// Panic-free bitwise shift-left; yields `self << mask(rhs)`, - /// where `mask` removes any high-order bits of `rhs` that - /// would cause the shift to exceed the bitwidth of the type. - /// - /// Note that this is *not* the same as a rotate-left; the - /// RHS of a wrapping shift-left is restricted to the range - /// of the type, rather than the bits shifted out of the LHS - /// being returned to the other end. The primitive integer - /// types all implement a `rotate_left` function, which may - /// be what you want instead. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(1u8.wrapping_shl(7), 128); - /// assert_eq!(1u8.wrapping_shl(8), 1); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline] - pub fn wrapping_shl(self, rhs: u32) -> Self { - unsafe { - intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) + doc_comment! { + concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, +where `mask` removes any high-order bits of `rhs` that +would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-left; the +RHS of a wrapping shift-left is restricted to the range +of the type, rather than the bits shifted out of the LHS +being returned to the other end. The primitive integer +types all implement a `rotate_left` function, which may +be what you want instead. + +# Examples + +Basic usage: + +``` +assert_eq!(1", stringify!($SelfT), ".wrapping_shl(7), 128); +assert_eq!(1", stringify!($SelfT), ".wrapping_shl(", stringify!($BITS), "), 1); +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline] + pub fn wrapping_shl(self, rhs: u32) -> Self { + unsafe { + intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) + } } } - /// Panic-free bitwise shift-right; yields `self >> mask(rhs)`, - /// where `mask` removes any high-order bits of `rhs` that - /// would cause the shift to exceed the bitwidth of the type. - /// - /// Note that this is *not* the same as a rotate-right; the - /// RHS of a wrapping shift-right is restricted to the range - /// of the type, rather than the bits shifted out of the LHS - /// being returned to the other end. The primitive integer - /// types all implement a `rotate_right` function, which may - /// be what you want instead. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(128u8.wrapping_shr(7), 1); - /// assert_eq!(128u8.wrapping_shr(8), 128); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline] - pub fn wrapping_shr(self, rhs: u32) -> Self { - unsafe { - intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) + doc_comment! { + concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, +where `mask` removes any high-order bits of `rhs` that +would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-right; the +RHS of a wrapping shift-right is restricted to the range +of the type, rather than the bits shifted out of the LHS +being returned to the other end. The primitive integer +types all implement a `rotate_right` function, which may +be what you want instead. + +# Examples + +Basic usage: + +``` +assert_eq!(128", stringify!($SelfT), ".wrapping_shr(7), 1); +assert_eq!(128", stringify!($SelfT), ".wrapping_shr(", stringify!($BITS), "), 128); +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline] + pub fn wrapping_shr(self, rhs: u32) -> Self { + unsafe { + intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) + } } } - /// Calculates `self` + `rhs` - /// - /// Returns a tuple of the addition along with a boolean indicating - /// whether an arithmetic overflow would occur. If an overflow would - /// have occurred then the wrapped value is returned. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// use std::u32; - /// - /// assert_eq!(5u32.overflowing_add(2), (7, false)); - /// assert_eq!(u32::MAX.overflowing_add(1), (0, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_add(self, rhs: Self) -> (Self, bool) { - let (a, b) = unsafe { - intrinsics::add_with_overflow(self as $ActualT, - rhs as $ActualT) - }; - (a as Self, b) + doc_comment! { + concat!("Calculates `self` + `rhs` + +Returns a tuple of the addition along with a boolean indicating +whether an arithmetic overflow would occur. If an overflow would +have occurred then the wrapped value is returned. + +# Examples + +Basic usage + +``` +use std::u32; + +assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); +assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_add(self, rhs: Self) -> (Self, bool) { + let (a, b) = unsafe { + intrinsics::add_with_overflow(self as $ActualT, + rhs as $ActualT) + }; + (a as Self, b) + } } - /// Calculates `self` - `rhs` - /// - /// Returns a tuple of the subtraction along with a boolean indicating - /// whether an arithmetic overflow would occur. If an overflow would - /// have occurred then the wrapped value is returned. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// use std::u32; - /// - /// assert_eq!(5u32.overflowing_sub(2), (3, false)); - /// assert_eq!(0u32.overflowing_sub(1), (u32::MAX, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) { - let (a, b) = unsafe { - intrinsics::sub_with_overflow(self as $ActualT, - rhs as $ActualT) - }; - (a as Self, b) + doc_comment! { + concat!("Calculates `self` - `rhs` + +Returns a tuple of the subtraction along with a boolean indicating +whether an arithmetic overflow would occur. If an overflow would +have occurred then the wrapped value is returned. + +# Examples + +Basic usage + +``` +use std::u32; + +assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); +assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + let (a, b) = unsafe { + intrinsics::sub_with_overflow(self as $ActualT, + rhs as $ActualT) + }; + (a as Self, b) + } } /// Calculates the multiplication of `self` and `rhs`. @@ -2093,129 +2155,140 @@ macro_rules! uint_impl { (a as Self, b) } - /// Calculates the divisor when `self` is divided by `rhs`. - /// - /// Returns a tuple of the divisor along with a boolean indicating - /// whether an arithmetic overflow would occur. Note that for unsigned - /// integers overflow never occurs, so the second value is always - /// `false`. - /// - /// # Panics - /// - /// This function will panic if `rhs` is 0. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// assert_eq!(5u32.overflowing_div(2), (2, false)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_div(self, rhs: Self) -> (Self, bool) { - (self / rhs, false) + doc_comment! { + concat!("Calculates the divisor when `self` is divided by `rhs`. + +Returns a tuple of the divisor along with a boolean indicating +whether an arithmetic overflow would occur. Note that for unsigned +integers overflow never occurs, so the second value is always +`false`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_div(self, rhs: Self) -> (Self, bool) { + (self / rhs, false) + } } - /// Calculates the remainder when `self` is divided by `rhs`. - /// - /// Returns a tuple of the remainder after dividing along with a boolean - /// indicating whether an arithmetic overflow would occur. Note that for - /// unsigned integers overflow never occurs, so the second value is - /// always `false`. - /// - /// # Panics - /// - /// This function will panic if `rhs` is 0. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// assert_eq!(5u32.overflowing_rem(2), (1, false)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_rem(self, rhs: Self) -> (Self, bool) { - (self % rhs, false) + doc_comment! { + concat!("Calculates the remainder when `self` is divided by `rhs`. + +Returns a tuple of the remainder after dividing along with a boolean +indicating whether an arithmetic overflow would occur. Note that for +unsigned integers overflow never occurs, so the second value is +always `false`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_rem(self, rhs: Self) -> (Self, bool) { + (self % rhs, false) + } } - /// Negates self in an overflowing fashion. - /// - /// Returns `!self + 1` using wrapping operations to return the value - /// that represents the negation of this unsigned value. Note that for - /// positive unsigned values overflow always occurs, but negating 0 does - /// not overflow. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// assert_eq!(0u32.overflowing_neg(), (0, false)); - /// assert_eq!(2u32.overflowing_neg(), (-2i32 as u32, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_neg(self) -> (Self, bool) { - ((!self).wrapping_add(1), self != 0) + doc_comment! { + concat!("Negates self in an overflowing fashion. + +Returns `!self + 1` using wrapping operations to return the value +that represents the negation of this unsigned value. Note that for +positive unsigned values overflow always occurs, but negating 0 does +not overflow. + +# Examples + +Basic usage + +``` +assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false)); +assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT), ", true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_neg(self) -> (Self, bool) { + ((!self).wrapping_add(1), self != 0) + } } - /// Shifts self left by `rhs` bits. - /// - /// Returns a tuple of the shifted version of self along with a boolean - /// indicating whether the shift value was larger than or equal to the - /// number of bits. If the shift value is too large, then value is - /// masked (N-1) where N is the number of bits, and this value is then - /// used to perform the shift. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// assert_eq!(0x10u32.overflowing_shl(4), (0x100, false)); - /// assert_eq!(0x10u32.overflowing_shl(36), (0x100, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) + doc_comment! { + concat!("Shifts self left by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean +indicating whether the shift value was larger than or equal to the +number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then +used to perform the shift. + +# Examples + +Basic usage + +``` +assert_eq!(0x10", stringify!($SelfT), ".overflowing_shl(4), (0x100, false)); +assert_eq!(0x10", stringify!($SelfT), ".overflowing_shl(132), (0x100, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) + } } - /// Shifts self right by `rhs` bits. - /// - /// Returns a tuple of the shifted version of self along with a boolean - /// indicating whether the shift value was larger than or equal to the - /// number of bits. If the shift value is too large, then value is - /// masked (N-1) where N is the number of bits, and this value is then - /// used to perform the shift. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// assert_eq!(0x10u32.overflowing_shr(4), (0x1, false)); - /// assert_eq!(0x10u32.overflowing_shr(36), (0x1, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) + doc_comment! { + concat!("Shifts self right by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean +indicating whether the shift value was larger than or equal to the +number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then +used to perform the shift. + +# Examples + +Basic usage + +``` +assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); +assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) + } } - /// Raises self to the power of `exp`, using exponentiation by squaring. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(2u32.pow(4), 16); - /// ``` + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +# Examples + +Basic usage: + +``` +assert_eq!(2", stringify!($SelfT), ".pow(4), 16); +```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] #[rustc_inherit_overflow_checks] @@ -2240,21 +2313,24 @@ macro_rules! uint_impl { acc } + } - /// Returns `true` if and only if `self == 2^k` for some `k`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!(16u8.is_power_of_two()); - /// assert!(!10u8.is_power_of_two()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_power_of_two(self) -> bool { - (self.wrapping_sub(1)) & self == 0 && !(self == 0) + doc_comment! { + concat!("Returns `true` if and only if `self == 2^k` for some `k`. + +# Examples + +Basic usage: + +``` +assert!(16", stringify!($SelfT), ".is_power_of_two()); +assert!(!10", stringify!($SelfT), ".is_power_of_two()); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_power_of_two(self) -> bool { + (self.wrapping_sub(1)) & self == 0 && !(self == 0) + } } // Returns one less than next power of two. @@ -2279,50 +2355,54 @@ macro_rules! uint_impl { <$SelfT>::max_value() >> z } - /// Returns the smallest power of two greater than or equal to `self`. - /// - /// When return value overflows (i.e. `self > (1 << (N-1))` for type - /// `uN`), it panics in debug mode and return value is wrapped to 0 in - /// release mode (the only situation in which method can return 0). - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(2u8.next_power_of_two(), 2); - /// assert_eq!(3u8.next_power_of_two(), 4); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn next_power_of_two(self) -> Self { - // Call the trait to get overflow checks - ops::Add::add(self.one_less_than_next_power_of_two(), 1) + doc_comment! { + concat!("Returns the smallest power of two greater than or equal to `self`. + +When return value overflows (i.e. `self > (1 << (N-1))` for type +`uN`), it panics in debug mode and return value is wrapped to 0 in +release mode (the only situation in which method can return 0). + +# Examples + +Basic usage: + +``` +assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2); +assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn next_power_of_two(self) -> Self { + // Call the trait to get overflow checks + ops::Add::add(self.one_less_than_next_power_of_two(), 1) + } } - /// Returns the smallest power of two greater than or equal to `n`. If - /// the next power of two is greater than the type's maximum value, - /// `None` is returned, otherwise the power of two is wrapped in `Some`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(2u8.checked_next_power_of_two(), Some(2)); - /// assert_eq!(3u8.checked_next_power_of_two(), Some(4)); - /// assert_eq!(200u8.checked_next_power_of_two(), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn checked_next_power_of_two(self) -> Option { - self.one_less_than_next_power_of_two().checked_add(1) + doc_comment! { + concat!("Returns the smallest power of two greater than or equal to `n`. If +the next power of two is greater than the type's maximum value, +`None` is returned, otherwise the power of two is wrapped in `Some`. + +# Examples + +Basic usage: + +``` +assert_eq!(2", stringify!($SelfT), ".checked_next_power_of_two(), Some(2)); +assert_eq!(3", stringify!($SelfT), ".checked_next_power_of_two(), Some(4)); +assert_eq!(", stringify!($SelfT), "::max_value().checked_next_power_of_two(), None); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + pub fn checked_next_power_of_two(self) -> Option { + self.one_less_than_next_power_of_two().checked_add(1) + } } } } #[lang = "u8"] impl u8 { - uint_impl! { u8, u8, 8 } + uint_impl! { u8, u8, 8, 255 } /// Checks if the value is within the ASCII range. @@ -2868,39 +2948,39 @@ impl u8 { #[lang = "u16"] impl u16 { - uint_impl! { u16, u16, 16 } + uint_impl! { u16, u16, 16, 65535 } } #[lang = "u32"] impl u32 { - uint_impl! { u32, u32, 32 } + uint_impl! { u32, u32, 32, 4294967295 } } #[lang = "u64"] impl u64 { - uint_impl! { u64, u64, 64 } + uint_impl! { u64, u64, 64, 18446744073709551615 } } #[lang = "u128"] impl u128 { - uint_impl! { u128, u128, 128 } + uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455 } } #[cfg(target_pointer_width = "16")] #[lang = "usize"] impl usize { - uint_impl! { usize, u16, 16 } + uint_impl! { usize, u16, 16, 65536 } } #[cfg(target_pointer_width = "32")] #[lang = "usize"] impl usize { - uint_impl! { usize, u32, 32 } + uint_impl! { usize, u32, 32, 4294967295 } } #[cfg(target_pointer_width = "64")] #[lang = "usize"] impl usize { - uint_impl! { usize, u64, 64 } + uint_impl! { usize, u64, 64, 18446744073709551615 } } /// A classification of floating point numbers. -- cgit 1.4.1-3-g733a5 From 0f789aad2b3cfc0b0925b726295200267130e69d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 08:05:46 +0100 Subject: add core::iter::repeat_with --- src/libcore/iter/sources.rs | 104 ++++++++++++++++++++++++++++++++++++++++++++ src/libcore/tests/iter.rs | 44 +++++++++++++++++++ 2 files changed, 148 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index b05a893e661..980f3fc7443 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -57,6 +57,12 @@ unsafe impl TrustedLen for Repeat {} /// /// [`take`]: trait.Iterator.html#method.take /// +/// If the element type of the iterator you need does not implement `Clone`, +/// or if you do not want to keep the repeated element in memory, you can +/// instead use the [`repeat_with`] function. +/// +/// [`repeat_with`]: fn.repeat_with.html +/// /// # Examples /// /// Basic usage: @@ -99,6 +105,104 @@ pub fn repeat(elt: T) -> Repeat { Repeat{element: elt} } +/// An iterator that repeats elements of type `A` endlessly by +/// applying the provided closure `F: FnMut() -> A`. +/// +/// This `struct` is created by the [`repeat_with`] function. +/// See its documentation for more. +/// +/// [`repeat_with`]: fn.repeat_with.html +#[unstable(feature = "iterator_repeat_with", issue = "0")] +pub struct RepeatWith { + repeater: F +} + +#[unstable(feature = "iterator_repeat_with", issue = "0")] +impl A> Iterator for RepeatWith { + type Item = A; + + #[inline] + fn next(&mut self) -> Option { Some((self.repeater)()) } + + #[inline] + fn size_hint(&self) -> (usize, Option) { (usize::MAX, None) } +} + +#[unstable(feature = "iterator_repeat_with", issue = "0")] +impl A> DoubleEndedIterator for RepeatWith { + #[inline] + fn next_back(&mut self) -> Option { self.next() } +} + +#[unstable(feature = "fused", issue = "35602")] +impl A> FusedIterator for RepeatWith {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl A> TrustedLen for RepeatWith {} + +/// Creates a new that repeats elements of type `A` endlessly by +/// applying the provided closure, the repeater, `F: FnMut() -> A`. +/// +/// The `repeat_with()` function calls the repeater over and over and over and +/// over and over and 🔁. +/// +/// Infinite iterators like `repeat_with()` are often used with adapters like +/// [`take`], in order to make them finite. +/// +/// [`take`]: trait.Iterator.html#method.take +/// +/// If the element type of the iterator you need implements `Clone`, and +/// it is OK to keep the source element in memory, you should instead use +/// the [`repeat`] function. +/// +/// [`repeat`]: fn.repeat.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter; +/// +/// // let's assume we have some value of a type that is not `Clone` +/// // or which don't want to have in memory just yet because it is expensive: +/// #[derive(PartialEq, Debug)] +/// struct Expensive; +/// +/// // a particular value forever: +/// let mut things = iter::repeat_with(|| Expensive); +/// +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// assert_eq!(Some(Expensive), things.next()); +/// ``` +/// +/// Using mutation and going finite: +/// +/// ```rust +/// use std::iter; +/// +/// // From the zeroth to the third power of two: +/// let mut curr = 1; +/// let mut pow2 = iter::repeat_with(|| { let tmp = curr; curr *= 2; tmp }) +/// .take(4); +/// +/// assert_eq!(Some(1), pow2.next()); +/// assert_eq!(Some(2), pow2.next()); +/// assert_eq!(Some(4), pow2.next()); +/// assert_eq!(Some(8), pow2.next()); +/// +/// // ... and now we're done +/// assert_eq!(None, pow2.next()); +/// ``` +#[inline] +#[unstable(feature = "iterator_repeat_with", issue = "0")] +pub fn repeat_with A>(repeater: F) -> RepeatWith { + RepeatWith { repeater } +} + /// An iterator that yields nothing. /// /// This `struct` is created by the [`empty`] function. See its documentation for more. diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index b2a5243d5e6..ca5318d198e 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1549,6 +1549,50 @@ fn test_repeat_take_collect() { assert_eq!(v, vec![42, 42, 42]); } +#[test] +fn test_repeat_with() { + struct NotClone(usize); + let mut it = repeat_with(|| NotClone(42)); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(repeat_with(|| NotClone(42)).size_hint(), (usize::MAX, None)); +} + +#[test] +fn test_repeat_with_rev() { + let mut curr = 1; + let mut pow2 = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) + .rev().take(4); + assert_eq!(it.next(), Some(1)); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.next(), Some(4)); + assert_eq!(it.next(), Some(8)); + assert_eq!(it.next(), None); +} + +#[test] +fn test_repeat_with_take() { + let mut it = repeat_with(|| 42).take(3); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), None); + is_trusted_len(repeat_with(|| 42).take(3)); + assert_eq!(repeat_with(|| 42).take(3).size_hint(), (3, Some(3))); + assert_eq!(repeat_with(|| 42).take(0).size_hint(), (0, Some(0))); + assert_eq!(repeat_with(|| 42).take(usize::MAX).size_hint(), + (usize::MAX, Some(usize::MAX))); +} + +#[test] +fn test_repeat_take_collect() { + let mut curr = 1; + let v: Vec<_> = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) + .take(5).collect(); + assert_eq!(v, vec![1, 2, 4, 8, 16]); +} + #[test] fn test_fuse() { let mut it = 0..3; -- cgit 1.4.1-3-g733a5 From c4099ca4b11acb9949ef0da804a819b4ddfa24a2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 08:25:39 +0100 Subject: core::iter::repeat_with: general fixes --- src/libcore/iter/mod.rs | 2 ++ src/libcore/iter/sources.rs | 4 ++++ src/libcore/lib.rs | 1 + 3 files changed, 7 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 29b62c901f3..ac3fb5a57dd 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -333,6 +333,8 @@ pub use self::range::Step; #[stable(feature = "rust1", since = "1.0.0")] pub use self::sources::{Repeat, repeat}; +#[unstable(feature = "iterator_repeat_with", issue = "0")] +pub use self::sources::{RepeatWith, repeat_with}; #[stable(feature = "iter_empty", since = "1.2.0")] pub use self::sources::{Empty, empty}; #[stable(feature = "iter_once", since = "1.2.0")] diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 980f3fc7443..2cf90fd079e 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -162,6 +162,8 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Basic usage: /// /// ``` +/// #![feature("iterator_repeat_with")] +/// /// use std::iter; /// /// // let's assume we have some value of a type that is not `Clone` @@ -182,6 +184,8 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Using mutation and going finite: /// /// ```rust +/// #![feature("iterator_repeat_with")] +/// /// use std::iter; /// /// // From the zeroth to the third power of two: diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 59a296c2a76..447e144bf0f 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -92,6 +92,7 @@ #![feature(unwind_attributes)] #![feature(doc_spotlight)] #![feature(rustc_const_unstable)] +#![feature(iterator_repeat_with)] #[prelude_import] #[allow(unused)] -- cgit 1.4.1-3-g733a5 From 1af9ee1350cc69e7c1873d26637064824d07c2b8 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 08:35:12 +0100 Subject: core::iter::repeat_with: derive Copy, Clone, Debug --- src/libcore/iter/sources.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libcore') diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 2cf90fd079e..d77e8d4db04 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -112,6 +112,7 @@ pub fn repeat(elt: T) -> Repeat { /// See its documentation for more. /// /// [`repeat_with`]: fn.repeat_with.html +#[derive(Copy, Clone, Debug)] #[unstable(feature = "iterator_repeat_with", issue = "0")] pub struct RepeatWith { repeater: F -- cgit 1.4.1-3-g733a5 From f025eff21d1832fcd3941ae847fec2aaf23d3b0b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 09:13:47 +0100 Subject: core::iter::repeat_with: fix tests --- src/libcore/tests/iter.rs | 3 ++- src/libcore/tests/lib.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index ca5318d198e..f42970685f5 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1551,6 +1551,7 @@ fn test_repeat_take_collect() { #[test] fn test_repeat_with() { + #[derive(PartialEq, Debug)] struct NotClone(usize); let mut it = repeat_with(|| NotClone(42)); assert_eq!(it.next(), Some(NotClone(42))); @@ -1586,7 +1587,7 @@ fn test_repeat_with_take() { } #[test] -fn test_repeat_take_collect() { +fn test_repeat_with_take_collect() { let mut curr = 1; let v: Vec<_> = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) .take(5).collect(); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 9e90313bc0e..2b9fae88bf4 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -27,6 +27,7 @@ #![feature(iterator_try_fold)] #![feature(iter_rfind)] #![feature(iter_rfold)] +#![feature(iterator_repeat_with)] #![feature(nonzero)] #![feature(pattern)] #![feature(raw)] -- cgit 1.4.1-3-g733a5 From 55c669c4d9f7b245e2c237dc2b5d0390afe2620d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 09:15:13 +0100 Subject: core::iter::repeat_with: fix tests some more --- src/libcore/tests/iter.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index f42970685f5..4c33c8440a3 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1565,11 +1565,11 @@ fn test_repeat_with_rev() { let mut curr = 1; let mut pow2 = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) .rev().take(4); - assert_eq!(it.next(), Some(1)); - assert_eq!(it.next(), Some(2)); - assert_eq!(it.next(), Some(4)); - assert_eq!(it.next(), Some(8)); - assert_eq!(it.next(), None); + assert_eq!(pow2.next(), Some(1)); + assert_eq!(pow2.next(), Some(2)); + assert_eq!(pow2.next(), Some(4)); + assert_eq!(pow2.next(), Some(8)); + assert_eq!(pow2.next(), None); } #[test] -- cgit 1.4.1-3-g733a5 From efa332038c74931738c44f48622c2a99b5a36cf0 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 09:18:22 +0100 Subject: core::iter::repeat_with: fix doc tests --- src/libcore/iter/sources.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index d77e8d4db04..b364292f57e 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -163,7 +163,7 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Basic usage: /// /// ``` -/// #![feature("iterator_repeat_with")] +/// #![feature(iterator_repeat_with)] /// /// use std::iter; /// @@ -185,7 +185,7 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Using mutation and going finite: /// /// ```rust -/// #![feature("iterator_repeat_with")] +/// #![feature(iterator_repeat_with)] /// /// use std::iter; /// -- cgit 1.4.1-3-g733a5 From 0bb818cc0b2885b01ce670ce192aac1dbc6db16a Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Mon, 12 Feb 2018 01:39:01 -0800 Subject: Add Iterator::try_for_each The fallible version of for_each and the stateless version of try_fold. --- src/libcore/iter/iterator.rs | 48 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 296fb8733ba..a485e2c82ba 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1366,9 +1366,9 @@ pub trait Iterator { /// /// In particular, try to have this call `try_fold()` on the internal parts /// from which this iterator is composed. If multiple calls are needed, - /// the `?` operator be convenient for chaining the accumulator value along, - /// but beware any invariants that need to be upheld before those early - /// returns. This is a `&mut self` method, so iteration needs to be + /// the `?` operator may be convenient for chaining the accumulator value + /// along, but beware any invariants that need to be upheld before those + /// early returns. This is a `&mut self` method, so iteration needs to be /// resumable after hitting an error here. /// /// # Examples @@ -1414,6 +1414,42 @@ pub trait Iterator { Try::from_ok(accum) } + /// An iterator method that applies a fallible function to each item in the + /// iterator, stopping at the first error and returning that error. + /// + /// This can also be thought of as the fallible form of [`for_each()`] + /// or as the stateless version of [`try_fold()`]. + /// + /// [`for_each()`]: #method.for_each + /// [`try_fold()`]: #method.try_fold + /// + /// # Examples + /// + /// ``` + /// #![feature(iterator_try_fold)] + /// use std::fs::rename; + /// use std::io::{stdout, Write}; + /// use std::path::Path; + /// + /// let data = ["no_tea.txt", "stale_bread.json", "torrential_rain.png"]; + /// + /// let res = data.iter().try_for_each(|x| writeln!(stdout(), "{}", x)); + /// assert!(res.is_ok()); + /// + /// let mut it = data.iter().cloned(); + /// let res = it.try_for_each(|x| rename(x, Path::new(x).with_extension("old"))); + /// assert!(res.is_err()); + /// // It short-circuited, so the remaining items are still in the iterator: + /// assert_eq!(it.next(), Some("stale_bread.json")); + /// ``` + #[inline] + #[unstable(feature = "iterator_try_fold", issue = "45594")] + fn try_for_each(&mut self, mut f: F) -> R where + Self: Sized, F: FnMut(Self::Item) -> R, R: Try + { + self.try_fold((), move |(), x| f(x)) + } + /// An iterator method that applies a function, producing a single, final value. /// /// `fold()` takes two arguments: an initial value, and a closure with two @@ -1528,7 +1564,7 @@ pub trait Iterator { fn all(&mut self, mut f: F) -> bool where Self: Sized, F: FnMut(Self::Item) -> bool { - self.try_fold((), move |(), x| { + self.try_for_each(move |x| { if f(x) { LoopState::Continue(()) } else { LoopState::Break(()) } }) == LoopState::Continue(()) @@ -1577,7 +1613,7 @@ pub trait Iterator { Self: Sized, F: FnMut(Self::Item) -> bool { - self.try_fold((), move |(), x| { + self.try_for_each(move |x| { if f(x) { LoopState::Break(()) } else { LoopState::Continue(()) } }) == LoopState::Break(()) @@ -1631,7 +1667,7 @@ pub trait Iterator { Self: Sized, P: FnMut(&Self::Item) -> bool, { - self.try_fold((), move |(), x| { + self.try_for_each(move |x| { if predicate(&x) { LoopState::Break(x) } else { LoopState::Continue(()) } }).break_value() -- cgit 1.4.1-3-g733a5 From 146b81c2c61507acf3910db421677186b01054be Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 12 Feb 2018 08:07:10 -0500 Subject: Fix tidy errors --- src/libcore/num/mod.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index da46eeb44bf..5f85cbdef80 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1126,8 +1126,8 @@ assert_eq!(0x10i32.overflowing_shr(36), (0x1, true)); concat!("Computes the absolute value of `self`. Returns a tuple of the absolute version of self along with a boolean indicating whether an overflow -happened. If self is the minimum value (e.g. ", stringify!($SelfT), "::MIN for values of type -", stringify!($SelfT), "), then the minimum value will be returned again and true will be returned +happened. If self is the minimum value (e.g. ", stringify!($SelfT), "::MIN for values of type + ", stringify!($SelfT), "), then the minimum value will be returned again and true will be returned for an overflow happening. # Examples @@ -1307,7 +1307,8 @@ impl i64 { #[lang = "i128"] impl i128 { - int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, 170141183460469231731687303715884105727 } + int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, + 170141183460469231731687303715884105727 } } #[cfg(target_pointer_width = "16")] @@ -1875,7 +1876,8 @@ Basic usage: use std::", stringify!($SelfT), "; assert_eq!(100", stringify!($SelfT), ".saturating_mul(127), 12700); -assert_eq!((1", stringify!($SelfT), " << 23).saturating_mul(1 << 23), ", stringify!($SelfT), "::MAX); +assert_eq!((1", stringify!($SelfT), " << 23).saturating_mul(1 << 23), ", stringify!($SelfT), +"::MAX); ```"), #[stable(feature = "wrapping", since = "1.7.0")] #[inline] @@ -2004,9 +2006,11 @@ Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where Basic usage: ``` -assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), ", stringify!($SelfT), "::max_value() - 100 + 1); +assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), ", stringify!($SelfT), +"::max_value() - 100 + 1); assert_eq!(0", stringify!($SelfT), ".wrapping_neg(), 0); -assert_eq!(180", stringify!($SelfT), ".wrapping_neg(), ", stringify!($SelfT), "::max_value() - 180 + 1); +assert_eq!(180", stringify!($SelfT), ".wrapping_neg(), ", stringify!($SelfT), +"::max_value() - 180 + 1); assert_eq!(180", stringify!($SelfT), ".wrapping_neg(), (", stringify!($SelfT), "::max_value() / 2", "+ 1) - (180", stringify!($SelfT), " - (", stringify!($SelfT), "::max_value() / 2 + 1))); ```"), -- cgit 1.4.1-3-g733a5 From 9cee79a7ff09851109f621bd4510909f5740ae28 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 18:03:56 +0100 Subject: core::iter::repeat_with: document DoubleEndedIterator behavior --- src/libcore/iter/sources.rs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index b364292f57e..abf2befa9cd 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -158,6 +158,12 @@ unsafe impl A> TrustedLen for RepeatWith {} /// /// [`repeat`]: fn.repeat.html /// +/// An iterator produced by `repeat_with()` is a `DoubleEndedIterator`. +/// It is important to not that reversing `repeat_with(f)` will produce +/// the exact same sequence as the non-reversed iterator. In other words, +/// `repeat_with(f).rev().collect::>()` is equivalent to +/// `repeat_with(f).collect::>()`. +/// /// # Examples /// /// Basic usage: -- cgit 1.4.1-3-g733a5 From 91a4b9044d7f104516984d1076b04b99cef7a6b9 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 12 Feb 2018 21:47:59 +0100 Subject: core::iter::repeat_with: tracking issue is #48169 --- src/libcore/iter/mod.rs | 2 +- src/libcore/iter/sources.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index ac3fb5a57dd..d929d1d65a9 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -333,7 +333,7 @@ pub use self::range::Step; #[stable(feature = "rust1", since = "1.0.0")] pub use self::sources::{Repeat, repeat}; -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] pub use self::sources::{RepeatWith, repeat_with}; #[stable(feature = "iter_empty", since = "1.2.0")] pub use self::sources::{Empty, empty}; diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index abf2befa9cd..eb8a22709b0 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -113,12 +113,12 @@ pub fn repeat(elt: T) -> Repeat { /// /// [`repeat_with`]: fn.repeat_with.html #[derive(Copy, Clone, Debug)] -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] pub struct RepeatWith { repeater: F } -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] impl A> Iterator for RepeatWith { type Item = A; @@ -129,7 +129,7 @@ impl A> Iterator for RepeatWith { fn size_hint(&self) -> (usize, Option) { (usize::MAX, None) } } -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] impl A> DoubleEndedIterator for RepeatWith { #[inline] fn next_back(&mut self) -> Option { self.next() } @@ -209,7 +209,7 @@ unsafe impl A> TrustedLen for RepeatWith {} /// assert_eq!(None, pow2.next()); /// ``` #[inline] -#[unstable(feature = "iterator_repeat_with", issue = "0")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] pub fn repeat_with A>(repeater: F) -> RepeatWith { RepeatWith { repeater } } -- cgit 1.4.1-3-g733a5 From db13296b6fd6b68ab06055bdcb9a22078b11de6a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 13 Feb 2018 06:20:17 +0100 Subject: core::iter::repeat_with: fix missing word, see @Pazzaz's review --- src/libcore/iter/sources.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index eb8a22709b0..3e9d799c089 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -141,7 +141,7 @@ impl A> FusedIterator for RepeatWith {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl A> TrustedLen for RepeatWith {} -/// Creates a new that repeats elements of type `A` endlessly by +/// Creates a new iterator that repeats elements of type `A` endlessly by /// applying the provided closure, the repeater, `F: FnMut() -> A`. /// /// The `repeat_with()` function calls the repeater over and over and over and -- cgit 1.4.1-3-g733a5 From 9a30673d2b5a647af1e54bf852ee7503f6151f9f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 Feb 2018 21:27:40 +0100 Subject: Add missing feature --- src/libcore/num/mod.rs | 488 +++++++++++++++++++++++++++---------------------- 1 file changed, 270 insertions(+), 218 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 5f85cbdef80..dcadf830f1e 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -105,7 +105,8 @@ macro_rules! doc_comment { // `Int` + `SignedInt` implemented for signed integers macro_rules! int_impl { - ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr) => { + ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr, + $EndFeature:expr) => { doc_comment! { concat!("Returns the smallest value that can be represented by this integer type. @@ -114,7 +115,8 @@ macro_rules! int_impl { Basic usage: ``` -assert_eq!(", stringify!($SelfT), "::min_value(), ", stringify!($Min), "); +", $Feature, "assert_eq!(", stringify!($SelfT), "::min_value(), ", stringify!($Min), ");", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -131,7 +133,8 @@ assert_eq!(", stringify!($SelfT), "::min_value(), ", stringify!($Min), "); Basic usage: ``` -assert_eq!(", stringify!($SelfT), "::max_value(), ", stringify!($Max), "); +", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value(), ", stringify!($Max), ");", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -160,7 +163,8 @@ This function panics if `radix` is not in the range from 2 to 36. Basic usage: ``` -assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10)); +", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] pub fn from_str_radix(src: &str, radix: u32) -> Result { @@ -176,9 +180,10 @@ assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10)); Basic usage: ``` -let n = -0b1000_0000", stringify!($SelfT), "; +", $Feature, "let n = 0b100_0000", stringify!($SelfT), "; -assert_eq!(n.count_ones(), 1); +assert_eq!(n.count_ones(), 1);", +$EndFeature, " ``` "), #[stable(feature = "rust1", since = "1.0.0")] @@ -194,9 +199,7 @@ assert_eq!(n.count_ones(), 1); Basic usage: ``` -let n = -0b1000_0000", stringify!($SelfT), "; - -assert_eq!(n.count_zeros(), 7); +", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 1);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -213,9 +216,10 @@ assert_eq!(n.count_zeros(), 7); Basic usage: ``` -let n = -1", stringify!($SelfT), "; +", $Feature, "let n = -1", stringify!($SelfT), "; -assert_eq!(n.leading_zeros(), 0); +assert_eq!(n.leading_zeros(), 0);", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -232,9 +236,10 @@ assert_eq!(n.leading_zeros(), 0); Basic usage: ``` -let n = -4", stringify!($SelfT), "; +", $Feature, "let n = -4", stringify!($SelfT), "; -assert_eq!(n.trailing_zeros(), 2); +assert_eq!(n.trailing_zeros(), 2);", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -317,13 +322,14 @@ On big endian this is a no-op. On little endian the bytes are swapped. Basic usage: ``` -let n = 0xA1", stringify!($SelfT), "; +", $Feature, "let n = 0x1A", stringify!($SelfT), "; if cfg!(target_endian = \"big\") { assert_eq!(", stringify!($SelfT), "::from_be(n), n) } else { assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) -} +}", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -342,13 +348,14 @@ On little endian this is a no-op. On big endian the bytes are swapped. Basic usage: ``` -let n = 0xA1", stringify!($SelfT), "; +", $Feature, "let n = 0x1A", stringify!($SelfT), "; if cfg!(target_endian = \"little\") { assert_eq!(", stringify!($SelfT), "::from_le(n), n) } else { assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes()) -} +}", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -367,13 +374,14 @@ On big endian this is a no-op. On little endian the bytes are swapped. Basic usage: ``` -let n = 0xA1", stringify!($SelfT), "; +", $Feature, "let n = 0x1A", stringify!($SelfT), "; if cfg!(target_endian = \"big\") { assert_eq!(n.to_be(), n) } else { assert_eq!(n.to_be(), n.swap_bytes()) -} +}", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -392,13 +400,14 @@ On little endian this is a no-op. On big endian the bytes are swapped. Basic usage: ``` -let n = 0xA1", stringify!($SelfT), "; +", $Feature, "let n = 0x1A", stringify!($SelfT), "; if cfg!(target_endian = \"little\") { assert_eq!(n.to_le(), n) } else { assert_eq!(n.to_le(), n.swap_bytes()) -} +}", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -416,9 +425,10 @@ if overflow occurred. Basic usage: ``` -assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(1), Some(", -stringify!($SelfT), "::max_value() - 1)); -assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3), None); +", $Feature, "assert_eq!((", stringify!($SelfT), +"::max_value() - 2).checked_add(1), Some(", stringify!($SelfT), "::max_value() - 1)); +assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3), None);", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -437,9 +447,10 @@ overflow occurred. Basic usage: ``` -assert_eq!((", stringify!($SelfT), "::min_value() + 2).checked_sub(1), Some(", -stringify!($SelfT), "::min_value() + 1)); -assert_eq!((", stringify!($SelfT), "::min_value() + 2).checked_sub(3), None); +", $Feature, "assert_eq!((", stringify!($SelfT), +"::min_value() + 2).checked_sub(1), Some(", stringify!($SelfT), "::min_value() + 1)); +assert_eq!((", stringify!($SelfT), "::min_value() + 2).checked_sub(3), None);", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -458,9 +469,10 @@ overflow occurred. Basic usage: ``` -assert_eq!(", stringify!($SelfT), "::max_value().checked_mul(1), Some(", stringify!($SelfT), -"::max_value())); -assert_eq!(", stringify!($SelfT), "::max_value().checked_mul(2), None); +", $Feature, "assert_eq!(", stringify!($SelfT), +"::max_value().checked_mul(1), Some(", stringify!($SelfT), "::max_value())); +assert_eq!(", stringify!($SelfT), "::max_value().checked_mul(2), None);", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -479,10 +491,11 @@ or the division results in overflow. Basic usage: ``` -assert_eq!((", stringify!($SelfT), "::min_value() + 1).checked_div(-1), Some(", -stringify!($Max), ")); +", $Feature, "assert_eq!((", stringify!($SelfT), +"::min_value() + 1).checked_div(-1), Some(", stringify!($Max), ")); assert_eq!(", stringify!($SelfT), "::min_value().checked_div(-1), None); -assert_eq!((1", stringify!($SelfT), ").checked_div(0), None); +assert_eq!((1", stringify!($SelfT), ").checked_div(0), None);", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -504,11 +517,12 @@ assert_eq!((1", stringify!($SelfT), ").checked_div(0), None); Basic usage: ``` -use std::", stringify!($SelfT), "; +", $Feature, "use std::", stringify!($SelfT), "; assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None); -assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None); +assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None);", +$EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] #[inline] @@ -529,10 +543,11 @@ assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None); Basic usage: ``` -use std::", stringify!($SelfT), "; +", $Feature, "use std::", stringify!($SelfT), "; assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5)); -assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None); +assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None);", +$EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] #[inline] @@ -551,8 +566,9 @@ than or equal to the number of bits in `self`. Basic usage: ``` -assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); -assert_eq!(0x1", stringify!($SelfT), ".checked_shl(70), None); +", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); +assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);", +$EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] #[inline] @@ -571,8 +587,9 @@ larger than or equal to the number of bits in `self`. Basic usage: ``` -assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); -assert_eq!(0x10", stringify!($SelfT), ".checked_shr(70), None); +", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); +assert_eq!(0x10", stringify!($SelfT), ".checked_shr(128), None);", +$EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] #[inline] @@ -591,10 +608,11 @@ assert_eq!(0x10", stringify!($SelfT), ".checked_shr(70), None); Basic usage: ``` -use std::", stringify!($SelfT), "; +", $Feature, "use std::", stringify!($SelfT), "; assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5)); -assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None); +assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None);", +$EndFeature, " ```"), #[stable(feature = "no_panic_abs", since = "1.13.0")] #[inline] @@ -616,9 +634,10 @@ bounds instead of overflowing. Basic usage: ``` -assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); assert_eq!(", stringify!($SelfT), "::max_value().saturating_add(100), ", stringify!($SelfT), -"::max_value()); +"::max_value());", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -640,9 +659,10 @@ numeric bounds instead of overflowing. Basic usage: ``` -assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27); +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27); assert_eq!(", stringify!($SelfT), "::min_value().saturating_sub(100), ", stringify!($SelfT), -"::min_value()); +"::min_value());", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -664,11 +684,12 @@ numeric bounds instead of overflowing. Basic usage: ``` -use std::", stringify!($SelfT), "; +", $Feature, "use std::", stringify!($SelfT), "; assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(11 << 23), ", stringify!($SelfT), "::MAX); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(1 << 23), ", stringify!($SelfT), "::MIN); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(10), ", stringify!($SelfT), "::MAX); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(10), ", stringify!($SelfT), "::MIN);", +$EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] #[inline] @@ -692,9 +713,10 @@ boundary of the type. Basic usage: ``` -assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127); +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127); assert_eq!(", stringify!($SelfT), "::max_value().wrapping_add(2), ", stringify!($SelfT), -"::min_value() + 1); +"::min_value() + 1);", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -714,9 +736,10 @@ boundary of the type. Basic usage: ``` -assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127); -assert_eq!((-2i8).wrapping_sub(", stringify!($SelfT), "::max_value()), ", -stringify!($SelfT), "::max_value()); +", $Feature, "assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127); +assert_eq!((-2", stringify!($SelfT), ").wrapping_sub(", stringify!($SelfT), "::max_value()), ", +stringify!($SelfT), "::max_value());", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -736,8 +759,9 @@ the boundary of the type. Basic usage: ``` -assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120); -assert_eq!(11i8.wrapping_mul(12), -124); +", $Feature, "assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120); +assert_eq!(11i8.wrapping_mul(12), -124);", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -765,8 +789,9 @@ This function will panic if `rhs` is 0. Basic usage: ``` -assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10); -assert_eq!((-128i8).wrapping_div(-1), -128); +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10); +assert_eq!((-128i8).wrapping_div(-1), -128);", +$EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline] @@ -792,8 +817,9 @@ This function will panic if `rhs` is 0. Basic usage: ``` -assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0); -assert_eq!((-128i8).wrapping_rem(-1), 0); +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0); +assert_eq!((-128i8).wrapping_rem(-1), 0);", +$EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline] @@ -815,9 +841,10 @@ in the type. In such a case, this function returns `MIN` itself. Basic usage: ``` -assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100); +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100); assert_eq!(", stringify!($SelfT), "::min_value().wrapping_neg(), ", stringify!($SelfT), -"::min_value()); +"::min_value());", +$EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline] @@ -840,8 +867,9 @@ instead. Basic usage: ``` -assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128); -assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(64), -1); +", $Feature, "assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128); +assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);", +$EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline] @@ -866,8 +894,9 @@ instead. Basic usage: ``` -assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1); -assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(64), -128); +", $Feature, "assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1); +assert_eq!((-128i16).wrapping_shr(64), -128);", +$EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline] @@ -891,11 +920,12 @@ such a case, this function returns `MIN` itself. Basic usage: ``` -assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100); +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100); assert_eq!((-100", stringify!($SelfT), ").wrapping_abs(), 100); assert_eq!(", stringify!($SelfT), "::min_value().wrapping_abs(), ", stringify!($SelfT), "::min_value()); -assert_eq!((-128i8).wrapping_abs() as u8, 128); +assert_eq!((-128i8).wrapping_abs() as u8, 128);", +$EndFeature, " ```"), #[stable(feature = "no_panic_abs", since = "1.13.0")] #[inline] @@ -919,10 +949,11 @@ occur. If an overflow would have occurred then the wrapped value is returned. Basic usage: ``` -use std::", stringify!($SelfT), "; +", $Feature, "use std::", stringify!($SelfT), "; assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); -assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT), "::MIN, true)); +assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT), +"::MIN, true));", $EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] @@ -946,10 +977,11 @@ would occur. If an overflow would have occurred then the wrapped value is return Basic usage: ``` -use std::", stringify!($SelfT), "; +", $Feature, "use std::", stringify!($SelfT), "; assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT), "::MAX, true)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT), +"::MAX, true));", $EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] @@ -973,8 +1005,9 @@ would occur. If an overflow would have occurred then the wrapped value is return Basic usage: ``` -assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false)); -assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true)); +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false)); +assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));", +$EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] @@ -1002,11 +1035,12 @@ This function will panic if `rhs` is 0. Basic usage: ``` -use std::", stringify!($SelfT), "; +", $Feature, "use std::", stringify!($SelfT), "; assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false)); -assert_eq!(i", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT), -"::MIN, true)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT), +"::MIN, true));", +$EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] @@ -1034,10 +1068,11 @@ This function will panic if `rhs` is 0. Basic usage: ``` -use std::", stringify!($SelfT), "; +", $Feature, "use std::", stringify!($SelfT), "; assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true));", +$EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] @@ -1062,10 +1097,11 @@ minimum value will be returned again and `true` will be returned for an overflow Basic usage: ``` -use std::", stringify!($SelfT), "; +", $Feature, "use std::", stringify!($SelfT), "; assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT), "::MIN, true)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT), +"::MIN, true));", $EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] @@ -1090,8 +1126,9 @@ masked (N-1) where N is the number of bits, and this value is then used to perfo Basic usage: ``` -assert_eq!(0x10", stringify!($SelfT), ".overflowing_shl(4), (0x100, false)); -assert_eq!(0x10i32.overflowing_shl(36), (0x100, true)); +", $Feature, "assert_eq!(0x1", stringify!($SelfT),".overflowing_shl(4), (0x10, false)); +assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));", +$EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] @@ -1112,8 +1149,9 @@ masked (N-1) where N is the number of bits, and this value is then used to perfo Basic usage: ``` -assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); -assert_eq!(0x10i32.overflowing_shr(36), (0x1, true)); +", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); +assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));", +$EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] @@ -1135,10 +1173,11 @@ for an overflow happening. Basic usage: ``` -assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false)); +", $Feature, "assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false)); assert_eq!((-10", stringify!($SelfT), ").overflowing_abs(), (10, false)); -assert_eq!((", stringify!($SelfT), "::min_value()).overflowing_abs(), (-", stringify!($SelfT), -"::min_value(), true)); +assert_eq!((", stringify!($SelfT), "::min_value()).overflowing_abs(), (", stringify!($SelfT), +"::min_value(), true));", +$EndFeature, " ```"), #[stable(feature = "no_panic_abs", since = "1.13.0")] #[inline] @@ -1159,9 +1198,10 @@ assert_eq!((", stringify!($SelfT), "::min_value()).overflowing_abs(), (-", strin Basic usage: ``` -let x: ", stringify!($SelfT), " = 2; // or any other integer type +", $Feature, "let x: ", stringify!($SelfT), " = 2; // or any other integer type -assert_eq!(x.pow(4), 16); +assert_eq!(x.pow(4), 16);", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1204,8 +1244,9 @@ stringify!($SelfT), "::min_value()` without a panic. Basic usage: ``` -assert_eq!(10", stringify!($SelfT), ".abs(), 10); -assert_eq!((-10", stringify!($SelfT), ").abs(), 10); +", $Feature, "assert_eq!(10", stringify!($SelfT), ".abs(), 10); +assert_eq!((-10", stringify!($SelfT), ").abs(), 10);", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1234,9 +1275,10 @@ assert_eq!((-10", stringify!($SelfT), ").abs(), 10); Basic usage: ``` -assert_eq!(10", stringify!($SelfT), ".signum(), 1); +", $Feature, "assert_eq!(10", stringify!($SelfT), ".signum(), 1); assert_eq!(0", stringify!($SelfT), ".signum(), 0); -assert_eq!((-10", stringify!($SelfT), ").signum(), -1); +assert_eq!((-10", stringify!($SelfT), ").signum(), -1);", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1258,8 +1300,9 @@ negative. Basic usage: ``` -assert!(10", stringify!($SelfT), ".is_positive()); -assert!(!(-10", stringify!($SelfT), ").is_positive()); +", $Feature, "assert!(10", stringify!($SelfT), ".is_positive()); +assert!(!(-10", stringify!($SelfT), ").is_positive());", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1275,8 +1318,9 @@ positive. Basic usage: ``` -assert!((-10", stringify!($SelfT), ").is_negative()); -assert!(!10", stringify!($SelfT), ".is_negative()); +", $Feature, "assert!((-10", stringify!($SelfT), ").is_negative()); +assert!(!10", stringify!($SelfT), ".is_negative());", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1287,51 +1331,55 @@ assert!(!10", stringify!($SelfT), ".is_negative()); #[lang = "i8"] impl i8 { - int_impl! { i8, i8, u8, 8, -128, 127 } + int_impl! { i8, i8, u8, 8, -128, 127, "", "" } } #[lang = "i16"] impl i16 { - int_impl! { i16, i16, u16, 16, -32768, 32767 } + int_impl! { i16, i16, u16, 16, -32768, 32767, "", "" } } #[lang = "i32"] impl i32 { - int_impl! { i32, i32, u32, 32, -2147483648, 2147483647 } + int_impl! { i32, i32, u32, 32, -2147483648, 2147483647, "", "" } } #[lang = "i64"] impl i64 { - int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807 } + int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "" } } #[lang = "i128"] impl i128 { int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, - 170141183460469231731687303715884105727 } + 170141183460469231731687303715884105727, "#![feature(i128_type)] +#![feature(i128)] +# fn main() { +", " +# }" } } #[cfg(target_pointer_width = "16")] #[lang = "isize"] impl isize { - int_impl! { isize, i16, u16, 16 } + int_impl! { isize, i16, u16, 16, "", "" } } #[cfg(target_pointer_width = "32")] #[lang = "isize"] impl isize { - int_impl! { isize, i32, u32, 32 } + int_impl! { isize, i32, u32, 32, "", "" } } #[cfg(target_pointer_width = "64")] #[lang = "isize"] impl isize { - int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807 } + int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "" } } // `Int` + `UnsignedInt` implemented for unsigned integers macro_rules! uint_impl { - ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr) => { + ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr) => { doc_comment! { concat!("Returns the smallest value that can be represented by this integer type. @@ -1340,7 +1388,7 @@ macro_rules! uint_impl { Basic usage: ``` -assert_eq!(", stringify!($SelfT), "::min_value(), 0); +", $Feature, "assert_eq!(", stringify!($SelfT), "::min_value(), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1355,7 +1403,8 @@ assert_eq!(", stringify!($SelfT), "::min_value(), 0); Basic usage: ``` -assert_eq!(", stringify!($SelfT), "::max_value(), ", stringify!($MaxV), "); +", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value(), ", +stringify!($MaxV), ");", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1383,7 +1432,8 @@ This function panics if `radix` is not in the range from 2 to 36. Basic usage: ``` -assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10)); +", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] pub fn from_str_radix(src: &str, radix: u32) -> Result { @@ -1399,9 +1449,9 @@ assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10)); Basic usage: ``` -let n = 0b01001100", stringify!($SelfT), "; +", $Feature, "let n = 0b01001100", stringify!($SelfT), "; -assert_eq!(n.count_ones(), 3); +assert_eq!(n.count_ones(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1418,9 +1468,7 @@ assert_eq!(n.count_ones(), 3); Basic usage: ``` -let n = 0b01001100", stringify!($SelfT), "; - -assert_eq!(n.count_zeros(), 5); +", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1456,9 +1504,9 @@ of `self`. Basic usage: ``` -let n = 0b0101000", stringify!($SelfT), "; +", $Feature, "let n = 0b0101000", stringify!($SelfT), "; -assert_eq!(n.trailing_zeros(), 3); +assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1559,13 +1607,13 @@ swapped. Basic usage: ``` -let n = 0xA1", stringify!($SelfT), "; +", $Feature, "let n = 0x1A", stringify!($SelfT), "; if cfg!(target_endian = \"big\") { assert_eq!(", stringify!($SelfT), "::from_be(n), n) } else { assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) -} +}", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1585,13 +1633,13 @@ swapped. Basic usage: ``` -let n = 0xA1", stringify!($SelfT), "; +", $Feature, "let n = 0x1A", stringify!($SelfT), "; if cfg!(target_endian = \"little\") { - assert_eq!(u64::from_le(n), n) + assert_eq!(", stringify!($SelfT), "::from_le(n), n) } else { - assert_eq!(u64::from_le(n), n.swap_bytes()) -} + assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes()) +}", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1611,13 +1659,13 @@ swapped. Basic usage: ``` -let n = 0xA1", stringify!($SelfT), "; +", $Feature, "let n = 0x1A", stringify!($SelfT), "; if cfg!(target_endian = \"big\") { assert_eq!(n.to_be(), n) } else { assert_eq!(n.to_be(), n.swap_bytes()) -} +}", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1637,13 +1685,13 @@ swapped. Basic usage: ``` -let n = 0xA1", stringify!($SelfT), "; +", $Feature, "let n = 0x1A", stringify!($SelfT), "; if cfg!(target_endian = \"little\") { assert_eq!(n.to_le(), n) } else { assert_eq!(n.to_le(), n.swap_bytes()) -} +}", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1661,9 +1709,9 @@ if overflow occurred. Basic usage: ``` -assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(1), ", +", $Feature, "assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(1), ", "Some(", stringify!($SelfT), "::max_value() - 1)); -assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3),None); +assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3),None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1682,8 +1730,8 @@ assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3),None); Basic usage: ``` -assert_eq!(1", stringify!($SelfT), ".checked_sub(1), Some(0)); -assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None); +", $Feature, "assert_eq!(1", stringify!($SelfT), ".checked_sub(1), Some(0)); +assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1702,8 +1750,8 @@ assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None); Basic usage: ``` -assert_eq!(5", stringify!($SelfT), ".checked_mul(1), Some(5)); -assert_eq!(5", stringify!($SelfT), ".checked_mul(2), None); +", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_mul(1), Some(5)); +assert_eq!(", stringify!($SelfT), "::max_value().checked_mul(2), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1722,8 +1770,8 @@ if `rhs == 0`. Basic usage: ``` -assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64)); -assert_eq!(1", stringify!($SelfT), ".checked_div(0), None); +", $Feature, "assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64)); +assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1744,8 +1792,8 @@ if `rhs == 0`. Basic usage: ``` -assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); -assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None); +", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] #[inline] @@ -1769,8 +1817,8 @@ Note that negating any positive integer will overflow. Basic usage: ``` -assert_eq!(0", stringify!($SelfT), ".checked_neg(), Some(0)); -assert_eq!(1", stringify!($SelfT), ".checked_neg(), None); +", $Feature, "assert_eq!(0", stringify!($SelfT), ".checked_neg(), Some(0)); +assert_eq!(1", stringify!($SelfT), ".checked_neg(), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] #[inline] @@ -1789,8 +1837,8 @@ if `rhs` is larger than or equal to the number of bits in `self`. Basic usage: ``` -assert_eq!(0x10", stringify!($SelfT), ".checked_shl(4), Some(0x100)); -assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None); +", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); +assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] #[inline] @@ -1809,8 +1857,8 @@ if `rhs` is larger than or equal to the number of bits in `self`. Basic usage: ``` -assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); -assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None); +", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); +assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] #[inline] @@ -1829,8 +1877,8 @@ the numeric bounds instead of overflowing. Basic usage: ``` -assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); -assert_eq!(200", stringify!($SelfT), ".saturating_add(127), 255); +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); +assert_eq!(200u8.saturating_add(127), 255);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1851,8 +1899,8 @@ at the numeric bounds instead of overflowing. Basic usage: ``` -assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73); -assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0); +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73); +assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1873,11 +1921,11 @@ saturating at the numeric bounds instead of overflowing. Basic usage: ``` -use std::", stringify!($SelfT), "; +", $Feature, "use std::", stringify!($SelfT), "; -assert_eq!(100", stringify!($SelfT), ".saturating_mul(127), 12700); -assert_eq!((1", stringify!($SelfT), " << 23).saturating_mul(1 << 23), ", stringify!($SelfT), -"::MAX); +assert_eq!(2", stringify!($SelfT), ".saturating_mul(10), 20); +assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($SelfT), +"::MAX);", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] #[inline] @@ -1895,8 +1943,9 @@ wrapping around at the boundary of the type. Basic usage: ``` -assert_eq!(200", stringify!($SelfT), ".wrapping_add(55), 255); -assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::max_value()), 199); +", $Feature, "assert_eq!(200", stringify!($SelfT), ".wrapping_add(55), 255); +assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::max_value()), 199);", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1916,8 +1965,9 @@ wrapping around at the boundary of the type. Basic usage: ``` -assert_eq!(100u8.wrapping_sub(100), 0); -assert_eq!(100u8.wrapping_sub(", stringify!($SelfT), "::max_value()), 101); +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_sub(100), 0); +assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::max_value()), 101);", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1959,7 +2009,7 @@ are accounted for in the wrapping operations. Basic usage: ``` -assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10); +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline] @@ -1981,7 +2031,7 @@ are accounted for in the wrapping operations. Basic usage: ``` -assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0); +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline] @@ -1990,35 +2040,28 @@ assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0); } } - doc_comment! { - concat!("Wrapping (modular) negation. Computes `-self`, -wrapping around at the boundary of the type. - -Since unsigned types do not have negative equivalents -all applications of this function will wrap (except for `-0`). -For values smaller than the corresponding signed type's maximum -the result is the same as casting the corresponding signed value. -Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where -`MAX` is the corresponding signed type's maximum. - -# Examples - -Basic usage: - -``` -assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), ", stringify!($SelfT), -"::max_value() - 100 + 1); -assert_eq!(0", stringify!($SelfT), ".wrapping_neg(), 0); -assert_eq!(180", stringify!($SelfT), ".wrapping_neg(), ", stringify!($SelfT), -"::max_value() - 180 + 1); -assert_eq!(180", stringify!($SelfT), ".wrapping_neg(), (", stringify!($SelfT), "::max_value() / 2", -"+ 1) - (180", stringify!($SelfT), " - (", stringify!($SelfT), "::max_value() / 2 + 1))); -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline] - pub fn wrapping_neg(self) -> Self { - self.overflowing_neg().0 - } + /// Wrapping (modular) negation. Computes `-self`, + /// wrapping around at the boundary of the type. + /// + /// Since unsigned types do not have negative equivalents + /// all applications of this function will wrap (except for `-0`). + /// For values smaller than the corresponding signed type's maximum + /// the result is the same as casting the corresponding signed value. + /// Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where + /// `MAX` is the corresponding signed type's maximum. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert_eq!(100i8.wrapping_neg(), -100); + /// assert_eq!((-128i8).wrapping_neg(), -128); + /// ``` + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline] + pub fn wrapping_neg(self) -> Self { + self.overflowing_neg().0 } doc_comment! { @@ -2038,8 +2081,8 @@ be what you want instead. Basic usage: ``` -assert_eq!(1", stringify!($SelfT), ".wrapping_shl(7), 128); -assert_eq!(1", stringify!($SelfT), ".wrapping_shl(", stringify!($BITS), "), 1); +", $Feature, "assert_eq!(1", stringify!($SelfT), ".wrapping_shl(7), 128); +assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline] @@ -2067,8 +2110,8 @@ be what you want instead. Basic usage: ``` -assert_eq!(128", stringify!($SelfT), ".wrapping_shr(7), 1); -assert_eq!(128", stringify!($SelfT), ".wrapping_shr(", stringify!($BITS), "), 128); +", $Feature, "assert_eq!(128", stringify!($SelfT), ".wrapping_shr(7), 1); +assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline] @@ -2091,10 +2134,10 @@ have occurred then the wrapped value is returned. Basic usage ``` -use std::u32; +", $Feature, "use std::", stringify!($SelfT), "; assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); -assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true)); +assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));", $EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] @@ -2119,10 +2162,11 @@ have occurred then the wrapped value is returned. Basic usage ``` -use std::u32; +", $Feature, "use std::", stringify!($SelfT), "; assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); -assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true)); +assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));", +$EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] @@ -2176,7 +2220,7 @@ This function will panic if `rhs` is 0. Basic usage ``` -assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false)); +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));", $EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] @@ -2202,7 +2246,7 @@ This function will panic if `rhs` is 0. Basic usage ``` -assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false)); +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));", $EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] @@ -2224,8 +2268,9 @@ not overflow. Basic usage ``` -assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false)); -assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT), ", true)); +", $Feature, "assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false)); +assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT), +", true));", $EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] @@ -2248,8 +2293,8 @@ used to perform the shift. Basic usage ``` -assert_eq!(0x10", stringify!($SelfT), ".overflowing_shl(4), (0x100, false)); -assert_eq!(0x10", stringify!($SelfT), ".overflowing_shl(132), (0x100, true)); +", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false)); +assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] @@ -2272,8 +2317,8 @@ used to perform the shift. Basic usage ``` -assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); -assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true)); +", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); +assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, " ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] @@ -2291,7 +2336,7 @@ assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true)); Basic usage: ``` -assert_eq!(2", stringify!($SelfT), ".pow(4), 16); +", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(4), 16);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -2327,8 +2372,8 @@ assert_eq!(2", stringify!($SelfT), ".pow(4), 16); Basic usage: ``` -assert!(16", stringify!($SelfT), ".is_power_of_two()); -assert!(!10", stringify!($SelfT), ".is_power_of_two()); +", $Feature, "assert!(16", stringify!($SelfT), ".is_power_of_two()); +assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -2371,8 +2416,8 @@ release mode (the only situation in which method can return 0). Basic usage: ``` -assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2); -assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4); +", $Feature, "assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2); +assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -2392,9 +2437,11 @@ the next power of two is greater than the type's maximum value, Basic usage: ``` -assert_eq!(2", stringify!($SelfT), ".checked_next_power_of_two(), Some(2)); +", $Feature, "assert_eq!(2", stringify!($SelfT), +".checked_next_power_of_two(), Some(2)); assert_eq!(3", stringify!($SelfT), ".checked_next_power_of_two(), Some(4)); -assert_eq!(", stringify!($SelfT), "::max_value().checked_next_power_of_two(), None); +assert_eq!(", stringify!($SelfT), "::max_value().checked_next_power_of_two(), None);", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] pub fn checked_next_power_of_two(self) -> Option { @@ -2406,7 +2453,7 @@ assert_eq!(", stringify!($SelfT), "::max_value().checked_next_power_of_two(), No #[lang = "u8"] impl u8 { - uint_impl! { u8, u8, 8, 255 } + uint_impl! { u8, u8, 8, 255, "", "" } /// Checks if the value is within the ASCII range. @@ -2952,39 +2999,44 @@ impl u8 { #[lang = "u16"] impl u16 { - uint_impl! { u16, u16, 16, 65535 } + uint_impl! { u16, u16, 16, 65535, "", "" } } #[lang = "u32"] impl u32 { - uint_impl! { u32, u32, 32, 4294967295 } + uint_impl! { u32, u32, 32, 4294967295, "", "" } } #[lang = "u64"] impl u64 { - uint_impl! { u64, u64, 64, 18446744073709551615 } + uint_impl! { u64, u64, 64, 18446744073709551615, "", "" } } #[lang = "u128"] impl u128 { - uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455 } + uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "#![feature(i128_type)] +#![feature(i128)] + +# fn main() { +", " +# }" } } #[cfg(target_pointer_width = "16")] #[lang = "usize"] impl usize { - uint_impl! { usize, u16, 16, 65536 } + uint_impl! { usize, u16, 16, 65536, "", "" } } #[cfg(target_pointer_width = "32")] #[lang = "usize"] impl usize { - uint_impl! { usize, u32, 32, 4294967295 } + uint_impl! { usize, u32, 32, 4294967295, "", "" } } #[cfg(target_pointer_width = "64")] #[lang = "usize"] impl usize { - uint_impl! { usize, u64, 64, 18446744073709551615 } + uint_impl! { usize, u64, 64, 18446744073709551615, "", "" } } /// A classification of floating point numbers. -- cgit 1.4.1-3-g733a5 From f1c1fc2dbe442bedf214219d281b0d83b42cff67 Mon Sep 17 00:00:00 2001 From: Maxim Nazarenko Date: Wed, 14 Feb 2018 09:19:01 +0200 Subject: rephrase UnsafeCell doc Make UnsafeCell doc easier to follow --- src/libcore/cell.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index ec0d1b704dc..6270e87c9cc 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1164,11 +1164,12 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// The compiler makes optimizations based on the knowledge that `&T` is not mutably aliased or /// mutated, and that `&mut T` is unique. When building abstractions like `Cell`, `RefCell`, /// `Mutex`, etc, you need to turn these optimizations off. `UnsafeCell` is the only legal way -/// to do this. When `UnsafeCell` is immutably aliased, it is still safe to obtain a mutable -/// reference to its interior and/or to mutate it. However, it is up to the abstraction designer -/// to ensure that no two mutable references obtained this way are active at the same time, and -/// that there are no active mutable references or mutations when an immutable reference is obtained -/// from the cell. This is often done via runtime checks. +/// to do this. When `UnsafeCell` _itself_ is immutably aliased, it is still safe to obtain +/// a mutable reference to its _interior_ and/or to mutate the interior. However, it is up to +/// the abstraction designer to ensure that no two mutable references obtained this way are active +/// at the same time, there are no active immutable reference when a mutable reference is obtained +/// from the cell, and that there are no active mutable references or mutations when an immutable +/// reference is obtained. This is often done via runtime checks. /// /// Note that while mutating or mutably aliasing the contents of an `& UnsafeCell` is /// okay (provided you enforce the invariants some other way); it is still undefined behavior @@ -1240,9 +1241,9 @@ impl UnsafeCell { /// Gets a mutable pointer to the wrapped value. /// /// This can be cast to a pointer of any kind. - /// Ensure that the access is unique when casting to - /// `&mut T`, and ensure that there are no mutations or mutable - /// aliases going on when casting to `&T` + /// Ensure that the access is unique (no active references, mutable or not) + /// when casting to `&mut T`, and ensure that there are no mutations + /// or mutable aliases going on when casting to `&T` /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From b9b82490206fc41eb10662d6847a1ad28618ee59 Mon Sep 17 00:00:00 2001 From: Maxim Nazarenko Date: Wed, 14 Feb 2018 10:11:37 +0200 Subject: fix tidy checks --- src/libcore/cell.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 6270e87c9cc..6f91e743999 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1165,7 +1165,7 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// mutated, and that `&mut T` is unique. When building abstractions like `Cell`, `RefCell`, /// `Mutex`, etc, you need to turn these optimizations off. `UnsafeCell` is the only legal way /// to do this. When `UnsafeCell` _itself_ is immutably aliased, it is still safe to obtain -/// a mutable reference to its _interior_ and/or to mutate the interior. However, it is up to +/// a mutable reference to its _interior_ and/or to mutate the interior. However, it is up to /// the abstraction designer to ensure that no two mutable references obtained this way are active /// at the same time, there are no active immutable reference when a mutable reference is obtained /// from the cell, and that there are no active mutable references or mutations when an immutable @@ -1243,7 +1243,7 @@ impl UnsafeCell { /// This can be cast to a pointer of any kind. /// Ensure that the access is unique (no active references, mutable or not) /// when casting to `&mut T`, and ensure that there are no mutations - /// or mutable aliases going on when casting to `&T` + /// or mutable aliases going on when casting to `&T` /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 288c0c3081419c0d522d76cfbb36fabd038ed4f2 Mon Sep 17 00:00:00 2001 From: Jacob Hughes Date: Wed, 14 Feb 2018 11:30:53 +0000 Subject: Clarified why `Sized` bound not implicit on trait's implicit `Self` type. --- src/libcore/marker.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 3032fb2de33..5b482d467bc 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -63,9 +63,13 @@ impl !Send for *mut T { } /// struct BarUse(Bar<[i32]>); // OK /// ``` /// -/// The one exception is the implicit `Self` type of a trait, which does not -/// get an implicit `Sized` bound. This is because a `Sized` bound prevents -/// the trait from being used to form a [trait object]: +/// The one exception is the implicit `Self` type of a trait. A trait does not +/// have an implicit `Sized` bound as this is incompatible with [trait object]s +/// where, by definition, one cannot know the size of all possible +/// implementations of the trait. +/// +/// Although Rust will let you bind `Sized` to a trait, you won't +/// be able to use it as a trait object later: /// /// ``` /// # #![allow(unused_variables)] -- cgit 1.4.1-3-g733a5 From ec36e7e972e8036fe7bd428458462a2aacd40927 Mon Sep 17 00:00:00 2001 From: kennytm Date: Wed, 14 Feb 2018 23:18:18 +0800 Subject: Partially revert #47333. Removed the `assume()` which we assumed is the cause of misoptimization in issue #48116. --- src/libcore/slice/mod.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index aacbbd5058e..ac390313a67 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1246,15 +1246,18 @@ macro_rules! iterator { { // The addition might panic on overflow // Use the len of the slice to hint optimizer to remove result index bounds check. - let n = make_slice!(self.ptr, self.end).len(); + let _n = make_slice!(self.ptr, self.end).len(); self.try_fold(0, move |i, x| { if predicate(x) { Err(i) } else { Ok(i + 1) } }).err() - .map(|i| { - unsafe { assume(i < n) }; - i - }) + // // FIXME(#48116/#45964): + // // This assume() causes misoptimization on LLVM 6. + // // Commented out until it is fixed again. + // .map(|i| { + // unsafe { assume(i < n) }; + // i + // }) } #[inline] @@ -1271,10 +1274,13 @@ macro_rules! iterator { if predicate(x) { Err(i) } else { Ok(i) } }).err() - .map(|i| { - unsafe { assume(i < n) }; - i - }) + // // FIXME(#48116/#45964): + // // This assume() causes misoptimization on LLVM 6. + // // Commented out until it is fixed again. + // .map(|i| { + // unsafe { assume(i < n) }; + // i + // }) } } -- cgit 1.4.1-3-g733a5 From 38064a9a7ce6b5050ca1d629aef22f17f2548d07 Mon Sep 17 00:00:00 2001 From: Jacob Hughes Date: Wed, 14 Feb 2018 19:14:25 +0000 Subject: Review change - Expanded on explanation. --- src/libcore/marker.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 5b482d467bc..98e0f71eb93 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -65,11 +65,11 @@ impl !Send for *mut T { } /// /// The one exception is the implicit `Self` type of a trait. A trait does not /// have an implicit `Sized` bound as this is incompatible with [trait object]s -/// where, by definition, one cannot know the size of all possible -/// implementations of the trait. +/// where, by definition, the trait needs to work with all possible implementors, +/// and thus could be any size. /// /// Although Rust will let you bind `Sized` to a trait, you won't -/// be able to use it as a trait object later: +/// be able to use it to form a trait object later: /// /// ``` /// # #![allow(unused_variables)] -- cgit 1.4.1-3-g733a5 From 220bb22e1b621ad5a10a44080e3e1872d99f3e9f Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Wed, 14 Feb 2018 17:25:42 +0000 Subject: add Self: Trait<..> inside the param_env of a default impl --- src/libcore/iter/mod.rs | 6 +-- src/librustc/traits/select.rs | 44 ++++++---------------- src/librustc/ty/mod.rs | 25 +----------- src/librustc_typeck/collect.rs | 20 +++++++++- .../specialization-trait-item-not-implemented.rs | 2 + .../specialization-trait-not-implemented.rs | 4 ++ .../defaultimpl/specialization-wfcheck.rs | 2 + .../specialization-trait-item-not-implemented.rs | 10 ++++- 8 files changed, 51 insertions(+), 62 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index bf8367d85fd..652e0027383 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -579,15 +579,15 @@ impl<'a, I, T: 'a> FusedIterator for Cloned {} #[doc(hidden)] -default unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned +unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned where I: TrustedRandomAccess, T: Clone { - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { + default unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { self.it.get_unchecked(i).clone() } #[inline] - fn may_have_side_effect() -> bool { true } + default fn may_have_side_effect() -> bool { true } } #[doc(hidden)] diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index aa43bf8ca2e..4ed25646d43 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1710,44 +1710,22 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("assemble_candidates_from_impls(obligation={:?})", obligation); - // Check if default impls should be emitted. - // default impls are emitted if the param_env is refered to a default impl. - // The param_env should contain a Self: Trait<..> predicate in those cases - let self_trait_is_present:Vec<&ty::Predicate<'tcx>> = - obligation.param_env - .caller_bounds - .iter() - .filter(|predicate| { - match **predicate { - ty::Predicate::Trait(ref trait_predicate) => { - trait_predicate.def_id() == - obligation.predicate.def_id() && - obligation.predicate.0.trait_ref.self_ty() == - trait_predicate.skip_binder().self_ty() - } - _ => false - } - }).collect::>>(); - self.tcx().for_each_relevant_impl( obligation.predicate.def_id(), obligation.predicate.0.trait_ref.self_ty(), |impl_def_id| { - if self_trait_is_present.len() > 0 || - !self.tcx().impl_is_default(impl_def_id) { - self.probe(|this, snapshot| { /* [1] */ - match this.match_impl(impl_def_id, obligation, snapshot) { - Ok(skol_map) => { - candidates.vec.push(ImplCandidate(impl_def_id)); - - // NB: we can safely drop the skol map - // since we are in a probe [1] - mem::drop(skol_map); - } - Err(_) => { } + self.probe(|this, snapshot| { /* [1] */ + match this.match_impl(impl_def_id, obligation, snapshot) { + Ok(skol_map) => { + candidates.vec.push(ImplCandidate(impl_def_id)); + + // NB: we can safely drop the skol map + // since we are in a probe [1] + mem::drop(skol_map); } - }); - } + Err(_) => { } + } + }); } ); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 52d33c750f8..f52f2ea0f9f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2606,31 +2606,8 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ParamEnv<'tcx> { // Compute the bounds on Self and the type parameters. - let mut predicates = tcx.predicates_of(def_id); - match tcx.hir.as_local_node_id(def_id) - .and_then(|node_id| tcx.hir.find(node_id)) - .and_then(|item| { - match item { - hir::map::NodeItem(..) => { - if tcx.impl_is_default(def_id) { - tcx.impl_trait_ref(def_id) - } else { - None - } - } - _ => None - } - }) { - Some(trait_ref) => - predicates.predicates - .push( - trait_ref.to_poly_trait_ref() - .to_predicate() - ), - None => {} - } - let bounds = predicates.instantiate_identity(tcx); + let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx); let predicates = bounds.predicates; // Finally, we have to normalize the bounds in the environment, in diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d5328a18c22..1c8d22e4666 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1364,6 +1364,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let node = tcx.hir.get(node_id); let mut is_trait = None; + let mut is_default_impl_trait = None; let icx = ItemCtxt::new(tcx, def_id); let no_generics = hir::Generics::empty(); @@ -1373,8 +1374,13 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { + ItemImpl(_, _, defaultness, ref generics, ..) => { + if defaultness.is_default() { + is_default_impl_trait = tcx.impl_trait_ref(def_id); + } + generics + } ItemFn(.., ref generics, _) | - ItemImpl(_, _, _, ref generics, ..) | ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | @@ -1446,6 +1452,18 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); } + // In default impls, we can assume that the self type implements + // the trait. So in: + // + // default impl Foo for Bar { .. } + // + // we add a default where clause `Foo: Bar`. We do a similar thing for traits + // (see below). Recall that a default impl is not itself an impl, but rather a + // set of defaults that can be incorporated into another impl. + if let Some(trait_ref) = is_default_impl_trait { + predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); + } + // Collect the region predicates that were declared inline as // well. In the case of parameters declared on a fn or method, we // have to be careful to only iterate over early-bound regions. diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index 072507851d7..eacec2e40f0 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Tests that default impls do not have to supply all items but regular impls do. + #![feature(specialization)] trait Foo { diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs index d020a677577..04ddf9ebb17 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs @@ -8,6 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Tests that: +// - default impls do not have to supply all items and +// - a default impl does not count as an impl (in this case, an incomplete default impl). + #![feature(specialization)] trait Foo { diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs index 34229737992..445a59a373e 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Tests that a default impl still has to have a WF trait ref. + #![feature(specialization)] trait Foo<'a, T: Eq + 'a> { } diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index e11a3021497..fc731202005 100644 --- a/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs +++ b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -8,18 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Tests that we can combine a default impl that supplies one method with a +// full impl that supplies the other, and they can invoke one another. + #![feature(specialization)] trait Foo { fn foo_one(&self) -> &'static str; fn foo_two(&self) -> &'static str; + fn foo_three(&self) -> &'static str; } struct MyStruct; default impl Foo for T { fn foo_one(&self) -> &'static str { - "generic" + self.foo_three() } } @@ -27,6 +31,10 @@ impl Foo for MyStruct { fn foo_two(&self) -> &'static str { self.foo_one() } + + fn foo_three(&self) -> &'static str { + "generic" + } } fn main() { -- cgit 1.4.1-3-g733a5 From 137f5bc64e3259a3921ceefb660aae134adbe528 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 15 Feb 2018 14:44:58 -0500 Subject: spelling fix in comment --- src/libcore/str/pattern.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 089d691773a..95bb8f18947 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -324,7 +324,7 @@ unsafe impl<'a> Searcher<'a> for CharSearcher<'a> { // the second byte when searching for the third. // // However, this is totally okay. While we have the invariant that - // self.finger is on a UTF8 boundary, this invariant is not relid upon + // self.finger is on a UTF8 boundary, this invariant is not relied upon // within this method (it is relied upon in CharSearcher::next()). // // We only exit this method when we reach the end of the string, or if we -- cgit 1.4.1-3-g733a5 From 3bf989f4c945e91c2ff99ac66ef0f6405e975ff4 Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Fri, 16 Feb 2018 10:30:31 +0100 Subject: Add link to yield_now --- src/libcore/sync/atomic.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index f22862ae701..63fb6e437e4 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -97,9 +97,10 @@ use fmt; /// Save power or switch hyperthreads in a busy-wait spin-loop. /// /// This function is deliberately more primitive than -/// `std::thread::yield_now` and does not directly yield to the -/// system's scheduler. In some cases it might be useful to use a -/// combination of both functions. Careful benchmarking is advised. +/// [`std::thread::yield_now`](../../thread/fn.yield_now.html) and +/// does not directly yield to the system's scheduler. +/// In some cases it might be useful to use a combination of both functions. +/// Careful benchmarking is advised. /// /// On some platforms this function may not do anything at all. #[inline] -- cgit 1.4.1-3-g733a5 From e812da0ed050e2bfa7e12b6f35f077c6c3f19a1b Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Fri, 16 Feb 2018 12:20:54 +0100 Subject: Force the link to std::thread::yield_now() --- src/libcore/sync/atomic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 63fb6e437e4..25827edee7d 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -97,7 +97,7 @@ use fmt; /// Save power or switch hyperthreads in a busy-wait spin-loop. /// /// This function is deliberately more primitive than -/// [`std::thread::yield_now`](../../thread/fn.yield_now.html) and +/// [`std::thread::yield_now`](../../../std/thread/fn.yield_now.html) and /// does not directly yield to the system's scheduler. /// In some cases it might be useful to use a combination of both functions. /// Careful benchmarking is advised. -- cgit 1.4.1-3-g733a5 From a58409dd918eeb67c2cd333e09f53007f8b9a7d2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 Feb 2018 19:44:07 +0100 Subject: Notify users that this example is shared through integer types --- src/libcore/num/mod.rs | 66 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 19 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index dcadf830f1e..9c84eb6dba5 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -255,6 +255,9 @@ $EndFeature, " /// /// # Examples /// + /// Please note that this example is shared between integer types. + /// Which explains why `i64` is used here. + /// /// Basic usage: /// /// ``` @@ -277,6 +280,9 @@ $EndFeature, " /// /// # Examples /// + /// Please note that this example is shared between integer types. + /// Which explains why `i64` is used here. + /// /// Basic usage: /// /// ``` @@ -295,6 +301,9 @@ $EndFeature, " /// /// # Examples /// + /// Please note that this example is shared between integer types. + /// Which explains why `i16` is used here. + /// /// Basic usage: /// /// ``` @@ -1362,13 +1371,13 @@ impl i128 { #[cfg(target_pointer_width = "16")] #[lang = "isize"] impl isize { - int_impl! { isize, i16, u16, 16, "", "" } + int_impl! { isize, i16, u16, 16, -32768, 32767, "", "" } } #[cfg(target_pointer_width = "32")] #[lang = "isize"] impl isize { - int_impl! { isize, i32, u32, 32, "", "" } + int_impl! { isize, i32, u32, 32, -2147483648, 2147483647, "", "" } } #[cfg(target_pointer_width = "64")] @@ -1477,22 +1486,23 @@ Basic usage: } } - /// Returns the number of leading zeros in the binary representation - /// of `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 0b0101000u16; - /// - /// assert_eq!(n.leading_zeros(), 10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn leading_zeros(self) -> u32 { - unsafe { intrinsics::ctlz(self as $ActualT) as u32 } + doc_comment! { + concat!("Returns the number of leading zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = ", stringify!($SelfT), "::max_value() >> 2; + +assert_eq!(n.leading_zeros(), 2);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn leading_zeros(self) -> u32 { + unsafe { intrinsics::ctlz(self as $ActualT) as u32 } + } } doc_comment! { @@ -1537,6 +1547,9 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " /// /// Basic usage: /// + /// Please note that this example is shared between integer types. + /// Which explains why `u64` is used here. + /// /// ``` /// let n = 0x0123456789ABCDEFu64; /// let m = 0x3456789ABCDEF012u64; @@ -1561,6 +1574,9 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " /// /// Basic usage: /// + /// Please note that this example is shared between integer types. + /// Which explains why `u64` is used here. + /// /// ``` /// let n = 0x0123456789ABCDEFu64; /// let m = 0xDEF0123456789ABCu64; @@ -1581,6 +1597,9 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " /// /// Basic usage: /// + /// Please note that this example is shared between integer types. + /// Which explains why `u16` is used here. + /// /// ``` /// let n: u16 = 0b0000000_01010101; /// assert_eq!(n, 85); @@ -1985,6 +2004,9 @@ $EndFeature, " /// /// Basic usage: /// + /// Please note that this example is shared between integer types. + /// Which explains why `u8` is used here. + /// /// ``` /// assert_eq!(10u8.wrapping_mul(12), 120); /// assert_eq!(25u8.wrapping_mul(12), 44); @@ -2054,6 +2076,9 @@ Basic usage: /// /// Basic usage: /// + /// Please note that this example is shared between integer types. + /// Which explains why `i8` is used here. + /// /// ``` /// assert_eq!(100i8.wrapping_neg(), -100); /// assert_eq!((-128i8).wrapping_neg(), -128); @@ -2187,7 +2212,10 @@ $EndFeature, " /// /// # Examples /// - /// Basic usage + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u32` is used here. /// /// ``` /// assert_eq!(5u32.overflowing_mul(2), (10, false)); -- cgit 1.4.1-3-g733a5 From 6e27aa88a70b584dd36817a448d5089b42569183 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 16 Feb 2018 22:14:32 +0100 Subject: core::iter::repeat_with: fix spelling, s/not/note --- src/libcore/iter/sources.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 3e9d799c089..dfd42f3e733 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -159,7 +159,7 @@ unsafe impl A> TrustedLen for RepeatWith {} /// [`repeat`]: fn.repeat.html /// /// An iterator produced by `repeat_with()` is a `DoubleEndedIterator`. -/// It is important to not that reversing `repeat_with(f)` will produce +/// It is important to note that reversing `repeat_with(f)` will produce /// the exact same sequence as the non-reversed iterator. In other words, /// `repeat_with(f).rev().collect::>()` is equivalent to /// `repeat_with(f).collect::>()`. -- cgit 1.4.1-3-g733a5 From b31ff95ae6fe3fe9501065b11afb8435ce8f783a Mon Sep 17 00:00:00 2001 From: Jewoo Lee Date: Sun, 18 Feb 2018 20:14:21 +0900 Subject: Add non-panicking variants of pow to all integer types Currently, calling pow may panic in case of overflow, and the function does not have non-panicking counterparts. Thus, it would be beneficial to add those in. --- src/libcore/num/mod.rs | 308 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 560dcf295b2..2b656fad171 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -634,6 +634,46 @@ $EndFeature, " } } + doc_comment! { + concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +#![feature(no_panic_pow)] +", $Feature, "assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64)); +assert_eq!(", stringify!($SelfT), "::max_value().checked_pow(2), None);", +$EndFeature, " +```"), + + #[unstable(feature = "no_panic_pow", issue = "48320")] + #[inline] + pub fn checked_pow(self, mut exp: u32) -> Option { + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.checked_mul(base)?; + } + exp /= 2; + base = base.checked_mul(base)?; + } + + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + if exp == 1 { + acc = acc.checked_mul(base)?; + } + + Some(acc) + } + } + doc_comment! { concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric bounds instead of overflowing. @@ -713,6 +753,34 @@ $EndFeature, " } } + doc_comment! { + concat!("Saturating integer exponentiation. Computes `self.pow(exp)`, +saturating at the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +#![feature(no_panic_pow)] +", $Feature, "use std::", stringify!($SelfT), "; + +assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT), "::MAX); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);", +$EndFeature, " +```"), + #[unstable(feature = "no_panic_pow", issue = "48320")] + #[inline] + pub fn saturating_pow(self, exp: u32) -> Self { + match self.checked_pow(exp) { + Some(x) => x, + None if self < 0 && exp % 2 == 1 => Self::min_value(), + None => Self::max_value(), + } + } + } + doc_comment! { concat!("Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the boundary of the type. @@ -947,6 +1015,46 @@ $EndFeature, " } } + doc_comment! { + concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`, +wrapping around at the boundary of the type. + +# Examples + +Basic usage: + +``` +#![feature(no_panic_pow)] +", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81); +assert_eq!(3i8.wrapping_pow(5), -13); +assert_eq!(3i8.wrapping_pow(6), -39);", +$EndFeature, " +```"), + #[unstable(feature = "no_panic_pow", issue = "48320")] + #[inline] + pub fn wrapping_pow(self, mut exp: u32) -> Self { + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.wrapping_mul(base); + } + exp /= 2; + base = base.wrapping_mul(base); + } + + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + if exp == 1 { + acc = acc.wrapping_mul(base); + } + + acc + } + } + doc_comment! { concat!("Calculates `self` + `rhs` @@ -1202,6 +1310,56 @@ $EndFeature, " doc_comment! { concat!("Raises self to the power of `exp`, using exponentiation by squaring. +Returns a tuple of the exponentiation along with a bool indicating +whether an overflow happened. + +# Examples + +Basic usage: + +``` +#![feature(no_panic_pow)] +", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false)); +assert_eq!(3i8.overflowing_pow(5), (-13, true));", +$EndFeature, " +```"), + #[unstable(feature = "no_panic_pow", issue = "48320")] + #[inline] + pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { + let mut base = self; + let mut acc: Self = 1; + let mut overflown = false; + // Scratch space for storing results of overflowing_mul. + let mut r; + + while exp > 1 { + if (exp & 1) == 1 { + r = acc.overflowing_mul(base); + acc = r.0; + overflown |= r.1; + } + exp /= 2; + r = base.overflowing_mul(base); + base = r.0; + overflown |= r.1; + } + + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + if exp == 1 { + r = acc.overflowing_mul(base); + acc = r.0; + overflown |= r.1; + } + + (acc, overflown) + } + } + + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + # Examples Basic usage: @@ -1887,6 +2045,44 @@ assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);", $EndFeature, } } + doc_comment! { + concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +#![feature(no_panic_pow)] +", $Feature, "assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32)); +assert_eq!(", stringify!($SelfT), "::max_value().checked_pow(2), None);", $EndFeature, " +```"), + #[unstable(feature = "no_panic_pow", issue = "48320")] + #[inline] + pub fn checked_pow(self, mut exp: u32) -> Option { + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.checked_mul(base)?; + } + exp /= 2; + base = base.checked_mul(base)?; + } + + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + if exp == 1 { + acc = acc.checked_mul(base)?; + } + + Some(acc) + } + } + doc_comment! { concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric bounds instead of overflowing. @@ -1953,6 +2149,32 @@ assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($Se } } + doc_comment! { + concat!("Saturating integer exponentiation. Computes `self.pow(exp)`, +saturating at the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +#![feature(no_panic_pow)] +", $Feature, "use std::", stringify!($SelfT), "; + +assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);", +$EndFeature, " +```"), + #[unstable(feature = "no_panic_pow", issue = "48320")] + #[inline] + pub fn saturating_pow(self, exp: u32) -> Self { + match self.checked_pow(exp) { + Some(x) => x, + None => Self::max_value(), + } + } + } + doc_comment! { concat!("Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the boundary of the type. @@ -2147,6 +2369,44 @@ assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, " } } + doc_comment! { + concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`, +wrapping around at the boundary of the type. + +# Examples + +Basic usage: + +``` +#![feature(no_panic_pow)] +", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243); +assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, " +```"), + #[unstable(feature = "no_panic_pow", issue = "48320")] + #[inline] + pub fn wrapping_pow(self, mut exp: u32) -> Self { + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.wrapping_mul(base); + } + exp /= 2; + base = base.wrapping_mul(base); + } + + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + if exp == 1 { + acc = acc.wrapping_mul(base); + } + + acc + } + } + doc_comment! { concat!("Calculates `self` + `rhs` @@ -2353,7 +2613,55 @@ assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $E pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) { (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) } + } + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +Returns a tuple of the exponentiation along with a bool indicating +whether an overflow happened. + +# Examples + +Basic usage: + +``` +#![feature(no_panic_pow)] +", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false)); +assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, " +```"), + #[unstable(feature = "no_panic_pow", issue = "48320")] + #[inline] + pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { + let mut base = self; + let mut acc: Self = 1; + let mut overflown = false; + // Scratch space for storing results of overflowing_mul. + let mut r; + + while exp > 1 { + if (exp & 1) == 1 { + r = acc.overflowing_mul(base); + acc = r.0; + overflown |= r.1; + } + exp /= 2; + r = base.overflowing_mul(base); + base = r.0; + overflown |= r.1; + } + + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + if exp == 1 { + r = acc.overflowing_mul(base); + acc = r.0; + overflown |= r.1; + } + + (acc, overflown) + } } doc_comment! { -- cgit 1.4.1-3-g733a5 From c0e87f13a4d2f6fcef92c8c01bdc8dda9e0549a5 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 15 Feb 2018 15:54:40 +0000 Subject: Make ".e0" not parse as 0.0 This forces floats to have either a digit before the separating point, or after. Thus ".e0" is invalid like ".", when using `parse()`. --- src/libcore/num/dec2flt/parse.rs | 3 ++- src/libcore/tests/num/dec2flt/mod.rs | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/num/dec2flt/parse.rs b/src/libcore/num/dec2flt/parse.rs index d20986faa0f..69418434ebe 100644 --- a/src/libcore/num/dec2flt/parse.rs +++ b/src/libcore/num/dec2flt/parse.rs @@ -73,7 +73,8 @@ pub fn parse_decimal(s: &str) -> ParseResult { } Some(&b'.') => { let (fractional, s) = eat_digits(&s[1..]); - if integral.is_empty() && fractional.is_empty() && s.is_empty() { + if integral.is_empty() && fractional.is_empty() { + // We require at least a single digit before or after the point. return Invalid; } diff --git a/src/libcore/tests/num/dec2flt/mod.rs b/src/libcore/tests/num/dec2flt/mod.rs index 9934e1dab96..17b2f59cd4d 100644 --- a/src/libcore/tests/num/dec2flt/mod.rs +++ b/src/libcore/tests/num/dec2flt/mod.rs @@ -101,6 +101,12 @@ fn lonely_dot() { assert!(".".parse::().is_err()); } +#[test] +fn exponentiated_dot() { + assert!(".e0".parse::().is_err()); + assert!(".e0".parse::().is_err()); +} + #[test] fn lonely_sign() { assert!("+".parse::().is_err()); -- cgit 1.4.1-3-g733a5 From 3f931515df876ac21760edc1c1c13b8cf351cf3d Mon Sep 17 00:00:00 2001 From: Gil Cottle Date: Mon, 19 Feb 2018 20:51:48 +0000 Subject: Fix count usize link typo in docs --- src/libcore/iter/iterator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 33adb3f49dd..c1a0518cd22 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -168,7 +168,7 @@ pub trait Iterator { /// This function might panic if the iterator has more than [`usize::MAX`] /// elements. /// - /// [`usize::MAX`]: ../../std/isize/constant.MAX.html + /// [`usize::MAX`]: ../../std/usize/constant.MAX.html /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From bde855518b9f21fe877e1ed62eaa114861131d15 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 20 Feb 2018 05:52:26 +0100 Subject: RefCell: document panics in Clone, PartialEq, PartialOrd, Ord. Fixes #47400 --- src/libcore/cell.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index ec0d1b704dc..e91b2c793c5 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -863,6 +863,9 @@ impl !Sync for RefCell {} #[stable(feature = "rust1", since = "1.0.0")] impl Clone for RefCell { + /// # Panics + /// + /// Panics if the value is currently mutably borrowed. #[inline] fn clone(&self) -> RefCell { RefCell::new(self.borrow().clone()) @@ -880,6 +883,9 @@ impl Default for RefCell { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for RefCell { + /// # Panics + /// + /// Panics if the value is currently mutably borrowed. #[inline] fn eq(&self, other: &RefCell) -> bool { *self.borrow() == *other.borrow() @@ -891,26 +897,41 @@ impl Eq for RefCell {} #[stable(feature = "cell_ord", since = "1.10.0")] impl PartialOrd for RefCell { + /// # Panics + /// + /// Panics if the value is currently mutably borrowed. #[inline] fn partial_cmp(&self, other: &RefCell) -> Option { self.borrow().partial_cmp(&*other.borrow()) } + /// # Panics + /// + /// Panics if the value is currently mutably borrowed. #[inline] fn lt(&self, other: &RefCell) -> bool { *self.borrow() < *other.borrow() } + /// # Panics + /// + /// Panics if the value is currently mutably borrowed. #[inline] fn le(&self, other: &RefCell) -> bool { *self.borrow() <= *other.borrow() } + /// # Panics + /// + /// Panics if the value is currently mutably borrowed. #[inline] fn gt(&self, other: &RefCell) -> bool { *self.borrow() > *other.borrow() } + /// # Panics + /// + /// Panics if the value is currently mutably borrowed. #[inline] fn ge(&self, other: &RefCell) -> bool { *self.borrow() >= *other.borrow() @@ -919,6 +940,9 @@ impl PartialOrd for RefCell { #[stable(feature = "cell_ord", since = "1.10.0")] impl Ord for RefCell { + /// # Panics + /// + /// Panics if the value is currently mutably borrowed. #[inline] fn cmp(&self, other: &RefCell) -> Ordering { self.borrow().cmp(&*other.borrow()) -- cgit 1.4.1-3-g733a5 From 6af23f977c44fc67d8611b2581c334e795999bcd Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 20 Feb 2018 08:26:30 +0100 Subject: add Iterator::flatten and redefine flat_map(f) in terms of map(f).flatten() --- src/libcore/iter/iterator.rs | 47 +++++++++++++++++++++++-- src/libcore/iter/mod.rs | 81 ++++++++++++++++++++------------------------ src/libcore/lib.rs | 1 + src/libcore/tests/iter.rs | 2 ++ 4 files changed, 84 insertions(+), 47 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 33adb3f49dd..8ed3450dc3a 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -12,7 +12,7 @@ use cmp::Ordering; use ops::Try; use super::{AlwaysOk, LoopState}; -use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, FlatMap, Fuse}; +use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, Flatten, FlatMap, Fuse}; use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev}; use super::{Zip, Sum, Product}; use super::{ChainState, FromIterator, ZipImpl}; @@ -997,11 +997,15 @@ pub trait Iterator { /// an extra layer of indirection. `flat_map()` will remove this extra layer /// on its own. /// + /// You can think of [`flat_map(f)`][flat_map] as the equivalent of + /// [`map`]ping, and then [`flatten`]ing as in `map(f).flatten()`. + /// /// Another way of thinking about `flat_map()`: [`map`]'s closure returns /// one item for each element, and `flat_map()`'s closure returns an /// iterator for each element. /// /// [`map`]: #method.map + /// [`flatten`]: #method.flatten /// /// # Examples /// @@ -1021,7 +1025,46 @@ pub trait Iterator { fn flat_map(self, f: F) -> FlatMap where Self: Sized, U: IntoIterator, F: FnMut(Self::Item) -> U, { - FlatMap{iter: self, f: f, frontiter: None, backiter: None } + self.map(f).flatten() + } + + /// Creates an iterator that flattens nested structure. + /// + /// This is useful when you have an iterator of iterators or an iterator of + /// things that can be turned into iterators and you want to remove one + /// level of indirection. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iterator_flatten)] + /// + /// let data = vec![vec![1, 2, 3, 4], vec![5, 6]]; + /// let flattened = data.into_iter().flatten().collect::>(); + /// assert_eq!(flattened, &[1, 2, 3, 4, 5, 6]); + /// ``` + /// + /// Mapping and then flattening: + /// + /// ``` + /// #![feature(iterator_flatten)] + /// + /// let words = ["alpha", "beta", "gamma"]; + /// + /// // chars() returns an iterator + /// let merged: String = words.iter() + /// .map(|s| s.chars()) + /// .flatten() + /// .collect(); + /// assert_eq!(merged, "alphabetagamma"); + /// ``` + #[inline] + #[unstable(feature = "iterator_flatten", issue = "0")] + fn flatten(self) -> Flatten::IntoIter> + where Self: Sized, Self::Item: IntoIterator { + Flatten { iter: self, frontiter: None, backiter: None } } /// Creates an iterator which ends after the first [`None`]. diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 1a2da83429a..bd801d2ae69 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -2403,37 +2403,35 @@ impl Iterator for Scan where /// An iterator that maps each element to an iterator, and yields the elements /// of the produced iterators. /// -/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its +/// This `type` is created by the [`flat_map`] method on [`Iterator`]. See its /// documentation for more. /// /// [`flat_map`]: trait.Iterator.html#method.flat_map /// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct FlatMap { - iter: I, - f: F, - frontiter: Option, - backiter: Option, -} +type FlatMap = Flatten, ::IntoIter>; -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for FlatMap - where U::IntoIter: fmt::Debug -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("FlatMap") - .field("iter", &self.iter) - .field("frontiter", &self.frontiter) - .field("backiter", &self.backiter) - .finish() - } +/// An iterator that flattens one level of nesting in an iterator of things +/// that can be turned into iterators. +/// +/// This `struct` is created by the [`flatten`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`flatten`]: trait.Iterator.html#method.flatten +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +#[unstable(feature = "iterator_flatten", issue = "0")] +#[derive(Clone, Debug)] +pub struct Flatten { + iter: I, + frontiter: Option, + backiter: Option, } -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for FlatMap - where F: FnMut(I::Item) -> U, +#[unstable(feature = "iterator_flatten", issue = "0")] +impl Iterator for Flatten + where I::Item: IntoIterator { type Item = U::Item; @@ -2441,13 +2439,11 @@ impl Iterator for FlatMap fn next(&mut self) -> Option { loop { if let Some(ref mut inner) = self.frontiter { - if let Some(x) = inner.by_ref().next() { - return Some(x) - } + if let elt@Some(_) = inner.next() { return elt } } - match self.iter.next().map(&mut self.f) { + match self.iter.next() { None => return self.backiter.as_mut().and_then(|it| it.next()), - next => self.frontiter = next.map(IntoIterator::into_iter), + Some(inner) => self.frontiter = Some(inner.into_iter()), } } } @@ -2473,10 +2469,9 @@ impl Iterator for FlatMap self.frontiter = None; { - let f = &mut self.f; let frontiter = &mut self.frontiter; init = self.iter.try_fold(init, |acc, x| { - let mut mid = f(x).into_iter(); + let mut mid = x.into_iter(); let r = mid.try_fold(acc, &mut fold); *frontiter = Some(mid); r @@ -2497,27 +2492,24 @@ impl Iterator for FlatMap where Fold: FnMut(Acc, Self::Item) -> Acc, { self.frontiter.into_iter() - .chain(self.iter.map(self.f).map(U::into_iter)) + .chain(self.iter.map(IntoIterator::into_iter)) .chain(self.backiter) .fold(init, |acc, iter| iter.fold(acc, &mut fold)) } } -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for FlatMap where - F: FnMut(I::Item) -> U, - U: IntoIterator, - U::IntoIter: DoubleEndedIterator +#[unstable(feature = "iterator_flatten", issue = "0")] +impl DoubleEndedIterator for Flatten + where I: DoubleEndedIterator, U: DoubleEndedIterator, + I::Item: IntoIterator { #[inline] fn next_back(&mut self) -> Option { loop { if let Some(ref mut inner) = self.backiter { - if let Some(y) = inner.next_back() { - return Some(y) - } + if let elt@Some(_) = inner.next_back() { return elt } } - match self.iter.next_back().map(&mut self.f) { + match self.iter.next_back() { None => return self.frontiter.as_mut().and_then(|it| it.next_back()), next => self.backiter = next.map(IntoIterator::into_iter), } @@ -2534,10 +2526,9 @@ impl DoubleEndedIterator for FlatMap wher self.backiter = None; { - let f = &mut self.f; let backiter = &mut self.backiter; init = self.iter.try_rfold(init, |acc, x| { - let mut mid = f(x).into_iter(); + let mut mid = x.into_iter(); let r = mid.try_rfold(acc, &mut fold); *backiter = Some(mid); r @@ -2558,15 +2549,15 @@ impl DoubleEndedIterator for FlatMap wher where Fold: FnMut(Acc, Self::Item) -> Acc, { self.frontiter.into_iter() - .chain(self.iter.map(self.f).map(U::into_iter)) + .chain(self.iter.map(IntoIterator::into_iter)) .chain(self.backiter) .rfold(init, |acc, iter| iter.rfold(acc, &mut fold)) } } -#[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for FlatMap - where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {} +#[unstable(feature = "fused", issue = "0")] +impl FusedIterator for Flatten + where I::Item: IntoIterator {} /// An iterator that yields `None` forever after the underlying iterator /// yields `None` once. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index d2162d307e0..3dd30ee1c69 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -93,6 +93,7 @@ #![feature(doc_spotlight)] #![feature(rustc_const_unstable)] #![feature(iterator_repeat_with)] +#![feature(iterator_flatten)] #[prelude_import] #[allow(unused)] diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index f91c919d744..f28f5ef181c 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -836,6 +836,8 @@ fn test_iterator_scan() { assert_eq!(i, ys.len()); } +// Note: We test flatten() by testing flat_map(). + #[test] fn test_iterator_flat_map() { let xs = [0, 3, 6]; -- cgit 1.4.1-3-g733a5 From 36be763d0e5b0e6ceb7cbf55097427a269caec1a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 10 Feb 2018 07:22:46 +0100 Subject: Iterator::flatten: fix tracking issue number on FusedIterator for Flatten --- src/libcore/iter/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index bd801d2ae69..cd823d1028e 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -2555,7 +2555,7 @@ impl DoubleEndedIterator for Flatten } } -#[unstable(feature = "fused", issue = "0")] +#[unstable(feature = "fused", issue = "35602")] impl FusedIterator for Flatten where I::Item: IntoIterator {} -- cgit 1.4.1-3-g733a5 From 0e394010e6ad3d6fa68c9b8c651d4745348881cd Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 14 Feb 2018 00:58:14 +0100 Subject: core::iter::Flatten: update FlatMap & Flatten according to discussion --- src/libcore/iter/iterator.rs | 26 +++++-- src/libcore/iter/mod.rs | 178 ++++++++++++++++++++++++++++++++++++++++--- src/libcore/tests/iter.rs | 108 +++++++++++++++++++++++++- src/libcore/tests/lib.rs | 2 + 4 files changed, 294 insertions(+), 20 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 8ed3450dc3a..879696ba8e7 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -12,7 +12,8 @@ use cmp::Ordering; use ops::Try; use super::{AlwaysOk, LoopState}; -use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, Flatten, FlatMap, Fuse}; +use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, Fuse}; +use super::{Flatten, FlatMap, flatten_compat}; use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev}; use super::{Zip, Sum, Product}; use super::{ChainState, FromIterator, ZipImpl}; @@ -997,8 +998,8 @@ pub trait Iterator { /// an extra layer of indirection. `flat_map()` will remove this extra layer /// on its own. /// - /// You can think of [`flat_map(f)`][flat_map] as the equivalent of - /// [`map`]ping, and then [`flatten`]ing as in `map(f).flatten()`. + /// You can think of [`flat_map(f)`][flat_map] as the semantic equivalent + /// of [`map`]ping, and then [`flatten`]ing as in `map(f).flatten()`. /// /// Another way of thinking about `flat_map()`: [`map`]'s closure returns /// one item for each element, and `flat_map()`'s closure returns an @@ -1025,7 +1026,7 @@ pub trait Iterator { fn flat_map(self, f: F) -> FlatMap where Self: Sized, U: IntoIterator, F: FnMut(Self::Item) -> U, { - self.map(f).flatten() + FlatMap { inner: flatten_compat(self.map(f)) } } /// Creates an iterator that flattens nested structure. @@ -1060,11 +1061,24 @@ pub trait Iterator { /// .collect(); /// assert_eq!(merged, "alphabetagamma"); /// ``` + /// + /// You can also rewrite this in terms of [`flat_map()`] which is preferable + /// in this case since that conveys intent clearer: + /// + /// ``` + /// let words = ["alpha", "beta", "gamma"]; + /// + /// // chars() returns an iterator + /// let merged: String = words.iter() + /// .flat_map(|s| s.chars()) + /// .collect(); + /// assert_eq!(merged, "alphabetagamma"); + /// ``` #[inline] #[unstable(feature = "iterator_flatten", issue = "0")] - fn flatten(self) -> Flatten::IntoIter> + fn flatten(self) -> Flatten where Self: Sized, Self::Item: IntoIterator { - Flatten { iter: self, frontiter: None, backiter: None } + Flatten { inner: flatten_compat(self) } } /// Creates an iterator which ends after the first [`None`]. diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index cd823d1028e..e498f7d1b93 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -2403,14 +2403,87 @@ impl Iterator for Scan where /// An iterator that maps each element to an iterator, and yields the elements /// of the produced iterators. /// -/// This `type` is created by the [`flat_map`] method on [`Iterator`]. See its +/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its /// documentation for more. /// /// [`flat_map`]: trait.Iterator.html#method.flat_map /// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] -type FlatMap = Flatten, ::IntoIter>; +pub struct FlatMap { + inner: FlattenCompat, ::IntoIter> +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for FlatMap + where ::IntoIter: Clone +{ + fn clone(&self) -> Self { FlatMap { inner: self.inner.clone() } } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for FlatMap + where U::IntoIter: fmt::Debug +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("FlatMap").field("inner", &self.inner).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for FlatMap + where F: FnMut(I::Item) -> U, +{ + type Item = U::Item; + + #[inline] + fn next(&mut self) -> Option { self.inner.next() } + + #[inline] + fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + self.inner.try_fold(init, fold) + } + + #[inline] + fn fold(self, init: Acc, fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.inner.fold(init, fold) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for FlatMap + where F: FnMut(I::Item) -> U, + U: IntoIterator, + U::IntoIter: DoubleEndedIterator +{ + #[inline] + fn next_back(&mut self) -> Option { self.inner.next_back() } + + #[inline] + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + self.inner.try_rfold(init, fold) + } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.inner.rfold(init, fold) + } +} + +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for FlatMap + where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {} /// An iterator that flattens one level of nesting in an iterator of things /// that can be turned into iterators. @@ -2422,16 +2495,102 @@ type FlatMap = Flatten, ::IntoIter>; /// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[unstable(feature = "iterator_flatten", issue = "0")] +pub struct Flatten +where I::Item: IntoIterator { + inner: FlattenCompat::IntoIter>, +} + +#[unstable(feature = "iterator_flatten", issue = "0")] +impl fmt::Debug for Flatten + where I: Iterator + fmt::Debug, U: Iterator + fmt::Debug, + I::Item: IntoIterator, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Flatten").field("inner", &self.inner).finish() + } +} + +#[unstable(feature = "iterator_flatten", issue = "0")] +impl Clone for Flatten + where I: Iterator + Clone, U: Iterator + Clone, + I::Item: IntoIterator, +{ + fn clone(&self) -> Self { Flatten { inner: self.inner.clone() } } +} + +#[unstable(feature = "iterator_flatten", issue = "0")] +impl Iterator for Flatten + where I: Iterator, U: Iterator, + I::Item: IntoIterator +{ + type Item = U::Item; + + #[inline] + fn next(&mut self) -> Option { self.inner.next() } + + #[inline] + fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + self.inner.try_fold(init, fold) + } + + #[inline] + fn fold(self, init: Acc, fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.inner.fold(init, fold) + } +} + +#[unstable(feature = "iterator_flatten", issue = "0")] +impl DoubleEndedIterator for Flatten + where I: DoubleEndedIterator, U: DoubleEndedIterator, + I::Item: IntoIterator +{ + #[inline] + fn next_back(&mut self) -> Option { self.inner.next_back() } + + #[inline] + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + self.inner.try_rfold(init, fold) + } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.inner.rfold(init, fold) + } +} + +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for Flatten + where I: FusedIterator, U: Iterator, + I::Item: IntoIterator {} + +/// Adapts an iterator by flattening it, for use in `flatten()` and `flat_map()`. +fn flatten_compat(iter: I) -> FlattenCompat { + FlattenCompat { iter, frontiter: None, backiter: None } +} + +/// Real logic of both `Flatten` and `FlatMap` which simply delegate to +/// this type. #[derive(Clone, Debug)] -pub struct Flatten { +struct FlattenCompat { iter: I, frontiter: Option, backiter: Option, } -#[unstable(feature = "iterator_flatten", issue = "0")] -impl Iterator for Flatten - where I::Item: IntoIterator +impl Iterator for FlattenCompat + where I: Iterator, U: Iterator, + I::Item: IntoIterator { type Item = U::Item; @@ -2498,8 +2657,7 @@ impl Iterator for Flatten } } -#[unstable(feature = "iterator_flatten", issue = "0")] -impl DoubleEndedIterator for Flatten +impl DoubleEndedIterator for FlattenCompat where I: DoubleEndedIterator, U: DoubleEndedIterator, I::Item: IntoIterator { @@ -2555,10 +2713,6 @@ impl DoubleEndedIterator for Flatten } } -#[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for Flatten - where I::Item: IntoIterator {} - /// An iterator that yields `None` forever after the underlying iterator /// yields `None` once. /// diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index f28f5ef181c..edd75f7795e 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -836,8 +836,6 @@ fn test_iterator_scan() { assert_eq!(i, ys.len()); } -// Note: We test flatten() by testing flat_map(). - #[test] fn test_iterator_flat_map() { let xs = [0, 3, 6]; @@ -876,6 +874,44 @@ fn test_iterator_flat_map_fold() { assert_eq!(i, 0); } +#[test] +fn test_iterator_flatten() { + let xs = [0, 3, 6]; + let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let it = xs.iter().map(|&x| (x..).step_by(1).take(3)).flatten(); + let mut i = 0; + for x in it { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); +} + +/// Test `Flatten::fold` with items already picked off the front and back, +/// to make sure all parts of the `Flatten` are folded correctly. +#[test] +fn test_iterator_flatten_fold() { + let xs = [0, 3, 6]; + let ys = [1, 2, 3, 4, 5, 6, 7]; + let mut it = xs.iter().map(|&x| x..x+3).flatten(); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next_back(), Some(8)); + let i = it.fold(0, |i, x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); + + let mut it = xs.iter().map(|&x| x..x+3).flatten(); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next_back(), Some(8)); + let i = it.rfold(ys.len(), |i, x| { + assert_eq!(x, ys[i - 1]); + i - 1 + }); + assert_eq!(i, 0); +} + #[test] fn test_inspect() { let xs = [1, 2, 3, 4]; @@ -1289,6 +1325,23 @@ fn test_double_ended_flat_map() { assert_eq!(it.next_back(), None); } +#[test] +fn test_double_ended_flatten() { + let u = [0,1]; + let v = [5,6,7,8]; + let mut it = u.iter().map(|x| &v[*x..v.len()]).flatten(); + assert_eq!(it.next_back().unwrap(), &8); + assert_eq!(it.next().unwrap(), &5); + assert_eq!(it.next_back().unwrap(), &7); + assert_eq!(it.next_back().unwrap(), &6); + assert_eq!(it.next_back().unwrap(), &8); + assert_eq!(it.next().unwrap(), &6); + assert_eq!(it.next_back().unwrap(), &7); + assert_eq!(it.next_back(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next_back(), None); +} + #[test] fn test_double_ended_range() { assert_eq!((11..14).rev().collect::>(), [13, 12, 11]); @@ -1980,3 +2033,54 @@ fn test_flat_map_try_folds() { assert_eq!(iter.try_rfold(0, i8::checked_add), None); assert_eq!(iter.next_back(), Some(35)); } + +#[test] +fn test_flatten_try_folds() { + let f = &|acc, x| i32::checked_add(acc*2/3, x); + let mr = &|x| (5*x)..(5*x + 5); + assert_eq!((0..10).map(mr).flatten().try_fold(7, f), (0..50).try_fold(7, f)); + assert_eq!((0..10).map(mr).flatten().try_rfold(7, f), (0..50).try_rfold(7, f)); + let mut iter = (0..10).map(mr).flatten(); + iter.next(); iter.next_back(); // have front and back iters in progress + assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f)); + + let mut iter = (0..10).map(|x| (4*x)..(4*x + 4)).flatten(); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(17)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.next_back(), Some(35)); +} + +#[test] +fn test_functor_laws() { + // identity: + fn identity(x: T) -> T { x } + assert_eq!((0..10).map(identity).sum::(), (0..10).sum()); + + // composition: + fn f(x: usize) -> usize { x + 3 } + fn g(x: usize) -> usize { x * 2 } + fn h(x: usize) -> usize { g(f(x)) } + assert_eq!((0..10).map(f).map(g).sum::(), (0..10).map(h).sum()); +} + +#[test] +fn test_monad_laws_left_identity() { + fn f(x: usize) -> impl Iterator { + (0..10).map(move |y| x * y) + } + assert_eq!(once(42).flat_map(f.clone()).sum::(), f(42).sum()); +} + +#[test] +fn test_monad_laws_right_identity() { + assert_eq!((0..10).flat_map(|x| once(x)).sum::(), (0..10).sum()); +} + +#[test] +fn test_monad_laws_associativity() { + fn f(x: usize) -> impl Iterator { 0..x } + fn g(x: usize) -> impl Iterator { (0..x).rev() } + assert_eq!((0..10).flat_map(f).flat_map(g).sum::(), + (0..10).flat_map(|x| f(x).flat_map(g)).sum::()); +} diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 3e901a9d442..7954d52f6b1 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -25,6 +25,8 @@ #![feature(inclusive_range)] #![feature(inclusive_range_syntax)] #![feature(iterator_try_fold)] +#![feature(iterator_flatten)] +#![feature(conservative_impl_trait)] #![feature(iter_rfind)] #![feature(iter_rfold)] #![feature(iterator_repeat_with)] -- cgit 1.4.1-3-g733a5 From 3d74c74fa0761542353ee1a2f4a832e9ba9b5ac4 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 14 Feb 2018 17:31:23 +0100 Subject: core::iter::Iterator::flatten: tracking issue is #48213 --- src/libcore/iter/iterator.rs | 2 +- src/libcore/iter/mod.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 879696ba8e7..75a0e6aa2e6 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1075,7 +1075,7 @@ pub trait Iterator { /// assert_eq!(merged, "alphabetagamma"); /// ``` #[inline] - #[unstable(feature = "iterator_flatten", issue = "0")] + #[unstable(feature = "iterator_flatten", issue = "48213")] fn flatten(self) -> Flatten where Self: Sized, Self::Item: IntoIterator { Flatten { inner: flatten_compat(self) } diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index e498f7d1b93..623cad754dd 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -2494,13 +2494,13 @@ impl FusedIterator for FlatMap /// [`flatten`]: trait.Iterator.html#method.flatten /// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[unstable(feature = "iterator_flatten", issue = "0")] +#[unstable(feature = "iterator_flatten", issue = "48213")] pub struct Flatten where I::Item: IntoIterator { inner: FlattenCompat::IntoIter>, } -#[unstable(feature = "iterator_flatten", issue = "0")] +#[unstable(feature = "iterator_flatten", issue = "48213")] impl fmt::Debug for Flatten where I: Iterator + fmt::Debug, U: Iterator + fmt::Debug, I::Item: IntoIterator, @@ -2510,7 +2510,7 @@ impl fmt::Debug for Flatten } } -#[unstable(feature = "iterator_flatten", issue = "0")] +#[unstable(feature = "iterator_flatten", issue = "48213")] impl Clone for Flatten where I: Iterator + Clone, U: Iterator + Clone, I::Item: IntoIterator, @@ -2518,7 +2518,7 @@ impl Clone for Flatten fn clone(&self) -> Self { Flatten { inner: self.inner.clone() } } } -#[unstable(feature = "iterator_flatten", issue = "0")] +#[unstable(feature = "iterator_flatten", issue = "48213")] impl Iterator for Flatten where I: Iterator, U: Iterator, I::Item: IntoIterator @@ -2546,7 +2546,7 @@ impl Iterator for Flatten } } -#[unstable(feature = "iterator_flatten", issue = "0")] +#[unstable(feature = "iterator_flatten", issue = "48213")] impl DoubleEndedIterator for Flatten where I: DoubleEndedIterator, U: DoubleEndedIterator, I::Item: IntoIterator -- cgit 1.4.1-3-g733a5 From 819d57abc94d162e0d6f58fcbed757849f8305b4 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 16 Feb 2018 01:05:03 +0100 Subject: core::iter::Iterator::flatten: improve docs wrt. deep vs. shallow flatten per @clarcharr's review --- src/libcore/iter/iterator.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 75a0e6aa2e6..e68e0593852 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1074,6 +1074,26 @@ pub trait Iterator { /// .collect(); /// assert_eq!(merged, "alphabetagamma"); /// ``` + /// + /// Flattening once only removes one level of nesting: + /// + /// ``` + /// #![feature(iterator_flatten)] + /// + /// let d3 = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]; + /// + /// let d2 = d3.iter().flatten().collect::>(); + /// assert_eq!(d2, [&[1, 2], &[3, 4], &[5, 6], &[7, 8]]); + /// + /// let d1 = d3.iter().flatten().flatten().collect::>(); + /// assert_eq!(d1, [&1, &2, &3, &4, &5, &6, &7, &8]); + /// ``` + /// + /// Here we see that `flatten()` does not perform a "deep" flatten. + /// Instead, only one level of nesting is removed. That is, if you + /// `flatten()` a three-dimensional array the result will be + /// two-dimensional and not one-dimensional. To get a one-dimensional + /// structure, you have to `flatten()` again. #[inline] #[unstable(feature = "iterator_flatten", issue = "48213")] fn flatten(self) -> Flatten -- cgit 1.4.1-3-g733a5 From 33f5ceee1f2183b979aa0eccea7081ac7e43adfb Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sun, 18 Feb 2018 16:57:21 -0700 Subject: stage0 cfg cleanup --- src/libcore/any.rs | 26 -------------------------- src/librustc/lib.rs | 1 - src/librustc_const_eval/lib.rs | 1 - src/librustc_driver/lib.rs | 8 -------- src/librustc_metadata/lib.rs | 1 - src/librustc_mir/lib.rs | 1 - src/librustc_passes/lib.rs | 1 - src/librustc_plugin/lib.rs | 1 - src/librustc_privacy/lib.rs | 1 - src/librustc_resolve/lib.rs | 1 - src/librustc_trans/lib.rs | 2 -- src/librustc_trans_utils/lib.rs | 1 - src/librustc_typeck/lib.rs | 1 - src/librustdoc/Cargo.toml | 2 -- src/libstd/lib.rs | 1 - src/libsyntax/lib.rs | 1 - 16 files changed, 50 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 566bfe2a3fb..a6ba53087ac 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -349,31 +349,6 @@ pub struct TypeId { } impl TypeId { - /// Returns the `TypeId` of the type this generic function has been - /// instantiated with. - /// - /// # Examples - /// - /// ``` - /// use std::any::{Any, TypeId}; - /// - /// fn is_string(_s: &T) -> bool { - /// TypeId::of::() == TypeId::of::() - /// } - /// - /// fn main() { - /// assert_eq!(is_string(&0), false); - /// assert_eq!(is_string(&"cookie monster".to_string()), true); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - pub fn of() -> TypeId { - TypeId { - t: unsafe { intrinsics::type_id::() }, - } - } - /// Returns the `TypeId` of the type this generic function has been /// instantiated with. /// @@ -393,7 +368,6 @@ impl TypeId { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature="const_type_id")] - #[cfg(not(stage0))] pub const fn of() -> TypeId { TypeId { t: unsafe { intrinsics::type_id::() }, diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index a7a26195059..9520fa96856 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -179,5 +179,4 @@ fn noop() { // Build the diagnostics array at the end so that the metadata includes error use sites. -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc, DIAGNOSTICS } diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index b4563f6cf2e..9d636b48bd0 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -56,5 +56,4 @@ pub fn provide(providers: &mut Providers) { } // Build the diagnostics array at the end so that the metadata includes error use sites. -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_const_eval, DIAGNOSTICS } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 05dcaf73135..f872fd47546 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1478,14 +1478,6 @@ pub fn monitor(f: F) { } } -#[cfg(stage0)] -pub fn diagnostics_registry() -> errors::registry::Registry { - use errors::registry::Registry; - - Registry::new(&[]) -} - -#[cfg(not(stage0))] pub fn diagnostics_registry() -> errors::registry::Registry { use errors::registry::Registry; diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 33075e40432..2d015fa81f9 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -59,5 +59,4 @@ pub mod cstore; pub mod dynamic_lib; pub mod locator; -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_metadata, DIAGNOSTICS } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 1699ad0f19c..8c15d1cf8b0 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -79,5 +79,4 @@ pub fn provide(providers: &mut Providers) { providers.const_eval = interpret::const_eval_provider; } -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_mir, DIAGNOSTICS } diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 73c71ec0b2f..7db1f5665fb 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -44,7 +44,6 @@ pub mod loops; mod mir_stats; pub mod static_recursion; -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_passes, DIAGNOSTICS } pub fn provide(providers: &mut Providers) { diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs index 38df5986ce2..c0f830f1fbe 100644 --- a/src/librustc_plugin/lib.rs +++ b/src/librustc_plugin/lib.rs @@ -82,5 +82,4 @@ pub mod registry; pub mod load; pub mod build; -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_plugin, DIAGNOSTICS } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 6ae04760953..e9f970d886f 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1717,5 +1717,4 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Rc::new(visitor.access_levels) } -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_privacy, DIAGNOSTICS } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d8e03552a6a..a9ba278ea74 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -4183,5 +4183,4 @@ pub enum MakeGlobMap { No, } -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_resolve, DIAGNOSTICS } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 908d3790170..6c281ab5e7a 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -194,7 +194,6 @@ impl TransCrate for LlvmTransCrate { llvm_util::print_version(); } - #[cfg(not(stage0))] fn diagnostics(&self) -> &[(&'static str, &'static str)] { &DIAGNOSTICS } @@ -404,5 +403,4 @@ struct CrateInfo { used_crates_dynamic: Vec<(CrateNum, LibSource)>, } -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_trans, DIAGNOSTICS } diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index 9b7ab204492..bfecb201983 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -119,5 +119,4 @@ pub fn find_exported_symbols<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { }).collect() } -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_trans_utils, DIAGNOSTICS } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index bd7e200d620..af32738d9d0 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -383,5 +383,4 @@ pub fn hir_trait_to_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_trait: (principal, projections) } -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS } diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 09d0a0f610b..cfbb0a52b88 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -6,8 +6,6 @@ version = "0.0.0" [lib] name = "rustdoc" path = "lib.rs" -# SNAP/stage0(cargo) -doctest = false [dependencies] pulldown-cmark = { version = "0.1.0", default-features = false } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3c9004cdd19..854cefcb597 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -324,7 +324,6 @@ #![feature(doc_spotlight)] #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] -#![cfg_attr(stage0, feature(repr_align))] #![default_lib_allocator] diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 9181cca215c..14e39b5af42 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -152,5 +152,4 @@ pub mod ext { #[cfg(test)] mod test_snippet; -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { libsyntax, DIAGNOSTICS } -- cgit 1.4.1-3-g733a5 From a47fd3df89c267829d96748b3bdff305f20d27d5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 20 Feb 2018 13:49:54 -0500 Subject: make `#[unwind]` attribute specify expectations more clearly You can now choose between the following: - `#[unwind(allowed)]` - `#[unwind(aborts)]` Per rust-lang/rust#48251, the default is `#[unwind(allowed)]`, though I think we should change this eventually. --- src/libcore/panicking.rs | 3 ++- src/libpanic_unwind/gcc.rs | 3 ++- src/libpanic_unwind/lib.rs | 3 ++- src/libpanic_unwind/seh64_gnu.rs | 3 ++- src/libpanic_unwind/windows.rs | 9 +++++--- src/librustc_mir/build/mod.rs | 19 +++++++++++---- src/libstd/panicking.rs | 6 +++-- src/libsyntax/attr.rs | 45 ++++++++++++++++++++++++++++++++++++ src/libsyntax/diagnostic_list.rs | 27 ++++++++++++++++++++++ src/libsyntax/feature_gate.rs | 2 +- src/libunwind/libunwind.rs | 9 +++++--- src/test/codegen/extern-functions.rs | 2 +- src/test/run-pass/abort-on-c-abi.rs | 1 + 13 files changed, 113 insertions(+), 19 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 4170d91e5fc..94db0baa3f9 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -64,7 +64,8 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) #[allow(improper_ctypes)] extern { #[lang = "panic_fmt"] - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32, col: u32) -> !; } let (file, line, col) = *file_line_col; diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index 63e44f71a3a..ca2fd561cad 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -286,7 +286,8 @@ unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) // See docs in the `unwind` module. #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] #[lang = "eh_unwind_resume"] -#[unwind] +#[cfg_attr(stage0, unwind)] +#[cfg_attr(not(stage0), unwind(allowed))] unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! { uw::_Unwind_Resume(panic_ctx as *mut uw::_Unwind_Exception); } diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 92e40e8f26d..a5cebc3e4d0 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -112,7 +112,8 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8), // Entry point for raising an exception, just delegates to the platform-specific // implementation. #[no_mangle] -#[unwind] +#[cfg_attr(stage0, unwind)] +#[cfg_attr(not(stage0), unwind(allowed))] pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 { imp::panic(mem::transmute(raw::TraitObject { data: data as *mut (), diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs index 0a9fa7d9a80..090cd095380 100644 --- a/src/libpanic_unwind/seh64_gnu.rs +++ b/src/libpanic_unwind/seh64_gnu.rs @@ -108,7 +108,8 @@ unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut c::EXCEPTION_RECO } #[lang = "eh_unwind_resume"] -#[unwind] +#[cfg_attr(stage0, unwind)] +#[cfg_attr(not(stage0), unwind(allowed))] unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! { let params = [panic_ctx as c::ULONG_PTR]; c::RaiseException(RUST_PANIC, diff --git a/src/libpanic_unwind/windows.rs b/src/libpanic_unwind/windows.rs index a7e90071cea..50fba5faee7 100644 --- a/src/libpanic_unwind/windows.rs +++ b/src/libpanic_unwind/windows.rs @@ -79,18 +79,21 @@ pub enum EXCEPTION_DISPOSITION { pub use self::EXCEPTION_DISPOSITION::*; extern "system" { - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn RaiseException(dwExceptionCode: DWORD, dwExceptionFlags: DWORD, nNumberOfArguments: DWORD, lpArguments: *const ULONG_PTR); - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn RtlUnwindEx(TargetFrame: LPVOID, TargetIp: LPVOID, ExceptionRecord: *const EXCEPTION_RECORD, ReturnValue: LPVOID, OriginalContext: *const CONTEXT, HistoryTable: *const UNWIND_HISTORY_TABLE); - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8); } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 57059cd31a1..a325cfe3eaa 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -28,6 +28,7 @@ use std::mem; use std::u32; use syntax::abi::Abi; use syntax::ast; +use syntax::attr::{self, UnwindAttr}; use syntax::symbol::keywords; use syntax_pos::Span; use transform::MirSource; @@ -355,10 +356,9 @@ macro_rules! unpack { } fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - fn_id: ast::NodeId, + fn_def_id: DefId, abi: Abi) -> bool { - // Not callable from C, so we can safely unwind through these if abi == Abi::Rust || abi == Abi::RustCall { return false; } @@ -370,9 +370,17 @@ fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // This is a special case: some functions have a C abi but are meant to // unwind anyway. Don't stop them. - if tcx.has_attr(tcx.hir.local_def_id(fn_id), "unwind") { return false; } + let attrs = &tcx.get_attrs(fn_def_id); + match attr::find_unwind_attr(Some(tcx.sess.diagnostic()), attrs) { + None => { + // FIXME(rust-lang/rust#48251) -- Had to disable + // abort-on-panic for backwards compatibility reasons. + false + } - return true; + Some(UnwindAttr::Allowed) => false, + Some(UnwindAttr::Aborts) => true, + } } /////////////////////////////////////////////////////////////////////////// @@ -399,13 +407,14 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, safety, return_ty); + let fn_def_id = tcx.hir.local_def_id(fn_id); let call_site_scope = region::Scope::CallSite(body.value.hir_id.local_id); let arg_scope = region::Scope::Arguments(body.value.hir_id.local_id); let mut block = START_BLOCK; let source_info = builder.source_info(span); let call_site_s = (call_site_scope, source_info); unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, block, |builder| { - if should_abort_on_panic(tcx, fn_id, abi) { + if should_abort_on_panic(tcx, fn_def_id, abi) { builder.schedule_abort(); } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 161c3fc7113..454ac64735c 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -55,7 +55,8 @@ extern { data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32; - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] fn __rust_start_panic(data: usize, vtable: usize) -> u32; } @@ -315,7 +316,8 @@ pub fn panicking() -> bool { /// Entry point of panic from the libcore crate. #[cfg(not(test))] #[lang = "panic_fmt"] -#[unwind] +#[cfg_attr(stage0, unwind)] +#[cfg_attr(not(stage0), unwind(allowed))] pub extern fn rust_begin_panic(msg: fmt::Arguments, file: &'static str, line: u32, diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index d18d6f5e6bd..d0822b69aa6 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -565,6 +565,51 @@ pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> In }) } +#[derive(Copy, Clone, PartialEq)] +pub enum UnwindAttr { + Allowed, + Aborts, +} + +/// Determine what `#[unwind]` attribute is present in `attrs`, if any. +pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option { + let syntax_error = |attr: &Attribute| { + mark_used(attr); + diagnostic.map(|d| { + span_err!(d, attr.span, E0633, "malformed `#[unwind]` attribute"); + }); + None + }; + + attrs.iter().fold(None, |ia, attr| { + if attr.path != "unwind" { + return ia; + } + let meta = match attr.meta() { + Some(meta) => meta.node, + None => return ia, + }; + match meta { + MetaItemKind::Word => { + syntax_error(attr) + } + MetaItemKind::List(ref items) => { + mark_used(attr); + if items.len() != 1 { + syntax_error(attr) + } else if list_contains_name(&items[..], "allowed") { + Some(UnwindAttr::Allowed) + } else if list_contains_name(&items[..], "aborts") { + Some(UnwindAttr::Aborts) + } else { + syntax_error(attr) + } + } + _ => ia, + } + }) +} + /// True if `#[inline]` or `#[inline(always)]` is present in `attrs`. pub fn requests_inline(attrs: &[Attribute]) -> bool { match find_inline_attr(None, attrs) { diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index d841281e485..84ab0336f16 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -342,6 +342,33 @@ fn main() { ``` "##, +E0633: r##" +The `unwind` attribute was malformed. + +Erroneous code example: + +```ignore (compile_fail not working here; see Issue #43707) +#[unwind()] // error: expected one argument +pub extern fn something() {} + +fn main() {} +``` + +The `#[unwind]` attribute should be used as follows: + +- `#[unwind(aborts)]` -- specifies that if a non-Rust ABI function + should abort the process if it attempts to unwind. This is the safer + and preferred option. + +- `#[unwind(allowed)]` -- specifies that a non-Rust ABI function + should be allowed to unwind. This can easily result in Undefined + Behavior (UB), so be careful. + +NB. The default behavior here is "allowed", but this is unspecified +and likely to change in the future. + +"##, + } register_diagnostics! { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 3b137f9570a..f1d0a70a22c 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -233,7 +233,7 @@ declare_features! ( // allow `extern "platform-intrinsic" { ... }` (active, platform_intrinsics, "1.4.0", Some(27731)), - // allow `#[unwind]` + // allow `#[unwind(..)]` // rust runtime internal (active, unwind_attributes, "1.4.0", None), diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index e6fff7963f7..aa73b11fb38 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -83,7 +83,8 @@ pub enum _Unwind_Context {} pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception); extern "C" { - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !; pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception); pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void; @@ -220,7 +221,8 @@ if #[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))] { if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { // Not 32-bit iOS extern "C" { - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, trace_argument: *mut c_void) @@ -229,7 +231,8 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { } else { // 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace() extern "C" { - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code; } diff --git a/src/test/codegen/extern-functions.rs b/src/test/codegen/extern-functions.rs index 7ee31070b26..90ee0c75680 100644 --- a/src/test/codegen/extern-functions.rs +++ b/src/test/codegen/extern-functions.rs @@ -19,7 +19,7 @@ extern { fn extern_fn(); // CHECK-NOT: Function Attrs: nounwind // CHECK: declare void @unwinding_extern_fn - #[unwind] + #[unwind(allowed)] fn unwinding_extern_fn(); } diff --git a/src/test/run-pass/abort-on-c-abi.rs b/src/test/run-pass/abort-on-c-abi.rs index 17661c0b120..5039c334f26 100644 --- a/src/test/run-pass/abort-on-c-abi.rs +++ b/src/test/run-pass/abort-on-c-abi.rs @@ -19,6 +19,7 @@ use std::io::prelude::*; use std::io; use std::process::{Command, Stdio}; +#[unwind(aborts)] extern "C" fn panic_in_ffi() { panic!("Test"); } -- cgit 1.4.1-3-g733a5 From 7e51e7ddd62211834de76dfa2fe3e5d8927e9b12 Mon Sep 17 00:00:00 2001 From: Hidehito Yabuuchi Date: Wed, 21 Feb 2018 22:30:40 +0900 Subject: Take 2^5 as examples in document of pow() (fixes #48396) Current document takes 2^4, which is equal to 4^2. This example is not very helpful for those unfamiliar with math words in English and thus rely on example codes. --- src/libcore/num/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 560dcf295b2..43330b63f9b 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1209,7 +1209,7 @@ Basic usage: ``` ", $Feature, "let x: ", stringify!($SelfT), " = 2; // or any other integer type -assert_eq!(x.pow(4), 16);", +assert_eq!(x.pow(5), 32);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] @@ -2364,7 +2364,7 @@ assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $E Basic usage: ``` -", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(4), 16);", $EndFeature, " +", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(5), 32);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] -- cgit 1.4.1-3-g733a5 From 238bb38a948ddf3d782f8138b39868cb08356c91 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 22 Feb 2018 13:53:59 -0500 Subject: First version --- src/libcore/cell.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index ec0d1b704dc..75ed562ae54 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -10,10 +10,24 @@ //! Shareable mutable containers. //! +//! Rust memory safety is based on this rule: Given an object `T`, is only possible to +//! have one of the following: +//! +//! - Having several inmutable references (`&T`) to the object (also know as Aliasing). +//! - Having one mutable reference (`&mut T`) to the object (also know as Mutability). +//! +//! This is enforced by the Rust compiler. However, there are situations where this rule is not +//! flexible enough. Sometimes is required to have multiple references to an object and yet +//! mutate it. +//! +//! Shareable mutable containers exist to permit mutability in presence of aliasing in a +//! controlled manner. Both `Cell` and `RefCell` allows to do this in a single threaded +//! way. For multiple threads is possible to use `Mutex`, `RwLock` or `AtomicXXX`. +//! //! Values of the `Cell` and `RefCell` types may be mutated through shared references (i.e. //! the common `&T` type), whereas most Rust types can only be mutated through unique (`&mut T`) //! references. We say that `Cell` and `RefCell` provide 'interior mutability', in contrast -//! with typical Rust types that exhibit 'inherited mutability'. +//! with typical Rust types that exhibit 'inherited mutability'. //! //! Cell types come in two flavors: `Cell` and `RefCell`. `Cell` implements interior //! mutability by moving values in and out of the `Cell`. To use references instead of values, -- cgit 1.4.1-3-g733a5 From b1a6c8bdd3a76207eff76b004945bc2a13755eca Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Thu, 22 Feb 2018 19:53:44 -0500 Subject: Stabilize [T]::rotate_{left,right} https://github.com/rust-lang/rust/issues/41891 --- src/liballoc/benches/lib.rs | 1 - src/liballoc/lib.rs | 1 - src/liballoc/slice.rs | 20 +++----------------- src/liballoc/tests/lib.rs | 1 - src/libcore/slice/mod.rs | 4 ++-- src/libcore/tests/lib.rs | 1 - 6 files changed, 5 insertions(+), 23 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index 174628ccd07..2de0ffb4b26 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -13,7 +13,6 @@ #![feature(i128_type)] #![feature(rand)] #![feature(repr_simd)] -#![feature(slice_rotate)] #![feature(test)] extern crate rand; diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 5139e54b560..d250cfe1880 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -79,7 +79,6 @@ #![cfg_attr(test, feature(placement_in))] #![cfg_attr(not(test), feature(core_float))] #![cfg_attr(not(test), feature(exact_size_is_empty))] -#![cfg_attr(not(test), feature(slice_rotate))] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(rand, test))] #![feature(allow_internal_unstable)] diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 028983de556..dc40062ef13 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -1460,8 +1460,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_rotate)] - /// /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; /// a.rotate_left(2); /// assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']); @@ -1470,23 +1468,15 @@ impl [T] { /// Rotating a subslice: /// /// ``` - /// #![feature(slice_rotate)] - /// /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; /// a[1..5].rotate_left(1); /// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']); - /// ``` - #[unstable(feature = "slice_rotate", issue = "41891")] + /// ``` + #[stable(feature = "slice_rotate", since = "1.26.0")] pub fn rotate_left(&mut self, mid: usize) { core_slice::SliceExt::rotate_left(self, mid); } - #[unstable(feature = "slice_rotate", issue = "41891")] - #[rustc_deprecated(since = "", reason = "renamed to `rotate_left`")] - pub fn rotate(&mut self, mid: usize) { - core_slice::SliceExt::rotate_left(self, mid); - } - /// Rotates the slice in-place such that the first `self.len() - k` /// elements of the slice move to the end while the last `k` elements move /// to the front. After calling `rotate_right`, the element previously at @@ -1505,8 +1495,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_rotate)] - /// /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; /// a.rotate_right(2); /// assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']); @@ -1515,13 +1503,11 @@ impl [T] { /// Rotate a subslice: /// /// ``` - /// #![feature(slice_rotate)] - /// /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; /// a[1..5].rotate_right(1); /// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']); /// ``` - #[unstable(feature = "slice_rotate", issue = "41891")] + #[stable(feature = "slice_rotate", since = "1.26.0")] pub fn rotate_right(&mut self, k: usize) { core_slice::SliceExt::rotate_right(self, k); } diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 427a7adcbde..168dbb2ce9b 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -23,7 +23,6 @@ #![feature(pattern)] #![feature(placement_in_syntax)] #![feature(rand)] -#![feature(slice_rotate)] #![feature(splice)] #![feature(str_escape)] #![feature(string_retain)] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index ac390313a67..a43ed65907f 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -211,10 +211,10 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] fn ends_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq; - #[unstable(feature = "slice_rotate", issue = "41891")] + #[stable(feature = "slice_rotate", since = "1.26.0")] fn rotate_left(&mut self, mid: usize); - #[unstable(feature = "slice_rotate", issue = "41891")] + #[stable(feature = "slice_rotate", since = "1.26.0")] fn rotate_right(&mut self, k: usize); #[stable(feature = "clone_from_slice", since = "1.7.0")] diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 3e901a9d442..cb8bac10d2b 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -35,7 +35,6 @@ #![feature(refcell_replace_swap)] #![feature(sip_hash_13)] #![feature(slice_patterns)] -#![feature(slice_rotate)] #![feature(sort_internals)] #![feature(specialization)] #![feature(step_trait)] -- cgit 1.4.1-3-g733a5 From f9e049afc544e70dc595df67d878b52c098aaa9a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 23 Feb 2018 12:57:18 -0500 Subject: add info about sync --- src/libcore/cell.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 75ed562ae54..1067b6ff0c1 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -22,7 +22,9 @@ //! //! Shareable mutable containers exist to permit mutability in presence of aliasing in a //! controlled manner. Both `Cell` and `RefCell` allows to do this in a single threaded -//! way. For multiple threads is possible to use `Mutex`, `RwLock` or `AtomicXXX`. +//! way, you can mutate them using an inmutable reference. However, neither `Cell` nor +//! `RefCell` are thread safe (they do not implement `Sync`), if you need to do Aliasing and +//! Mutation between multiple threads is possible to use `Mutex`, `RwLock` or `AtomicXXX`. //! //! Values of the `Cell` and `RefCell` types may be mutated through shared references (i.e. //! the common `&T` type), whereas most Rust types can only be mutated through unique (`&mut T`) -- cgit 1.4.1-3-g733a5 From 58d1f839520b97ac06e48aeb49d814282b20056c Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 23 Feb 2018 13:00:26 -0500 Subject: remove redundant info --- src/libcore/cell.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 1067b6ff0c1..b3a7d20c4aa 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -17,19 +17,19 @@ //! - Having one mutable reference (`&mut T`) to the object (also know as Mutability). //! //! This is enforced by the Rust compiler. However, there are situations where this rule is not -//! flexible enough. Sometimes is required to have multiple references to an object and yet +//! flexible enough. Sometimes is required to have multiple references to an object and yet //! mutate it. //! //! Shareable mutable containers exist to permit mutability in presence of aliasing in a //! controlled manner. Both `Cell` and `RefCell` allows to do this in a single threaded -//! way, you can mutate them using an inmutable reference. However, neither `Cell` nor -//! `RefCell` are thread safe (they do not implement `Sync`), if you need to do Aliasing and -//! Mutation between multiple threads is possible to use `Mutex`, `RwLock` or `AtomicXXX`. +//! way. However, neither `Cell` nor `RefCell` are thread safe (they do not implement +//! `Sync`), if you need to do Aliasing and Mutation between multiple threads is possible to use +//! `Mutex`, `RwLock` or `AtomicXXX`. //! //! Values of the `Cell` and `RefCell` types may be mutated through shared references (i.e. //! the common `&T` type), whereas most Rust types can only be mutated through unique (`&mut T`) //! references. We say that `Cell` and `RefCell` provide 'interior mutability', in contrast -//! with typical Rust types that exhibit 'inherited mutability'. +//! with typical Rust types that exhibit 'inherited mutability'. //! //! Cell types come in two flavors: `Cell` and `RefCell`. `Cell` implements interior //! mutability by moving values in and out of the `Cell`. To use references instead of values, -- cgit 1.4.1-3-g733a5 From 43de01f97eeee13f9bf9f19b0b241e8368633d11 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 23 Feb 2018 15:12:28 -0500 Subject: cleaned trailing whitespaces --- src/libcore/cell.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index b3a7d20c4aa..6f0655f2033 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -20,9 +20,9 @@ //! flexible enough. Sometimes is required to have multiple references to an object and yet //! mutate it. //! -//! Shareable mutable containers exist to permit mutability in presence of aliasing in a +//! Shareable mutable containers exist to permit mutability in presence of aliasing in a //! controlled manner. Both `Cell` and `RefCell` allows to do this in a single threaded -//! way. However, neither `Cell` nor `RefCell` are thread safe (they do not implement +//! way. However, neither `Cell` nor `RefCell` are thread safe (they do not implement //! `Sync`), if you need to do Aliasing and Mutation between multiple threads is possible to use //! `Mutex`, `RwLock` or `AtomicXXX`. //! -- cgit 1.4.1-3-g733a5 From bbd64b256320013d02734504c744cd3c0b180ebf Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Sat, 24 Feb 2018 11:37:38 -0500 Subject: Slight modification to the as_ref example of std::option::Option A user in a reddit thread was confused by the name of the variable "num_as_int"; they thought the example was trying to convert the string "10" as if it were binary 2 by calling str::len(). In reality, the example is simply demonstrating how to take an immutable reference to the value of an Option. The confusion comes from the coincidence that the length of the string "10" is also its binary representation, and the implication from the variable names that a conversion was occuring ("num_as_str" to "num_as_int"). This PR changes the example number to 12 instead of 10, and changes the variable name from "num_as_int" to "num_length" to better communicate what the example is doing. The reddit thread: https://www.reddit.com/r/rust/comments/7zpvev/notyetawesome_rust_what_use_cases_would_you_like/dur39xw/ --- src/libcore/option.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/option.rs b/src/libcore/option.rs index b8fe28d0f0d..96b551d8704 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -233,10 +233,10 @@ impl Option { /// [`usize`]: ../../std/primitive.usize.html /// /// ``` - /// let num_as_str: Option = Some("10".to_string()); + /// let num_as_str: Option = Some("12".to_string()); /// // First, cast `Option` to `Option<&String>` with `as_ref`, /// // then consume *that* with `map`, leaving `num_as_str` on the stack. - /// let num_as_int: Option = num_as_str.as_ref().map(|n| n.len()); + /// let num_length: Option = num_as_str.as_ref().map(|n| n.len()); /// println!("still can print num_as_str: {:?}", num_as_str); /// ``` #[inline] -- cgit 1.4.1-3-g733a5 From ce3ad263ff085ac15016430de5f4abb154427433 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 24 Feb 2018 18:04:08 -0500 Subject: added link to sync containers --- src/libcore/cell.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 6f0655f2033..91074c18d77 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -24,7 +24,8 @@ //! controlled manner. Both `Cell` and `RefCell` allows to do this in a single threaded //! way. However, neither `Cell` nor `RefCell` are thread safe (they do not implement //! `Sync`), if you need to do Aliasing and Mutation between multiple threads is possible to use -//! `Mutex`, `RwLock` or `AtomicXXX`. +//! [`Mutex`](../sync/struct.Mutex.html), [`RwLock`](../sync/struct.RwLock.html) or +//! [`atomic`](../sync/atomic/index.html) types. //! //! Values of the `Cell` and `RefCell` types may be mutated through shared references (i.e. //! the common `&T` type), whereas most Rust types can only be mutated through unique (`&mut T`) -- cgit 1.4.1-3-g733a5 From 7ded7f764c2d590d0c3ad71b9ffbbcfaec2174fb Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 24 Feb 2018 18:06:01 -0500 Subject: corrected grammar errors --- src/libcore/cell.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 91074c18d77..858bdcbb721 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -10,17 +10,17 @@ //! Shareable mutable containers. //! -//! Rust memory safety is based on this rule: Given an object `T`, is only possible to +//! Rust memory safety is based on this rule: Given an object `T`, it is only possible to //! have one of the following: //! -//! - Having several inmutable references (`&T`) to the object (also know as Aliasing). +//! - Having several immutable references (`&T`) to the object (also know as Aliasing). //! - Having one mutable reference (`&mut T`) to the object (also know as Mutability). //! //! This is enforced by the Rust compiler. However, there are situations where this rule is not -//! flexible enough. Sometimes is required to have multiple references to an object and yet +//! flexible enough. Sometimes it is required to have multiple references to an object and yet //! mutate it. //! -//! Shareable mutable containers exist to permit mutability in presence of aliasing in a +//! Shareable mutable containers exist to permit mutability in the presence of aliasing in a //! controlled manner. Both `Cell` and `RefCell` allows to do this in a single threaded //! way. However, neither `Cell` nor `RefCell` are thread safe (they do not implement //! `Sync`), if you need to do Aliasing and Mutation between multiple threads is possible to use -- cgit 1.4.1-3-g733a5 From 64236092e5aa8fca2b9175df5a1192fd3d46e29b Mon Sep 17 00:00:00 2001 From: Nathan Ringo Date: Sat, 24 Feb 2018 23:48:51 -0600 Subject: Fixes docs for ASCII functions to no longer claim U+0021 is '@'. --- src/libcore/num/mod.rs | 2 +- src/libstd/ascii.rs | 2 +- src/libstd_unicode/char.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 43330b63f9b..7d5aa25016b 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2892,7 +2892,7 @@ impl u8 { } /// Checks if the value is an ASCII graphic character: - /// U+0021 '@' ... U+007E '~'. + /// U+0021 '!' ... U+007E '~'. /// /// # Examples /// diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 82e1a3447dc..430c9df396a 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -245,7 +245,7 @@ pub trait AsciiExt { fn is_ascii_punctuation(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII graphic character: - /// U+0021 '@' ... U+007E '~'. + /// U+0021 '!' ... U+007E '~'. /// For strings, true if all characters in the string are /// ASCII graphic characters. /// diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index b4be4a96911..844ff7a3c12 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -1332,7 +1332,7 @@ impl char { } /// Checks if the value is an ASCII graphic character: - /// U+0021 '@' ... U+007E '~'. + /// U+0021 '!' ... U+007E '~'. /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 397ce8a1aedd0734cbf9b7dfb36ea18fbe6a5d91 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 24 Feb 2018 22:43:30 -0500 Subject: fixed links --- src/libcore/cell.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 858bdcbb721..a946aca68d1 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -24,8 +24,8 @@ //! controlled manner. Both `Cell` and `RefCell` allows to do this in a single threaded //! way. However, neither `Cell` nor `RefCell` are thread safe (they do not implement //! `Sync`), if you need to do Aliasing and Mutation between multiple threads is possible to use -//! [`Mutex`](../sync/struct.Mutex.html), [`RwLock`](../sync/struct.RwLock.html) or -//! [`atomic`](../sync/atomic/index.html) types. +//! [`Mutex`](../../std/sync/struct.Mutex.html), [`RwLock`](../../std/sync/struct.RwLock.html) or +//! [`atomic`](../../core/sync/atomic/index.html) types. //! //! Values of the `Cell` and `RefCell` types may be mutated through shared references (i.e. //! the common `&T` type), whereas most Rust types can only be mutated through unique (`&mut T`) -- cgit 1.4.1-3-g733a5 From e8904f935ab45a033c61e2136674a080046fd733 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Sun, 25 Feb 2018 15:46:17 -0500 Subject: Change the example string to something arbitrary The choice of string is arbitrary, so all references to a number in the string were removed. The string is now the standard "Hello world!". --- src/libcore/option.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 96b551d8704..5c9fe860076 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -233,11 +233,12 @@ impl Option { /// [`usize`]: ../../std/primitive.usize.html /// /// ``` - /// let num_as_str: Option = Some("12".to_string()); + /// let text: Option = Some("Hello, world!".to_string()); /// // First, cast `Option` to `Option<&String>` with `as_ref`, - /// // then consume *that* with `map`, leaving `num_as_str` on the stack. - /// let num_length: Option = num_as_str.as_ref().map(|n| n.len()); - /// println!("still can print num_as_str: {:?}", num_as_str); + /// // then consume *that* with `map`, leaving `text` on the stack. + /// let text_length: Option = text.as_ref().map(|s| s.len()); + /// println!("text length: {}", text_length); + /// println!("still can print text: {:?}", text); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -- cgit 1.4.1-3-g733a5 From 9091584def3b566f24f8fbeac495e6dc87178be8 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 26 Feb 2018 11:14:40 -0500 Subject: some grammar corrections --- src/libcore/cell.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index a946aca68d1..37f301c5909 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -13,18 +13,19 @@ //! Rust memory safety is based on this rule: Given an object `T`, it is only possible to //! have one of the following: //! -//! - Having several immutable references (`&T`) to the object (also know as Aliasing). -//! - Having one mutable reference (`&mut T`) to the object (also know as Mutability). +//! - Having several immutable references (`&T`) to the object (also known as **aliasing**). +//! - Having one mutable reference (`&mut T`) to the object (also known as **mutability**). //! //! This is enforced by the Rust compiler. However, there are situations where this rule is not //! flexible enough. Sometimes it is required to have multiple references to an object and yet //! mutate it. //! -//! Shareable mutable containers exist to permit mutability in the presence of aliasing in a -//! controlled manner. Both `Cell` and `RefCell` allows to do this in a single threaded +//! Shareable mutable containers exist to permit mutability in a controlled manner, even in the +//! presence of aliasing. Both `Cell` and `RefCell` allows to do this in a single threaded //! way. However, neither `Cell` nor `RefCell` are thread safe (they do not implement -//! `Sync`), if you need to do Aliasing and Mutation between multiple threads is possible to use -//! [`Mutex`](../../std/sync/struct.Mutex.html), [`RwLock`](../../std/sync/struct.RwLock.html) or +//! `Sync`). If you need to do aliasing and mutation between multiple threads it is possible to +//! use [`Mutex`](../../std/sync/struct.Mutex.html), +//! [`RwLock`](../../std/sync/struct.RwLock.html) or //! [`atomic`](../../core/sync/atomic/index.html) types. //! //! Values of the `Cell` and `RefCell` types may be mutated through shared references (i.e. -- cgit 1.4.1-3-g733a5 From c689db2c463f42422ff4ee47e28ebeb2865951ba Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Mon, 26 Feb 2018 11:35:36 -0800 Subject: atomic: remove 'Atomic*' from Debug output --- src/libcore/sync/atomic.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 25827edee7d..8017055a5d9 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -990,9 +990,7 @@ macro_rules! atomic_int { #[$stable_debug] impl fmt::Debug for $atomic_type { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple(stringify!($atomic_type)) - .field(&self.load(Ordering::SeqCst)) - .finish() + fmt::Debug::fmt(&self.load(Ordering::SeqCst), f) } } @@ -1866,7 +1864,7 @@ pub fn compiler_fence(order: Ordering) { #[stable(feature = "atomic_debug", since = "1.3.0")] impl fmt::Debug for AtomicBool { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("AtomicBool").field(&self.load(Ordering::SeqCst)).finish() + fmt::Debug::fmt(&self.load(Ordering::SeqCst), f) } } @@ -1874,7 +1872,7 @@ impl fmt::Debug for AtomicBool { #[stable(feature = "atomic_debug", since = "1.3.0")] impl fmt::Debug for AtomicPtr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("AtomicPtr").field(&self.load(Ordering::SeqCst)).finish() + fmt::Debug::fmt(&self.load(Ordering::SeqCst), f) } } -- cgit 1.4.1-3-g733a5 From b7b3498ce86d025ed84b0daa9a28588190ac444a Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Mon, 26 Feb 2018 19:48:15 -0500 Subject: Fix doctest failure Tried to be fancy with print statements. --- src/libcore/option.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 5c9fe860076..2b77ba39122 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -237,7 +237,6 @@ impl Option { /// // First, cast `Option` to `Option<&String>` with `as_ref`, /// // then consume *that* with `map`, leaving `text` on the stack. /// let text_length: Option = text.as_ref().map(|s| s.len()); - /// println!("text length: {}", text_length); /// println!("still can print text: {:?}", text); /// ``` #[inline] -- cgit 1.4.1-3-g733a5 From f05d9679d708ccd1a6a643838bbf3a64ccf271bf Mon Sep 17 00:00:00 2001 From: Björn Steinbrink Date: Tue, 27 Feb 2018 14:20:13 +0100 Subject: Backport LLVM fixes for a JumpThreading / assume intrinsic bug --- src/libcore/slice/mod.rs | 24 +++++++++--------------- src/llvm | 2 +- 2 files changed, 10 insertions(+), 16 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index ac390313a67..aacbbd5058e 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1246,18 +1246,15 @@ macro_rules! iterator { { // The addition might panic on overflow // Use the len of the slice to hint optimizer to remove result index bounds check. - let _n = make_slice!(self.ptr, self.end).len(); + let n = make_slice!(self.ptr, self.end).len(); self.try_fold(0, move |i, x| { if predicate(x) { Err(i) } else { Ok(i + 1) } }).err() - // // FIXME(#48116/#45964): - // // This assume() causes misoptimization on LLVM 6. - // // Commented out until it is fixed again. - // .map(|i| { - // unsafe { assume(i < n) }; - // i - // }) + .map(|i| { + unsafe { assume(i < n) }; + i + }) } #[inline] @@ -1274,13 +1271,10 @@ macro_rules! iterator { if predicate(x) { Err(i) } else { Ok(i) } }).err() - // // FIXME(#48116/#45964): - // // This assume() causes misoptimization on LLVM 6. - // // Commented out until it is fixed again. - // .map(|i| { - // unsafe { assume(i < n) }; - // i - // }) + .map(|i| { + unsafe { assume(i < n) }; + i + }) } } diff --git a/src/llvm b/src/llvm index 9f81beaf326..5c6b7fea4a3 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 9f81beaf32608fbe1fe0f2a82f974e800e9d8c62 +Subproject commit 5c6b7fea4a302261f18b1cc6ea22b2a9eec2abd9 -- cgit 1.4.1-3-g733a5 From 273166e7655dc736f444de43505c3ddda5c742f7 Mon Sep 17 00:00:00 2001 From: Maxim Nazarenko Date: Tue, 27 Feb 2018 16:41:28 +0200 Subject: remove italic remove italic as per @GuillaumeGomez suggestion --- src/libcore/cell.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 6f91e743999..4a1d68efc99 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1164,8 +1164,8 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// The compiler makes optimizations based on the knowledge that `&T` is not mutably aliased or /// mutated, and that `&mut T` is unique. When building abstractions like `Cell`, `RefCell`, /// `Mutex`, etc, you need to turn these optimizations off. `UnsafeCell` is the only legal way -/// to do this. When `UnsafeCell` _itself_ is immutably aliased, it is still safe to obtain -/// a mutable reference to its _interior_ and/or to mutate the interior. However, it is up to +/// to do this. When `UnsafeCell` itself is immutably aliased, it is still safe to obtain +/// a mutable reference to its interior and/or to mutate the interior. However, it is up to /// the abstraction designer to ensure that no two mutable references obtained this way are active /// at the same time, there are no active immutable reference when a mutable reference is obtained /// from the cell, and that there are no active mutable references or mutations when an immutable -- cgit 1.4.1-3-g733a5 From f8ebb3f09fa98cf5583f6bd8d5677a1f4dd0941d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 27 Feb 2018 15:48:50 +0100 Subject: fix wording on panics in binary operators on RefCells" --- src/libcore/cell.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index e91b2c793c5..419ae96b94b 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -885,7 +885,7 @@ impl Default for RefCell { impl PartialEq for RefCell { /// # Panics /// - /// Panics if the value is currently mutably borrowed. + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn eq(&self, other: &RefCell) -> bool { *self.borrow() == *other.borrow() @@ -899,7 +899,7 @@ impl Eq for RefCell {} impl PartialOrd for RefCell { /// # Panics /// - /// Panics if the value is currently mutably borrowed. + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn partial_cmp(&self, other: &RefCell) -> Option { self.borrow().partial_cmp(&*other.borrow()) @@ -907,7 +907,7 @@ impl PartialOrd for RefCell { /// # Panics /// - /// Panics if the value is currently mutably borrowed. + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn lt(&self, other: &RefCell) -> bool { *self.borrow() < *other.borrow() @@ -915,7 +915,7 @@ impl PartialOrd for RefCell { /// # Panics /// - /// Panics if the value is currently mutably borrowed. + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn le(&self, other: &RefCell) -> bool { *self.borrow() <= *other.borrow() @@ -923,7 +923,7 @@ impl PartialOrd for RefCell { /// # Panics /// - /// Panics if the value is currently mutably borrowed. + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn gt(&self, other: &RefCell) -> bool { *self.borrow() > *other.borrow() @@ -931,7 +931,7 @@ impl PartialOrd for RefCell { /// # Panics /// - /// Panics if the value is currently mutably borrowed. + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn ge(&self, other: &RefCell) -> bool { *self.borrow() >= *other.borrow() @@ -942,7 +942,7 @@ impl PartialOrd for RefCell { impl Ord for RefCell { /// # Panics /// - /// Panics if the value is currently mutably borrowed. + /// Panics if the value in either `RefCell` is currently borrowed. #[inline] fn cmp(&self, other: &RefCell) -> Ordering { self.borrow().cmp(&*other.borrow()) -- cgit 1.4.1-3-g733a5 From 44be054a2acbeeb682d02a5f88ddedc0cb5c9bf2 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Tue, 27 Feb 2018 16:24:52 +0100 Subject: Further refinement of Borrow documentation. --- src/libcore/borrow.rs | 68 +++++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 32 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 1f692d019c3..c0f1989f879 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -17,36 +17,41 @@ /// In Rust, it is common to provide different representations of a type for /// different use cases. For instance, storage location and management for a /// value can be specifically chosen as appropriate for a particular use via -/// pointer types such as [`Box`] or [`Rc`] or one can opt into -/// concurrency via synchronization types such as [`Mutex`], avoiding the -/// associated cost when in parallel doesn’t happen. Beyond these generic +/// pointer types such as [`Box`] or [`Rc`]. Beyond these generic /// wrappers that can be used with any type, some types provide optional /// facets providing potentially costly functionality. An example for such a /// type is [`String`] which adds the ability to extend a string to the basic /// [`str`]. This requires keeping additional information unnecessary for a -/// simple, imutable string. +/// simple, immutable string. /// /// These types signal that they are a specialized representation of a basic /// type `T` by implementing `Borrow`. The method `borrow` provides a way -/// to convert a reference to the type into a reference to the underlying -/// basic type. +/// to convert a reference to the type into a reference to this basic type +/// `T`. /// -/// If a type implementing `Borrow` implements other traits also -/// implemented by `T`, these implementations behave identically if the trait -/// is concerned with the data rather than its representation. For instance, -/// the comparison traits such as `PartialEq` or `PartialOrd` must behave -/// identical for `T` and any type implemeting `Borrow`. +/// Further, when providing implementations for additional traits, it needs +/// to be considered whether they should behave identical to those of the +/// underlying type as a consequence of acting as a representation of that +/// underlying type. /// -/// When writing generic code, a use of `Borrow` should always be justified -/// by additional trait bounds, making it clear that the two types need to -/// behave identically in a certain context. If the code should merely be -/// able to operate on any type that can produce a reference to a given type, -/// you should use [`AsRef`] instead. +/// Generic code typically uses `Borrow` when it not only needs access +/// to a reference of the underlying type but relies on the identical +/// behavior of these additional trait implementations. These traits are +/// likely to appear as additional trait bounds. /// -/// The companion trait [`BorrowMut`] provides the same guarantees for -/// mutable references. +/// If generic code merely needs to work for all types that can +/// provide a reference to related type `T`, it is often better to use +/// [`AsRef`] as more types can safely implement it. /// -/// [`AsRef`]: ../../std/convert/trait.AsRef.html +/// If a type implementing `Borrow` also wishes to allow mutable access +/// to the underlying type `T`, it can do so by implementing the companion +/// trait [`BorrowMut`]. +/// +/// Note also that it is perfectly fine for a single type to have multiple +/// implementations of `Borrow` for different `T`s. In fact, a blanket +/// implementation lets every type be at least a borrow of itself. +/// +/// [`AsRef`]: ../../std/convert/trait.AsRef.html /// [`BorrowMut`]: trait.BorrowMut.html /// [`Box`]: ../../std/boxed/struct.Box.html /// [`Mutex`]: ../../std/sync/struct.Mutex.html @@ -111,7 +116,7 @@ /// data, called `Q` in the method signature above. It states that `K` is a /// representation of `Q` by requiring that `K: Borrow`. By additionally /// requiring `Q: Hash + Eq`, it demands that `K` and `Q` have -/// implementations of the `Hash` and `Eq` traits that procude identical +/// implementations of the `Hash` and `Eq` traits that produce identical /// results. /// /// The implementation of `get` relies in particular on identical @@ -124,15 +129,15 @@ /// type that wraps a string but compares ASCII letters ignoring their case: /// /// ``` -/// pub struct CIString(String); +/// pub struct CaseInsensitiveString(String); /// -/// impl PartialEq for CIString { +/// impl PartialEq for CaseInsensitiveString { /// fn eq(&self, other: &Self) -> bool { /// self.0.eq_ignore_ascii_case(&other.0) /// } /// } /// -/// impl Eq for CIString { } +/// impl Eq for CaseInsensitiveString { } /// ``` /// /// Because two equal values need to produce the same hash value, the @@ -140,8 +145,8 @@ /// /// ``` /// # use std::hash::{Hash, Hasher}; -/// # pub struct CIString(String); -/// impl Hash for CIString { +/// # pub struct CaseInsensitiveString(String); +/// impl Hash for CaseInsensitiveString { /// fn hash(&self, state: &mut H) { /// for c in self.0.as_bytes() { /// c.to_ascii_lowercase().hash(state) @@ -150,13 +155,12 @@ /// } /// ``` /// -/// Can `CIString` implement `Borrow`? It certainly can provide a -/// reference to a string slice via its contained owned string. But because -/// its `Hash` implementation differs, it cannot fulfill the guarantee for -/// `Borrow` that all common trait implementations must behave the same way -/// and must not, in fact, implement `Borrow`. If it wants to allow -/// others access to the underlying `str`, it can do that via `AsRef` -/// which doesn’t carry any such restrictions. +/// Can `CaseInsensitiveString` implement `Borrow`? It certainly can +/// provide a reference to a string slice via its contained owned string. +/// But because its `Hash` implementation differs, it behaves differently +/// from `str` and therefore must not, in fact, implement `Borrow`. +/// If it wants to allow others access to the underlying `str`, it can do +/// that via `AsRef` which doesn’t carry any extra requirements. /// /// [`Hash`]: ../../std/hash/trait.Hash.html /// [`HashMap`]: ../../std/collections/struct.HashMap.html -- cgit 1.4.1-3-g733a5 From d9b8724a8072d51c014d2d8c6852e5a398c757d3 Mon Sep 17 00:00:00 2001 From: Maxim Nazarenko Date: Tue, 27 Feb 2018 23:21:04 +0200 Subject: style fix --- src/libcore/cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 4a1d68efc99..01e618421cc 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1172,7 +1172,7 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// reference is obtained. This is often done via runtime checks. /// /// Note that while mutating or mutably aliasing the contents of an `& UnsafeCell` is -/// okay (provided you enforce the invariants some other way); it is still undefined behavior +/// okay (provided you enforce the invariants some other way), it is still undefined behavior /// to have multiple `&mut UnsafeCell` aliases. /// /// -- cgit 1.4.1-3-g733a5 From 50f5ea919231b41b7d8ccb1023b4dc0fd6e6730d Mon Sep 17 00:00:00 2001 From: Maxim Nazarenko Date: Tue, 27 Feb 2018 23:23:19 +0200 Subject: Simplify Merge three rules into one following @cramertj --- src/libcore/cell.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 01e618421cc..b57667df991 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1165,11 +1165,15 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// mutated, and that `&mut T` is unique. When building abstractions like `Cell`, `RefCell`, /// `Mutex`, etc, you need to turn these optimizations off. `UnsafeCell` is the only legal way /// to do this. When `UnsafeCell` itself is immutably aliased, it is still safe to obtain -/// a mutable reference to its interior and/or to mutate the interior. However, it is up to -/// the abstraction designer to ensure that no two mutable references obtained this way are active -/// at the same time, there are no active immutable reference when a mutable reference is obtained -/// from the cell, and that there are no active mutable references or mutations when an immutable -/// reference is obtained. This is often done via runtime checks. +/// a mutable reference to its interior and/or to mutate the interior. However, the abstraction +/// designer must ensure that any active mutable references to the interior obtained this way does +/// not co-exist with other active references to the interior, either mutable or not. This is often +/// done via runtime checks. Naturally, several active immutable references to the interior can +/// co-exits with each other (but not with a mutable reference). +/// +/// To put it in other words, if a mutable reference to the contents is active, no other references +/// can be active at the same time, and if an immutable reference to the contents is active, then +/// only other immutable reference may be active. /// /// Note that while mutating or mutably aliasing the contents of an `& UnsafeCell` is /// okay (provided you enforce the invariants some other way), it is still undefined behavior -- cgit 1.4.1-3-g733a5 From ff6754c68ec293d46eb294f3b7efeca8300b2251 Mon Sep 17 00:00:00 2001 From: Maxim Nazarenko Date: Tue, 27 Feb 2018 23:34:38 +0200 Subject: fix tidy checks --- src/libcore/cell.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index b57667df991..6f18b8466a6 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1166,12 +1166,12 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// `Mutex`, etc, you need to turn these optimizations off. `UnsafeCell` is the only legal way /// to do this. When `UnsafeCell` itself is immutably aliased, it is still safe to obtain /// a mutable reference to its interior and/or to mutate the interior. However, the abstraction -/// designer must ensure that any active mutable references to the interior obtained this way does -/// not co-exist with other active references to the interior, either mutable or not. This is often +/// designer must ensure that any active mutable references to the interior obtained this way does +/// not co-exist with other active references to the interior, either mutable or not. This is often /// done via runtime checks. Naturally, several active immutable references to the interior can /// co-exits with each other (but not with a mutable reference). /// -/// To put it in other words, if a mutable reference to the contents is active, no other references +/// To put it in other words, if a mutable reference to the contents is active, no other references /// can be active at the same time, and if an immutable reference to the contents is active, then /// only other immutable reference may be active. /// -- cgit 1.4.1-3-g733a5 From 78789add6c4ab8a4b81e717803be63c384438595 Mon Sep 17 00:00:00 2001 From: Maxim Nazarenko Date: Tue, 27 Feb 2018 23:52:47 +0200 Subject: and some more tidy checks --- src/libcore/cell.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 6f18b8466a6..8accbc204c1 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1168,12 +1168,12 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// a mutable reference to its interior and/or to mutate the interior. However, the abstraction /// designer must ensure that any active mutable references to the interior obtained this way does /// not co-exist with other active references to the interior, either mutable or not. This is often -/// done via runtime checks. Naturally, several active immutable references to the interior can +/// done via runtime checks. Naturally, several active immutable references to the interior can /// co-exits with each other (but not with a mutable reference). /// /// To put it in other words, if a mutable reference to the contents is active, no other references /// can be active at the same time, and if an immutable reference to the contents is active, then -/// only other immutable reference may be active. +/// only other immutable reference may be active. /// /// Note that while mutating or mutably aliasing the contents of an `& UnsafeCell` is /// okay (provided you enforce the invariants some other way), it is still undefined behavior -- cgit 1.4.1-3-g733a5 From db6a5ee1aa57ec5f1d41b8a2a8519b7ee7d3598f Mon Sep 17 00:00:00 2001 From: Alexander Ronald Altman Date: Tue, 27 Feb 2018 23:57:47 -0600 Subject: Minor grammatical/style fix in docs. --- src/libcore/iter/iterator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 9d8a71250f8..b06534c9c1e 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1062,8 +1062,8 @@ pub trait Iterator { /// assert_eq!(merged, "alphabetagamma"); /// ``` /// - /// You can also rewrite this in terms of [`flat_map()`] which is preferable - /// in this case since that conveys intent clearer: + /// You can also rewrite this in terms of [`flat_map()`], which is preferable + /// in this case since it conveys intent more clearly: /// /// ``` /// let words = ["alpha", "beta", "gamma"]; -- cgit 1.4.1-3-g733a5 From 02e021b6d4e1ae779dc538404a4fa0c54ed5f7ed Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 7 Apr 2016 18:16:40 +0100 Subject: Add bitreverse intrinsic --- src/libcore/intrinsics.rs | 4 ++++ src/librustc_trans/context.rs | 6 ++++++ src/librustc_trans/intrinsic.rs | 8 ++++++-- src/librustc_typeck/check/intrinsic.rs | 3 ++- src/test/run-pass/intrinsics-integer.rs | 10 ++++++++++ 5 files changed, 28 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index a05d67a304f..830ebad0654 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1292,6 +1292,10 @@ extern "rust-intrinsic" { /// Reverses the bytes in an integer type `T`. pub fn bswap(x: T) -> T; + /// Reverses the bits in an integer type `T`. + #[cfg(not(stage0))] + pub fn bitreverse(x: T) -> T; + /// Performs checked integer addition. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_add` method. For example, diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index a285e5f263a..b93e8c2ad21 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -597,6 +597,12 @@ fn declare_intrinsic(cx: &CodegenCx, key: &str) -> Option { ifn!("llvm.bswap.i64", fn(t_i64) -> t_i64); ifn!("llvm.bswap.i128", fn(t_i128) -> t_i128); + ifn!("llvm.bitreverse.i8", fn(t_i8) -> t_i8); + ifn!("llvm.bitreverse.i16", fn(t_i16) -> t_i16); + ifn!("llvm.bitreverse.i32", fn(t_i32) -> t_i32); + ifn!("llvm.bitreverse.i64", fn(t_i64) -> t_i64); + ifn!("llvm.bitreverse.i128", fn(t_i128) -> t_i128); + ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index b1f1fb52c90..3f87ce7e047 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -287,8 +287,8 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, ], None) }, "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" | - "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" | - "overflowing_add" | "overflowing_sub" | "overflowing_mul" | + "bitreverse" | "add_with_overflow" | "sub_with_overflow" | + "mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" | "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" => { let ty = arg_tys[0]; match int_type_width_signed(ty, cx) { @@ -315,6 +315,10 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, &[args[0].immediate()], None) } } + "bitreverse" => { + bx.call(cx.get_intrinsic(&format!("llvm.bitreverse.i{}", width)), + &[args[0].immediate()], None) + } "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => { let intrinsic = format!("llvm.{}{}.with.overflow.i{}", if signed { 's' } else { 'u' }, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 23243c3ad66..2e00040d99a 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -275,7 +275,8 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "volatile_store" => (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil()), - "ctpop" | "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "bswap" => + "ctpop" | "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | + "bswap" | "bitreverse" => (1, vec![param(0)], param(0)), "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs index 4896f02da20..6e0712f6767 100644 --- a/src/test/run-pass/intrinsics-integer.rs +++ b/src/test/run-pass/intrinsics-integer.rs @@ -18,6 +18,7 @@ mod rusti { pub fn cttz(x: T) -> T; pub fn cttz_nonzero(x: T) -> T; pub fn bswap(x: T) -> T; + pub fn bitreverse(x: T) -> T; } } @@ -138,5 +139,14 @@ pub fn main() { assert_eq!(bswap(0x0ABBCC0Di32), 0x0DCCBB0A); assert_eq!(bswap(0x0122334455667708u64), 0x0877665544332201); assert_eq!(bswap(0x0122334455667708i64), 0x0877665544332201); + + assert_eq!(bitreverse(0x0Au8), 0x50); + assert_eq!(bitreverse(0x0Ai8), 0x50); + assert_eq!(bitreverse(0x0A0Cu16), 0x3050); + assert_eq!(bitreverse(0x0A0Ci16), 0x3050); + assert_eq!(bitreverse(0x0ABBCC0Eu32), 0x7033DD50); + assert_eq!(bitreverse(0x0ABBCC0Ei32), 0x7033DD50); + assert_eq!(bitreverse(0x0122334455667708u64), 0x10EE66AA22CC4480); + assert_eq!(bitreverse(0x0122334455667708i64), 0x10EE66AA22CC4480); } } -- cgit 1.4.1-3-g733a5 From df8dd3fd3ef2080c01360db38de610c13db1766e Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Wed, 28 Feb 2018 22:27:47 +0200 Subject: doc: no need for the references Also: - apply some rustfmt love - fix output of one example --- src/libcore/iter/iterator.rs | 53 ++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 31 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 9d8a71250f8..722e50fe0f4 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1180,19 +1180,19 @@ pub trait Iterator { /// /// // this iterator sequence is complex. /// let sum = a.iter() - /// .cloned() - /// .filter(|&x| x % 2 == 0) - /// .fold(0, |sum, i| sum + i); + /// .cloned() + /// .filter(|x| x % 2 == 0) + /// .fold(0, |sum, i| sum + i); /// /// println!("{}", sum); /// /// // let's add some inspect() calls to investigate what's happening /// let sum = a.iter() - /// .cloned() - /// .inspect(|x| println!("about to filter: {}", x)) - /// .filter(|&x| x % 2 == 0) - /// .inspect(|x| println!("made it through filter: {}", x)) - /// .fold(0, |sum, i| sum + i); + /// .cloned() + /// .inspect(|x| println!("about to filter: {}", x)) + /// .filter(|x| x % 2 == 0) + /// .inspect(|x| println!("made it through filter: {}", x)) + /// .fold(0, |sum, i| sum + i); /// /// println!("{}", sum); /// ``` @@ -1200,6 +1200,7 @@ pub trait Iterator { /// This will print: /// /// ```text + /// 6 /// about to filter: 1 /// about to filter: 4 /// made it through filter: 4 @@ -1230,8 +1231,7 @@ pub trait Iterator { /// /// let iter = a.into_iter(); /// - /// let sum: i32 = iter.take(5) - /// .fold(0, |acc, &i| acc + i ); + /// let sum: i32 = iter.take(5).fold(0, |acc, i| acc + i ); /// /// assert_eq!(sum, 6); /// @@ -1245,9 +1245,7 @@ pub trait Iterator { /// let mut iter = a.into_iter(); /// /// // instead, we add in a .by_ref() - /// let sum: i32 = iter.by_ref() - /// .take(2) - /// .fold(0, |acc, &i| acc + i ); + /// let sum: i32 = iter.by_ref().take(2).fold(0, |acc, i| acc + i ); /// /// assert_eq!(sum, 3); /// @@ -1304,9 +1302,7 @@ pub trait Iterator { /// /// let a = [1, 2, 3]; /// - /// let doubled: VecDeque = a.iter() - /// .map(|&x| x * 2) - /// .collect(); + /// let doubled: VecDeque = a.iter().map(|&x| x * 2).collect(); /// /// assert_eq!(2, doubled[0]); /// assert_eq!(4, doubled[1]); @@ -1318,9 +1314,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let doubled = a.iter() - /// .map(|&x| x * 2) - /// .collect::>(); + /// let doubled = a.iter().map(|x| x * 2).collect::>(); /// /// assert_eq!(vec![2, 4, 6], doubled); /// ``` @@ -1331,9 +1325,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let doubled = a.iter() - /// .map(|&x| x * 2) - /// .collect::>(); + /// let doubled = a.iter().map(|x| x * 2).collect::>(); /// /// assert_eq!(vec![2, 4, 6], doubled); /// ``` @@ -1344,9 +1336,9 @@ pub trait Iterator { /// let chars = ['g', 'd', 'k', 'k', 'n']; /// /// let hello: String = chars.iter() - /// .map(|&x| x as u8) - /// .map(|x| (x + 1) as char) - /// .collect(); + /// .map(|&x| x as u8) + /// .map(|x| (x + 1) as char) + /// .collect(); /// /// assert_eq!("hello", hello); /// ``` @@ -1393,8 +1385,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let (even, odd): (Vec, Vec) = a.into_iter() - /// .partition(|&n| n % 2 == 0); + /// let (even, odd): (Vec, Vec) = a + /// .into_iter() + /// .partition(|&n| n % 2 == 0); /// /// assert_eq!(even, vec![2]); /// assert_eq!(odd, vec![1, 3]); @@ -1457,8 +1450,7 @@ pub trait Iterator { /// let a = [1, 2, 3]; /// /// // the checked sum of all of the elements of the array - /// let sum = a.iter() - /// .try_fold(0i8, |acc, &x| acc.checked_add(x)); + /// let sum = a.iter().try_fold(0i8, |acc, &x| acc.checked_add(x)); /// /// assert_eq!(sum, Some(6)); /// ``` @@ -1556,8 +1548,7 @@ pub trait Iterator { /// let a = [1, 2, 3]; /// /// // the sum of all of the elements of the array - /// let sum = a.iter() - /// .fold(0, |acc, &x| acc + x); + /// let sum = a.iter().fold(0, |acc, x| acc + x); /// /// assert_eq!(sum, 6); /// ``` -- cgit 1.4.1-3-g733a5 From 25b69c4ede107c646f633ede0e6c87f46a6e0fa2 Mon Sep 17 00:00:00 2001 From: M Farkas-Dyck Date: Wed, 28 Feb 2018 21:00:48 -0800 Subject: impl Default + Hash for ::core::cmp::Reverse --- src/libcore/cmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index e6759d1bad9..b9847044982 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -343,7 +343,7 @@ impl Ordering { /// v.sort_by_key(|&num| (num > 3, Reverse(num))); /// assert_eq!(v, vec![3, 2, 1, 6, 5, 4]); /// ``` -#[derive(PartialEq, Eq, Debug, Copy, Clone)] +#[derive(PartialEq, Eq, Debug, Copy, Clone, Default, Hash)] #[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub struct Reverse(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T); -- cgit 1.4.1-3-g733a5 From 70d5a4600b21451aa98b447cd59384d86e2eadce Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 1 Mar 2018 01:57:25 -0800 Subject: Specialize Zip::nth for TrustedRandomAccess Makes the bench asked about on URLO 58x faster :) --- src/libcore/benches/iter.rs | 29 +++++++++++++++++++++++++++++ src/libcore/iter/mod.rs | 38 ++++++++++++++++++++++++++++++++++++++ src/libcore/tests/iter.rs | 17 +++++++++++++++++ 3 files changed, 84 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/benches/iter.rs b/src/libcore/benches/iter.rs index b284d855c45..6c597301ac2 100644 --- a/src/libcore/benches/iter.rs +++ b/src/libcore/benches/iter.rs @@ -281,3 +281,32 @@ bench_sums! { bench_take_while_chain_ref_sum, (0i64..1000000).chain(1000000..).take_while(|&x| x < 1111111) } + +// Checks whether Skip> is as fast as Zip, Skip>, from +// https://users.rust-lang.org/t/performance-difference-between-iterator-zip-and-skip-order/15743 +#[bench] +fn bench_zip_then_skip(b: &mut Bencher) { + let v: Vec<_> = (0..100_000).collect(); + let t: Vec<_> = (0..100_000).collect(); + + b.iter(|| { + let s = v.iter().zip(t.iter()).skip(10000) + .take_while(|t| *t.0 < 10100) + .map(|(a, b)| *a + *b) + .sum::(); + assert_eq!(s, 2009900); + }); +} +#[bench] +fn bench_skip_then_zip(b: &mut Bencher) { + let v: Vec<_> = (0..100_000).collect(); + let t: Vec<_> = (0..100_000).collect(); + + b.iter(|| { + let s = v.iter().skip(10000).zip(t.iter().skip(10000)) + .take_while(|t| *t.0 < 10100) + .map(|(a, b)| *a + *b) + .sum::(); + assert_eq!(s, 2009900); + }); +} diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 623cad754dd..533ff388b76 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -1045,6 +1045,11 @@ impl Iterator for Zip where A: Iterator, B: Iterator fn size_hint(&self) -> (usize, Option) { ZipImpl::size_hint(self) } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + ZipImpl::nth(self, n) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1065,6 +1070,14 @@ trait ZipImpl { fn new(a: A, b: B) -> Self; fn next(&mut self) -> Option; fn size_hint(&self) -> (usize, Option); + fn nth(&mut self, n: usize) -> Option; + fn super_nth(&mut self, mut n: usize) -> Option { + while let Some(x) = self.next() { + if n == 0 { return Some(x) } + n -= 1; + } + None + } fn next_back(&mut self) -> Option where A: DoubleEndedIterator + ExactSizeIterator, B: DoubleEndedIterator + ExactSizeIterator; @@ -1094,6 +1107,12 @@ impl ZipImpl for Zip }) } + #[inline] + default fn nth(&mut self, n: usize) -> Option + { + self.super_nth(n) + } + #[inline] default fn next_back(&mut self) -> Option<(A::Item, B::Item)> where A: DoubleEndedIterator + ExactSizeIterator, @@ -1174,6 +1193,25 @@ impl ZipImpl for Zip (len, Some(len)) } + #[inline] + fn nth(&mut self, n: usize) -> Option + { + let delta = cmp::min(n, self.len - self.index); + let end = self.index + delta; + while self.index < end { + let i = self.index; + self.index += 1; + if A::may_have_side_effect() { + unsafe { self.a.get_unchecked(i); } + } + if B::may_have_side_effect() { + unsafe { self.b.get_unchecked(i); } + } + } + + self.super_nth(n - delta) + } + #[inline] fn next_back(&mut self) -> Option<(A::Item, B::Item)> where A: DoubleEndedIterator + ExactSizeIterator, diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index edd75f7795e..5e2fef95d26 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -144,6 +144,23 @@ fn test_iterator_chain_find() { assert_eq!(iter.next(), None); } +#[test] +fn test_zip_nth() { + let xs = [0, 1, 2, 4, 5]; + let ys = [10, 11, 12]; + + let mut it = xs.iter().zip(&ys); + assert_eq!(it.nth(0), Some((&0, &10))); + assert_eq!(it.nth(1), Some((&2, &12))); + assert_eq!(it.nth(0), None); + + let mut it = xs.iter().zip(&ys); + assert_eq!(it.nth(3), None); + + let mut it = ys.iter().zip(&xs); + assert_eq!(it.nth(3), None); +} + #[test] fn test_iterator_step_by() { // Identity -- cgit 1.4.1-3-g733a5 From 11fefeb61c959c6a964120036992aed34f9d4282 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 1 Mar 2018 02:17:50 -0800 Subject: Add a Zip::nth test for side effects --- src/libcore/tests/iter.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 5e2fef95d26..a962efadd64 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -161,6 +161,26 @@ fn test_zip_nth() { assert_eq!(it.nth(3), None); } +#[test] +fn test_zip_nth_side_effects() { + let mut a = Vec::new(); + let mut b = Vec::new(); + let value = [1, 2, 3, 4, 5, 6].iter().cloned() + .map(|n| { + a.push(n); + n * 10 + }) + .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| { + b.push(n * 100); + n * 1000 + })) + .skip(1) + .nth(3); + assert_eq!(value, Some((50, 6000))); + assert_eq!(a, vec![1, 2, 3, 4, 5]); + assert_eq!(b, vec![200, 300, 400, 500, 600]); +} + #[test] fn test_iterator_step_by() { // Identity -- cgit 1.4.1-3-g733a5 From 5105fc1681bb5be631850a6ae699dd97f929dd76 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 1 Mar 2018 02:29:46 -0800 Subject: Fix braces --- src/libcore/iter/mod.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 533ff388b76..257d7d6caaa 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -1108,8 +1108,7 @@ impl ZipImpl for Zip } #[inline] - default fn nth(&mut self, n: usize) -> Option - { + default fn nth(&mut self, n: usize) -> Option { self.super_nth(n) } @@ -1194,8 +1193,7 @@ impl ZipImpl for Zip } #[inline] - fn nth(&mut self, n: usize) -> Option - { + fn nth(&mut self, n: usize) -> Option { let delta = cmp::min(n, self.len - self.index); let end = self.index + delta; while self.index < end { -- cgit 1.4.1-3-g733a5 From f7693c06338c825d0d49eb1373e2039416b38389 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Wed, 21 Feb 2018 16:12:23 +0100 Subject: Fix spelling s/casted/cast/ --- src/libcore/char.rs | 4 ++-- src/librustc_lint/types.rs | 2 +- src/libsyntax/parse/parser.rs | 2 +- src/test/run-pass/extern-types-pointer-cast.rs | 2 +- src/test/ui/cast_char.rs | 4 ++-- src/test/ui/cast_char.stderr | 4 ++-- src/test/ui/issue-22644.stderr | 16 ++++++++-------- src/test/ui/issue-42954.stderr | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 7215bd2a476..55d4b590f91 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -79,7 +79,7 @@ pub const MAX: char = '\u{10ffff}'; /// Converts a `u32` to a `char`. /// -/// Note that all [`char`]s are valid [`u32`]s, and can be casted to one with +/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with /// [`as`]: /// /// ``` @@ -131,7 +131,7 @@ pub fn from_u32(i: u32) -> Option { /// Converts a `u32` to a `char`, ignoring validity. /// -/// Note that all [`char`]s are valid [`u32`]s, and can be casted to one with +/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with /// [`as`]: /// /// ``` diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index f734f3182a9..2207bbd1ca0 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -184,7 +184,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { let mut err = cx.struct_span_lint( OVERFLOWING_LITERALS, parent_expr.span, - "only u8 can be casted into char"); + "only u8 can be cast into char"); err.span_suggestion(parent_expr.span, &"use a char literal instead", format!("'\\u{{{:X}}}'", lit_val)); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7915109ce3a..fdeed5391f7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3094,7 +3094,7 @@ impl<'a> Parser<'a> { let expr_str = self.sess.codemap().span_to_snippet(expr.span) .unwrap_or(pprust::expr_to_string(&expr)); err.span_suggestion(expr.span, - &format!("try {} the casted value", op_verb), + &format!("try {} the cast value", op_verb), format!("({})", expr_str)); err.emit(); diff --git a/src/test/run-pass/extern-types-pointer-cast.rs b/src/test/run-pass/extern-types-pointer-cast.rs index 628a570665a..0dede8eb70d 100644 --- a/src/test/run-pass/extern-types-pointer-cast.rs +++ b/src/test/run-pass/extern-types-pointer-cast.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that pointers to extern types can be casted from/to usize, +// Test that pointers to extern types can be cast from/to usize, // despite being !Sized. #![feature(extern_types)] diff --git a/src/test/ui/cast_char.rs b/src/test/ui/cast_char.rs index cd8ade5e51a..4dfa5037bc5 100644 --- a/src/test/ui/cast_char.rs +++ b/src/test/ui/cast_char.rs @@ -12,9 +12,9 @@ fn main() { const XYZ: char = 0x1F888 as char; - //~^ ERROR only u8 can be casted into char + //~^ ERROR only u8 can be cast into char const XY: char = 129160 as char; - //~^ ERROR only u8 can be casted into char + //~^ ERROR only u8 can be cast into char const ZYX: char = '\u{01F888}'; println!("{}", XYZ); } diff --git a/src/test/ui/cast_char.stderr b/src/test/ui/cast_char.stderr index e42a38dace9..5da763992e3 100644 --- a/src/test/ui/cast_char.stderr +++ b/src/test/ui/cast_char.stderr @@ -1,4 +1,4 @@ -error: only u8 can be casted into char +error: only u8 can be cast into char --> $DIR/cast_char.rs:14:23 | 14 | const XYZ: char = 0x1F888 as char; @@ -10,7 +10,7 @@ note: lint level defined here 11 | #![deny(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ -error: only u8 can be casted into char +error: only u8 can be cast into char --> $DIR/cast_char.rs:16:22 | 16 | const XY: char = 129160 as char; diff --git a/src/test/ui/issue-22644.stderr b/src/test/ui/issue-22644.stderr index 91107fbe356..60ad222c7ab 100644 --- a/src/test/ui/issue-22644.stderr +++ b/src/test/ui/issue-22644.stderr @@ -5,7 +5,7 @@ error: `<` is interpreted as a start of generic arguments for `usize`, not a com | ---------- ^ --------- interpreted as generic arguments | | | | | not interpreted as comparison - | help: try comparing the casted value: `(a as usize)` + | help: try comparing the cast value: `(a as usize)` error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison --> $DIR/issue-22644.rs:17:33 @@ -14,7 +14,7 @@ error: `<` is interpreted as a start of generic arguments for `usize`, not a com | ---------- ^ -------------------- interpreted as generic arguments | | | | | not interpreted as comparison - | help: try comparing the casted value: `(a as usize)` + | help: try comparing the cast value: `(a as usize)` error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison --> $DIR/issue-22644.rs:19:31 @@ -23,7 +23,7 @@ error: `<` is interpreted as a start of generic arguments for `usize`, not a com | ---------- ^ - interpreted as generic arguments | | | | | not interpreted as comparison - | help: try comparing the casted value: `(a as usize)` + | help: try comparing the cast value: `(a as usize)` error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison --> $DIR/issue-22644.rs:21:31 @@ -32,7 +32,7 @@ error: `<` is interpreted as a start of generic arguments for `usize`, not a com | -------- ^ -------------------- interpreted as generic arguments | | | | | not interpreted as comparison - | help: try comparing the casted value: `(a: usize)` + | help: try comparing the cast value: `(a: usize)` error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison --> $DIR/issue-22644.rs:23:29 @@ -41,7 +41,7 @@ error: `<` is interpreted as a start of generic arguments for `usize`, not a com | -------- ^ - interpreted as generic arguments | | | | | not interpreted as comparison - | help: try comparing the casted value: `(a: usize)` + | help: try comparing the cast value: `(a: usize)` error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison --> $DIR/issue-22644.rs:28:20 @@ -50,7 +50,7 @@ error: `<` is interpreted as a start of generic arguments for `usize`, not a com | ^ not interpreted as comparison 29 | 4); | - interpreted as generic arguments -help: try comparing the casted value +help: try comparing the cast value | 25 | println!("{}", (a 26 | as @@ -64,7 +64,7 @@ error: `<` is interpreted as a start of generic arguments for `usize`, not a com | ^ not interpreted as comparison 38 | 5); | - interpreted as generic arguments -help: try comparing the casted value +help: try comparing the cast value | 30 | println!("{}", (a 31 | @@ -81,7 +81,7 @@ error: `<` is interpreted as a start of generic arguments for `usize`, not a shi | ---------- ^^ --------- interpreted as generic arguments | | | | | not interpreted as shift - | help: try shifting the casted value: `(a as usize)` + | help: try shifting the cast value: `(a as usize)` error: expected type, found `4` --> $DIR/issue-22644.rs:42:28 diff --git a/src/test/ui/issue-42954.stderr b/src/test/ui/issue-42954.stderr index d0fc410c474..205fa82274a 100644 --- a/src/test/ui/issue-42954.stderr +++ b/src/test/ui/issue-42954.stderr @@ -5,7 +5,7 @@ error: `<` is interpreted as a start of generic arguments for `u32`, not a compa | --------- ^ - interpreted as generic arguments | | | | | not interpreted as comparison - | help: try comparing the casted value: `($i as u32)` + | help: try comparing the cast value: `($i as u32)` ... 19 | is_plainly_printable!(c); | ------------------------- in this macro invocation -- cgit 1.4.1-3-g733a5 From c72537f20442c9afd0f2f90999163adb43f34953 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 17 Feb 2018 17:23:19 -0800 Subject: std: Add `arch` and `simd` modules This commit imports the `stdsimd` crate into the standard library, creating an `arch` and `simd` module inside of both libcore and libstd. Both of these modules are **unstable** and will continue to be so until RFC 2335 is stabilized. As a brief recap, the modules are organized as so: * `arch` contains all current architectures with intrinsics, for example `std::arch::x86`, `std::arch::x86_64`, `std::arch::arm`, etc. These modules contain all of the intrinsics defined for the platform, like `_mm_set1_epi8`. * In the standard library, the `arch` module also exports a `is_target_feature_detected` macro which performs runtime detection to determine whether a target feature is available at runtime. * The `simd` module contains experimental versions of strongly-typed lane-aware SIMD primitives, to be fully fleshed out in a future RFC. The main purpose of this commit is to start pulling in all these intrinsics and such into the standard library on nightly and allow testing and such. This'll help allow users to easily kick the tires and see if intrinsics work as well as allow us to test out all the infrastructure for moving the intrinsics into the standard library. --- .gitmodules | 3 +++ src/libcore/lib.rs | 33 +++++++++++++++++++++++++++++---- src/libstd/lib.rs | 30 ++++++++++++++++++++++++++++++ src/stdsimd | 1 + src/tools/tidy/src/lib.rs | 1 + 5 files changed, 64 insertions(+), 4 deletions(-) create mode 160000 src/stdsimd (limited to 'src/libcore') diff --git a/.gitmodules b/.gitmodules index fc2f8bbc8a3..5b7fd481299 100644 --- a/.gitmodules +++ b/.gitmodules @@ -50,3 +50,6 @@ [submodule "src/llvm-emscripten"] path = src/llvm-emscripten url = https://github.com/rust-lang/llvm +[submodule "src/stdsimd"] + path = src/stdsimd + url = https://github.com/rust-lang-nursery/stdsimd diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 3dd30ee1c69..1efd605112d 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -68,16 +68,21 @@ #![feature(allow_internal_unstable)] #![feature(asm)] #![feature(associated_type_defaults)] +#![feature(attr_literals)] #![feature(cfg_target_feature)] #![feature(cfg_target_has_atomic)] #![feature(concat_idents)] #![feature(const_fn)] #![feature(custom_attribute)] +#![feature(doc_spotlight)] #![feature(fundamental)] #![feature(i128_type)] #![feature(inclusive_range_syntax)] #![feature(intrinsics)] +#![feature(iterator_flatten)] +#![feature(iterator_repeat_with)] #![feature(lang_items)] +#![feature(link_llvm_intrinsics)] #![feature(never_type)] #![feature(no_core)] #![feature(on_unimplemented)] @@ -85,15 +90,17 @@ #![feature(prelude_import)] #![feature(repr_simd, platform_intrinsics)] #![feature(rustc_attrs)] +#![feature(rustc_const_unstable)] +#![feature(simd_ffi)] #![feature(specialization)] #![feature(staged_api)] +#![feature(stmt_expr_attributes)] +#![feature(target_feature)] #![feature(unboxed_closures)] #![feature(untagged_unions)] #![feature(unwind_attributes)] -#![feature(doc_spotlight)] -#![feature(rustc_const_unstable)] -#![feature(iterator_repeat_with)] -#![feature(iterator_flatten)] + +#![cfg_attr(stage0, allow(unused_attributes))] #[prelude_import] #[allow(unused)] @@ -179,3 +186,21 @@ mod char_private; mod iter_private; mod tuple; mod unit; + +// Pull in the the `coresimd` crate directly into libcore. This is where all the +// architecture-specific (and vendor-specific) intrinsics are defined. AKA +// things like SIMD and such. Note that the actual source for all this lies in a +// different repository, rust-lang-nursery/stdsimd. That's why the setup here is +// a bit wonky. +#[path = "../stdsimd/coresimd/mod.rs"] +#[allow(missing_docs, missing_debug_implementations, dead_code)] +#[unstable(feature = "stdsimd", issue = "48556")] +#[cfg(not(stage0))] // allow changes to how stdsimd works in stage0 +mod coresimd; + +#[unstable(feature = "stdsimd", issue = "48556")] +#[cfg(not(stage0))] +pub use coresimd::simd; +#[unstable(feature = "stdsimd", issue = "48556")] +#[cfg(not(stage0))] +pub use coresimd::arch; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d7d856fe3ad..a7e1c0ce732 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -299,6 +299,7 @@ #![feature(rand)] #![feature(raw)] #![feature(rustc_attrs)] +#![feature(stdsimd)] #![feature(sip_hash_13)] #![feature(slice_bytes)] #![feature(slice_concat_ext)] @@ -501,6 +502,35 @@ mod memchr; // compiler pub mod rt; +// Pull in the the `stdsimd` crate directly into libstd. This is the same as +// libcore's arch/simd modules where the source of truth here is in a different +// repository, but we pull things in here manually to get it into libstd. +// +// Note that the #[cfg] here is intended to do two things. First it allows us to +// change the rustc implementation of intrinsics in stage0 by not compiling simd +// intrinsics in stage0. Next it doesn't compile anything in test mode as +// stdsimd has tons of its own tests which we don't want to run. +#[path = "../stdsimd/stdsimd/mod.rs"] +#[allow(missing_debug_implementations, missing_docs, dead_code)] +#[unstable(feature = "stdsimd", issue = "48556")] +#[cfg(all(not(stage0), not(test)))] +mod stdsimd; + +// A "fake" module needed by the `stdsimd` module to compile, not actually +// exported though. +#[cfg(not(stage0))] +mod coresimd { + pub use core::arch; + pub use core::simd; +} + +#[unstable(feature = "stdsimd", issue = "48556")] +#[cfg(all(not(stage0), not(test)))] +pub use stdsimd::simd; +#[unstable(feature = "stdsimd", issue = "48556")] +#[cfg(all(not(stage0), not(test)))] +pub use stdsimd::arch; + // Include a number of private modules that exist solely to provide // the rustdoc documentation for primitive types. Using `include!` // because rustdoc only looks for these modules at the crate level. diff --git a/src/stdsimd b/src/stdsimd new file mode 160000 index 00000000000..678cbd325c8 --- /dev/null +++ b/src/stdsimd @@ -0,0 +1 @@ +Subproject commit 678cbd325c84070c9dbe4303969fbd2734c0b4ee diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 4d89008d5ca..1def3048ce0 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -71,6 +71,7 @@ fn filter_dirs(path: &Path) -> bool { "src/librustc/mir/interpret", "src/librustc_mir/interpret", "src/target", + "src/stdsimd", ]; skip.iter().any(|p| path.ends_with(p)) } -- cgit 1.4.1-3-g733a5 From 1011b8a3f10d15a6a003a6565705ec86bed56b94 Mon Sep 17 00:00:00 2001 From: tinaun Date: Fri, 16 Feb 2018 02:14:34 -0500 Subject: Stabilize Unsafe Pointer Methods also minor doc fixes. Closes #43941 --- src/libcore/ptr.rs | 108 +++++++++++++++-------------------------------------- 1 file changed, 30 insertions(+), 78 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index b266771b818..6270e5892b3 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -740,8 +740,6 @@ impl *const T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// let s: &str = "123"; /// let ptr: *const u8 = s.as_ptr(); /// @@ -750,7 +748,7 @@ impl *const T { /// println!("{}", *ptr.add(2) as char); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn add(self, count: usize) -> Self where T: Sized, @@ -799,8 +797,6 @@ impl *const T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// let s: &str = "123"; /// /// unsafe { @@ -809,7 +805,7 @@ impl *const T { /// println!("{}", *end.sub(2) as char); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn sub(self, count: usize) -> Self where T: Sized, @@ -836,8 +832,6 @@ impl *const T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// // Iterate using a raw pointer in increments of two elements /// let data = [1u8, 2, 3, 4, 5]; /// let mut ptr: *const u8 = data.as_ptr(); @@ -852,7 +846,7 @@ impl *const T { /// ptr = ptr.wrapping_add(step); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub fn wrapping_add(self, count: usize) -> Self where T: Sized, @@ -879,8 +873,6 @@ impl *const T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// // Iterate using a raw pointer in increments of two elements (backwards) /// let data = [1u8, 2, 3, 4, 5]; /// let mut ptr: *const u8 = data.as_ptr(); @@ -895,7 +887,7 @@ impl *const T { /// ptr = ptr.wrapping_sub(step); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub fn wrapping_sub(self, count: usize) -> Self where T: Sized, @@ -922,8 +914,6 @@ impl *const T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// let x = 12; /// let y = &x as *const i32; /// @@ -931,7 +921,7 @@ impl *const T { /// assert_eq!(y.read(), 12); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read(self) -> T where T: Sized, @@ -974,8 +964,6 @@ impl *const T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// let x = 12; /// let y = &x as *const i32; /// @@ -983,7 +971,7 @@ impl *const T { /// assert_eq!(y.read_volatile(), 12); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read_volatile(self) -> T where T: Sized, @@ -1010,8 +998,6 @@ impl *const T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// let x = 12; /// let y = &x as *const i32; /// @@ -1019,7 +1005,7 @@ impl *const T { /// assert_eq!(y.read_unaligned(), 12); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read_unaligned(self) -> T where T: Sized, @@ -1046,8 +1032,6 @@ impl *const T { /// Efficiently create a Rust vector from an unsafe buffer: /// /// ``` - /// #![feature(pointer_methods)] - /// /// # #[allow(dead_code)] /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { /// let mut dst = Vec::with_capacity(elts); @@ -1056,7 +1040,7 @@ impl *const T { /// dst /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_to(self, dest: *mut T, count: usize) where T: Sized, @@ -1085,8 +1069,6 @@ impl *const T { /// Efficiently create a Rust vector from an unsafe buffer: /// /// ``` - /// #![feature(pointer_methods)] - /// /// # #[allow(dead_code)] /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { /// let mut dst = Vec::with_capacity(elts); @@ -1095,7 +1077,7 @@ impl *const T { /// dst /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) where T: Sized, @@ -1443,8 +1425,6 @@ impl *mut T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// let s: &str = "123"; /// let ptr: *const u8 = s.as_ptr(); /// @@ -1453,7 +1433,7 @@ impl *mut T { /// println!("{}", *ptr.add(2) as char); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn add(self, count: usize) -> Self where T: Sized, @@ -1502,8 +1482,6 @@ impl *mut T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// let s: &str = "123"; /// /// unsafe { @@ -1512,7 +1490,7 @@ impl *mut T { /// println!("{}", *end.sub(2) as char); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn sub(self, count: usize) -> Self where T: Sized, @@ -1539,8 +1517,6 @@ impl *mut T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// // Iterate using a raw pointer in increments of two elements /// let data = [1u8, 2, 3, 4, 5]; /// let mut ptr: *const u8 = data.as_ptr(); @@ -1555,7 +1531,7 @@ impl *mut T { /// ptr = ptr.wrapping_add(step); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub fn wrapping_add(self, count: usize) -> Self where T: Sized, @@ -1582,8 +1558,6 @@ impl *mut T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// // Iterate using a raw pointer in increments of two elements (backwards) /// let data = [1u8, 2, 3, 4, 5]; /// let mut ptr: *const u8 = data.as_ptr(); @@ -1598,7 +1572,7 @@ impl *mut T { /// ptr = ptr.wrapping_sub(step); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub fn wrapping_sub(self, count: usize) -> Self where T: Sized, @@ -1625,8 +1599,6 @@ impl *mut T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// let x = 12; /// let y = &x as *const i32; /// @@ -1634,7 +1606,7 @@ impl *mut T { /// assert_eq!(y.read(), 12); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read(self) -> T where T: Sized, @@ -1668,7 +1640,7 @@ impl *mut T { /// Beyond accepting a raw pointer, this is unsafe because it semantically /// moves the value out of `self` without preventing further usage of `self`. /// If `T` is not `Copy`, then care must be taken to ensure that the value at - /// `src` is not used before the data is overwritten again (e.g. with `write`, + /// `self` is not used before the data is overwritten again (e.g. with `write`, /// `write_bytes`, or `copy`). Note that `*self = foo` counts as a use /// because it will attempt to drop the value previously at `*self`. /// @@ -1677,8 +1649,6 @@ impl *mut T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// let x = 12; /// let y = &x as *const i32; /// @@ -1686,7 +1656,7 @@ impl *mut T { /// assert_eq!(y.read_volatile(), 12); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read_volatile(self) -> T where T: Sized, @@ -1713,8 +1683,6 @@ impl *mut T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// let x = 12; /// let y = &x as *const i32; /// @@ -1722,7 +1690,7 @@ impl *mut T { /// assert_eq!(y.read_unaligned(), 12); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read_unaligned(self) -> T where T: Sized, @@ -1749,8 +1717,6 @@ impl *mut T { /// Efficiently create a Rust vector from an unsafe buffer: /// /// ``` - /// #![feature(pointer_methods)] - /// /// # #[allow(dead_code)] /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { /// let mut dst = Vec::with_capacity(elts); @@ -1759,7 +1725,7 @@ impl *mut T { /// dst /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_to(self, dest: *mut T, count: usize) where T: Sized, @@ -1788,8 +1754,6 @@ impl *mut T { /// Efficiently create a Rust vector from an unsafe buffer: /// /// ``` - /// #![feature(pointer_methods)] - /// /// # #[allow(dead_code)] /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { /// let mut dst = Vec::with_capacity(elts); @@ -1798,7 +1762,7 @@ impl *mut T { /// dst /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) where T: Sized, @@ -1825,8 +1789,6 @@ impl *mut T { /// Efficiently create a Rust vector from an unsafe buffer: /// /// ``` - /// #![feature(pointer_methods)] - /// /// # #[allow(dead_code)] /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { /// let mut dst: Vec = Vec::with_capacity(elts); @@ -1835,7 +1797,7 @@ impl *mut T { /// dst /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_from(self, src: *const T, count: usize) where T: Sized, @@ -1864,8 +1826,6 @@ impl *mut T { /// Efficiently create a Rust vector from an unsafe buffer: /// /// ``` - /// #![feature(pointer_methods)] - /// /// # #[allow(dead_code)] /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { /// let mut dst: Vec = Vec::with_capacity(elts); @@ -1874,7 +1834,7 @@ impl *mut T { /// dst /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize) where T: Sized, @@ -1899,7 +1859,7 @@ impl *mut T { /// /// This has all the same safety problems as `ptr::read` with respect to /// invalid pointers, types, and double drops. - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn drop_in_place(self) { drop_in_place(self) @@ -1929,8 +1889,6 @@ impl *mut T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// let mut x = 0; /// let y = &mut x as *mut i32; /// let z = 12; @@ -1940,7 +1898,7 @@ impl *mut T { /// assert_eq!(y.read(), 12); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn write(self, val: T) where T: Sized, @@ -1954,8 +1912,6 @@ impl *mut T { /// # Examples /// /// ``` - /// #![feature(pointer_methods)] - /// /// let mut vec = vec![0; 4]; /// unsafe { /// let vec_ptr = vec.as_mut_ptr(); @@ -1963,7 +1919,7 @@ impl *mut T { /// } /// assert_eq!(vec, [b'a', b'a', 0, 0]); /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn write_bytes(self, val: u8, count: usize) where T: Sized, @@ -2008,8 +1964,6 @@ impl *mut T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// let mut x = 0; /// let y = &mut x as *mut i32; /// let z = 12; @@ -2019,7 +1973,7 @@ impl *mut T { /// assert_eq!(y.read_volatile(), 12); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn write_volatile(self, val: T) where T: Sized, @@ -2040,8 +1994,8 @@ impl *mut T { /// allocations or resources, so care must be taken not to overwrite an object /// that should be dropped. /// - /// Additionally, it does not drop `src`. Semantically, `src` is moved into the - /// location pointed to by `dst`. + /// Additionally, it does not drop `self`. Semantically, `self` is moved into the + /// location pointed to by `val`. /// /// This is appropriate for initializing uninitialized memory, or overwriting /// memory that has previously been `read` from. @@ -2051,8 +2005,6 @@ impl *mut T { /// Basic usage: /// /// ``` - /// #![feature(pointer_methods)] - /// /// let mut x = 0; /// let y = &mut x as *mut i32; /// let z = 12; @@ -2062,7 +2014,7 @@ impl *mut T { /// assert_eq!(y.read_unaligned(), 12); /// } /// ``` - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn write_unaligned(self, val: T) where T: Sized, @@ -2077,7 +2029,7 @@ impl *mut T { /// /// This is only unsafe because it accepts a raw pointer. /// Otherwise, this operation is identical to `mem::replace`. - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn replace(self, src: T) -> T where T: Sized, @@ -2095,7 +2047,7 @@ impl *mut T { /// as arguments. /// /// Ensure that these pointers are valid before calling `swap`. - #[unstable(feature = "pointer_methods", issue = "43941")] + #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn swap(self, with: *mut T) where T: Sized, -- cgit 1.4.1-3-g733a5 From bc651cac8d671aee9be876b71d0fa86f94f56b0f Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Mon, 15 Jan 2018 19:59:10 +0100 Subject: core: Stabilize FusedIterator FusedIterator is a marker trait that promises that the implementing iterator continues to return `None` from `.next()` once it has returned `None` once (and/or `.next_back()`, if implemented). The effects of FusedIterator are already widely available through `.fuse()`, but with stable `FusedIterator`, stable Rust users can implement this trait for their iterators when appropriate. --- src/liballoc/binary_heap.rs | 6 +++--- src/liballoc/boxed.rs | 2 +- src/liballoc/btree/map.rs | 16 +++++++-------- src/liballoc/btree/set.rs | 14 ++++++------- src/liballoc/lib.rs | 3 +-- src/liballoc/linked_list.rs | 6 +++--- src/liballoc/str.rs | 2 +- src/liballoc/string.rs | 2 +- src/liballoc/vec.rs | 4 ++-- src/liballoc/vec_deque.rs | 8 ++++---- src/libcore/char.rs | 8 ++++---- src/libcore/iter/mod.rs | 42 +++++++++++++++++++------------------- src/libcore/iter/range.rs | 6 +++--- src/libcore/iter/sources.rs | 6 +++--- src/libcore/iter/traits.rs | 4 ++-- src/libcore/option.rs | 6 +++--- src/libcore/result.rs | 6 +++--- src/libcore/slice/mod.rs | 24 +++++++++++----------- src/libcore/str/mod.rs | 14 ++++++------- src/libstd/ascii.rs | 2 +- src/libstd/collections/hash/map.rs | 14 ++++++------- src/libstd/collections/hash/set.rs | 14 ++++++------- src/libstd/lib.rs | 1 - src/libstd/path.rs | 4 ++-- src/libstd_unicode/char.rs | 4 ++-- src/libstd_unicode/lib.rs | 1 - src/libstd_unicode/u_str.rs | 4 ++-- src/test/run-pass/issue-36053.rs | 1 - 28 files changed, 110 insertions(+), 114 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/binary_heap.rs b/src/liballoc/binary_heap.rs index 3041f85cd4c..a5694a90dbc 100644 --- a/src/liballoc/binary_heap.rs +++ b/src/liballoc/binary_heap.rs @@ -964,7 +964,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} /// An owning iterator over the elements of a `BinaryHeap`. @@ -1019,7 +1019,7 @@ impl ExactSizeIterator for IntoIter { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} /// A draining iterator over the elements of a `BinaryHeap`. @@ -1065,7 +1065,7 @@ impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 75a59de337c..6b000b6fa91 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -722,7 +722,7 @@ impl ExactSizeIterator for Box { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Box {} diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index 618ef81fdd9..7b7a6374db9 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -1156,7 +1156,7 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1235,7 +1235,7 @@ impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1365,7 +1365,7 @@ impl ExactSizeIterator for IntoIter { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1395,7 +1395,7 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1432,7 +1432,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for Values<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1482,7 +1482,7 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} @@ -1561,7 +1561,7 @@ impl<'a, K, V> Range<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for Range<'a, K, V> {} #[stable(feature = "btree_range", since = "1.17.0")] @@ -1630,7 +1630,7 @@ impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for RangeMut<'a, K, V> {} impl<'a, K, V> RangeMut<'a, K, V> { diff --git a/src/liballoc/btree/set.rs b/src/liballoc/btree/set.rs index 327eaaf4651..34cb7a08ed7 100644 --- a/src/liballoc/btree/set.rs +++ b/src/liballoc/btree/set.rs @@ -946,7 +946,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { fn len(&self) -> usize { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -971,7 +971,7 @@ impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} #[stable(feature = "btree_range", since = "1.17.0")] @@ -997,7 +997,7 @@ impl<'a, T> DoubleEndedIterator for Range<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Range<'a, T> {} /// Compare `x` and `y`, but return `short` if x is None and `long` if y is None @@ -1044,7 +1044,7 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T: Ord> FusedIterator for Difference<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1078,7 +1078,7 @@ impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T: Ord> FusedIterator for SymmetricDifference<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1116,7 +1116,7 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T: Ord> FusedIterator for Intersection<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1150,5 +1150,5 @@ impl<'a, T: Ord> Iterator for Union<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T: Ord> FusedIterator for Union<'a, T> {} diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index d250cfe1880..2212b62dfd8 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -96,7 +96,6 @@ #![feature(fmt_internals)] #![feature(from_ref)] #![feature(fundamental)] -#![feature(fused)] #![feature(generic_param_attrs)] #![feature(i128_type)] #![feature(inclusive_range)] @@ -125,7 +124,7 @@ #![feature(on_unimplemented)] #![feature(exact_chunks)] -#![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol, swap_with_slice, i128))] +#![cfg_attr(not(test), feature(fn_traits, placement_new_protocol, swap_with_slice, i128))] #![cfg_attr(test, feature(test, box_heap))] // Allow testing this library diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs index ec579e3fd68..87939fddfc8 100644 --- a/src/liballoc/linked_list.rs +++ b/src/liballoc/linked_list.rs @@ -897,7 +897,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Iter<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -946,7 +946,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} impl<'a, T> IterMut<'a, T> { @@ -1117,7 +1117,7 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index a00e3d17dd0..1a431bb2694 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -171,7 +171,7 @@ impl<'a> Iterator for EncodeUtf16<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for EncodeUtf16<'a> {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 409d2ab287e..1fcabd8a427 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2254,5 +2254,5 @@ impl<'a> DoubleEndedIterator for Drain<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for Drain<'a> {} diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 3c9b6b94b44..03c9750fb39 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2389,7 +2389,7 @@ impl ExactSizeIterator for IntoIter { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -2495,7 +2495,7 @@ impl<'a, T> ExactSizeIterator for Drain<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Drain<'a, T> {} /// A place for insertion at the back of a `Vec`. diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index 8b686365e69..3d7549abe6f 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -1991,7 +1991,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} @@ -2084,7 +2084,7 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} /// An owning iterator over the elements of a `VecDeque`. @@ -2140,7 +2140,7 @@ impl ExactSizeIterator for IntoIter { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} /// A draining iterator over the elements of a `VecDeque`. @@ -2247,7 +2247,7 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { #[stable(feature = "drain", since = "1.6.0")] impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 7215bd2a476..3ff31a7a928 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -643,7 +643,7 @@ impl ExactSizeIterator for EscapeUnicode { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for EscapeUnicode {} #[stable(feature = "char_struct_display", since = "1.16.0")] @@ -756,7 +756,7 @@ impl ExactSizeIterator for EscapeDefault { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for EscapeDefault {} #[stable(feature = "char_struct_display", since = "1.16.0")] @@ -790,7 +790,7 @@ impl Iterator for EscapeDebug { #[stable(feature = "char_escape_debug", since = "1.20.0")] impl ExactSizeIterator for EscapeDebug { } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for EscapeDebug {} #[stable(feature = "char_escape_debug", since = "1.20.0")] @@ -904,5 +904,5 @@ impl> Iterator for DecodeUtf8 { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl> FusedIterator for DecodeUtf8 {} diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 257d7d6caaa..9a8f7fc4e6a 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -344,7 +344,7 @@ pub use self::sources::{Once, once}; pub use self::traits::{FromIterator, IntoIterator, DoubleEndedIterator, Extend}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::{ExactSizeIterator, Sum, Product}; -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] pub use self::traits::FusedIterator; #[unstable(feature = "trusted_len", issue = "37572")] pub use self::traits::TrustedLen; @@ -506,7 +506,7 @@ impl ExactSizeIterator for Rev } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Rev where I: FusedIterator + DoubleEndedIterator {} @@ -589,7 +589,7 @@ impl<'a, I, T: 'a> ExactSizeIterator for Cloned } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, I, T: 'a> FusedIterator for Cloned where I: FusedIterator, T: Clone {} @@ -662,7 +662,7 @@ impl Iterator for Cycle where I: Clone + Iterator { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Cycle where I: Clone + Iterator {} /// An iterator for stepping iterators by a custom amount. @@ -1002,7 +1002,7 @@ impl DoubleEndedIterator for Chain where } // Note: *both* must be fused to handle double-ended iterators. -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Chain where A: FusedIterator, B: FusedIterator, @@ -1262,7 +1262,7 @@ unsafe impl TrustedRandomAccess for Zip } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Zip where A: FusedIterator, B: FusedIterator, {} @@ -1404,7 +1404,7 @@ impl ExactSizeIterator for Map } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Map where F: FnMut(I::Item) -> B {} @@ -1553,7 +1553,7 @@ impl DoubleEndedIterator for Filter } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Filter where P: FnMut(&I::Item) -> bool {} @@ -1663,7 +1663,7 @@ impl DoubleEndedIterator for FilterMap } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for FilterMap where F: FnMut(I::Item) -> Option {} @@ -1818,7 +1818,7 @@ unsafe impl TrustedRandomAccess for Enumerate } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Enumerate where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1938,7 +1938,7 @@ impl Iterator for Peekable { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Peekable {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Peekable {} impl Peekable { @@ -2072,7 +2072,7 @@ impl Iterator for SkipWhile } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for SkipWhile where I: FusedIterator, P: FnMut(&I::Item) -> bool {} @@ -2151,7 +2151,7 @@ impl Iterator for TakeWhile } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for TakeWhile where I: FusedIterator, P: FnMut(&I::Item) -> bool {} @@ -2290,7 +2290,7 @@ impl DoubleEndedIterator for Skip where I: DoubleEndedIterator + ExactSize } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Skip where I: FusedIterator {} /// An iterator that only iterates over the first `n` iterations of `iter`. @@ -2371,7 +2371,7 @@ impl Iterator for Take where I: Iterator{ #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Take where I: ExactSizeIterator {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Take where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -2517,7 +2517,7 @@ impl DoubleEndedIterator for FlatMap } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for FlatMap where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {} @@ -2605,7 +2605,7 @@ impl DoubleEndedIterator for Flatten } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Flatten where I: FusedIterator, U: Iterator, I::Item: IntoIterator {} @@ -2765,7 +2765,7 @@ pub struct Fuse { done: bool } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Fuse where I: Iterator {} #[stable(feature = "rust1", since = "1.0.0")] @@ -2896,7 +2896,7 @@ unsafe impl TrustedRandomAccess for Fuse } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl Iterator for Fuse where I: FusedIterator { #[inline] fn next(&mut self) -> Option<::Item> { @@ -2938,7 +2938,7 @@ impl Iterator for Fuse where I: FusedIterator { } } -#[unstable(feature = "fused", reason = "recently added", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl DoubleEndedIterator for Fuse where I: DoubleEndedIterator + FusedIterator { @@ -3082,6 +3082,6 @@ impl ExactSizeIterator for Inspect } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Inspect where F: FnMut(&I::Item) {} diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 65b38c94dda..7f3b227e8b7 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -295,7 +295,7 @@ impl DoubleEndedIterator for ops::Range { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for ops::Range {} #[stable(feature = "rust1", since = "1.0.0")] @@ -322,7 +322,7 @@ impl Iterator for ops::RangeFrom { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for ops::RangeFrom {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -463,5 +463,5 @@ impl DoubleEndedIterator for ops::RangeInclusive { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for ops::RangeInclusive {} diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index dfd42f3e733..149dff83bc0 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -41,7 +41,7 @@ impl DoubleEndedIterator for Repeat { fn next_back(&mut self) -> Option { Some(self.element.clone()) } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Repeat {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -259,7 +259,7 @@ impl ExactSizeIterator for Empty { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for Empty {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Empty {} // not #[derive] because that adds a Clone bound on T, @@ -340,7 +340,7 @@ impl ExactSizeIterator for Once { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for Once {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Once {} /// Creates an iterator that yields an element exactly once. diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 860742d9eab..a86f4e74706 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -959,10 +959,10 @@ impl Product> for Result /// [`None`]: ../../std/option/enum.Option.html#variant.None /// [`Iterator::fuse`]: ../../std/iter/trait.Iterator.html#method.fuse /// [`Fuse`]: ../../std/iter/struct.Fuse.html -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] pub trait FusedIterator: Iterator {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, I: FusedIterator + ?Sized> FusedIterator for &'a mut I {} /// An iterator that reports an accurate length using size_hint. diff --git a/src/libcore/option.rs b/src/libcore/option.rs index b8fe28d0f0d..99c1d7d9b36 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -1051,7 +1051,7 @@ impl<'a, A> DoubleEndedIterator for Iter<'a, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, A> ExactSizeIterator for Iter<'a, A> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, A> FusedIterator for Iter<'a, A> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1096,7 +1096,7 @@ impl<'a, A> DoubleEndedIterator for IterMut<'a, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, A> ExactSizeIterator for IterMut<'a, A> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, A> FusedIterator for IterMut<'a, A> {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {} @@ -1133,7 +1133,7 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 3801db94e15..5131fc837ef 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -1038,7 +1038,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Iter<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1082,7 +1082,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1125,7 +1125,7 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index a43ed65907f..02207f1738f 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1461,7 +1461,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1589,7 +1589,7 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1737,7 +1737,7 @@ impl<'a, T, P> SplitIter for Split<'a, T, P> where P: FnMut(&T) -> bool { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T, P> FusedIterator for Split<'a, T, P> where P: FnMut(&T) -> bool {} /// An iterator over the subslices of the vector which are separated @@ -1835,7 +1835,7 @@ impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> where } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {} /// An iterator over subslices separated by elements that match a predicate @@ -1892,7 +1892,7 @@ impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool { } } -//#[unstable(feature = "fused", issue = "35602")] +//#[stable(feature = "fused", since = "1.25.0")] #[unstable(feature = "slice_rsplit", issue = "41020")] impl<'a, T, P> FusedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {} @@ -1951,7 +1951,7 @@ impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where } } -//#[unstable(feature = "fused", issue = "35602")] +//#[stable(feature = "fused", since = "1.25.0")] #[unstable(feature = "slice_rsplit", issue = "41020")] impl<'a, T, P> FusedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {} @@ -2088,7 +2088,7 @@ macro_rules! forward_iterator { } } - #[unstable(feature = "fused", issue = "35602")] + #[stable(feature = "fused", since = "1.25.0")] impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {} } @@ -2194,7 +2194,7 @@ impl<'a, T> DoubleEndedIterator for Windows<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Windows<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Windows<'a, T> {} #[doc(hidden)] @@ -2313,7 +2313,7 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Chunks<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Chunks<'a, T> {} #[doc(hidden)] @@ -2429,7 +2429,7 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for ChunksMut<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for ChunksMut<'a, T> {} #[doc(hidden)] @@ -2539,7 +2539,7 @@ impl<'a, T> ExactSizeIterator for ExactChunks<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for ExactChunks<'a, T> {} #[doc(hidden)] @@ -2636,7 +2636,7 @@ impl<'a, T> ExactSizeIterator for ExactChunksMut<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for ExactChunksMut<'a, T> {} #[doc(hidden)] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 765b369e4b2..7e919b653f2 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -609,7 +609,7 @@ impl<'a> DoubleEndedIterator for Chars<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for Chars<'a> {} impl<'a> Chars<'a> { @@ -702,7 +702,7 @@ impl<'a> DoubleEndedIterator for CharIndices<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for CharIndices<'a> {} impl<'a> CharIndices<'a> { @@ -817,7 +817,7 @@ impl<'a> ExactSizeIterator for Bytes<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for Bytes<'a> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -977,10 +977,10 @@ macro_rules! generate_pattern_iterators { } } - #[unstable(feature = "fused", issue = "35602")] + #[stable(feature = "fused", since = "1.25.0")] impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} - #[unstable(feature = "fused", issue = "35602")] + #[stable(feature = "fused", since = "1.25.0")] impl<'a, P: Pattern<'a>> FusedIterator for $reverse_iterator<'a, P> where P::Searcher: ReverseSearcher<'a> {} @@ -1337,7 +1337,7 @@ impl<'a> DoubleEndedIterator for Lines<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for Lines<'a> {} /// Created with the method [`lines_any`]. @@ -1403,7 +1403,7 @@ impl<'a> DoubleEndedIterator for LinesAny<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] #[allow(deprecated)] impl<'a> FusedIterator for LinesAny<'a> {} diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 430c9df396a..ce3e38de7eb 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -590,7 +590,7 @@ impl DoubleEndedIterator for EscapeDefault { } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for EscapeDefault {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for EscapeDefault {} #[stable(feature = "std_debug", since = "1.16.0")] diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 4dfdc23ebee..9e48efeb113 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1750,7 +1750,7 @@ impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1773,7 +1773,7 @@ impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1808,7 +1808,7 @@ impl ExactSizeIterator for IntoIter { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1840,7 +1840,7 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1863,7 +1863,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for Values<'a, K, V> {} #[stable(feature = "map_values_mut", since = "1.10.0")] @@ -1886,7 +1886,7 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1921,7 +1921,7 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for Drain<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index e9427fb40a0..7a46603b2db 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -1097,7 +1097,7 @@ impl<'a, K> ExactSizeIterator for Iter<'a, K> { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K> FusedIterator for Iter<'a, K> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1124,7 +1124,7 @@ impl ExactSizeIterator for IntoIter { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1155,7 +1155,7 @@ impl<'a, K> ExactSizeIterator for Drain<'a, K> { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K> FusedIterator for Drain<'a, K> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1208,7 +1208,7 @@ impl<'a, T, S> fmt::Debug for Intersection<'a, T, S> } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T, S> FusedIterator for Intersection<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1244,7 +1244,7 @@ impl<'a, T, S> Iterator for Difference<'a, T, S> } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T, S> FusedIterator for Difference<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1283,7 +1283,7 @@ impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S> } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1307,7 +1307,7 @@ impl<'a, T, S> Clone for Union<'a, T, S> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T, S> FusedIterator for Union<'a, T, S> where T: Eq + Hash, S: BuildHasher diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d7d856fe3ad..82c4443a45e 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -266,7 +266,6 @@ #![feature(float_from_str_radix)] #![feature(fn_traits)] #![feature(fnbox)] -#![feature(fused)] #![feature(generic_param_attrs)] #![feature(hashmap_hasher)] #![feature(heap_api)] diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 1608a752a46..0c54fb00d2d 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -905,7 +905,7 @@ impl<'a> DoubleEndedIterator for Iter<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for Iter<'a> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1008,7 +1008,7 @@ impl<'a> DoubleEndedIterator for Components<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for Components<'a> {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index 844ff7a3c12..2bbbf6c0655 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -70,7 +70,7 @@ impl Iterator for ToLowercase { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for ToLowercase {} /// Returns an iterator that yields the uppercase equivalent of a `char`. @@ -92,7 +92,7 @@ impl Iterator for ToUppercase { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for ToUppercase {} #[derive(Debug)] diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index dcae7d0af40..f155b62e3cc 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -36,7 +36,6 @@ #![feature(str_internals)] #![feature(decode_utf8)] #![feature(fn_traits)] -#![feature(fused)] #![feature(lang_items)] #![feature(non_exhaustive)] #![feature(staged_api)] diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs index 5d1611acb7e..ed2f205b580 100644 --- a/src/libstd_unicode/u_str.rs +++ b/src/libstd_unicode/u_str.rs @@ -127,7 +127,7 @@ impl Iterator for Utf16Encoder } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Utf16Encoder where I: FusedIterator {} @@ -186,5 +186,5 @@ impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for SplitWhitespace<'a> {} diff --git a/src/test/run-pass/issue-36053.rs b/src/test/run-pass/issue-36053.rs index 2411996cf05..ece58eedc56 100644 --- a/src/test/run-pass/issue-36053.rs +++ b/src/test/run-pass/issue-36053.rs @@ -14,7 +14,6 @@ // `FusedIterator` in std but I was not able to isolate that into an // external crate. -#![feature(fused)] use std::iter::FusedIterator; struct Thing<'a>(&'a str); -- cgit 1.4.1-3-g733a5 From c7c23fe9482c129855a667909ff58969f6efe1f6 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sat, 3 Mar 2018 14:15:28 +0100 Subject: core: Update stability attributes for FusedIterator --- src/liballoc/binary_heap.rs | 6 +++--- src/liballoc/boxed.rs | 2 +- src/liballoc/btree/map.rs | 16 +++++++-------- src/liballoc/btree/set.rs | 14 ++++++------- src/liballoc/linked_list.rs | 6 +++--- src/liballoc/str.rs | 2 +- src/liballoc/string.rs | 2 +- src/liballoc/vec.rs | 4 ++-- src/liballoc/vec_deque.rs | 8 ++++---- src/libcore/char.rs | 8 ++++---- src/libcore/iter/mod.rs | 42 +++++++++++++++++++------------------- src/libcore/iter/range.rs | 6 +++--- src/libcore/iter/sources.rs | 8 ++++---- src/libcore/iter/traits.rs | 4 ++-- src/libcore/option.rs | 6 +++--- src/libcore/result.rs | 6 +++--- src/libcore/slice/mod.rs | 22 +++++++++----------- src/libcore/str/mod.rs | 14 ++++++------- src/libstd/ascii.rs | 2 +- src/libstd/collections/hash/map.rs | 14 ++++++------- src/libstd/collections/hash/set.rs | 14 ++++++------- src/libstd/path.rs | 6 +++--- src/libstd_unicode/char.rs | 4 ++-- src/libstd_unicode/u_str.rs | 3 +-- 24 files changed, 108 insertions(+), 111 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/binary_heap.rs b/src/liballoc/binary_heap.rs index a5694a90dbc..8aaac5d6e08 100644 --- a/src/liballoc/binary_heap.rs +++ b/src/liballoc/binary_heap.rs @@ -964,7 +964,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} /// An owning iterator over the elements of a `BinaryHeap`. @@ -1019,7 +1019,7 @@ impl ExactSizeIterator for IntoIter { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} /// A draining iterator over the elements of a `BinaryHeap`. @@ -1065,7 +1065,7 @@ impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 6b000b6fa91..b776556d59f 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -722,7 +722,7 @@ impl ExactSizeIterator for Box { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Box {} diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index 7b7a6374db9..ed9c8c18f0d 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -1156,7 +1156,7 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1235,7 +1235,7 @@ impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1365,7 +1365,7 @@ impl ExactSizeIterator for IntoIter { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1395,7 +1395,7 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1432,7 +1432,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Values<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1482,7 +1482,7 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} @@ -1561,7 +1561,7 @@ impl<'a, K, V> Range<'a, K, V> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Range<'a, K, V> {} #[stable(feature = "btree_range", since = "1.17.0")] @@ -1630,7 +1630,7 @@ impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for RangeMut<'a, K, V> {} impl<'a, K, V> RangeMut<'a, K, V> { diff --git a/src/liballoc/btree/set.rs b/src/liballoc/btree/set.rs index 34cb7a08ed7..2e3157147a0 100644 --- a/src/liballoc/btree/set.rs +++ b/src/liballoc/btree/set.rs @@ -946,7 +946,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { fn len(&self) -> usize { self.iter.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -971,7 +971,7 @@ impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { self.iter.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[stable(feature = "btree_range", since = "1.17.0")] @@ -997,7 +997,7 @@ impl<'a, T> DoubleEndedIterator for Range<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Range<'a, T> {} /// Compare `x` and `y`, but return `short` if x is None and `long` if y is None @@ -1044,7 +1044,7 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: Ord> FusedIterator for Difference<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1078,7 +1078,7 @@ impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: Ord> FusedIterator for SymmetricDifference<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1116,7 +1116,7 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: Ord> FusedIterator for Intersection<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1150,5 +1150,5 @@ impl<'a, T: Ord> Iterator for Union<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: Ord> FusedIterator for Union<'a, T> {} diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs index 87939fddfc8..097d2e414f5 100644 --- a/src/liballoc/linked_list.rs +++ b/src/liballoc/linked_list.rs @@ -897,7 +897,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Iter<'a, T> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -946,7 +946,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} impl<'a, T> IterMut<'a, T> { @@ -1117,7 +1117,7 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 1a431bb2694..82f8476d670 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -171,7 +171,7 @@ impl<'a> Iterator for EncodeUtf16<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for EncodeUtf16<'a> {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 1fcabd8a427..370fb6b4e89 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2254,5 +2254,5 @@ impl<'a> DoubleEndedIterator for Drain<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Drain<'a> {} diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 03c9750fb39..9e5672ef148 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2389,7 +2389,7 @@ impl ExactSizeIterator for IntoIter { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -2495,7 +2495,7 @@ impl<'a, T> ExactSizeIterator for Drain<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Drain<'a, T> {} /// A place for insertion at the back of a `Vec`. diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index 3d7549abe6f..68add3cbd51 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -1991,7 +1991,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} @@ -2084,7 +2084,7 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} /// An owning iterator over the elements of a `VecDeque`. @@ -2140,7 +2140,7 @@ impl ExactSizeIterator for IntoIter { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} /// A draining iterator over the elements of a `VecDeque`. @@ -2247,7 +2247,7 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { #[stable(feature = "drain", since = "1.6.0")] impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 3ff31a7a928..c90cca7dbe4 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -643,7 +643,7 @@ impl ExactSizeIterator for EscapeUnicode { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for EscapeUnicode {} #[stable(feature = "char_struct_display", since = "1.16.0")] @@ -756,7 +756,7 @@ impl ExactSizeIterator for EscapeDefault { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for EscapeDefault {} #[stable(feature = "char_struct_display", since = "1.16.0")] @@ -790,7 +790,7 @@ impl Iterator for EscapeDebug { #[stable(feature = "char_escape_debug", since = "1.20.0")] impl ExactSizeIterator for EscapeDebug { } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for EscapeDebug {} #[stable(feature = "char_escape_debug", since = "1.20.0")] @@ -904,5 +904,5 @@ impl> Iterator for DecodeUtf8 { } } -#[stable(feature = "fused", since = "1.25.0")] +#[unstable(feature = "decode_utf8", issue = "33906")] impl> FusedIterator for DecodeUtf8 {} diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 9a8f7fc4e6a..a6802d606ca 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -344,7 +344,7 @@ pub use self::sources::{Once, once}; pub use self::traits::{FromIterator, IntoIterator, DoubleEndedIterator, Extend}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::{ExactSizeIterator, Sum, Product}; -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] pub use self::traits::FusedIterator; #[unstable(feature = "trusted_len", issue = "37572")] pub use self::traits::TrustedLen; @@ -506,7 +506,7 @@ impl ExactSizeIterator for Rev } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Rev where I: FusedIterator + DoubleEndedIterator {} @@ -589,7 +589,7 @@ impl<'a, I, T: 'a> ExactSizeIterator for Cloned } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, I, T: 'a> FusedIterator for Cloned where I: FusedIterator, T: Clone {} @@ -662,7 +662,7 @@ impl Iterator for Cycle where I: Clone + Iterator { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Cycle where I: Clone + Iterator {} /// An iterator for stepping iterators by a custom amount. @@ -1002,7 +1002,7 @@ impl DoubleEndedIterator for Chain where } // Note: *both* must be fused to handle double-ended iterators. -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Chain where A: FusedIterator, B: FusedIterator, @@ -1262,7 +1262,7 @@ unsafe impl TrustedRandomAccess for Zip } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Zip where A: FusedIterator, B: FusedIterator, {} @@ -1404,7 +1404,7 @@ impl ExactSizeIterator for Map } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Map where F: FnMut(I::Item) -> B {} @@ -1553,7 +1553,7 @@ impl DoubleEndedIterator for Filter } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Filter where P: FnMut(&I::Item) -> bool {} @@ -1663,7 +1663,7 @@ impl DoubleEndedIterator for FilterMap } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for FilterMap where F: FnMut(I::Item) -> Option {} @@ -1818,7 +1818,7 @@ unsafe impl TrustedRandomAccess for Enumerate } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Enumerate where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1938,7 +1938,7 @@ impl Iterator for Peekable { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Peekable {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Peekable {} impl Peekable { @@ -2072,7 +2072,7 @@ impl Iterator for SkipWhile } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for SkipWhile where I: FusedIterator, P: FnMut(&I::Item) -> bool {} @@ -2151,7 +2151,7 @@ impl Iterator for TakeWhile } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for TakeWhile where I: FusedIterator, P: FnMut(&I::Item) -> bool {} @@ -2290,7 +2290,7 @@ impl DoubleEndedIterator for Skip where I: DoubleEndedIterator + ExactSize } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Skip where I: FusedIterator {} /// An iterator that only iterates over the first `n` iterations of `iter`. @@ -2371,7 +2371,7 @@ impl Iterator for Take where I: Iterator{ #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Take where I: ExactSizeIterator {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Take where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -2517,7 +2517,7 @@ impl DoubleEndedIterator for FlatMap } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for FlatMap where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {} @@ -2605,7 +2605,7 @@ impl DoubleEndedIterator for Flatten } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Flatten where I: FusedIterator, U: Iterator, I::Item: IntoIterator {} @@ -2765,7 +2765,7 @@ pub struct Fuse { done: bool } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Fuse where I: Iterator {} #[stable(feature = "rust1", since = "1.0.0")] @@ -2896,7 +2896,7 @@ unsafe impl TrustedRandomAccess for Fuse } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl Iterator for Fuse where I: FusedIterator { #[inline] fn next(&mut self) -> Option<::Item> { @@ -2938,7 +2938,7 @@ impl Iterator for Fuse where I: FusedIterator { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl DoubleEndedIterator for Fuse where I: DoubleEndedIterator + FusedIterator { @@ -3082,6 +3082,6 @@ impl ExactSizeIterator for Inspect } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Inspect where F: FnMut(&I::Item) {} diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 7f3b227e8b7..9a3fd215dcf 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -295,7 +295,7 @@ impl DoubleEndedIterator for ops::Range { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::Range {} #[stable(feature = "rust1", since = "1.0.0")] @@ -322,7 +322,7 @@ impl Iterator for ops::RangeFrom { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::RangeFrom {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -463,5 +463,5 @@ impl DoubleEndedIterator for ops::RangeInclusive { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::RangeInclusive {} diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 149dff83bc0..0fc1a3aa8ac 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -41,7 +41,7 @@ impl DoubleEndedIterator for Repeat { fn next_back(&mut self) -> Option { Some(self.element.clone()) } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Repeat {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -135,7 +135,7 @@ impl A> DoubleEndedIterator for RepeatWith { fn next_back(&mut self) -> Option { self.next() } } -#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] impl A> FusedIterator for RepeatWith {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -259,7 +259,7 @@ impl ExactSizeIterator for Empty { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for Empty {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Empty {} // not #[derive] because that adds a Clone bound on T, @@ -340,7 +340,7 @@ impl ExactSizeIterator for Once { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for Once {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Once {} /// Creates an iterator that yields an element exactly once. diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index a86f4e74706..0267fcd3754 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -959,10 +959,10 @@ impl Product> for Result /// [`None`]: ../../std/option/enum.Option.html#variant.None /// [`Iterator::fuse`]: ../../std/iter/trait.Iterator.html#method.fuse /// [`Fuse`]: ../../std/iter/struct.Fuse.html -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] pub trait FusedIterator: Iterator {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, I: FusedIterator + ?Sized> FusedIterator for &'a mut I {} /// An iterator that reports an accurate length using size_hint. diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 99c1d7d9b36..b66aad246fe 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -1051,7 +1051,7 @@ impl<'a, A> DoubleEndedIterator for Iter<'a, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, A> ExactSizeIterator for Iter<'a, A> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, A> FusedIterator for Iter<'a, A> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1096,7 +1096,7 @@ impl<'a, A> DoubleEndedIterator for IterMut<'a, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, A> ExactSizeIterator for IterMut<'a, A> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, A> FusedIterator for IterMut<'a, A> {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {} @@ -1133,7 +1133,7 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 5131fc837ef..c152d4979b9 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -1038,7 +1038,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Iter<'a, T> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1082,7 +1082,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1125,7 +1125,7 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 02207f1738f..4f1ee2d9491 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1461,7 +1461,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1589,7 +1589,7 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1737,7 +1737,7 @@ impl<'a, T, P> SplitIter for Split<'a, T, P> where P: FnMut(&T) -> bool { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, P> FusedIterator for Split<'a, T, P> where P: FnMut(&T) -> bool {} /// An iterator over the subslices of the vector which are separated @@ -1835,7 +1835,7 @@ impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> where } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {} /// An iterator over subslices separated by elements that match a predicate @@ -1892,7 +1892,6 @@ impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool { } } -//#[stable(feature = "fused", since = "1.25.0")] #[unstable(feature = "slice_rsplit", issue = "41020")] impl<'a, T, P> FusedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {} @@ -1951,7 +1950,6 @@ impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where } } -//#[stable(feature = "fused", since = "1.25.0")] #[unstable(feature = "slice_rsplit", issue = "41020")] impl<'a, T, P> FusedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {} @@ -2088,7 +2086,7 @@ macro_rules! forward_iterator { } } - #[stable(feature = "fused", since = "1.25.0")] + #[stable(feature = "fused", since = "1.26.0")] impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {} } @@ -2194,7 +2192,7 @@ impl<'a, T> DoubleEndedIterator for Windows<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Windows<'a, T> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Windows<'a, T> {} #[doc(hidden)] @@ -2313,7 +2311,7 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Chunks<'a, T> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Chunks<'a, T> {} #[doc(hidden)] @@ -2429,7 +2427,7 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for ChunksMut<'a, T> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for ChunksMut<'a, T> {} #[doc(hidden)] @@ -2539,7 +2537,7 @@ impl<'a, T> ExactSizeIterator for ExactChunks<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[unstable(feature = "exact_chunks", issue = "47115")] impl<'a, T> FusedIterator for ExactChunks<'a, T> {} #[doc(hidden)] @@ -2636,7 +2634,7 @@ impl<'a, T> ExactSizeIterator for ExactChunksMut<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[unstable(feature = "exact_chunks", issue = "47115")] impl<'a, T> FusedIterator for ExactChunksMut<'a, T> {} #[doc(hidden)] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 7e919b653f2..e225c9522bc 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -609,7 +609,7 @@ impl<'a> DoubleEndedIterator for Chars<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Chars<'a> {} impl<'a> Chars<'a> { @@ -702,7 +702,7 @@ impl<'a> DoubleEndedIterator for CharIndices<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for CharIndices<'a> {} impl<'a> CharIndices<'a> { @@ -817,7 +817,7 @@ impl<'a> ExactSizeIterator for Bytes<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Bytes<'a> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -977,10 +977,10 @@ macro_rules! generate_pattern_iterators { } } - #[stable(feature = "fused", since = "1.25.0")] + #[stable(feature = "fused", since = "1.26.0")] impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} - #[stable(feature = "fused", since = "1.25.0")] + #[stable(feature = "fused", since = "1.26.0")] impl<'a, P: Pattern<'a>> FusedIterator for $reverse_iterator<'a, P> where P::Searcher: ReverseSearcher<'a> {} @@ -1337,7 +1337,7 @@ impl<'a> DoubleEndedIterator for Lines<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Lines<'a> {} /// Created with the method [`lines_any`]. @@ -1403,7 +1403,7 @@ impl<'a> DoubleEndedIterator for LinesAny<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] #[allow(deprecated)] impl<'a> FusedIterator for LinesAny<'a> {} diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index ce3e38de7eb..d5bf9e9bb2f 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -590,7 +590,7 @@ impl DoubleEndedIterator for EscapeDefault { } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for EscapeDefault {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for EscapeDefault {} #[stable(feature = "std_debug", since = "1.16.0")] diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 9e48efeb113..e86264569a0 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1750,7 +1750,7 @@ impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1773,7 +1773,7 @@ impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { self.inner.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1808,7 +1808,7 @@ impl ExactSizeIterator for IntoIter { self.inner.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1840,7 +1840,7 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { self.inner.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1863,7 +1863,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { self.inner.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Values<'a, K, V> {} #[stable(feature = "map_values_mut", since = "1.10.0")] @@ -1886,7 +1886,7 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { self.inner.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1921,7 +1921,7 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { self.inner.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Drain<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 7a46603b2db..f41b7a62918 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -1097,7 +1097,7 @@ impl<'a, K> ExactSizeIterator for Iter<'a, K> { self.iter.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K> FusedIterator for Iter<'a, K> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1124,7 +1124,7 @@ impl ExactSizeIterator for IntoIter { self.iter.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1155,7 +1155,7 @@ impl<'a, K> ExactSizeIterator for Drain<'a, K> { self.iter.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K> FusedIterator for Drain<'a, K> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1208,7 +1208,7 @@ impl<'a, T, S> fmt::Debug for Intersection<'a, T, S> } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, S> FusedIterator for Intersection<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1244,7 +1244,7 @@ impl<'a, T, S> Iterator for Difference<'a, T, S> } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, S> FusedIterator for Difference<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1283,7 +1283,7 @@ impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S> } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1307,7 +1307,7 @@ impl<'a, T, S> Clone for Union<'a, T, S> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, S> FusedIterator for Union<'a, T, S> where T: Eq + Hash, S: BuildHasher diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 0c54fb00d2d..cd2af99d6ac 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -905,7 +905,7 @@ impl<'a> DoubleEndedIterator for Iter<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Iter<'a> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1008,7 +1008,7 @@ impl<'a> DoubleEndedIterator for Components<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Components<'a> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1076,7 +1076,7 @@ impl<'a> Iterator for Ancestors<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "path_ancestors", issue = "48581")] impl<'a> FusedIterator for Ancestors<'a> {} //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index 2bbbf6c0655..8d3df749ed7 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -70,7 +70,7 @@ impl Iterator for ToLowercase { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ToLowercase {} /// Returns an iterator that yields the uppercase equivalent of a `char`. @@ -92,7 +92,7 @@ impl Iterator for ToUppercase { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ToUppercase {} #[derive(Debug)] diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs index ed2f205b580..a72e1210d93 100644 --- a/src/libstd_unicode/u_str.rs +++ b/src/libstd_unicode/u_str.rs @@ -127,7 +127,6 @@ impl Iterator for Utf16Encoder } } -#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Utf16Encoder where I: FusedIterator {} @@ -186,5 +185,5 @@ impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for SplitWhitespace<'a> {} -- cgit 1.4.1-3-g733a5 From 4e4c1b5b325c4c474426a7e3c346c316fbc644f1 Mon Sep 17 00:00:00 2001 From: 1011X <1011XXXXX@gmail.com> Date: Sun, 4 Mar 2018 13:33:34 -0500 Subject: Added `ascii` module to core --- src/libcore/ascii.rs | 499 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 499 insertions(+) create mode 100644 src/libcore/ascii.rs (limited to 'src/libcore') diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs new file mode 100644 index 00000000000..e7bee41ac34 --- /dev/null +++ b/src/libcore/ascii.rs @@ -0,0 +1,499 @@ +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Operations on ASCII strings and characters. +//! +//! Most string operations in Rust act on UTF-8 strings. However, at times it +//! makes more sense to only consider the ASCII character set for a specific +//! operation. +//! +//! The [`escape_default`] function provides an iterator over the bytes of an +//! escaped version of the character given. +//! +//! [`escape_default`]: fn.escape_default.html + +#![stable(feature = "rust1", since = "1.0.0")] + +use fmt; +use ops::Range; +use iter::FusedIterator; + +/// An iterator over the escaped version of a byte. +/// +/// This `struct` is created by the [`escape_default`] function. See its +/// documentation for more. +/// +/// [`escape_default`]: fn.escape_default.html +#[unstable(feature = "core_ascii", issue = "46409")] +pub struct EscapeDefault { + range: Range, + data: [u8; 4], +} + +/// Returns an iterator that produces an escaped version of a `u8`. +/// +/// The default is chosen with a bias toward producing literals that are +/// legal in a variety of languages, including C++11 and similar C-family +/// languages. The exact rules are: +/// +/// * Tab is escaped as `\t`. +/// * Carriage return is escaped as `\r`. +/// * Line feed is escaped as `\n`. +/// * Single quote is escaped as `\'`. +/// * Double quote is escaped as `\"`. +/// * Backslash is escaped as `\\`. +/// * Any character in the 'printable ASCII' range `0x20` .. `0x7e` +/// inclusive is not escaped. +/// * Any other chars are given hex escapes of the form '\xNN'. +/// * Unicode escapes are never generated by this function. +/// +/// # Examples +/// +/// ``` +/// let escaped = ascii::escape_default(b'0').next().unwrap(); +/// assert_eq!(b'0', escaped); +/// +/// let mut escaped = ascii::escape_default(b'\t'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b't', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\r'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'r', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\n'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'n', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\''); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'\'', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'"'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'"', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\\'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\x9d'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'x', escaped.next().unwrap()); +/// assert_eq!(b'9', escaped.next().unwrap()); +/// assert_eq!(b'd', escaped.next().unwrap()); +/// ``` +#[unstable(feature = "core_ascii", issue = "46409")] +pub fn escape_ascii(c: u8) -> EscapeDefault { + let (data, len) = match c { + b'\t' => ([b'\\', b't', 0, 0], 2), + b'\r' => ([b'\\', b'r', 0, 0], 2), + b'\n' => ([b'\\', b'n', 0, 0], 2), + b'\\' => ([b'\\', b'\\', 0, 0], 2), + b'\'' => ([b'\\', b'\'', 0, 0], 2), + b'"' => ([b'\\', b'"', 0, 0], 2), + b'\x20' ... b'\x7e' => ([c, 0, 0, 0], 1), + _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4), + }; + + return EscapeDefault { range: 0..len, data }; + + fn hexify(b: u8) -> u8 { + match b { + 0 ... 9 => b'0' + b, + _ => b'a' + b - 10, + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for EscapeDefault { + type Item = u8; + fn next(&mut self) -> Option { self.range.next().map(|i| self.data[i]) } + fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for EscapeDefault { + fn next_back(&mut self) -> Option { + self.range.next_back().map(|i| self.data[i]) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for EscapeDefault {} +#[unstable(feature = "fused", issue = "35602")] +impl FusedIterator for EscapeDefault {} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for EscapeDefault { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("EscapeDefault { .. }") + } +} + + +#[cfg(test)] +mod tests { + use char::from_u32; + + #[test] + fn test_is_ascii() { + assert!(b"".is_ascii()); + assert!(b"banana\0\x7F".is_ascii()); + assert!(b"banana\0\x7F".iter().all(|b| b.is_ascii())); + assert!(!b"Vi\xe1\xbb\x87t Nam".is_ascii()); + assert!(!b"Vi\xe1\xbb\x87t Nam".iter().all(|b| b.is_ascii())); + assert!(!b"\xe1\xbb\x87".iter().any(|b| b.is_ascii())); + + assert!("".is_ascii()); + assert!("banana\0\u{7F}".is_ascii()); + assert!("banana\0\u{7F}".chars().all(|c| c.is_ascii())); + assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii())); + assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii())); + } + + #[test] + fn test_to_ascii_uppercase() { + assert_eq!("url()URL()uRl()ürl".to_ascii_uppercase(), "URL()URL()URL()üRL"); + assert_eq!("hıKß".to_ascii_uppercase(), "HıKß"); + + for i in 0..501 { + let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 } + else { i }; + assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_uppercase(), + (from_u32(upper).unwrap()).to_string()); + } + } + + #[test] + fn test_to_ascii_lowercase() { + assert_eq!("url()URL()uRl()Ürl".to_ascii_lowercase(), "url()url()url()Ürl"); + // Dotted capital I, Kelvin sign, Sharp S. + assert_eq!("HİKß".to_ascii_lowercase(), "hİKß"); + + for i in 0..501 { + let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } + else { i }; + assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_lowercase(), + (from_u32(lower).unwrap()).to_string()); + } + } + + #[test] + fn test_make_ascii_lower_case() { + macro_rules! test { + ($from: expr, $to: expr) => { + { + let mut x = $from; + x.make_ascii_lowercase(); + assert_eq!(x, $to); + } + } + } + test!(b'A', b'a'); + test!(b'a', b'a'); + test!(b'!', b'!'); + test!('A', 'a'); + test!('À', 'À'); + test!('a', 'a'); + test!('!', '!'); + test!(b"H\xc3\x89".to_vec(), b"h\xc3\x89"); + test!("HİKß".to_string(), "hİKß"); + } + + + #[test] + fn test_make_ascii_upper_case() { + macro_rules! test { + ($from: expr, $to: expr) => { + { + let mut x = $from; + x.make_ascii_uppercase(); + assert_eq!(x, $to); + } + } + } + test!(b'a', b'A'); + test!(b'A', b'A'); + test!(b'!', b'!'); + test!('a', 'A'); + test!('à', 'à'); + test!('A', 'A'); + test!('!', '!'); + test!(b"h\xc3\xa9".to_vec(), b"H\xc3\xa9"); + test!("hıKß".to_string(), "HıKß"); + + let mut x = "Hello".to_string(); + x[..3].make_ascii_uppercase(); // Test IndexMut on String. + assert_eq!(x, "HELlo") + } + + #[test] + fn test_eq_ignore_ascii_case() { + assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl")); + assert!(!"Ürl".eq_ignore_ascii_case("ürl")); + // Dotted capital I, Kelvin sign, Sharp S. + assert!("HİKß".eq_ignore_ascii_case("hİKß")); + assert!(!"İ".eq_ignore_ascii_case("i")); + assert!(!"K".eq_ignore_ascii_case("k")); + assert!(!"ß".eq_ignore_ascii_case("s")); + + for i in 0..501 { + let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } + else { i }; + assert!((from_u32(i).unwrap()).to_string().eq_ignore_ascii_case( + &from_u32(lower).unwrap().to_string())); + } + } + + #[test] + fn inference_works() { + let x = "a".to_string(); + x.eq_ignore_ascii_case("A"); + } + + // Shorthands used by the is_ascii_* tests. + macro_rules! assert_all { + ($what:ident, $($str:tt),+) => {{ + $( + for b in $str.chars() { + if !b.$what() { + panic!("expected {}({}) but it isn't", + stringify!($what), b); + } + } + for b in $str.as_bytes().iter() { + if !b.$what() { + panic!("expected {}(0x{:02x})) but it isn't", + stringify!($what), b); + } + } + assert!($str.$what()); + assert!($str.as_bytes().$what()); + )+ + }}; + ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+)) + } + macro_rules! assert_none { + ($what:ident, $($str:tt),+) => {{ + $( + for b in $str.chars() { + if b.$what() { + panic!("expected not-{}({}) but it is", + stringify!($what), b); + } + } + for b in $str.as_bytes().iter() { + if b.$what() { + panic!("expected not-{}(0x{:02x})) but it is", + stringify!($what), b); + } + } + )* + }}; + ($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+)) + } + + #[test] + fn test_is_ascii_alphabetic() { + assert_all!(is_ascii_alphabetic, + "", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + ); + assert_none!(is_ascii_alphabetic, + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); + } + + #[test] + fn test_is_ascii_uppercase() { + assert_all!(is_ascii_uppercase, + "", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + ); + assert_none!(is_ascii_uppercase, + "abcdefghijklmnopqrstuvwxyz", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); + } + + #[test] + fn test_is_ascii_lowercase() { + assert_all!(is_ascii_lowercase, + "abcdefghijklmnopqrstuvwxyz", + ); + assert_none!(is_ascii_lowercase, + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); + } + + #[test] + fn test_is_ascii_alphanumeric() { + assert_all!(is_ascii_alphanumeric, + "", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + ); + assert_none!(is_ascii_alphanumeric, + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); + } + + #[test] + fn test_is_ascii_digit() { + assert_all!(is_ascii_digit, + "", + "0123456789", + ); + assert_none!(is_ascii_digit, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); + } + + #[test] + fn test_is_ascii_hexdigit() { + assert_all!(is_ascii_hexdigit, + "", + "0123456789", + "abcdefABCDEF", + ); + assert_none!(is_ascii_hexdigit, + "ghijklmnopqrstuvwxyz", + "GHIJKLMNOQPRSTUVWXYZ", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); + } + + #[test] + fn test_is_ascii_punctuation() { + assert_all!(is_ascii_punctuation, + "", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + ); + assert_none!(is_ascii_punctuation, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); + } + + #[test] + fn test_is_ascii_graphic() { + assert_all!(is_ascii_graphic, + "", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + ); + assert_none!(is_ascii_graphic, + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); + } + + #[test] + fn test_is_ascii_whitespace() { + assert_all!(is_ascii_whitespace, + "", + " \t\n\x0c\r", + ); + assert_none!(is_ascii_whitespace, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x0b\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); + } + + #[test] + fn test_is_ascii_control() { + assert_all!(is_ascii_control, + "", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); + assert_none!(is_ascii_control, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " ", + ); + } +} -- cgit 1.4.1-3-g733a5 From 16076d47507cc42e2c519f2fbd5e4a1733b17b55 Mon Sep 17 00:00:00 2001 From: 1011X <1011XXXXX@gmail.com> Date: Sun, 4 Mar 2018 13:44:43 -0500 Subject: Declare `ascii` module in libcore/lib.rs --- src/libcore/lib.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 1efd605112d..b6208f91ac0 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -165,6 +165,7 @@ pub mod borrow; pub mod any; pub mod array; +pub mod ascii; pub mod sync; pub mod cell; pub mod char; -- cgit 1.4.1-3-g733a5 From bebc34003e2d60297448b73b964db89a8030ba47 Mon Sep 17 00:00:00 2001 From: 1011X <1011XXXXX@gmail.com> Date: Sun, 4 Mar 2018 14:39:14 -0500 Subject: Fix unintended rename and a doc example --- src/libcore/ascii.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index e7bee41ac34..989a98ec8e7 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -57,6 +57,8 @@ pub struct EscapeDefault { /// # Examples /// /// ``` +/// use core::ascii; +/// /// let escaped = ascii::escape_default(b'0').next().unwrap(); /// assert_eq!(b'0', escaped); /// @@ -98,7 +100,7 @@ pub struct EscapeDefault { /// assert_eq!(b'd', escaped.next().unwrap()); /// ``` #[unstable(feature = "core_ascii", issue = "46409")] -pub fn escape_ascii(c: u8) -> EscapeDefault { +pub fn escape_default(c: u8) -> EscapeDefault { let (data, len) = match c { b'\t' => ([b'\\', b't', 0, 0], 2), b'\r' => ([b'\\', b'r', 0, 0], 2), -- cgit 1.4.1-3-g733a5 From c68440cad49f6d0cda09f8c7d4989ff63f55a26e Mon Sep 17 00:00:00 2001 From: Songbird0 Date: Sun, 4 Mar 2018 21:59:53 +0100 Subject: Add a potential cause raising `ParseIntError`. Initially, I wanted to add it directly to the documentation of `str. parse()' method, I finally found that it was more relevant (I hope so?) to directly document the structure in question. I've added a scenario, in which we could all get caught at least once, to make it easier to diagnose the problem when parsing integers. --- src/libcore/num/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 59a67fff48c..1b51ebefb60 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3845,7 +3845,13 @@ fn from_str_radix(src: &str, radix: u32) -> Result Date: Sun, 4 Mar 2018 22:18:42 +0100 Subject: Tidy error: add a new line The error was: ``` [00:05:25] tidy error: /checkout/src/libcore/num/mod.rs:3848: trailing whitespace [00:05:25] tidy error: /checkout/src/libcore/num/mod.rs:3851: line longer than 100 chars [00:05:25] tidy error: /checkout/src/libcore/num/mod.rs:3851: trailing whitespace [00:05:26] some tidy checks failed ``` The line was truncated to 92 characters. --- src/libcore/num/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 1b51ebefb60..00a46dca876 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3848,7 +3848,8 @@ fn from_str_radix(src: &str, radix: u32) -> Result Date: Sun, 4 Mar 2018 18:36:32 -0500 Subject: Fix doc example --- src/libcore/ascii.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libcore') diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index 989a98ec8e7..32847506cdf 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -57,6 +57,7 @@ pub struct EscapeDefault { /// # Examples /// /// ``` +/// #![no_std] /// use core::ascii; /// /// let escaped = ascii::escape_default(b'0').next().unwrap(); -- cgit 1.4.1-3-g733a5 From 9bfc06272310600e93e3127a3a257031d15eab7f Mon Sep 17 00:00:00 2001 From: 1011X <1011XXXXX@gmail.com> Date: Sun, 4 Mar 2018 20:32:44 -0500 Subject: Fix doc example, and change fn annotation to stable --- src/libcore/ascii.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index 32847506cdf..d61b9199560 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -31,7 +31,7 @@ use iter::FusedIterator; /// documentation for more. /// /// [`escape_default`]: fn.escape_default.html -#[unstable(feature = "core_ascii", issue = "46409")] +#[stable(feature = "core_ascii", since = "1.26.0")] pub struct EscapeDefault { range: Range, data: [u8; 4], @@ -57,8 +57,7 @@ pub struct EscapeDefault { /// # Examples /// /// ``` -/// #![no_std] -/// use core::ascii; +/// use std::ascii; /// /// let escaped = ascii::escape_default(b'0').next().unwrap(); /// assert_eq!(b'0', escaped); @@ -100,7 +99,7 @@ pub struct EscapeDefault { /// assert_eq!(b'9', escaped.next().unwrap()); /// assert_eq!(b'd', escaped.next().unwrap()); /// ``` -#[unstable(feature = "core_ascii", issue = "46409")] +#[stable(feature = "core_ascii", since = "1.26.0")] pub fn escape_default(c: u8) -> EscapeDefault { let (data, len) = match c { b'\t' => ([b'\\', b't', 0, 0], 2), -- cgit 1.4.1-3-g733a5 From ef1aae1cc2310ae6c05bed273da55a9ba85b1ef5 Mon Sep 17 00:00:00 2001 From: Songbird0 Date: Mon, 5 Mar 2018 03:57:33 +0100 Subject: Modify wording and remove useless whitespaces. --- src/libcore/num/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 00a46dca876..8b43aeefade 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3845,11 +3845,11 @@ fn from_str_radix(src: &str, radix: u32) -> Result Date: Mon, 5 Mar 2018 14:33:37 +0100 Subject: Fix spelling error for `whitespaces`. --- src/libcore/num/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 8b43aeefade..929d6ef4c20 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3848,7 +3848,7 @@ fn from_str_radix(src: &str, radix: u32) -> Result Date: Mon, 5 Mar 2018 16:39:09 -0500 Subject: Move tests, re-export items from core::ascii --- src/libcore/ascii.rs | 356 +-------------------------------- src/libcore/tests/ascii.rs | 349 +++++++++++++++++++++++++++++++++ src/libstd/ascii.rs | 477 +-------------------------------------------- 3 files changed, 353 insertions(+), 829 deletions(-) create mode 100644 src/libcore/tests/ascii.rs (limited to 'src/libcore') diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index d61b9199560..f409536d1b0 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -19,7 +19,7 @@ //! //! [`escape_default`]: fn.escape_default.html -#![stable(feature = "rust1", since = "1.0.0")] +#![stable(feature = "core_ascii", since = "1.26.0")] use fmt; use ops::Range; @@ -145,357 +145,3 @@ impl fmt::Debug for EscapeDefault { f.pad("EscapeDefault { .. }") } } - - -#[cfg(test)] -mod tests { - use char::from_u32; - - #[test] - fn test_is_ascii() { - assert!(b"".is_ascii()); - assert!(b"banana\0\x7F".is_ascii()); - assert!(b"banana\0\x7F".iter().all(|b| b.is_ascii())); - assert!(!b"Vi\xe1\xbb\x87t Nam".is_ascii()); - assert!(!b"Vi\xe1\xbb\x87t Nam".iter().all(|b| b.is_ascii())); - assert!(!b"\xe1\xbb\x87".iter().any(|b| b.is_ascii())); - - assert!("".is_ascii()); - assert!("banana\0\u{7F}".is_ascii()); - assert!("banana\0\u{7F}".chars().all(|c| c.is_ascii())); - assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii())); - assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii())); - } - - #[test] - fn test_to_ascii_uppercase() { - assert_eq!("url()URL()uRl()ürl".to_ascii_uppercase(), "URL()URL()URL()üRL"); - assert_eq!("hıKß".to_ascii_uppercase(), "HıKß"); - - for i in 0..501 { - let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 } - else { i }; - assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_uppercase(), - (from_u32(upper).unwrap()).to_string()); - } - } - - #[test] - fn test_to_ascii_lowercase() { - assert_eq!("url()URL()uRl()Ürl".to_ascii_lowercase(), "url()url()url()Ürl"); - // Dotted capital I, Kelvin sign, Sharp S. - assert_eq!("HİKß".to_ascii_lowercase(), "hİKß"); - - for i in 0..501 { - let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } - else { i }; - assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_lowercase(), - (from_u32(lower).unwrap()).to_string()); - } - } - - #[test] - fn test_make_ascii_lower_case() { - macro_rules! test { - ($from: expr, $to: expr) => { - { - let mut x = $from; - x.make_ascii_lowercase(); - assert_eq!(x, $to); - } - } - } - test!(b'A', b'a'); - test!(b'a', b'a'); - test!(b'!', b'!'); - test!('A', 'a'); - test!('À', 'À'); - test!('a', 'a'); - test!('!', '!'); - test!(b"H\xc3\x89".to_vec(), b"h\xc3\x89"); - test!("HİKß".to_string(), "hİKß"); - } - - - #[test] - fn test_make_ascii_upper_case() { - macro_rules! test { - ($from: expr, $to: expr) => { - { - let mut x = $from; - x.make_ascii_uppercase(); - assert_eq!(x, $to); - } - } - } - test!(b'a', b'A'); - test!(b'A', b'A'); - test!(b'!', b'!'); - test!('a', 'A'); - test!('à', 'à'); - test!('A', 'A'); - test!('!', '!'); - test!(b"h\xc3\xa9".to_vec(), b"H\xc3\xa9"); - test!("hıKß".to_string(), "HıKß"); - - let mut x = "Hello".to_string(); - x[..3].make_ascii_uppercase(); // Test IndexMut on String. - assert_eq!(x, "HELlo") - } - - #[test] - fn test_eq_ignore_ascii_case() { - assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl")); - assert!(!"Ürl".eq_ignore_ascii_case("ürl")); - // Dotted capital I, Kelvin sign, Sharp S. - assert!("HİKß".eq_ignore_ascii_case("hİKß")); - assert!(!"İ".eq_ignore_ascii_case("i")); - assert!(!"K".eq_ignore_ascii_case("k")); - assert!(!"ß".eq_ignore_ascii_case("s")); - - for i in 0..501 { - let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } - else { i }; - assert!((from_u32(i).unwrap()).to_string().eq_ignore_ascii_case( - &from_u32(lower).unwrap().to_string())); - } - } - - #[test] - fn inference_works() { - let x = "a".to_string(); - x.eq_ignore_ascii_case("A"); - } - - // Shorthands used by the is_ascii_* tests. - macro_rules! assert_all { - ($what:ident, $($str:tt),+) => {{ - $( - for b in $str.chars() { - if !b.$what() { - panic!("expected {}({}) but it isn't", - stringify!($what), b); - } - } - for b in $str.as_bytes().iter() { - if !b.$what() { - panic!("expected {}(0x{:02x})) but it isn't", - stringify!($what), b); - } - } - assert!($str.$what()); - assert!($str.as_bytes().$what()); - )+ - }}; - ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+)) - } - macro_rules! assert_none { - ($what:ident, $($str:tt),+) => {{ - $( - for b in $str.chars() { - if b.$what() { - panic!("expected not-{}({}) but it is", - stringify!($what), b); - } - } - for b in $str.as_bytes().iter() { - if b.$what() { - panic!("expected not-{}(0x{:02x})) but it is", - stringify!($what), b); - } - } - )* - }}; - ($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+)) - } - - #[test] - fn test_is_ascii_alphabetic() { - assert_all!(is_ascii_alphabetic, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - ); - assert_none!(is_ascii_alphabetic, - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_uppercase() { - assert_all!(is_ascii_uppercase, - "", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - ); - assert_none!(is_ascii_uppercase, - "abcdefghijklmnopqrstuvwxyz", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_lowercase() { - assert_all!(is_ascii_lowercase, - "abcdefghijklmnopqrstuvwxyz", - ); - assert_none!(is_ascii_lowercase, - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_alphanumeric() { - assert_all!(is_ascii_alphanumeric, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - ); - assert_none!(is_ascii_alphanumeric, - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_digit() { - assert_all!(is_ascii_digit, - "", - "0123456789", - ); - assert_none!(is_ascii_digit, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_hexdigit() { - assert_all!(is_ascii_hexdigit, - "", - "0123456789", - "abcdefABCDEF", - ); - assert_none!(is_ascii_hexdigit, - "ghijklmnopqrstuvwxyz", - "GHIJKLMNOQPRSTUVWXYZ", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_punctuation() { - assert_all!(is_ascii_punctuation, - "", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - ); - assert_none!(is_ascii_punctuation, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_graphic() { - assert_all!(is_ascii_graphic, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - ); - assert_none!(is_ascii_graphic, - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_whitespace() { - assert_all!(is_ascii_whitespace, - "", - " \t\n\x0c\r", - ); - assert_none!(is_ascii_whitespace, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x0b\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_control() { - assert_all!(is_ascii_control, - "", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - assert_none!(is_ascii_control, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " ", - ); - } -} diff --git a/src/libcore/tests/ascii.rs b/src/libcore/tests/ascii.rs new file mode 100644 index 00000000000..9cc3cd18be5 --- /dev/null +++ b/src/libcore/tests/ascii.rs @@ -0,0 +1,349 @@ +use char::from_u32; + +#[test] +fn test_is_ascii() { + assert!(b"".is_ascii()); + assert!(b"banana\0\x7F".is_ascii()); + assert!(b"banana\0\x7F".iter().all(|b| b.is_ascii())); + assert!(!b"Vi\xe1\xbb\x87t Nam".is_ascii()); + assert!(!b"Vi\xe1\xbb\x87t Nam".iter().all(|b| b.is_ascii())); + assert!(!b"\xe1\xbb\x87".iter().any(|b| b.is_ascii())); + + assert!("".is_ascii()); + assert!("banana\0\u{7F}".is_ascii()); + assert!("banana\0\u{7F}".chars().all(|c| c.is_ascii())); + assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii())); + assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii())); +} + +#[test] +fn test_to_ascii_uppercase() { + assert_eq!("url()URL()uRl()ürl".to_ascii_uppercase(), "URL()URL()URL()üRL"); + assert_eq!("hıKß".to_ascii_uppercase(), "HıKß"); + + for i in 0..501 { + let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 } + else { i }; + assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_uppercase(), + (from_u32(upper).unwrap()).to_string()); + } +} + +#[test] +fn test_to_ascii_lowercase() { + assert_eq!("url()URL()uRl()Ürl".to_ascii_lowercase(), "url()url()url()Ürl"); + // Dotted capital I, Kelvin sign, Sharp S. + assert_eq!("HİKß".to_ascii_lowercase(), "hİKß"); + + for i in 0..501 { + let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } + else { i }; + assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_lowercase(), + (from_u32(lower).unwrap()).to_string()); + } +} + +#[test] +fn test_make_ascii_lower_case() { + macro_rules! test { + ($from: expr, $to: expr) => { + { + let mut x = $from; + x.make_ascii_lowercase(); + assert_eq!(x, $to); + } + } + } + test!(b'A', b'a'); + test!(b'a', b'a'); + test!(b'!', b'!'); + test!('A', 'a'); + test!('À', 'À'); + test!('a', 'a'); + test!('!', '!'); + test!(b"H\xc3\x89".to_vec(), b"h\xc3\x89"); + test!("HİKß".to_string(), "hİKß"); +} + + +#[test] +fn test_make_ascii_upper_case() { + macro_rules! test { + ($from: expr, $to: expr) => { + { + let mut x = $from; + x.make_ascii_uppercase(); + assert_eq!(x, $to); + } + } + } + test!(b'a', b'A'); + test!(b'A', b'A'); + test!(b'!', b'!'); + test!('a', 'A'); + test!('à', 'à'); + test!('A', 'A'); + test!('!', '!'); + test!(b"h\xc3\xa9".to_vec(), b"H\xc3\xa9"); + test!("hıKß".to_string(), "HıKß"); + + let mut x = "Hello".to_string(); + x[..3].make_ascii_uppercase(); // Test IndexMut on String. + assert_eq!(x, "HELlo") +} + +#[test] +fn test_eq_ignore_ascii_case() { + assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl")); + assert!(!"Ürl".eq_ignore_ascii_case("ürl")); + // Dotted capital I, Kelvin sign, Sharp S. + assert!("HİKß".eq_ignore_ascii_case("hİKß")); + assert!(!"İ".eq_ignore_ascii_case("i")); + assert!(!"K".eq_ignore_ascii_case("k")); + assert!(!"ß".eq_ignore_ascii_case("s")); + + for i in 0..501 { + let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } + else { i }; + assert!((from_u32(i).unwrap()).to_string().eq_ignore_ascii_case( + &from_u32(lower).unwrap().to_string())); + } +} + +#[test] +fn inference_works() { + let x = "a".to_string(); + x.eq_ignore_ascii_case("A"); +} + +// Shorthands used by the is_ascii_* tests. +macro_rules! assert_all { + ($what:ident, $($str:tt),+) => {{ + $( + for b in $str.chars() { + if !b.$what() { + panic!("expected {}({}) but it isn't", + stringify!($what), b); + } + } + for b in $str.as_bytes().iter() { + if !b.$what() { + panic!("expected {}(0x{:02x})) but it isn't", + stringify!($what), b); + } + } + assert!($str.$what()); + assert!($str.as_bytes().$what()); + )+ + }}; + ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+)) +} +macro_rules! assert_none { + ($what:ident, $($str:tt),+) => {{ + $( + for b in $str.chars() { + if b.$what() { + panic!("expected not-{}({}) but it is", + stringify!($what), b); + } + } + for b in $str.as_bytes().iter() { + if b.$what() { + panic!("expected not-{}(0x{:02x})) but it is", + stringify!($what), b); + } + } + )* + }}; + ($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+)) +} + +#[test] +fn test_is_ascii_alphabetic() { + assert_all!(is_ascii_alphabetic, + "", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + ); + assert_none!(is_ascii_alphabetic, + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_uppercase() { + assert_all!(is_ascii_uppercase, + "", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + ); + assert_none!(is_ascii_uppercase, + "abcdefghijklmnopqrstuvwxyz", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_lowercase() { + assert_all!(is_ascii_lowercase, + "abcdefghijklmnopqrstuvwxyz", + ); + assert_none!(is_ascii_lowercase, + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_alphanumeric() { + assert_all!(is_ascii_alphanumeric, + "", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + ); + assert_none!(is_ascii_alphanumeric, + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_digit() { + assert_all!(is_ascii_digit, + "", + "0123456789", + ); + assert_none!(is_ascii_digit, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_hexdigit() { + assert_all!(is_ascii_hexdigit, + "", + "0123456789", + "abcdefABCDEF", + ); + assert_none!(is_ascii_hexdigit, + "ghijklmnopqrstuvwxyz", + "GHIJKLMNOQPRSTUVWXYZ", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_punctuation() { + assert_all!(is_ascii_punctuation, + "", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + ); + assert_none!(is_ascii_punctuation, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_graphic() { + assert_all!(is_ascii_graphic, + "", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + ); + assert_none!(is_ascii_graphic, + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_whitespace() { + assert_all!(is_ascii_whitespace, + "", + " \t\n\x0c\r", + ); + assert_none!(is_ascii_whitespace, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x0b\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_control() { + assert_all!(is_ascii_control, + "", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); + assert_none!(is_ascii_control, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " ", + ); +} diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 430c9df396a..70fef9ef5d4 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -30,6 +30,9 @@ use fmt; use ops::Range; use iter::FusedIterator; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::ascii::{EscapeDefault, escape_default}; + /// Extension methods for ASCII-subset only operations. /// /// Be aware that operations on seemingly non-ASCII characters can sometimes @@ -483,477 +486,3 @@ impl AsciiExt for str { self.bytes().all(|b| b.is_ascii_control()) } } - -/// An iterator over the escaped version of a byte. -/// -/// This `struct` is created by the [`escape_default`] function. See its -/// documentation for more. -/// -/// [`escape_default`]: fn.escape_default.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct EscapeDefault { - range: Range, - data: [u8; 4], -} - -/// Returns an iterator that produces an escaped version of a `u8`. -/// -/// The default is chosen with a bias toward producing literals that are -/// legal in a variety of languages, including C++11 and similar C-family -/// languages. The exact rules are: -/// -/// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively. -/// - Single-quote, double-quote and backslash chars are backslash-escaped. -/// - Any other chars in the range [0x20,0x7e] are not escaped. -/// - Any other chars are given hex escapes of the form '\xNN'. -/// - Unicode escapes are never generated by this function. -/// -/// # Examples -/// -/// ``` -/// use std::ascii; -/// -/// let escaped = ascii::escape_default(b'0').next().unwrap(); -/// assert_eq!(b'0', escaped); -/// -/// let mut escaped = ascii::escape_default(b'\t'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b't', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'\r'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'r', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'\n'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'n', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'\''); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'\'', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'"'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'"', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'\\'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'\x9d'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'x', escaped.next().unwrap()); -/// assert_eq!(b'9', escaped.next().unwrap()); -/// assert_eq!(b'd', escaped.next().unwrap()); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn escape_default(c: u8) -> EscapeDefault { - let (data, len) = match c { - b'\t' => ([b'\\', b't', 0, 0], 2), - b'\r' => ([b'\\', b'r', 0, 0], 2), - b'\n' => ([b'\\', b'n', 0, 0], 2), - b'\\' => ([b'\\', b'\\', 0, 0], 2), - b'\'' => ([b'\\', b'\'', 0, 0], 2), - b'"' => ([b'\\', b'"', 0, 0], 2), - b'\x20' ... b'\x7e' => ([c, 0, 0, 0], 1), - _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4), - }; - - return EscapeDefault { range: (0.. len), data: data }; - - fn hexify(b: u8) -> u8 { - match b { - 0 ... 9 => b'0' + b, - _ => b'a' + b - 10, - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for EscapeDefault { - type Item = u8; - fn next(&mut self) -> Option { self.range.next().map(|i| self.data[i]) } - fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for EscapeDefault { - fn next_back(&mut self) -> Option { - self.range.next_back().map(|i| self.data[i]) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for EscapeDefault {} -#[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for EscapeDefault {} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for EscapeDefault { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("EscapeDefault { .. }") - } -} - - -#[cfg(test)] -mod tests { - //! Note that most of these tests are not testing `AsciiExt` methods, but - //! test inherent ascii methods of char, u8, str and [u8]. `AsciiExt` is - //! just using those methods, though. - use super::AsciiExt; - use char::from_u32; - - #[test] - fn test_is_ascii() { - assert!(b"".is_ascii()); - assert!(b"banana\0\x7F".is_ascii()); - assert!(b"banana\0\x7F".iter().all(|b| b.is_ascii())); - assert!(!b"Vi\xe1\xbb\x87t Nam".is_ascii()); - assert!(!b"Vi\xe1\xbb\x87t Nam".iter().all(|b| b.is_ascii())); - assert!(!b"\xe1\xbb\x87".iter().any(|b| b.is_ascii())); - - assert!("".is_ascii()); - assert!("banana\0\u{7F}".is_ascii()); - assert!("banana\0\u{7F}".chars().all(|c| c.is_ascii())); - assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii())); - assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii())); - } - - #[test] - fn test_to_ascii_uppercase() { - assert_eq!("url()URL()uRl()ürl".to_ascii_uppercase(), "URL()URL()URL()üRL"); - assert_eq!("hıKß".to_ascii_uppercase(), "HıKß"); - - for i in 0..501 { - let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 } - else { i }; - assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_uppercase(), - (from_u32(upper).unwrap()).to_string()); - } - } - - #[test] - fn test_to_ascii_lowercase() { - assert_eq!("url()URL()uRl()Ürl".to_ascii_lowercase(), "url()url()url()Ürl"); - // Dotted capital I, Kelvin sign, Sharp S. - assert_eq!("HİKß".to_ascii_lowercase(), "hİKß"); - - for i in 0..501 { - let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } - else { i }; - assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_lowercase(), - (from_u32(lower).unwrap()).to_string()); - } - } - - #[test] - fn test_make_ascii_lower_case() { - macro_rules! test { - ($from: expr, $to: expr) => { - { - let mut x = $from; - x.make_ascii_lowercase(); - assert_eq!(x, $to); - } - } - } - test!(b'A', b'a'); - test!(b'a', b'a'); - test!(b'!', b'!'); - test!('A', 'a'); - test!('À', 'À'); - test!('a', 'a'); - test!('!', '!'); - test!(b"H\xc3\x89".to_vec(), b"h\xc3\x89"); - test!("HİKß".to_string(), "hİKß"); - } - - - #[test] - fn test_make_ascii_upper_case() { - macro_rules! test { - ($from: expr, $to: expr) => { - { - let mut x = $from; - x.make_ascii_uppercase(); - assert_eq!(x, $to); - } - } - } - test!(b'a', b'A'); - test!(b'A', b'A'); - test!(b'!', b'!'); - test!('a', 'A'); - test!('à', 'à'); - test!('A', 'A'); - test!('!', '!'); - test!(b"h\xc3\xa9".to_vec(), b"H\xc3\xa9"); - test!("hıKß".to_string(), "HıKß"); - - let mut x = "Hello".to_string(); - x[..3].make_ascii_uppercase(); // Test IndexMut on String. - assert_eq!(x, "HELlo") - } - - #[test] - fn test_eq_ignore_ascii_case() { - assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl")); - assert!(!"Ürl".eq_ignore_ascii_case("ürl")); - // Dotted capital I, Kelvin sign, Sharp S. - assert!("HİKß".eq_ignore_ascii_case("hİKß")); - assert!(!"İ".eq_ignore_ascii_case("i")); - assert!(!"K".eq_ignore_ascii_case("k")); - assert!(!"ß".eq_ignore_ascii_case("s")); - - for i in 0..501 { - let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } - else { i }; - assert!((from_u32(i).unwrap()).to_string().eq_ignore_ascii_case( - &from_u32(lower).unwrap().to_string())); - } - } - - #[test] - fn inference_works() { - let x = "a".to_string(); - x.eq_ignore_ascii_case("A"); - } - - // Shorthands used by the is_ascii_* tests. - macro_rules! assert_all { - ($what:ident, $($str:tt),+) => {{ - $( - for b in $str.chars() { - if !b.$what() { - panic!("expected {}({}) but it isn't", - stringify!($what), b); - } - } - for b in $str.as_bytes().iter() { - if !b.$what() { - panic!("expected {}(0x{:02x})) but it isn't", - stringify!($what), b); - } - } - assert!($str.$what()); - assert!($str.as_bytes().$what()); - )+ - }}; - ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+)) - } - macro_rules! assert_none { - ($what:ident, $($str:tt),+) => {{ - $( - for b in $str.chars() { - if b.$what() { - panic!("expected not-{}({}) but it is", - stringify!($what), b); - } - } - for b in $str.as_bytes().iter() { - if b.$what() { - panic!("expected not-{}(0x{:02x})) but it is", - stringify!($what), b); - } - } - )* - }}; - ($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+)) - } - - #[test] - fn test_is_ascii_alphabetic() { - assert_all!(is_ascii_alphabetic, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - ); - assert_none!(is_ascii_alphabetic, - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_uppercase() { - assert_all!(is_ascii_uppercase, - "", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - ); - assert_none!(is_ascii_uppercase, - "abcdefghijklmnopqrstuvwxyz", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_lowercase() { - assert_all!(is_ascii_lowercase, - "abcdefghijklmnopqrstuvwxyz", - ); - assert_none!(is_ascii_lowercase, - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_alphanumeric() { - assert_all!(is_ascii_alphanumeric, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - ); - assert_none!(is_ascii_alphanumeric, - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_digit() { - assert_all!(is_ascii_digit, - "", - "0123456789", - ); - assert_none!(is_ascii_digit, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_hexdigit() { - assert_all!(is_ascii_hexdigit, - "", - "0123456789", - "abcdefABCDEF", - ); - assert_none!(is_ascii_hexdigit, - "ghijklmnopqrstuvwxyz", - "GHIJKLMNOQPRSTUVWXYZ", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_punctuation() { - assert_all!(is_ascii_punctuation, - "", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - ); - assert_none!(is_ascii_punctuation, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_graphic() { - assert_all!(is_ascii_graphic, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - ); - assert_none!(is_ascii_graphic, - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_whitespace() { - assert_all!(is_ascii_whitespace, - "", - " \t\n\x0c\r", - ); - assert_none!(is_ascii_whitespace, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x0b\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_control() { - assert_all!(is_ascii_control, - "", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - assert_none!(is_ascii_control, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " ", - ); - } -} -- cgit 1.4.1-3-g733a5 From a39b62d838d7642ca100c069b6b1b716ef7eb97b Mon Sep 17 00:00:00 2001 From: 1011X <1011XXXXX@gmail.com> Date: Mon, 5 Mar 2018 17:02:11 -0500 Subject: Copy license into libcore/tests/ascii.rs --- src/libcore/tests/ascii.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/tests/ascii.rs b/src/libcore/tests/ascii.rs index 9cc3cd18be5..dbed5920519 100644 --- a/src/libcore/tests/ascii.rs +++ b/src/libcore/tests/ascii.rs @@ -1,3 +1,13 @@ +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + use char::from_u32; #[test] -- cgit 1.4.1-3-g733a5 From 24fb4b766952edbd9daf71dc74dcdc62a7511711 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 27 Feb 2018 04:34:55 +0000 Subject: Add reverse_bits to integer types --- src/libcore/num/mod.rs | 54 ++++++++++++++++++++++++++++++++++++ src/libcore/tests/lib.rs | 1 + src/libcore/tests/num/uint_macros.rs | 11 ++++++++ 3 files changed, 66 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 59a67fff48c..a46ac2b5f0f 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -321,6 +321,33 @@ $EndFeature, " (self as $UnsignedT).swap_bytes() as Self } + /// Reverses the bit pattern of the integer. + /// + /// # Examples + /// + /// Please note that this example is shared between integer types. + /// Which explains why `i16` is used here. + /// + /// Basic usage: + /// + /// ``` + /// #![feature(reverse_bits)] + /// + /// let n: i16 = 0b0000000_01010101; + /// assert_eq!(n, 85); + /// + /// let m = n.reverse_bits(); + /// + /// assert_eq!(m as u16, 0b10101010_00000000); + /// assert_eq!(m, -22016); + /// ``` + #[unstable(feature = "reverse_bits", issue = "48763")] + #[cfg(not(stage0))] + #[inline] + pub fn reverse_bits(self) -> Self { + (self as $UnsignedT).reverse_bits() as Self + } + doc_comment! { concat!("Converts an integer from big endian to the target's endianness. @@ -1773,6 +1800,33 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " unsafe { intrinsics::bswap(self as $ActualT) as Self } } + /// Reverses the bit pattern of the integer. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u16` is used here. + /// + /// ``` + /// #![feature(reverse_bits)] + /// + /// let n: u16 = 0b0000000_01010101; + /// assert_eq!(n, 85); + /// + /// let m = n.reverse_bits(); + /// + /// assert_eq!(m, 0b10101010_00000000); + /// assert_eq!(m, 43520); + /// ``` + #[unstable(feature = "reverse_bits", issue = "48763")] + #[cfg(not(stage0))] + #[inline] + pub fn reverse_bits(self) -> Self { + unsafe { intrinsics::bitreverse(self as $ActualT) as Self } + } + doc_comment! { concat!("Converts an integer from big endian to the target's endianness. diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 0049ed66a10..a9c5683e0ef 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -46,6 +46,7 @@ #![feature(try_trait)] #![feature(exact_chunks)] #![feature(atomic_nand)] +#![feature(reverse_bits)] extern crate core; extern crate test; diff --git a/src/libcore/tests/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs index daa1cc3a7f4..ca6906f7310 100644 --- a/src/libcore/tests/num/uint_macros.rs +++ b/src/libcore/tests/num/uint_macros.rs @@ -97,6 +97,17 @@ mod tests { assert_eq!(_1.swap_bytes(), _1); } + #[test] + fn test_reverse_bits() { + assert_eq!(A.reverse_bits().reverse_bits(), A); + assert_eq!(B.reverse_bits().reverse_bits(), B); + assert_eq!(C.reverse_bits().reverse_bits(), C); + + // Swapping these should make no difference + assert_eq!(_0.reverse_bits(), _0); + assert_eq!(_1.reverse_bits(), _1); + } + #[test] fn test_le() { assert_eq!($T::from_le(A.to_le()), A); -- cgit 1.4.1-3-g733a5 From a0c626227eeb98f864f67c42845b76f126bc519a Mon Sep 17 00:00:00 2001 From: 1011X <1011XXXXX@gmail.com> Date: Tue, 6 Mar 2018 16:33:38 -0500 Subject: FusedIterator will be stabilized --- src/libcore/ascii.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index f409536d1b0..2c4bccebceb 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -136,7 +136,7 @@ impl DoubleEndedIterator for EscapeDefault { } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for EscapeDefault {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for EscapeDefault {} #[stable(feature = "std_debug", since = "1.16.0")] -- cgit 1.4.1-3-g733a5 From d04362f23d5899af5aa01562c27fc6ddb53a4d7e Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Tue, 6 Mar 2018 10:30:42 -0800 Subject: Stabilize option_ref_mut_cloned Closes #43738. --- src/libcore/option.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 25f57d8c0f7..570f745f833 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -829,14 +829,13 @@ impl<'a, T: Clone> Option<&'a mut T> { /// # Examples /// /// ``` - /// #![feature(option_ref_mut_cloned)] /// let mut x = 12; /// let opt_x = Some(&mut x); /// assert_eq!(opt_x, Some(&mut 12)); /// let cloned = opt_x.cloned(); /// assert_eq!(cloned, Some(12)); /// ``` - #[unstable(feature = "option_ref_mut_cloned", issue = "43738")] + #[stable(since = "1.26.0", feature = "option_ref_mut_cloned")] pub fn cloned(self) -> Option { self.map(|t| t.clone()) } -- cgit 1.4.1-3-g733a5 From 517083fbad1cab6652efe66f36ed7f085eb67b61 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Wed, 7 Mar 2018 16:13:15 +0900 Subject: Make `assert` macro a built-in procedural macro --- src/libcore/macros.rs | 15 +++++++++++ src/libstd/lib.rs | 3 ++- src/libstd/macros.rs | 54 ++++++++++++++++++++++++++++++++++++++ src/libsyntax_ext/assert.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++ src/libsyntax_ext/lib.rs | 2 ++ 5 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 src/libsyntax_ext/assert.rs (limited to 'src/libcore') diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 52eb9f29d57..8a87bea71e2 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -76,6 +76,7 @@ macro_rules! panic { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg(stage0)] macro_rules! assert { ($cond:expr) => ( if !$cond { @@ -784,4 +785,18 @@ mod builtin { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); } + + /// Ensure that a boolean expression is `true` at runtime. + /// + /// For more information, see the documentation for [`std::assert!`]. + /// + /// [`std::assert!`]: ../std/macro.assert.html + #[macro_export] + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(dox)] + macro_rules! assert { + ($cond:expr) => ({ /* compiler built-in */ }); + ($cond:expr,) => ({ /* compiler built-in */ }); + ($cond:expr, $($arg:tt)+) => ({ /* compiler built-in */ }); + } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a7e1c0ce732..b2e45f0f437 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -355,8 +355,9 @@ use prelude::v1::*; // We want to re-export a few macros from core but libcore has already been // imported by the compiler (via our #[no_std] attribute) In this case we just // add a new crate name so we can attach the re-exports to it. -#[macro_reexport(assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, +#[macro_reexport(assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, unreachable, unimplemented, write, writeln, try)] +#[cfg_attr(stage0, macro_reexport(assert))] extern crate core as __core; #[macro_use] diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index a18c811d196..da982af498b 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -719,6 +719,60 @@ pub mod builtin { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); } + + /// Ensure that a boolean expression is `true` at runtime. + /// + /// This will invoke the [`panic!`] macro if the provided expression cannot be + /// evaluated to `true` at runtime. + /// + /// # Uses + /// + /// Assertions are always checked in both debug and release builds, and cannot + /// be disabled. See [`debug_assert!`] for assertions that are not enabled in + /// release builds by default. + /// + /// Unsafe code relies on `assert!` to enforce run-time invariants that, if + /// violated could lead to unsafety. + /// + /// Other use-cases of `assert!` include [testing] and enforcing run-time + /// invariants in safe code (whose violation cannot result in unsafety). + /// + /// # Custom Messages + /// + /// This macro has a second form, where a custom panic message can + /// be provided with or without arguments for formatting. See [`std::fmt`] + /// for syntax for this form. + /// + /// [`panic!`]: macro.panic.html + /// [`debug_assert!`]: macro.debug_assert.html + /// [testing]: ../book/second-edition/ch11-01-writing-tests.html#checking-results-with-the-assert-macro + /// [`std::fmt`]: ../std/fmt/index.html + /// + /// # Examples + /// + /// ``` + /// // the panic message for these assertions is the stringified value of the + /// // expression given. + /// assert!(true); + /// + /// fn some_computation() -> bool { true } // a very simple function + /// + /// assert!(some_computation()); + /// + /// // assert with a custom message + /// let x = true; + /// assert!(x, "x wasn't true!"); + /// + /// let a = 3; let b = 27; + /// assert!(a + b == 30, "a = {}, b = {}", a, b); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + macro_rules! assert { + ($cond:expr) => ({ /* compiler built-in */ }); + ($cond:expr,) => ({ /* compiler built-in */ }); + ($cond:expr, $($arg:tt)+) => ({ /* compiler built-in */ }); + } } /// A macro for defining #[cfg] if-else statements. diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs new file mode 100644 index 00000000000..7962ec26c37 --- /dev/null +++ b/src/libsyntax_ext/assert.rs @@ -0,0 +1,64 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast::*; +use syntax::codemap::Spanned; +use syntax::ext::base::*; +use syntax::ext::build::AstBuilder; +use syntax::parse::token; +use syntax::print::pprust; +use syntax::tokenstream::{TokenStream, TokenTree}; +use syntax_pos::Span; + +pub fn expand_assert<'cx>( + cx: &'cx mut ExtCtxt, + sp: Span, + tts: &[TokenTree], +) -> Box { + let mut parser = cx.new_parser_from_tts(tts); + let cond_expr = panictry!(parser.parse_expr()); + let custom_msg_args = if parser.eat(&token::Comma) { + let ts = parser.parse_tokens(); + if !ts.is_empty() { + Some(ts) + } else { + None + } + } else { + None + }; + + let sp = sp.with_ctxt(sp.ctxt().apply_mark(cx.current_expansion.mark)); + let panic_call = Mac_ { + path: Path::from_ident(sp, Ident::from_str("panic")), + tts: if let Some(ts) = custom_msg_args { + ts.into() + } else { + let panic_str = format!("assertion failed: {}", pprust::expr_to_string(&cond_expr)); + TokenStream::from(token::Literal( + token::Lit::Str_(Name::intern(&panic_str)), + None, + )).into() + }, + }; + let if_expr = cx.expr_if( + sp, + cx.expr(sp, ExprKind::Unary(UnOp::Not, cond_expr)), + cx.expr( + sp, + ExprKind::Mac(Spanned { + span: sp, + node: panic_call, + }), + ), + None, + ); + MacEager::expr(if_expr) +} diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 772dec72ab9..a01878530b2 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -26,6 +26,7 @@ extern crate proc_macro; extern crate rustc_data_structures; extern crate rustc_errors as errors; +mod assert; mod asm; mod cfg; mod compile_error; @@ -111,6 +112,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, log_syntax: log_syntax::expand_syntax_ext, trace_macros: trace_macros::expand_trace_macros, compile_error: compile_error::expand_compile_error, + assert: assert::expand_assert, } // format_args uses `unstable` things internally. -- cgit 1.4.1-3-g733a5 From 918b6d763319863fb53c5b7bceebc14ad5fb4024 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 09:24:38 +0100 Subject: Produce instead of pointers --- src/libcore/cmp.rs | 4 +- src/librustc/dep_graph/dep_node.rs | 1 + src/librustc/middle/const_val.rs | 39 ++- src/librustc/middle/lang_items.rs | 1 + src/librustc/middle/mem_categorization.rs | 3 +- src/librustc/mir/interpret/value.rs | 10 + src/librustc/mir/mod.rs | 80 ++++- src/librustc/mir/tcx.rs | 2 +- src/librustc/mir/visit.rs | 14 +- src/librustc/ty/context.rs | 39 ++- src/librustc/ty/error.rs | 11 +- src/librustc/ty/inhabitedness/mod.rs | 2 +- src/librustc/ty/layout.rs | 4 +- src/librustc/ty/maps/config.rs | 1 + src/librustc/ty/maps/keys.rs | 1 + src/librustc/ty/maps/on_disk_cache.rs | 9 +- src/librustc/ty/mod.rs | 28 ++ src/librustc/ty/relate.rs | 9 + src/librustc/ty/structural_impls.rs | 55 ++++ src/librustc/ty/util.rs | 2 + src/librustc/util/ppaux.rs | 4 + src/librustc_const_eval/_match.rs | 180 +++++++++-- src/librustc_const_eval/eval.rs | 180 +++++------ src/librustc_const_eval/pattern.rs | 335 +++++++++++++-------- src/librustc_data_structures/stable_hasher.rs | 8 + src/librustc_lint/types.rs | 11 + src/librustc_metadata/decoder.rs | 38 ++- src/librustc_metadata/encoder.rs | 14 +- .../borrow_check/nll/type_check/mod.rs | 47 ++- src/librustc_mir/build/expr/as_rvalue.rs | 21 +- src/librustc_mir/build/matches/mod.rs | 2 +- src/librustc_mir/build/matches/test.rs | 69 ++++- src/librustc_mir/build/misc.rs | 19 +- src/librustc_mir/hair/cx/expr.rs | 46 ++- src/librustc_mir/hair/cx/mod.rs | 178 ++++++++++- src/librustc_mir/interpret/const_eval.rs | 153 +++++++--- src/librustc_mir/interpret/eval_context.rs | 4 +- src/librustc_mir/interpret/mod.rs | 2 +- src/librustc_mir/interpret/operator.rs | 5 + src/librustc_mir/interpret/place.rs | 43 +-- src/librustc_mir/interpret/terminator/mod.rs | 4 +- src/librustc_mir/monomorphize/item.rs | 2 +- src/librustc_mir/shim.rs | 29 +- src/librustc_mir/transform/generator.rs | 9 +- src/librustc_mir/transform/inline.rs | 7 + src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_mir/transform/simplify_branches.rs | 4 +- src/librustc_mir/util/elaborate_drops.rs | 15 +- src/librustc_passes/consts.rs | 23 +- src/librustc_trans/base.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/debuginfo/type_names.rs | 2 +- src/librustc_trans/mir/analyze.rs | 19 +- src/librustc_trans/mir/block.rs | 9 +- src/librustc_trans/mir/constant.rs | 110 ++++--- src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/check/op.rs | 8 +- src/librustc_typeck/collect.rs | 16 +- src/librustc_typeck/lib.rs | 1 + src/test/mir-opt/end_region_2.rs | 2 +- src/test/mir-opt/end_region_3.rs | 2 +- src/test/mir-opt/end_region_9.rs | 2 +- src/test/mir-opt/end_region_cyclic.rs | 2 +- src/test/mir-opt/issue-38669.rs | 2 +- src/test/mir-opt/match_false_edges.rs | 10 +- src/test/mir-opt/nll/region-liveness-basic.rs | 2 +- src/test/mir-opt/simplify_if.rs | 2 +- src/test/ui/const-eval-overflow-2.rs | 3 +- src/test/ui/const-eval-overflow-4.rs | 3 +- src/test/ui/const-eval/issue-43197.rs | 2 - src/test/ui/const-expr-addr-operator.rs | 3 +- src/test/ui/const-fn-error.rs | 13 +- src/test/ui/const-fn-error.stderr | 14 + src/test/ui/const-len-underflow-separate-spans.rs | 3 +- src/test/ui/const-pattern-not-const-evaluable.rs | 4 +- src/test/ui/feature-gate-const-indexing.rs | 3 +- src/test/ui/issue-38875/issue_38875.rs | 1 + src/test/ui/union/union-const-eval.rs | 9 +- 80 files changed, 1496 insertions(+), 532 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index b9847044982..6602643dc51 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -427,6 +427,7 @@ impl Ord for Reverse { /// } /// } /// ``` +#[cfg_attr(not(stage0), lang = "ord")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Ord: Eq + PartialOrd { /// This method returns an `Ordering` between `self` and `other`. @@ -596,7 +597,8 @@ impl PartialOrd for Ordering { /// assert_eq!(x < y, true); /// assert_eq!(x.lt(&y), true); /// ``` -#[lang = "ord"] +#[cfg_attr(stage0, lang = "ord")] +#[cfg_attr(not(stage0), lang = "partial_ord")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialOrd: PartialEq { diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index ed46296389d..15e1d38be69 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -63,6 +63,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use hir::map::DefPathHash; use hir::{HirId, ItemLocalId}; +use mir; use ich::Fingerprint; use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty}; diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 589890947cd..cf322010e05 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -14,7 +14,7 @@ use hir::def_id::DefId; use ty::{self, TyCtxt, layout}; use ty::subst::Substs; use rustc_const_math::*; -use mir::interpret::Value; +use mir::interpret::{Value, PrimVal}; use graphviz::IntoCow; use errors::DiagnosticBuilder; @@ -39,7 +39,7 @@ pub enum ConstVal<'tcx> { Function(DefId, &'tcx Substs<'tcx>), Aggregate(ConstAggregate<'tcx>), Unevaluated(DefId, &'tcx Substs<'tcx>), - /// A miri value, currently only produced if old ctfe fails, but miri succeeds + /// A miri value, currently only produced if --miri is enabled Value(Value), } @@ -71,12 +71,37 @@ impl<'tcx> Decodable for ConstAggregate<'tcx> { } impl<'tcx> ConstVal<'tcx> { - pub fn to_const_int(&self) -> Option { + pub fn to_u128(&self) -> Option { match *self { - ConstVal::Integral(i) => Some(i), - ConstVal::Bool(b) => Some(ConstInt::U8(b as u8)), - ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)), - _ => None + ConstVal::Integral(i) => i.to_u128(), + ConstVal::Bool(b) => Some(b as u128), + ConstVal::Char(ch) => Some(ch as u32 as u128), + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { + Some(b) + }, + _ => None, + } + } + pub fn unwrap_u64(&self) -> u64 { + match self.to_u128() { + Some(val) => { + assert_eq!(val as u64 as u128, val); + val as u64 + }, + None => bug!("expected constant u64, got {:#?}", self), + } + } + pub fn unwrap_usize<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> ConstUsize { + match *self { + ConstVal::Integral(ConstInt::Usize(i)) => i, + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { + assert_eq!(b as u64 as u128, b); + match ConstUsize::new(b as u64, tcx.sess.target.usize_ty) { + Ok(val) => val, + Err(e) => bug!("{:#?} is not a usize {:?}", self, e), + } + }, + _ => bug!("expected constant u64, got {:#?}", self), } } } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 447ce46ee5c..3b37031cf46 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -280,6 +280,7 @@ language_item_table! { GeneratorTraitLangItem, "generator", gen_trait; EqTraitLangItem, "eq", eq_trait; + PartialOrdTraitLangItem, "partial_ord", partial_ord_trait; OrdTraitLangItem, "ord", ord_trait; // A number of panic-related lang items. The `panic` item corresponds to diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index c532427cc9b..1c60ae36cd3 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -913,8 +913,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // Always promote `[T; 0]` (even when e.g. borrowed mutably). let promotable = match expr_ty.sty { - ty::TyArray(_, len) if - len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) => true, + ty::TyArray(_, len) if len.val.to_u128() == Some(0) => true, _ => promotable, }; diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 8d67856c0df..c00956c0a85 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -1,6 +1,7 @@ #![allow(unknown_lints)] use ty::layout::{Align, HasDataLayout}; +use ty; use super::{EvalResult, MemoryPointer, PointerArithmetic}; use syntax::ast::FloatTy; @@ -36,6 +37,15 @@ pub enum Value { ByValPair(PrimVal, PrimVal), } +impl<'tcx> ty::TypeFoldable<'tcx> for Value { + fn super_fold_with<'gcx: 'tcx, F: ty::fold::TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self { + *self + } + fn super_visit_with>(&self, _: &mut V) -> bool { + false + } +} + /// A wrapper type around `PrimVal` that cannot be turned back into a `PrimVal` accidentally. /// This type clears up a few APIs where having a `PrimVal` argument for something that is /// potentially an integer pointer or a pointer to an allocation was unclear. diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 4c1b8cb79ed..d35cbd0027f 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -15,7 +15,7 @@ use graphviz::IntoCow; use middle::const_val::ConstVal; use middle::region; -use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr}; +use rustc_const_math::{ConstUsize, ConstMathErr}; use rustc_data_structures::sync::{Lrc}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators}; @@ -25,9 +25,11 @@ use rustc_serialize as serialize; use hir::def::CtorKind; use hir::def_id::DefId; use mir::visit::MirVisitable; +use mir::interpret::{Value, PrimVal}; use ty::subst::{Subst, Substs}; use ty::{self, AdtDef, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use ty::TypeAndMut; use util::ppaux; use std::slice; use hir::{self, InlineAsm}; @@ -707,7 +709,7 @@ pub enum TerminatorKind<'tcx> { /// Possible values. The locations to branch to in each case /// are found in the corresponding indices from the `targets` vector. - values: Cow<'tcx, [ConstInt]>, + values: Cow<'tcx, [u128]>, /// Possible branch sites. The last element of this vector is used /// for the otherwise branch, so targets.len() == values.len() + 1 @@ -858,7 +860,7 @@ impl<'tcx> Terminator<'tcx> { impl<'tcx> TerminatorKind<'tcx> { pub fn if_<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> { - static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::U8(0)]; + static BOOL_SWITCH_FALSE: &'static [u128] = &[0]; TerminatorKind::SwitchInt { discr: cond, switch_ty: tcx.types.bool, @@ -1144,12 +1146,16 @@ impl<'tcx> TerminatorKind<'tcx> { match *self { Return | Resume | Abort | Unreachable | GeneratorDrop => vec![], Goto { .. } => vec!["".into()], - SwitchInt { ref values, .. } => { + SwitchInt { ref values, switch_ty, .. } => { values.iter() - .map(|const_val| { - let mut buf = String::new(); - fmt_const_val(&mut buf, &ConstVal::Integral(*const_val)).unwrap(); - buf.into() + .map(|&u| { + let mut s = String::new(); + print_miri_value( + Value::ByVal(PrimVal::Bytes(u)), + switch_ty, + &mut s, + ).unwrap(); + s.into() }) .chain(iter::once(String::from("otherwise").into())) .collect() @@ -1533,7 +1539,12 @@ impl<'tcx> Operand<'tcx> { ty, literal: Literal::Value { value: tcx.mk_const(ty::Const { - val: ConstVal::Function(def_id, substs), + val: if tcx.sess.opts.debugging_opts.miri { + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(def_id, substs) + }, ty }) }, @@ -1853,7 +1864,7 @@ impl<'tcx> Debug for Literal<'tcx> { match *self { Value { value } => { write!(fmt, "const ")?; - fmt_const_val(fmt, &value.val) + fmt_const_val(fmt, value) } Promoted { index } => { write!(fmt, "{:?}", index) @@ -1863,9 +1874,9 @@ impl<'tcx> Debug for Literal<'tcx> { } /// Write a `ConstVal` in a way closer to the original source code than the `Debug` output. -fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { +fn fmt_const_val(fmt: &mut W, const_val: &ty::Const) -> fmt::Result { use middle::const_val::ConstVal::*; - match *const_val { + match const_val.val { Float(f) => write!(fmt, "{:?}", f), Integral(n) => write!(fmt, "{}", n), Str(s) => write!(fmt, "{:?}", s), @@ -1882,7 +1893,41 @@ fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)), Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val), Unevaluated(..) => write!(fmt, "{:?}", const_val), - Value(val) => write!(fmt, "{:?}", val), + Value(val) => print_miri_value(val, const_val.ty, fmt), + } +} + +fn print_miri_value(value: Value, ty: Ty, f: &mut W) -> fmt::Result { + use ty::TypeVariants::*; + use rustc_const_math::ConstFloat; + match (value, &ty.sty) { + (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"), + (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"), + (Value::ByVal(PrimVal::Bytes(bits)), &TyFloat(fty)) => + write!(f, "{}", ConstFloat { bits, ty: fty }), + (Value::ByVal(PrimVal::Bytes(n)), &TyUint(ui)) => write!(f, "{:?}{}", n, ui), + (Value::ByVal(PrimVal::Bytes(n)), &TyInt(i)) => write!(f, "{:?}{}", n as i128, i), + (Value::ByVal(PrimVal::Bytes(n)), &TyChar) => + write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()), + (Value::ByVal(PrimVal::Undef), &TyFnDef(did, _)) => + write!(f, "{}", item_path_str(did)), + (Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len)), &TyRef(_, TypeAndMut { + ty: &ty::TyS { sty: TyStr, .. }, .. + })) => { + ty::tls::with(|tcx| { + let alloc = tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .expect("miri alloc not found"); + assert_eq!(len as usize as u128, len); + let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)]; + let s = ::std::str::from_utf8(slice) + .expect("non utf8 str from miri"); + write!(f, "{:?}", s) + }) + }, + _ => write!(f, "{:?}:{}", value, ty), } } @@ -2468,6 +2513,15 @@ impl<'tcx, B, V, T> TypeFoldable<'tcx> for Projection<'tcx, B, V, T> } } +impl<'tcx> TypeFoldable<'tcx> for Field { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self { + *self + } + fn super_visit_with>(&self, _: &mut V) -> bool { + false + } +} + impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { Constant { diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index bbfb9c89b3f..067c1742040 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -70,7 +70,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { PlaceTy::Ty { ty: match ty.sty { ty::TyArray(inner, size) => { - let size = size.val.to_const_int().unwrap().to_u64().unwrap(); + let size = size.val.unwrap_u64(); let len = size - (from as u64) - (to as u64); tcx.mk_array(inner, len) } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 0b6f1275bdb..54d3ed38d65 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -243,12 +243,6 @@ macro_rules! make_mir_visitor { self.super_generator_interior(interior); } - fn visit_const_int(&mut self, - const_int: &ConstInt, - _: Location) { - self.super_const_int(const_int); - } - fn visit_const_usize(&mut self, const_usize: & $($mutability)* ConstUsize, _: Location) { @@ -426,13 +420,10 @@ macro_rules! make_mir_visitor { TerminatorKind::SwitchInt { ref $($mutability)* discr, ref $($mutability)* switch_ty, - ref values, + values: _, ref targets } => { self.visit_operand(discr, source_location); self.visit_ty(switch_ty, TyContext::Location(source_location)); - for value in &values[..] { - self.visit_const_int(value, source_location); - } for &target in targets { self.visit_branch(block, target); } @@ -798,9 +789,6 @@ macro_rules! make_mir_visitor { _substs: & $($mutability)* ClosureSubsts<'tcx>) { } - fn super_const_int(&mut self, _const_int: &ConstInt) { - } - fn super_const_usize(&mut self, _const_usize: & $($mutability)* ConstUsize) { } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 520da34c40a..17926eeec00 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -30,7 +30,8 @@ use middle::cstore::EncodedMetadata; use middle::lang_items; use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::stability; -use mir::{Mir, interpret}; +use mir::{self, Mir, interpret}; +use mir::interpret::{Value, PrimVal}; use ty::subst::{Kind, Substs}; use ty::ReprOptions; use ty::Instance; @@ -1267,6 +1268,36 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.get_lang_items(LOCAL_CRATE) } + pub fn is_binop_lang_item(&self, def_id: DefId) -> Option<(mir::BinOp, bool)> { + let items = self.lang_items(); + let def_id = Some(def_id); + if items.i128_add_fn() == def_id { Some((mir::BinOp::Add, false)) } + else if items.u128_add_fn() == def_id { Some((mir::BinOp::Add, false)) } + else if items.i128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) } + else if items.u128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) } + else if items.i128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) } + else if items.u128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) } + else if items.i128_div_fn() == def_id { Some((mir::BinOp::Div, false)) } + else if items.u128_div_fn() == def_id { Some((mir::BinOp::Div, false)) } + else if items.i128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) } + else if items.u128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) } + else if items.i128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) } + else if items.u128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) } + else if items.i128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) } + else if items.u128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) } + else if items.i128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) } + else if items.u128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) } + else if items.i128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) } + else if items.u128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) } + else if items.i128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) } + else if items.u128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) } + else if items.i128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) } + else if items.u128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) } + else if items.i128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) } + else if items.u128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) } + else { None } + } + pub fn stability(self) -> Lrc> { self.stability_index(LOCAL_CRATE) } @@ -2068,7 +2099,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_array_const_usize(self, ty: Ty<'tcx>, n: ConstUsize) -> Ty<'tcx> { self.mk_ty(TyArray(ty, self.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::Usize(n)), + val: if self.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.as_u64().into()))) + } else { + ConstVal::Integral(ConstInt::Usize(n)) + }, ty: self.types.usize }))) } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index be89aeebdea..07920c58271 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -11,6 +11,7 @@ use hir::def_id::DefId; use middle::const_val::ConstVal; use ty::{self, BoundRegion, Region, Ty, TyCtxt}; +use mir::interpret::{Value, PrimVal}; use std::fmt; use syntax::abi; @@ -186,10 +187,12 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)), ty::TyArray(_, n) => { - if let ConstVal::Integral(ConstInt::Usize(n)) = n.val { - format!("array of {} elements", n) - } else { - "array".to_string() + match n.val { + ConstVal::Integral(ConstInt::Usize(n)) => + format!("array of {} elements", n), + ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))) => + format!("array of {} elements", n), + _ => "array".to_string(), } } ty::TySlice(_) => "slice".to_string(), diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 93e4cd9adf8..bfaa661b243 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -262,7 +262,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { })) }, TyArray(ty, len) => { - match len.val.to_const_int().and_then(|i| i.to_u64()) { + match len.val.to_u128() { // If the array is definitely non-empty, it's uninhabited if // the type of its elements is uninhabited. Some(n) if n != 0 => ty.uninhabited_from(visited, tcx), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 1aa7f671ad3..35d8fb2a67a 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -952,7 +952,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { enum StructKind { /// A tuple, closure, or univariant which cannot be coerced to unsized. AlwaysSized, - /// A univariant, the last field of which may be coerced to unsized. + /// A univariant, the last field of which fn compute_uncachedmay be coerced to unsized. MaybeUnsized, /// A univariant, but with a prefix of an arbitrary size & alignment (e.g. enum tag). Prefixed(Size, Align), @@ -1237,7 +1237,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } let element = self.layout_of(element)?; - let count = count.val.to_const_int().unwrap().to_u64().unwrap(); + let count = count.val.unwrap_u64(); let size = element.size.checked_mul(count, dl) .ok_or(LayoutError::SizeOverflow(ty))?; diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index d880b022e2f..ef1c8a8d4fa 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -13,6 +13,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex}; use ty::{self, Ty, TyCtxt}; use ty::maps::queries; use ty::subst::Substs; +use mir; use std::hash::Hash; use syntax_pos::symbol::InternedString; diff --git a/src/librustc/ty/maps/keys.rs b/src/librustc/ty/maps/keys.rs index b7b64c9761a..3dd482ad164 100644 --- a/src/librustc/ty/maps/keys.rs +++ b/src/librustc/ty/maps/keys.rs @@ -14,6 +14,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex}; use ty::{self, Ty, TyCtxt}; use ty::subst::Substs; use ty::fast_reject::SimplifiedType; +use mir; use std::fmt::Debug; use std::hash::Hash; diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index b18837ff35a..77e022fe730 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -15,7 +15,7 @@ use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId, RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE}; use hir::map::definitions::DefPathHash; use ich::{CachingCodemapView, Fingerprint}; -use mir; +use mir::{self, interpret}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -542,6 +542,13 @@ impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx, implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> ); + +impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result { + unimplemented!() + } +} + impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { fn specialized_decode(&mut self) -> Result { let tag: u8 = Decodable::decode(self)?; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index be27e3d5152..1577e78d81e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -26,6 +26,7 @@ use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangIte use middle::privacy::AccessLevels; use middle::resolve_lifetime::ObjectLifetimeDefault; use mir::Mir; +use mir::interpret::{Value, PrimVal}; use mir::GeneratorLayout; use session::CrateDisambiguator; use traits; @@ -1838,6 +1839,19 @@ impl<'a, 'gcx, 'tcx> AdtDef { Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => { discr = v; } + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + trace!("discriminants: {} ({:?})", b, repr_type); + use syntax::attr::IntType; + discr = match repr_type { + IntType::SignedInt(int_type) => ConstInt::new_signed( + b as i128, int_type, tcx.sess.target.isize_ty).unwrap(), + IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned( + b, uint_type, tcx.sess.target.usize_ty).unwrap(), + }; + } err => { if !expr_did.is_local() { span_bug!(tcx.def_span(expr_did), @@ -1879,6 +1893,20 @@ impl<'a, 'gcx, 'tcx> AdtDef { explicit_value = v; break; } + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + trace!("discriminants: {} ({:?})", b, repr_type); + use syntax::attr::IntType; + explicit_value = match repr_type { + IntType::SignedInt(int_type) => ConstInt::new_signed( + b as i128, int_type, tcx.sess.target.isize_ty).unwrap(), + IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned( + b, uint_type, tcx.sess.target.usize_ty).unwrap(), + }; + break; + } err => { if !expr_did.is_local() { span_bug!(tcx.def_span(expr_did), diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index b9927c7eeb2..bac78508993 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -20,6 +20,7 @@ use ty::subst::{UnpackedKind, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::{TypeVisitor, TypeFolder}; use ty::error::{ExpectedFound, TypeError}; +use mir::interpret::{Value, PrimVal}; use util::common::ErrorReported; use std::rc::Rc; use std::iter; @@ -483,6 +484,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result { match x.val { ConstVal::Integral(x) => Ok(x.to_u64().unwrap()), + ConstVal::Value(Value::ByVal(prim)) => Ok(prim.to_u64().unwrap()), ConstVal::Unevaluated(def_id, substs) => { // FIXME(eddyb) get the right param_env. let param_env = ty::ParamEnv::empty(Reveal::UserFacing); @@ -492,6 +494,13 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => { return Ok(x.to_u64().unwrap()); } + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + assert_eq!(b as u64 as u128, b); + return Ok(b as u64); + } _ => {} } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 54db2d4f06b..80250949b0b 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -890,6 +890,61 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use ty::InstanceDef::*; + Self { + substs: self.substs.fold_with(folder), + def: match self.def { + Item(did) => Item(did.fold_with(folder)), + Intrinsic(did) => Intrinsic(did.fold_with(folder)), + FnPtrShim(did, ty) => FnPtrShim( + did.fold_with(folder), + ty.fold_with(folder), + ), + Virtual(did, i) => Virtual( + did.fold_with(folder), + i, + ), + ClosureOnceShim { call_once } => ClosureOnceShim { + call_once: call_once.fold_with(folder), + }, + DropGlue(did, ty) => DropGlue( + did.fold_with(folder), + ty.fold_with(folder), + ), + CloneShim(did, ty) => CloneShim( + did.fold_with(folder), + ty.fold_with(folder), + ), + }, + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use ty::InstanceDef::*; + self.substs.visit_with(visitor) || + match self.def { + Item(did) => did.visit_with(visitor), + Intrinsic(did) => did.visit_with(visitor), + FnPtrShim(did, ty) => { + did.visit_with(visitor) || + ty.visit_with(visitor) + }, + Virtual(did, _) => did.visit_with(visitor), + ClosureOnceShim { call_once } => call_once.visit_with(visitor), + DropGlue(did, ty) => { + did.visit_with(visitor) || + ty.visit_with(visitor) + }, + CloneShim(did, ty) => { + did.visit_with(visitor) || + ty.visit_with(visitor) + }, + } + } +} + impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let sty = match self.sty { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 785035ee5f4..6ad2901ce3a 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -24,6 +24,7 @@ use ty::maps::TyCtxtAt; use ty::TypeVariants::*; use util::common::ErrorReported; use middle::lang_items; +use mir::interpret::{Value, PrimVal}; use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, @@ -765,6 +766,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> self.hash_discriminant_u8(&n.val); match n.val { ConstVal::Integral(x) => self.hash(x.to_u64().unwrap()), + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => self.hash(b), ConstVal::Unevaluated(def_id, _) => self.def_id(def_id), _ => bug!("arrays should not have {:?} as length", n) } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index a2620da4c10..63d1f146825 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -21,6 +21,7 @@ use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, Ty use ty::{TyDynamic, TyInt, TyUint, TyInfer}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use util::nodemap::FxHashSet; +use mir::interpret::{Value, PrimVal}; use std::cell::Cell; use std::fmt; @@ -1168,6 +1169,9 @@ define_print! { ConstVal::Integral(ConstInt::Usize(sz)) => { write!(f, "{}", sz)?; } + ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => { + write!(f, "{}", sz)?; + } ConstVal::Unevaluated(_def_id, substs) => { write!(f, "", &substs[..])?; } diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 8e3b99f2dbf..9e9eb4a81d0 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -28,6 +28,7 @@ use rustc::hir::RangeEnd; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::mir::Field; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::util::common::ErrorReported; use syntax_pos::{Span, DUMMY_SP}; @@ -195,6 +196,41 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } })).collect() } + box PatternKind::Constant { + value: &ty::Const { val: ConstVal::Value(b), ty } + } => { + match b { + Value::ByVal(PrimVal::Ptr(ptr)) => { + let is_array_ptr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == tcx.types.u8); + assert!(is_array_ptr); + let alloc = tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .unwrap(); + assert_eq!(ptr.offset, 0); + // FIXME: check length + alloc.bytes.iter().map(|b| { + &*pattern_arena.alloc(Pattern { + ty: tcx.types.u8, + span: pat.span, + kind: box PatternKind::Constant { + value: tcx.mk_const(ty::Const { + val: ConstVal::Value(Value::ByVal( + PrimVal::Bytes(*b as u128), + )), + ty: tcx.types.u8 + }) + } + }) + }).collect() + }, + _ => bug!("not a byte str: {:?}", b), + } + } _ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat) } }).clone() @@ -422,13 +458,17 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, ty::TyBool => { [true, false].iter().map(|&b| { ConstantValue(cx.tcx.mk_const(ty::Const { - val: ConstVal::Bool(b), + val: if cx.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))) + } else { + ConstVal::Bool(b) + }, ty: cx.tcx.types.bool })) }).collect() } - ty::TyArray(ref sub_ty, len) if len.val.to_const_int().is_some() => { - let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + ty::TyArray(ref sub_ty, len) if len.val.to_u128().is_some() => { + let len = len.val.unwrap_u64(); if len != 0 && cx.is_uninhabited(sub_ty) { vec![] } else { @@ -461,7 +501,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, } fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( - _cx: &mut MatchCheckCtxt<'a, 'tcx>, + cx: &mut MatchCheckCtxt<'a, 'tcx>, patterns: I) -> u64 where I: Iterator> { @@ -538,6 +578,25 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( PatternKind::Constant { value: &ty::Const { val: ConstVal::ByteStr(b), .. } } => { max_fixed_len = cmp::max(max_fixed_len, b.data.len() as u64); } + PatternKind::Constant { + value: &ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))), + ty, + } + } => { + let is_array_ptr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == cx.tcx.types.u8); + if is_array_ptr { + let alloc = cx.tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .unwrap(); + max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64); + } + } PatternKind::Slice { ref prefix, slice: None, ref suffix } => { let fixed_len = prefix.len() as u64 + suffix.len() as u64; max_fixed_len = cmp::max(max_fixed_len, fixed_len); @@ -581,7 +640,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, witness: WitnessPreference) -> Usefulness<'tcx> { let &Matrix(ref rows) = matrix; - debug!("is_useful({:?}, {:?})", matrix, v); + debug!("is_useful({:#?}, {:#?})", matrix, v); // The base case. We are pattern-matching on () and the return value is // based on whether our matrix has a row or not. @@ -626,10 +685,10 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0]))) }; - debug!("is_useful_expand_first_col: pcx={:?}, expanding {:?}", pcx, v[0]); + debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]); if let Some(constructors) = pat_constructors(cx, v[0], pcx) { - debug!("is_useful - expanding constructors: {:?}", constructors); + debug!("is_useful - expanding constructors: {:#?}", constructors); constructors.into_iter().map(|c| is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness) ).find(|result| result.is_useful()).unwrap_or(NotUseful) @@ -639,9 +698,9 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, let used_ctors: Vec = rows.iter().flat_map(|row| { pat_constructors(cx, row[0], pcx).unwrap_or(vec![]) }).collect(); - debug!("used_ctors = {:?}", used_ctors); + debug!("used_ctors = {:#?}", used_ctors); let all_ctors = all_constructors(cx, pcx); - debug!("all_ctors = {:?}", all_ctors); + debug!("all_ctors = {:#?}", all_ctors); let missing_ctors: Vec = all_ctors.iter().filter(|c| { !used_ctors.contains(*c) }).cloned().collect(); @@ -669,7 +728,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty); let is_declared_nonexhaustive = cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty); - debug!("missing_ctors={:?} is_privately_empty={:?} is_declared_nonexhaustive={:?}", + debug!("missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}", missing_ctors, is_privately_empty, is_declared_nonexhaustive); // For privately empty and non-exhaustive enums, we work as if there were an "extra" @@ -769,7 +828,7 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>( lty: Ty<'tcx>, witness: WitnessPreference) -> Usefulness<'tcx> { - debug!("is_useful_specialized({:?}, {:?}, {:?})", v, ctor, lty); + debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty); let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty); let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| { Pattern { @@ -821,7 +880,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt, Some(vec![ConstantRange(lo, hi, end)]), PatternKind::Array { .. } => match pcx.ty.sty { ty::TyArray(_, length) => Some(vec![ - Slice(length.val.to_const_int().unwrap().to_u64().unwrap()) + Slice(length.val.unwrap_u64()) ]), _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty) }, @@ -842,7 +901,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt, /// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3. /// A struct pattern's arity is the number of fields it contains, etc. fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 { - debug!("constructor_arity({:?}, {:?})", ctor, ty); + debug!("constructor_arity({:#?}, {:?})", ctor, ty); match ty.sty { ty::TyTuple(ref fs, _) => fs.len() as u64, ty::TySlice(..) | ty::TyArray(..) => match *ctor { @@ -866,12 +925,13 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor, ty: Ty<'tcx>) -> Vec> { - debug!("constructor_sub_pattern_tys({:?}, {:?})", ctor, ty); + debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty); match ty.sty { ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(), ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor { Slice(length) => (0..length).map(|_| ty).collect(), ConstantValue(_) => vec![], + Single => vec![ty], _ => bug!("bad slice pattern {:?} {:?}", ctor, ty) }, ty::TyRef(_, ref ty_and_mut) => vec![ty_and_mut.ty], @@ -880,6 +940,9 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, // Use T as the sub pattern type of Box. vec![substs.type_at(0)] } else { + if let ConstantValue(_) = *ctor { + return vec![]; + } adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| { let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); @@ -901,14 +964,30 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, } } -fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span, +fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, ctor: &Constructor, prefix: &[Pattern], slice: &Option, suffix: &[Pattern]) -> Result { - let data = match *ctor { + let data: &[u8] = match *ctor { ConstantValue(&ty::Const { val: ConstVal::ByteStr(b), .. }) => b.data, + ConstantValue(&ty::Const { val: ConstVal::Value( + Value::ByVal(PrimVal::Ptr(ptr)) + ), ty }) => { + let is_array_ptr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == tcx.types.u8); + assert!(is_array_ptr); + tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .unwrap() + .bytes + .as_ref() + } _ => bug!() }; @@ -928,6 +1007,12 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span, return Ok(false); } }, + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { + assert_eq!(b as u8 as u128, b); + if b as u8 != *ch { + return Ok(false); + } + } _ => span_bug!(pat.span, "bad const u8 {:?}", value) }, _ => {} @@ -937,32 +1022,43 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span, Ok(true) } -fn constructor_covered_by_range(tcx: TyCtxt, span: Span, - ctor: &Constructor, +fn constructor_covered_by_range(ctor: &Constructor, from: &ConstVal, to: &ConstVal, - end: RangeEnd) + end: RangeEnd, + ty: Ty) -> Result { - let cmp_from = |c_from| Ok(compare_const_vals(tcx, span, c_from, from)? != Ordering::Less); - let cmp_to = |c_to| compare_const_vals(tcx, span, c_to, to); + trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty); + let cmp_from = |c_from| compare_const_vals(c_from, from, ty) + .map(|res| res != Ordering::Less); + let cmp_to = |c_to| compare_const_vals(c_to, to, ty); + macro_rules! some_or_ok { + ($e:expr) => { + match $e { + Some(to) => to, + None => return Ok(false), // not char or int + } + }; + } match *ctor { ConstantValue(value) => { - let to = cmp_to(&value.val)?; + let to = some_or_ok!(cmp_to(&value.val)); let end = (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); - Ok(cmp_from(&value.val)? && end) + Ok(some_or_ok!(cmp_from(&value.val)) && end) }, ConstantRange(from, to, RangeEnd::Included) => { - let to = cmp_to(&to.val)?; + let to = some_or_ok!(cmp_to(&to.val)); let end = (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); - Ok(cmp_from(&from.val)? && end) + Ok(some_or_ok!(cmp_from(&from.val)) && end) }, ConstantRange(from, to, RangeEnd::Excluded) => { - let to = cmp_to(&to.val)?; + let to = some_or_ok!(cmp_to(&to.val)); let end = (to == Ordering::Less) || (end == RangeEnd::Excluded && to == Ordering::Equal); - Ok(cmp_from(&from.val)? && end) + Ok(some_or_ok!(cmp_from(&from.val)) && end) } + Variant(_) | Single => Ok(true), _ => bug!(), } @@ -979,7 +1075,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>( result[subpat.field.index()] = &subpat.pattern; } - debug!("patterns_for_variant({:?}, {:?}) = {:?}", subpatterns, wild_patterns, result); + debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result); result } @@ -994,7 +1090,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>( fn specialize<'p, 'a: 'p, 'tcx: 'a>( cx: &mut MatchCheckCtxt<'a, 'tcx>, r: &[&'p Pattern<'tcx>], - constructor: &Constructor, + constructor: &Constructor<'tcx>, wild_patterns: &[&'p Pattern<'tcx>]) -> Option>> { @@ -1031,12 +1127,32 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( None } } + ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => { + let is_array_ptr = value.ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == cx.tcx.types.u8); + assert!(is_array_ptr); + let data_len = cx.tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .unwrap() + .bytes + .len(); + if wild_patterns.len() == data_len { + Some(cx.lower_byte_str_pattern(pat)) + } else { + None + } + } _ => span_bug!(pat.span, "unexpected const-val {:?} with ctor {:?}", value, constructor) }, _ => { match constructor_covered_by_range( - cx.tcx, pat.span, constructor, &value.val, &value.val, RangeEnd::Included + constructor, &value.val, &value.val, RangeEnd::Included, + value.ty, ) { Ok(true) => Some(vec![]), Ok(false) => None, @@ -1048,7 +1164,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( PatternKind::Range { lo, hi, ref end } => { match constructor_covered_by_range( - cx.tcx, pat.span, constructor, &lo.val, &hi.val, end.clone() + constructor, &lo.val, &hi.val, end.clone(), lo.ty, ) { Ok(true) => Some(vec![]), Ok(false) => None, @@ -1092,7 +1208,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( } } }; - debug!("specialize({:?}, {:?}) = {:?}", r[0], wild_patterns, head); + debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head); head.map(|mut head| { head.extend_from_slice(&r[1 ..]); diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 2a571fa8264..58fe40d12be 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -26,7 +26,6 @@ use syntax::abi::Abi; use syntax::ast; use syntax::attr; use rustc::hir::{self, Expr}; -use syntax_pos::Span; use std::cmp::Ordering; @@ -104,60 +103,10 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, hir::ExprUnary(hir::UnNeg, ref inner) => { // unary neg literals already got their sign during creation if let hir::ExprLit(ref lit) = inner.node { - use syntax::ast::*; - use syntax::ast::LitIntType::*; - const I8_OVERFLOW: u128 = i8::min_value() as u8 as u128; - const I16_OVERFLOW: u128 = i16::min_value() as u16 as u128; - const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128; - const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128; - const I128_OVERFLOW: u128 = i128::min_value() as u128; - let negated = match (&lit.node, &ty.sty) { - (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) | - (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => { - Some(I8(i8::min_value())) - }, - (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) | - (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => { - Some(I16(i16::min_value())) - }, - (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) | - (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => { - Some(I32(i32::min_value())) - }, - (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) | - (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => { - Some(I64(i64::min_value())) - }, - (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) | - (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => { - Some(I128(i128::min_value())) - }, - (&LitKind::Int(n, _), &ty::TyInt(IntTy::Isize)) | - (&LitKind::Int(n, Signed(IntTy::Isize)), _) => { - match tcx.sess.target.isize_ty { - IntTy::I16 => if n == I16_OVERFLOW { - Some(Isize(Is16(i16::min_value()))) - } else { - None - }, - IntTy::I32 => if n == I32_OVERFLOW { - Some(Isize(Is32(i32::min_value()))) - } else { - None - }, - IntTy::I64 => if n == I64_OVERFLOW { - Some(Isize(Is64(i64::min_value()))) - } else { - None - }, - _ => span_bug!(e.span, "typeck error") - } - }, - _ => None + return match lit_to_const(&lit.node, tcx, ty, true) { + Ok(val) => Ok(mk_const(val)), + Err(err) => signal!(e, err), }; - if let Some(i) = negated { - return Ok(mk_const(Integral(i))); - } } mk_const(match cx.eval(inner)?.val { Float(f) => Float(-f), @@ -377,7 +326,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, }; callee_cx.eval(&body.value)? }, - hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty) { + hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty, false) { Ok(val) => mk_const(val), Err(err) => signal!(e, err), }, @@ -438,7 +387,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } hir::ExprRepeat(ref elem, _) => { let n = match ty.sty { - ty::TyArray(_, n) => n.val.to_const_int().unwrap().to_u64().unwrap(), + ty::TyArray(_, n) => n.val.unwrap_u64(), _ => span_bug!(e.span, "typeck error") }; mk_const(Aggregate(Repeat(cx.eval(elem)?, n))) @@ -447,7 +396,8 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, if let Aggregate(Tuple(fields)) = cx.eval(base)?.val { fields[index.node] } else { - signal!(base, ExpectedConstTuple); + span_bug!(base.span, "{:#?}", cx.eval(base)?.val); + //signal!(base, ExpectedConstTuple); } } hir::ExprField(ref base, field_name) => { @@ -557,7 +507,7 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }, ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty { ty::TyArray(ty, n) => { - let n = n.val.to_const_int().unwrap().to_u64().unwrap(); + let n = n.val.unwrap_u64(); if ty == tcx.types.u8 && n == b.data.len() as u64 { Ok(val) } else { @@ -583,13 +533,66 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, +pub fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, - mut ty: Ty<'tcx>) + mut ty: Ty<'tcx>, + neg: bool) -> Result, ErrKind<'tcx>> { use syntax::ast::*; use syntax::ast::LitIntType::*; + if tcx.sess.opts.debugging_opts.miri { + use rustc::mir::interpret::*; + let lit = match *lit { + LitKind::Str(ref s, _) => { + let s = s.as_str(); + let id = tcx.allocate_cached(s.as_bytes()); + let ptr = MemoryPointer::new(AllocId(id), 0); + Value::ByValPair( + PrimVal::Ptr(ptr), + PrimVal::from_u128(s.len() as u128), + ) + }, + LitKind::ByteStr(ref data) => { + let id = tcx.allocate_cached(data); + let ptr = MemoryPointer::new(AllocId(id), 0); + Value::ByVal(PrimVal::Ptr(ptr)) + }, + LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Int(n, _) if neg => { + let n = n as i128; + let n = n.overflowing_neg().0; + Value::ByVal(PrimVal::Bytes(n as u128)) + }, + LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Float(n, fty) => { + let n = n.as_str(); + let mut f = parse_float(&n, fty)?; + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::FloatUnsuffixed(n) => { + let fty = match ty.sty { + ty::TyFloat(fty) => fty, + _ => bug!() + }; + let n = n.as_str(); + let mut f = parse_float(&n, fty)?; + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), + LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), + }; + return Ok(ConstVal::Value(lit)); + } + if let ty::TyAdt(adt, _) = ty.sty { if adt.is_enum() { ty = adt.repr.discr_type().to_ty(tcx) @@ -604,26 +607,38 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, match (&ty.sty, hint) { (&ty::TyInt(ity), _) | (_, Signed(ity)) => { - Ok(Integral(ConstInt::new_signed_truncating(n as i128, + let mut n = n as i128; + if neg { + n = n.overflowing_neg().0; + } + Ok(Integral(ConstInt::new_signed_truncating(n, ity, tcx.sess.target.isize_ty))) } (&ty::TyUint(uty), _) | (_, Unsigned(uty)) => { - Ok(Integral(ConstInt::new_unsigned_truncating(n as u128, + Ok(Integral(ConstInt::new_unsigned_truncating(n, uty, tcx.sess.target.usize_ty))) } _ => bug!() } } LitKind::Float(n, fty) => { - parse_float(&n.as_str(), fty).map(Float) + let mut f = parse_float(&n.as_str(), fty)?; + if neg { + f = -f; + } + Ok(Float(f)) } LitKind::FloatUnsuffixed(n) => { let fty = match ty.sty { ty::TyFloat(fty) => fty, _ => bug!() }; - parse_float(&n.as_str(), fty).map(Float) + let mut f = parse_float(&n.as_str(), fty)?; + if neg { + f = -f; + } + Ok(Float(f)) } LitKind::Bool(b) => Ok(Bool(b)), LitKind::Char(c) => Ok(Char(c)), @@ -638,36 +653,31 @@ fn parse_float<'tcx>(num: &str, fty: ast::FloatTy) }) } -pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal) - -> Result -{ - let result = match (a, b) { +pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option { + trace!("compare_const_vals: {:?}, {:?}", a, b); + use rustc::mir::interpret::{Value, PrimVal}; + match (a, b) { (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(), - (&Float(a), &Float(b)) => a.try_cmp(b).ok(), - (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)), - (&Bool(a), &Bool(b)) => Some(a.cmp(&b)), - (&ByteStr(a), &ByteStr(b)) => Some(a.data.cmp(b.data)), (&Char(a), &Char(b)) => Some(a.cmp(&b)), + (&Value(Value::ByVal(PrimVal::Bytes(a))), + &Value(Value::ByVal(PrimVal::Bytes(b)))) => { + Some(if ty.is_signed() { + (a as i128).cmp(&(b as i128)) + } else { + a.cmp(&b) + }) + }, + _ if a == b => Some(Ordering::Equal), _ => None, - }; - - match result { - Some(result) => Ok(result), - None => { - // FIXME: can this ever be reached? - tcx.sess.delay_span_bug(span, - &format!("type mismatch comparing {:?} and {:?}", a, b)); - Err(ErrorReported) - } } } impl<'a, 'tcx> ConstContext<'a, 'tcx> { pub fn compare_lit_exprs(&self, - span: Span, a: &'tcx Expr, - b: &'tcx Expr) -> Result { + b: &'tcx Expr) -> Result, ErrorReported> { let tcx = self.tcx; + let ty = self.tables.expr_ty(a); let a = match self.eval(a) { Ok(a) => a, Err(e) => { @@ -682,6 +692,6 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { return Err(ErrorReported); } }; - compare_const_vals(tcx, span, &a.val, &b.val) + Ok(compare_const_vals(&a.val, &b.val, ty)) } } diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index a09e2f2edd5..a2daf22c3b4 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -10,8 +10,9 @@ use eval; -use rustc::middle::const_val::{ConstEvalErr, ConstVal}; +use rustc::middle::const_val::{ConstEvalErr, ConstVal, ConstAggregate}; use rustc::mir::{Field, BorrowKind, Mutability}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; use rustc::ty::subst::{Substs, Kind}; use rustc::hir::{self, PatKind, RangeEnd}; @@ -110,22 +111,35 @@ pub enum PatternKind<'tcx> { }, } -fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result { - match *value { +fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result { + match value.val { ConstVal::Float(ref x) => write!(f, "{}", x), ConstVal::Integral(ref i) => write!(f, "{}", i), ConstVal::Str(ref s) => write!(f, "{:?}", &s[..]), ConstVal::ByteStr(b) => write!(f, "{:?}", b.data), ConstVal::Bool(b) => write!(f, "{:?}", b), ConstVal::Char(c) => write!(f, "{:?}", c), + ConstVal::Value(v) => print_miri_value(v, value.ty, f), ConstVal::Variant(_) | ConstVal::Function(..) | ConstVal::Aggregate(_) | - ConstVal::Value(_) | ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value) } } +fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result { + use rustc::ty::TypeVariants::*; + match (value, &ty.sty) { + (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"), + (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"), + (Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n), + (Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128), + (Value::ByVal(PrimVal::Bytes(n)), &TyChar) => + write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()), + _ => bug!("{:?}: {} not printable in a pattern", value, ty), + } +} + impl<'tcx> fmt::Display for Pattern<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self.kind { @@ -233,15 +247,15 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { write!(f, "{}", subpattern) } PatternKind::Constant { value } => { - print_const_val(&value.val, f) + print_const_val(value, f) } PatternKind::Range { lo, hi, end } => { - print_const_val(&lo.val, f)?; + print_const_val(lo, f)?; match end { RangeEnd::Included => write!(f, "...")?, RangeEnd::Excluded => write!(f, "..")?, } - print_const_val(&hi.val, f) + print_const_val(hi, f) } PatternKind::Slice { ref prefix, ref slice, ref suffix } | PatternKind::Array { ref prefix, ref slice, ref suffix } => { @@ -362,7 +376,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } PatKind::Path(ref qpath) => { - return self.lower_path(qpath, pat.hir_id, pat.id, pat.span); + return self.lower_path(qpath, pat.hir_id, pat.span); } PatKind::Ref(ref subpattern, _) | @@ -581,7 +595,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty::TyArray(_, len) => { // fixed-length array - let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + let len = len.val.unwrap_u64(); assert!(len >= prefix.len() as u64 + suffix.len() as u64); PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix } } @@ -632,7 +646,6 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { fn lower_path(&mut self, qpath: &hir::QPath, id: hir::HirId, - pat_id: ast::NodeId, span: Span) -> Pattern<'tcx> { let ty = self.tables.node_id_to_type(id); @@ -644,29 +657,23 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let kind = match def { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = self.tables.node_substs(id); - match eval::lookup_const_by_id(self.tcx, self.param_env.and((def_id, substs))) { - Some((def_id, substs)) => { - // Enter the inlined constant's tables&substs temporarily. - let old_tables = self.tables; - let old_substs = self.substs; - self.tables = self.tcx.typeck_tables_of(def_id); - self.substs = substs; - let body = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { - self.tcx.hir.body(self.tcx.hir.body_owned_by(id)) - } else { - self.tcx.extern_const_body(def_id).body - }; - let pat = self.lower_const_expr(&body.value, pat_id, span); - self.tables = old_tables; - self.substs = old_substs; - return pat; - } - None => { - self.errors.push(if is_associated_const { - PatternError::AssociatedConstInPattern(span) - } else { - PatternError::StaticInPattern(span) - }); + match self.tcx.at(span).const_eval(self.param_env.and((def_id, substs))) { + Ok(value) => { + if self.tcx.sess.opts.debugging_opts.miri { + if let ConstVal::Value(_) = value.val {} else { + panic!("const eval produced non-miri value: {:#?}", value); + } + } + let instance = ty::Instance::resolve( + self.tcx, + self.param_env, + def_id, + substs, + ).unwrap(); + return self.const_to_pat(instance, value, span) + }, + Err(e) => { + self.errors.push(PatternError::ConstEval(e)); PatternKind::Wild } } @@ -682,6 +689,52 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> { + if self.tcx.sess.opts.debugging_opts.miri { + return match expr.node { + hir::ExprLit(ref lit) => { + let ty = self.tables.expr_ty(expr); + match ::eval::lit_to_const(&lit.node, self.tcx, ty, false) { + Ok(value) => PatternKind::Constant { + value: self.tcx.mk_const(ty::Const { + ty, + val: value, + }), + }, + Err(e) => { + self.errors.push(PatternError::ConstEval(ConstEvalErr { + span: lit.span, + kind: e, + })); + PatternKind::Wild + }, + } + }, + hir::ExprPath(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind, + hir::ExprUnary(hir::UnNeg, ref expr) => { + let ty = self.tables.expr_ty(expr); + let lit = match expr.node { + hir::ExprLit(ref lit) => lit, + _ => span_bug!(expr.span, "not a literal: {:?}", expr), + }; + match ::eval::lit_to_const(&lit.node, self.tcx, ty, true) { + Ok(value) => PatternKind::Constant { + value: self.tcx.mk_const(ty::Const { + ty, + val: value, + }), + }, + Err(e) => { + self.errors.push(PatternError::ConstEval(ConstEvalErr { + span: lit.span, + kind: e, + })); + PatternKind::Wild + }, + } + } + _ => span_bug!(expr.span, "not a literal: {:?}", expr), + } + } let const_cx = eval::ConstContext::new(self.tcx, self.param_env.and(self.substs), self.tables); @@ -701,118 +754,156 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } - fn lower_const_expr(&mut self, - expr: &'tcx hir::Expr, - pat_id: ast::NodeId, - span: Span) - -> Pattern<'tcx> { - let pat_ty = self.tables.expr_ty(expr); - debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id); - match pat_ty.sty { + fn const_to_pat( + &self, + instance: ty::Instance<'tcx>, + cv: &'tcx ty::Const<'tcx>, + span: Span, + ) -> Pattern<'tcx> { + debug!("const_to_pat: cv={:#?}", cv); + let kind = match cv.ty.sty { ty::TyFloat(_) => { self.tcx.sess.span_err(span, "floating point constants cannot be used in patterns"); + PatternKind::Wild } ty::TyAdt(adt_def, _) if adt_def.is_union() => { // Matching on union fields is unsafe, we can't hide it in constants self.tcx.sess.span_err(span, "cannot use unions in constant patterns"); + PatternKind::Wild } + ty::TyAdt(adt_def, _) if !self.tcx.has_attr(adt_def.did, "structural_match") => { + let msg = format!("to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + self.tcx.item_path_str(adt_def.did), + self.tcx.item_path_str(adt_def.did)); + self.tcx.sess.span_err(span, &msg); + PatternKind::Wild + }, + ty::TyAdt(adt_def, substs) if adt_def.is_enum() => { + match cv.val { + ConstVal::Value(val) => { + let discr = self.tcx.const_discr(self.param_env.and(( + instance, val, cv.ty + ))).unwrap(); + let variant_index = adt_def + .discriminants(self.tcx) + .position(|var| var.to_u128_unchecked() == discr) + .unwrap(); + PatternKind::Variant { + adt_def, + substs, + variant_index, + subpatterns: adt_def + .variants[variant_index] + .fields + .iter() + .enumerate() + .map(|(i, _)| { + let field = Field::new(i); + let val = match cv.val { + ConstVal::Value(miri) => self.tcx.const_val_field( + self.param_env.and((instance, field, miri, cv.ty)), + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; + FieldPattern { + field, + pattern: self.const_to_pat(instance, val, span), + } + }).collect(), + } + }, + ConstVal::Variant(var_did) => { + let variant_index = adt_def + .variants + .iter() + .position(|var| var.did == var_did) + .unwrap(); + PatternKind::Variant { + adt_def, + substs, + variant_index, + subpatterns: Vec::new(), + } + } + _ => return Pattern { + span, + ty: cv.ty, + kind: Box::new(PatternKind::Constant { + value: cv, + }), + } + } + }, ty::TyAdt(adt_def, _) => { - if !self.tcx.has_attr(adt_def.did, "structural_match") { - let msg = format!("to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - self.tcx.item_path_str(adt_def.did), - self.tcx.item_path_str(adt_def.did)); - self.tcx.sess.span_err(span, &msg); + let struct_var = adt_def.struct_variant(); + PatternKind::Leaf { + subpatterns: struct_var.fields.iter().enumerate().map(|(i, f)| { + let field = Field::new(i); + let val = match cv.val { + ConstVal::Aggregate(ConstAggregate::Struct(consts)) => { + consts.iter().find(|&&(name, _)| name == f.name).unwrap().1 + }, + ConstVal::Value(miri) => self.tcx.const_val_field( + self.param_env.and((instance, field, miri, cv.ty)), + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; + FieldPattern { + field, + pattern: self.const_to_pat(instance, val, span), + } + }).collect() } } - _ => { } - } - let kind = match expr.node { - hir::ExprTup(ref exprs) => { + ty::TyTuple(fields, _) => { PatternKind::Leaf { - subpatterns: exprs.iter().enumerate().map(|(i, expr)| { + subpatterns: (0..fields.len()).map(|i| { + let field = Field::new(i); + let val = match cv.val { + ConstVal::Aggregate(ConstAggregate::Tuple(consts)) => consts[i], + ConstVal::Value(miri) => self.tcx.const_val_field( + self.param_env.and((instance, field, miri, cv.ty)), + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; FieldPattern { - field: Field::new(i), - pattern: self.lower_const_expr(expr, pat_id, span) + field, + pattern: self.const_to_pat(instance, val, span), } }).collect() } } - - hir::ExprCall(ref callee, ref args) => { - let qpath = match callee.node { - hir::ExprPath(ref qpath) => qpath, - _ => bug!() - }; - let ty = self.tables.node_id_to_type(callee.hir_id); - let def = self.tables.qpath_def(qpath, callee.hir_id); - match def { - Def::Fn(..) | Def::Method(..) => self.lower_lit(expr), - _ => { - let subpatterns = args.iter().enumerate().map(|(i, expr)| { - FieldPattern { - field: Field::new(i), - pattern: self.lower_const_expr(expr, pat_id, span) - } - }).collect(); - self.lower_variant_or_leaf(def, ty, subpatterns) - } + ty::TyArray(_, n) => { + PatternKind::Leaf { + subpatterns: (0..n.val.unwrap_u64()).map(|i| { + let i = i as usize; + let field = Field::new(i); + let val = match cv.val { + ConstVal::Aggregate(ConstAggregate::Array(consts)) => consts[i], + ConstVal::Aggregate(ConstAggregate::Repeat(cv, _)) => cv, + ConstVal::Value(miri) => self.tcx.const_val_field( + self.param_env.and((instance, field, miri, cv.ty)), + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; + FieldPattern { + field, + pattern: self.const_to_pat(instance, val, span), + } + }).collect() } } - - hir::ExprStruct(ref qpath, ref fields, None) => { - let def = self.tables.qpath_def(qpath, expr.hir_id); - let adt_def = match pat_ty.sty { - ty::TyAdt(adt_def, _) => adt_def, - _ => { - span_bug!( - expr.span, - "struct expr without ADT type"); - } - }; - let variant_def = adt_def.variant_of_def(def); - - let subpatterns = - fields.iter() - .map(|field| { - let index = variant_def.index_of_field_named(field.name.node); - let index = index.unwrap_or_else(|| { - span_bug!( - expr.span, - "no field with name {:?}", - field.name); - }); - FieldPattern { - field: Field::new(index), - pattern: self.lower_const_expr(&field.expr, pat_id, span), - } - }) - .collect(); - - self.lower_variant_or_leaf(def, pat_ty, subpatterns) - } - - hir::ExprArray(ref exprs) => { - let pats = exprs.iter() - .map(|expr| self.lower_const_expr(expr, pat_id, span)) - .collect(); - PatternKind::Array { - prefix: pats, - slice: None, - suffix: vec![] + _ => { + PatternKind::Constant { + value: cv, } - } - - hir::ExprPath(ref qpath) => { - return self.lower_path(qpath, expr.hir_id, pat_id, span); - } - - _ => self.lower_lit(expr) + }, }; Pattern { span, - ty: pat_ty, + ty: cv.ty, kind: Box::new(kind), } } diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index d82b712b5b1..70733bc6aed 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -259,6 +259,14 @@ impl HashStable for f64 { } } +impl HashStable for ::std::cmp::Ordering { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (*self as i8).hash_stable(ctx, hasher); + } +} + impl, CTX> HashStable for (T1,) { fn hash_stable(&self, ctx: &mut CTX, diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 1c4bd0ff4c2..f400ce42a90 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -16,6 +16,7 @@ use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::layout::{self, LayoutOf}; use middle::const_val::ConstVal; use rustc_const_eval::ConstContext; +use rustc::mir::interpret::{Value, PrimVal}; use util::nodemap::FxHashSet; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; @@ -122,6 +123,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { .map(|i| i >= bits) .unwrap_or(true) } + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + ty, + }) => { + if ty.is_signed() { + (b as i128) < 0 + } else { + b >= bits as u128 + } + } _ => false, } }; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 3c3c489d0ff..1663cab0a59 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -276,38 +276,54 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result { const MAX1: usize = usize::max_value() - 1; - let mut interpret_interner = self.tcx.unwrap().interpret_interner.borrow_mut(); + let tcx = self.tcx; + let interpret_interner = || tcx.unwrap().interpret_interner.borrow_mut(); let pos = self.position(); - match self.read_usize()? { + match usize::decode(self)? { ::std::usize::MAX => { + let id = interpret_interner().reserve(); + let alloc_id = interpret::AllocId(id); + trace!("creating alloc id {:?} at {}", alloc_id, pos); + // insert early to allow recursive allocs + self.interpret_alloc_cache.insert(pos, alloc_id); + let allocation = interpret::Allocation::decode(self)?; - let id = interpret_interner.reserve(); + trace!("decoded alloc {:?} {:#?}", alloc_id, allocation); let allocation = self.tcx.unwrap().intern_const_alloc(allocation); - interpret_interner.intern_at_reserved(id, allocation); - let id = interpret::AllocId(id); - self.interpret_alloc_cache.insert(pos, id); + interpret_interner().intern_at_reserved(id, allocation); let num = usize::decode(self)?; let ptr = interpret::Pointer { primval: interpret::PrimVal::Ptr(interpret::MemoryPointer { - alloc_id: id, + alloc_id, offset: 0, }), }; for _ in 0..num { let glob = interpret::GlobalId::decode(self)?; - interpret_interner.cache(glob, ptr); + interpret_interner().cache(glob, ptr); } - Ok(id) + Ok(alloc_id) }, MAX1 => { + trace!("creating fn alloc id at {}", pos); let instance = ty::Instance::decode(self)?; - let id = interpret::AllocId(interpret_interner.create_fn_alloc(instance)); + trace!("decoded fn alloc instance: {:?}", instance); + let id = interpret::AllocId(interpret_interner().create_fn_alloc(instance)); + trace!("created fn alloc id: {:?}", id); self.interpret_alloc_cache.insert(pos, id); Ok(id) }, - shorthand => Ok(self.interpret_alloc_cache[&shorthand]), + shorthand => { + trace!("loading shorthand {}", shorthand); + if let Some(&alloc_id) = self.interpret_alloc_cache.get(&shorthand) { + return Ok(alloc_id); + } + trace!("shorthand {} not cached, loading entire allocation", shorthand); + // need to load allocation + self.with_position(shorthand, |this| interpret::AllocId::decode(this)) + }, } } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 928bf0a56ae..1e1baba2bac 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -189,12 +189,18 @@ impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> { + trace!("encoding {:?} at {}", alloc_id, self.position()); if let Some(shorthand) = self.interpret_alloc_shorthands.get(alloc_id).cloned() { - return self.emit_usize(shorthand); + trace!("encoding {:?} as shorthand to {}", alloc_id, shorthand); + return shorthand.encode(self); } let start = self.position(); + // cache the allocation shorthand now, because the allocation itself might recursively + // point to itself. + self.interpret_alloc_shorthands.insert(*alloc_id, start); let interpret_interner = self.tcx.interpret_interner.borrow(); if let Some(alloc) = interpret_interner.get_alloc(alloc_id.0) { + trace!("encoding {:?} with {:#?}", alloc_id, alloc); usize::max_value().encode(self)?; alloc.encode(self)?; let globals = interpret_interner.get_globals(interpret::Pointer { @@ -208,16 +214,12 @@ impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx glob.encode(self)?; } } else if let Some(fn_instance) = interpret_interner.get_fn(alloc_id.0) { + trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); (usize::max_value() - 1).encode(self)?; fn_instance.encode(self)?; } else { bug!("alloc id without corresponding allocation: {}", alloc_id.0); } - let len = self.position() - start * 7; - // Check that the shorthand is a not longer than the - // full encoding itself, i.e. it's an obvious win. - assert!(len >= 64 || (start as u64) < (1 << len)); - self.interpret_alloc_shorthands.insert(*alloc_id, start); Ok(()) } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index bbf4357e5b0..5955d0ca59a 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -26,6 +26,7 @@ use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants}; use rustc::middle::const_val::ConstVal; use rustc::mir::*; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::mir::tcx::PlaceTy; use rustc::mir::visit::{PlaceContext, Visitor}; use std::fmt; @@ -258,7 +259,24 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { // constraints on `'a` and `'b`. These constraints // would be lost if we just look at the normalized // value. - if let ConstVal::Function(def_id, ..) = value.val { + let did = match value.val { + ConstVal::Function(def_id, ..) => Some(def_id), + ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { + self.tcx() + .interpret_interner + .borrow() + .get_fn(p.alloc_id.0) + .map(|instance| instance.def_id()) + }, + ConstVal::Value(Value::ByVal(PrimVal::Undef)) => { + match value.ty.sty { + ty::TyFnDef(ty_def_id, _) => Some(ty_def_id), + _ => None, + } + }, + _ => None, + }; + if let Some(def_id) = did { let tcx = self.tcx(); let type_checker = &mut self.cx; @@ -436,7 +454,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ProjectionElem::Subslice { from, to } => PlaceTy::Ty { ty: match base_ty.sty { ty::TyArray(inner, size) => { - let size = size.val.to_const_int().unwrap().to_u64().unwrap(); + let size = size.val.unwrap_u64(); let min_size = (from as u64) + (to as u64); if let Some(rest_size) = size.checked_sub(min_size) { tcx.mk_array(inner, rest_size) @@ -1019,13 +1037,32 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { Literal::Value { value: &ty::Const { - val: ConstVal::Function(def_id, _), - .. + val, + ty, }, .. }, .. - }) => Some(def_id) == self.tcx().lang_items().box_free_fn(), + }) => match val { + ConstVal::Function(def_id, _) => { + Some(def_id) == self.tcx().lang_items().box_free_fn() + }, + ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { + let inst = self.tcx().interpret_interner.borrow().get_fn(p.alloc_id.0); + inst.map_or(false, |inst| { + Some(inst.def_id()) == self.tcx().lang_items().box_free_fn() + }) + }, + ConstVal::Value(Value::ByVal(PrimVal::Undef)) => { + match ty.sty { + ty::TyFnDef(ty_def_id, _) => { + Some(ty_def_id) == self.tcx().lang_items().box_free_fn() + } + _ => false, + } + } + _ => false, + } _ => false, } } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index d3cc9527590..b5b8f8d7e78 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -24,6 +24,7 @@ use rustc::middle::const_val::ConstVal; use rustc::middle::region; use rustc::ty::{self, Ty}; use rustc::mir::*; +use rustc::mir::interpret::{Value, PrimVal}; use syntax::ast; use syntax_pos::Span; @@ -203,7 +204,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ty: this.hir.tcx().types.u32, literal: Literal::Value { value: this.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::U32(0)), + val: if this.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Integral(ConstInt::U32(0)) + }, ty: this.hir.tcx().types.u32 }), }, @@ -401,7 +406,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(val), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.to_u128_unchecked()))) + } else { + ConstVal::Integral(val) + }, ty }) } @@ -439,7 +448,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(val), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes( + val.to_u128_unchecked() + ))) + } else { + ConstVal::Integral(val) + }, ty }) } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 58ce572ae8d..229e33dcd78 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -354,7 +354,7 @@ enum TestKind<'tcx> { // test the branches of enum SwitchInt { switch_ty: Ty<'tcx>, - options: Vec<&'tcx ty::Const<'tcx>>, + options: Vec, indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>, }, diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index bdcbfc0bdd8..fafdee5b1e1 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -24,6 +24,7 @@ use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; use rustc::ty::util::IntTypeExt; use rustc::mir::*; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::hir::RangeEnd; use syntax_pos::Span; use std::cmp::Ordering; @@ -112,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { test_place: &Place<'tcx>, candidate: &Candidate<'pat, 'tcx>, switch_ty: Ty<'tcx>, - options: &mut Vec<&'tcx ty::Const<'tcx>>, + options: &mut Vec, indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>) -> bool { @@ -128,7 +129,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { indices.entry(value) .or_insert_with(|| { - options.push(value); + options.push(value.val.to_u128().expect("switching on int")); options.len() - 1 }); true @@ -231,7 +232,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let tcx = self.hir.tcx(); for (idx, discr) in adt_def.discriminants(tcx).enumerate() { target_blocks.place_back() <- if variants.contains(idx) { - values.push(discr); + values.push(discr.to_u128_unchecked()); *(targets.place_back() <- self.cfg.start_new_block()) } else { if otherwise_block.is_none() { @@ -266,9 +267,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { assert!(options.len() > 0 && options.len() <= 2); let (true_bb, false_bb) = (self.cfg.start_new_block(), self.cfg.start_new_block()); - let ret = match options[0].val { - ConstVal::Bool(true) => vec![true_bb, false_bb], - ConstVal::Bool(false) => vec![false_bb, true_bb], + let ret = match options[0] { + 1 => vec![true_bb, false_bb], + 0 => vec![false_bb, true_bb], v => span_bug!(test.span, "expected boolean value but got {:?}", v) }; (ret, TerminatorKind::if_(self.hir.tcx(), Operand::Copy(place.clone()), @@ -282,13 +283,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .map(|_| self.cfg.start_new_block()) .chain(Some(otherwise)) .collect(); - let values: Vec<_> = options.iter().map(|v| - v.val.to_const_int().expect("switching on integral") - ).collect(); (targets.clone(), TerminatorKind::SwitchInt { discr: Operand::Copy(place.clone()), switch_ty, - values: From::from(values), + values: options.clone().into(), targets, }) }; @@ -300,14 +298,49 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let tcx = self.hir.tcx(); let mut val = Operand::Copy(place.clone()); + let bytes = match value.val { + ConstVal::ByteStr(bytes) => Some(bytes.data), + ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { + let is_array_ptr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == self.hir.tcx().types.u8); + if is_array_ptr { + self.hir + .tcx() + .interpret_interner + .borrow() + .get_alloc(p.alloc_id.0) + .map(|alloc| &alloc.bytes[..]) + } else { + None + } + }, + _ => None, + }; // If we're using b"..." as a pattern, we need to insert an // unsizing coercion, as the byte string has the type &[u8; N]. // // We want to do this even when the scrutinee is a reference to an // array, so we can call `<[u8]>::eq` rather than having to find an // `<[u8; N]>::eq`. - let (expect, val) = if let ConstVal::ByteStr(bytes) = value.val { - let array_ty = tcx.mk_array(tcx.types.u8, bytes.data.len() as u64); + let expect = if let Some(bytes) = bytes { + let tcx = self.hir.tcx(); + + // Unsize the place to &[u8], too, if necessary. + if let ty::TyRef(region, mt) = ty.sty { + if let ty::TyArray(_, _) = mt.ty.sty { + ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8)); + let val_slice = self.temp(ty, test.span); + self.cfg.push_assign(block, source_info, &val_slice, + Rvalue::Cast(CastKind::Unsize, val, ty)); + val = Operand::Move(val_slice); + } + } + + assert!(ty.is_slice()); + + let array_ty = tcx.mk_array(tcx.types.u8, bytes.len() as u64); let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty); let array = self.literal_operand(test.span, array_ref, Literal::Value { value @@ -324,11 +357,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Use PartialEq::eq for &str and &[u8] slices, instead of BinOp::Eq. let fail = self.cfg.start_new_block(); - let ty = expect.ty(&self.local_decls, tcx); - if let ty::TyRef(_, mt) = ty.sty { - assert!(ty.is_slice()); + let str_or_bytestr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|tam| match tam.ty.sty { + ty::TyStr => Some(tam.ty), + ty::TySlice(inner) if inner == self.hir.tcx().types.u8 => Some(tam.ty), + _ => None, + }); + if let Some(ty) = str_or_bytestr { let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap(); - let ty = mt.ty; let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]); let bool_ty = self.hir.bool_ty(); diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index a3350cb1671..efb36720118 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -16,6 +16,7 @@ use build::Builder; use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::mir::*; use syntax::ast; @@ -62,7 +63,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ty::TyChar => { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Char('\0'), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Char('\0') + }, ty }) } @@ -83,7 +88,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(val), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Integral(val) + }, ty }) } @@ -104,7 +113,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(val), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Integral(val) + }, ty }) } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 00ab2e45995..198e55358e7 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -10,7 +10,6 @@ use hair::*; use rustc_data_structures::indexed_vec::Idx; -use rustc_const_math::ConstInt; use hair::cx::Cx; use hair::cx::block; use hair::cx::to_ref::ToRef; @@ -18,6 +17,7 @@ use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::hir; use rustc::hir::def_id::LocalDefId; @@ -100,7 +100,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ExprKind::Deref { arg: expr.to_ref() } } Adjust::Deref(Some(deref)) => { - let call = deref.method_call(cx.tcx, expr.ty); + let call = deref.method_call(cx.tcx(), expr.ty); expr = Expr { temp_lifetime, @@ -314,7 +314,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } - hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) }, + hir::ExprLit(ref lit) => ExprKind::Literal { + literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false), + }, hir::ExprBinary(op, ref lhs, ref rhs) => { if cx.tables().is_method_call(expr) { @@ -400,9 +402,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, if cx.tables().is_method_call(expr) { overloaded_operator(cx, expr, vec![arg.to_ref()]) } else { - // FIXME runtime-overflow - if let hir::ExprLit(_) = arg.node { - ExprKind::Literal { literal: cx.const_eval_literal(expr) } + if let hir::ExprLit(ref lit) = arg.node { + ExprKind::Literal { + literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true), + } } else { ExprKind::Unary { op: UnOp::Neg, @@ -509,8 +512,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let def_id = cx.tcx.hir.body_owner_def_id(count); let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id); let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and((def_id, substs))) { - Ok(&ty::Const { val: ConstVal::Integral(ConstInt::Usize(u)), .. }) => u, - Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other), + Ok(cv) => cv.val.unwrap_usize(cx.tcx), Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") }; @@ -634,8 +636,8 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, span: expr.span, kind: ExprKind::Literal { literal: Literal::Value { - value: cx.tcx.mk_const(ty::Const { - val: ConstVal::Function(def_id, substs), + value: cx.tcx().mk_const(ty::Const { + val: const_fn(cx.tcx, def_id, substs), ty }), }, @@ -675,6 +677,28 @@ fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) } } +fn const_fn<'a, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>, +) -> ConstVal<'tcx> { + if tcx.sess.opts.debugging_opts.miri { + /* + let inst = ty::Instance::new(def_id, substs); + let ptr = tcx + .interpret_interner + .borrow_mut() + .create_fn_alloc(inst); + let ptr = MemoryPointer::new(AllocId(ptr), 0); + ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) + */ + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(def_id, substs) + } +} + fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, def: Def) @@ -688,7 +712,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::VariantCtor(def_id, CtorKind::Fn) => ExprKind::Literal { literal: Literal::Value { value: cx.tcx.mk_const(ty::Const { - val: ConstVal::Function(def_id, substs), + val: const_fn(cx.tcx.global_tcx(), def_id, substs), ty: cx.tables().node_id_to_type(expr.hir_id) }), }, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 44c41356117..7ebed0bbddb 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -17,7 +17,6 @@ use hair::*; use rustc::middle::const_val::{ConstEvalErr, ConstVal}; -use rustc_const_eval::ConstContext; use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map::blocks::FnLikeNode; @@ -32,6 +31,7 @@ use syntax::symbol::Symbol; use rustc::hir; use rustc_const_math::{ConstInt, ConstUsize}; use rustc_data_structures::sync::Lrc; +use rustc::mir::interpret::{Value, PrimVal}; #[derive(Clone)] pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { @@ -119,7 +119,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { Ok(val) => { Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::Usize(val)), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))) + } else { + ConstVal::Integral(ConstInt::Usize(val)) + }, ty: self.tcx.types.usize }) } @@ -139,7 +143,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { pub fn true_literal(&mut self) -> Literal<'tcx> { Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Bool(true), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(1))) + } else { + ConstVal::Bool(true) + }, ty: self.tcx.types.bool }) } @@ -148,20 +156,161 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { pub fn false_literal(&mut self) -> Literal<'tcx> { Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Bool(false), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Bool(false) + }, ty: self.tcx.types.bool }) } } - pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> { + pub fn const_eval_literal( + &mut self, + lit: &'tcx ast::LitKind, + ty: Ty<'tcx>, + sp: Span, + neg: bool, + ) -> Literal<'tcx> { let tcx = self.tcx.global_tcx(); - let const_cx = ConstContext::new(tcx, - self.param_env.and(self.identity_substs), - self.tables()); - match const_cx.eval(tcx.hir.expect_expr(e.id)) { - Ok(value) => Literal::Value { value }, - Err(s) => self.fatal_const_eval_err(&s, e.span, "expression") + + let mut repr_ty = ty; + if let ty::TyAdt(adt, _) = ty.sty { + if adt.is_enum() { + repr_ty = adt.repr.discr_type().to_ty(tcx) + } + } + + let parse_float = |num: &str, fty| -> ConstFloat { + ConstFloat::from_str(num, fty).unwrap_or_else(|_| { + // FIXME(#31407) this is only necessary because float parsing is buggy + tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)"); + }) + }; + + if tcx.sess.opts.debugging_opts.miri { + use rustc::mir::interpret::*; + let lit = match *lit { + LitKind::Str(ref s, _) => { + let s = s.as_str(); + let id = self.tcx.allocate_cached(s.as_bytes()); + let ptr = MemoryPointer::new(AllocId(id), 0); + Value::ByValPair( + PrimVal::Ptr(ptr), + PrimVal::from_u128(s.len() as u128), + ) + }, + LitKind::ByteStr(ref data) => { + let id = self.tcx.allocate_cached(data); + let ptr = MemoryPointer::new(AllocId(id), 0); + Value::ByVal(PrimVal::Ptr(ptr)) + }, + LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Int(n, _) if neg => { + let n = n as i128; + let n = n.overflowing_neg().0; + Value::ByVal(PrimVal::Bytes(n as u128)) + }, + LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(n)), + LitKind::Float(n, fty) => { + let n = n.as_str(); + let mut f = parse_float(&n, fty); + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::FloatUnsuffixed(n) => { + let fty = match ty.sty { + ty::TyFloat(fty) => fty, + _ => bug!() + }; + let n = n.as_str(); + let mut f = parse_float(&n, fty); + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), + LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), + }; + return Literal::Value { + value: self.tcx.mk_const(ty::Const { + val: Value(lit), + ty, + }), + }; + } + + use syntax::ast::*; + use syntax::ast::LitIntType::*; + use rustc::middle::const_val::ConstVal::*; + use rustc_const_math::ConstInt::*; + use rustc::ty::util::IntTypeExt; + use rustc::middle::const_val::ByteArray; + use rustc_const_math::ConstFloat; + + let lit = match *lit { + LitKind::Str(ref s, _) => Ok(Str(s.as_str())), + LitKind::ByteStr(ref data) => { + let data: &'tcx [u8] = data; + Ok(ByteStr(ByteArray { data })) + }, + LitKind::Byte(n) => Ok(Integral(U8(n))), + LitKind::Int(n, hint) => { + match (&repr_ty.sty, hint) { + (&ty::TyInt(ity), _) | + (_, Signed(ity)) => { + let mut n = n as i128; + if neg { + n = n.overflowing_neg().0; + } + Ok(Integral(ConstInt::new_signed_truncating(n, + ity, tcx.sess.target.isize_ty))) + } + (&ty::TyUint(uty), _) | + (_, Unsigned(uty)) => { + Ok(Integral(ConstInt::new_unsigned_truncating(n, + uty, tcx.sess.target.usize_ty))) + } + _ => bug!() + } + } + LitKind::Float(n, fty) => { + let mut f = parse_float(&n.as_str(), fty); + if neg { + f = -f; + } + Ok(ConstVal::Float(f)) + } + LitKind::FloatUnsuffixed(n) => { + let fty = match ty.sty { + ty::TyFloat(fty) => fty, + _ => bug!() + }; + let mut f = parse_float(&n.as_str(), fty); + if neg { + f = -f; + } + Ok(ConstVal::Float(f)) + } + LitKind::Bool(b) => Ok(Bool(b)), + LitKind::Char(c) => Ok(Char(c)), + }; + + match lit { + Ok(value) => Literal::Value { value: self.tcx.mk_const(ty::Const { + val: value, + ty, + }) }, + Err(kind) => self.fatal_const_eval_err(&ConstEvalErr { + span: sp, + kind, + }, sp, "expression") } } @@ -203,7 +352,12 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { return (method_ty, Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Function(item.def_id, substs), + val: if self.tcx.sess.opts.debugging_opts.miri { + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(item.def_id, substs) + }, ty: method_ty }), }); diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index bc555368f0f..ec8215fb64c 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -13,14 +13,13 @@ use syntax::ast::Mutability; use syntax::codemap::Span; use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal}; -use super::{Place, EvalContext, StackPopCleanup, ValTy}; +use super::{Place, EvalContext, StackPopCleanup, ValTy, HasMemory}; use rustc_const_math::ConstInt; use std::fmt; use std::error::Error; - pub fn mk_eval_cx<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, @@ -45,7 +44,7 @@ pub fn eval_body<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, param_env: ty::ParamEnv<'tcx>, -) -> EvalResult<'tcx, (Pointer, Ty<'tcx>)> { +) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> { debug!("eval_body: {:?}, {:?}", instance, param_env); let limits = super::ResourceLimits::default(); let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); @@ -82,7 +81,13 @@ pub fn eval_body<'a, 'tcx>( while ecx.step()? {} } let alloc = tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached"); - Ok((MemoryPointer::new(alloc, 0).into(), instance_ty)) + let align = ecx.layout_of(instance_ty)?.align; + let ptr = MemoryPointer::new(alloc, 0).into(); + let value = match ecx.try_read_value(ptr, align, instance_ty)? { + Some(val) => val, + _ => Value::ByRef(ptr, align), + }; + Ok((value, ptr, instance_ty)) } pub fn eval_body_as_integer<'a, 'tcx>( @@ -90,11 +95,9 @@ pub fn eval_body_as_integer<'a, 'tcx>( param_env: ty::ParamEnv<'tcx>, instance: Instance<'tcx>, ) -> EvalResult<'tcx, ConstInt> { - let ptr_ty = eval_body(tcx, instance, param_env); - let (ptr, ty) = ptr_ty?; - let ecx = mk_eval_cx(tcx, instance, param_env)?; - let prim = match ecx.try_read_value(ptr, ecx.layout_of(ty)?.align, ty)? { - Some(Value::ByVal(prim)) => prim.to_bytes()?, + let (value, _, ty) = eval_body(tcx, instance, param_env)?; + let prim = match value { + Value::ByVal(prim) => prim.to_bytes()?, _ => return err!(TypeNotPrimitive(ty)), }; use syntax::ast::{IntTy, UintTy}; @@ -133,7 +136,7 @@ pub struct CompileTimeEvaluator; impl<'tcx> Into> for ConstEvalError { fn into(self) -> EvalError<'tcx> { - EvalErrorKind::MachineError(Box::new(self)).into() + EvalErrorKind::MachineError(self.to_string()).into() } } @@ -193,7 +196,6 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { let mir = match ecx.load_mir(instance.def) { Ok(mir) => mir, Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { - // some simple things like `malloc` might get accepted in the future return Err( ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path)) .into(), @@ -302,6 +304,70 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { } } +pub fn const_val_field<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, mir::Field, Value, Ty<'tcx>)>, +) -> ::rustc::middle::const_val::EvalResult<'tcx> { + trace!("const_val_field: {:#?}", key); + match const_val_field_inner(tcx, key) { + Ok((field, ty)) => Ok(tcx.mk_const(ty::Const { + val: ConstVal::Value(field), + ty, + })), + Err(err) => Err(ConstEvalErr { + span: tcx.def_span(key.value.0.def_id()), + kind: err.into(), + }), + } +} + +fn const_val_field_inner<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, mir::Field, Value, Ty<'tcx>)>, +) -> ::rustc::mir::interpret::EvalResult<'tcx, (Value, Ty<'tcx>)> { + trace!("const_val_field: {:#?}", key); + let (instance, field, value, ty) = key.value; + let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + let (mut field, ty) = match value { + Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, field, ty)?.expect("const_val_field on non-field"), + Value::ByRef(ptr, align) => { + let place = Place::from_primval_ptr(ptr, align); + let layout = ecx.layout_of(ty)?; + let (place, layout) = ecx.place_field(place, field, layout)?; + let (ptr, align) = place.to_ptr_align(); + (Value::ByRef(ptr, align), layout.ty) + } + }; + if let Value::ByRef(ptr, align) = field { + if let Some(val) = ecx.try_read_value(ptr, align, ty)? { + field = val; + } + } + Ok((field, ty)) +} + +pub fn const_discr<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, Value, Ty<'tcx>)>, +) -> EvalResult<'tcx, u128> { + trace!("const_discr: {:#?}", key); + let (instance, value, ty) = key.value; + let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + let (ptr, align) = match value { + Value::ByValPair(..) | Value::ByVal(_) => { + let layout = ecx.layout_of(ty)?; + use super::MemoryKind; + let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?; + let ptr: Pointer = ptr.into(); + ecx.write_value_to_ptr(value, ptr, layout.align, ty)?; + (ptr, layout.align) + }, + Value::ByRef(ptr, align) => (ptr, align), + }; + let place = Place::from_primval_ptr(ptr, align); + ecx.read_discriminant_value(place, ty) +} + pub fn const_eval_provider<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>, @@ -340,35 +406,48 @@ pub fn const_eval_provider<'a, 'tcx>( return Err(ConstEvalErr { span: body.value.span, kind: TypeckError }) } + + let instance = ty::Instance::new(def_id, substs); + if tcx.sess.opts.debugging_opts.miri { + return match ::interpret::eval_body(tcx, instance, key.param_env) { + Ok((miri_value, _, miri_ty)) => Ok(tcx.mk_const(ty::Const { + val: ConstVal::Value(miri_value), + ty: miri_ty, + })), + Err(err) => { + Err(ConstEvalErr { span: body.value.span, kind: err.into() }) + } + }; + } + trace!("running old const eval"); let old_result = ConstContext::new(tcx, key.param_env.and(substs), tables).eval(&body.value); trace!("old const eval produced {:?}", old_result); - if tcx.sess.opts.debugging_opts.miri { - let instance = ty::Instance::new(def_id, substs); - trace!("const eval instance: {:?}, {:?}", instance, key.param_env); - let miri_result = ::interpret::eval_body(tcx, instance, key.param_env); - match (miri_result, old_result) { - (Err(err), Ok(ok)) => { - trace!("miri failed, ctfe returned {:?}", ok); - tcx.sess.span_warn( - tcx.def_span(key.value.0), - "miri failed to eval, while ctfe succeeded", - ); - let ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); - let () = unwrap_miri(&ecx, Err(err)); - Ok(ok) - }, - (_, Err(err)) => Err(err), - (Ok((miri_val, miri_ty)), Ok(ctfe)) => { - let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); - let layout = ecx.layout_of(miri_ty).unwrap(); - let miri_place = Place::from_primval_ptr(miri_val, layout.align); - check_ctfe_against_miri(&mut ecx, miri_place, miri_ty, ctfe.val); - Ok(ctfe) - } + trace!("const eval instance: {:?}, {:?}", instance, key.param_env); + let miri_result = ::interpret::eval_body(tcx, instance, key.param_env); + match (miri_result, old_result) { + (Err(err), Ok(ok)) => { + trace!("miri failed, ctfe returned {:?}", ok); + tcx.sess.span_warn( + tcx.def_span(key.value.0), + "miri failed to eval, while ctfe succeeded", + ); + let ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + let () = unwrap_miri(&ecx, Err(err)); + Ok(ok) + }, + (Ok((value, _, ty)), Err(_)) => Ok(tcx.mk_const(ty::Const { + val: ConstVal::Value(value), + ty, + })), + (Err(_), Err(err)) => Err(err), + (Ok((_, miri_ptr, miri_ty)), Ok(ctfe)) => { + let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + let layout = ecx.layout_of(miri_ty).unwrap(); + let miri_place = Place::from_primval_ptr(miri_ptr, layout.align); + check_ctfe_against_miri(&mut ecx, miri_place, miri_ty, ctfe.val); + Ok(ctfe) } - } else { - old_result } } @@ -451,7 +530,7 @@ fn check_ctfe_against_miri<'a, 'tcx>( } }, TyArray(elem_ty, n) => { - let n = n.val.to_const_int().unwrap().to_u64().unwrap(); + let n = n.val.unwrap_u64(); let vec: Vec<(ConstVal, Ty<'tcx>)> = match ctfe { ConstVal::ByteStr(arr) => arr.data.iter().map(|&b| { (ConstVal::Integral(ConstInt::U8(b)), ecx.tcx.types.u8) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e9e8ccd03b1..f37fb3072b5 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -601,7 +601,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Repeat(ref operand, _) => { let (elem_ty, length) = match dest_ty.sty { - ty::TyArray(elem_ty, n) => (elem_ty, n.val.to_const_int().unwrap().to_u64().unwrap()), + ty::TyArray(elem_ty, n) => (elem_ty, n.val.unwrap_u64()), _ => { bug!( "tried to assign array-repeat to non-array type {:?}", @@ -1386,7 +1386,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { let ptr = self.into_ptr(src)?; // u64 cast is from usize to u64, which is always good let valty = ValTy { - value: ptr.to_value_with_len(length.val.to_const_int().unwrap().to_u64().unwrap() ), + value: ptr.to_value_with_len(length.val.unwrap_u64() ), ty: dest_ty, }; self.write_value(valty, dest) diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index fee62c8a82e..a6ebdd45968 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -18,6 +18,6 @@ pub use self::place::{Place, PlaceExtra}; pub use self::memory::{Memory, MemoryKind, HasMemory}; -pub use self::const_eval::{eval_body_as_integer, eval_body, CompileTimeEvaluator, const_eval_provider}; +pub use self::const_eval::{eval_body_as_integer, eval_body, CompileTimeEvaluator, const_eval_provider, const_val_field, const_discr}; pub use self::machine::Machine; diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index 6ab1aec38b8..b20540b00ce 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -248,10 +248,15 @@ pub fn unary_op<'tcx>( (Not, I64) => !(bytes as i64) as u128, (Not, I128) => !(bytes as i128) as u128, + (Neg, I8) if bytes == i8::min_value() as u128 => return err!(OverflowingMath), (Neg, I8) => -(bytes as i8) as u128, + (Neg, I16) if bytes == i16::min_value() as u128 => return err!(OverflowingMath), (Neg, I16) => -(bytes as i16) as u128, + (Neg, I32) if bytes == i32::min_value() as u128 => return err!(OverflowingMath), (Neg, I32) => -(bytes as i32) as u128, + (Neg, I64) if bytes == i64::min_value() as u128 => return err!(OverflowingMath), (Neg, I64) => -(bytes as i64) as u128, + (Neg, I128) if bytes == i128::min_value() as u128 => return err!(OverflowingMath), (Neg, I128) => -(bytes as i128) as u128, (Neg, F32) => (-bytes_to_f32(bytes)).bits, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 701b7a07ac9..c5e4eeab867 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -71,7 +71,7 @@ impl<'tcx> Place { pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) { match ty.sty { - ty::TyArray(elem, n) => (elem, n.val.to_const_int().unwrap().to_u64().unwrap() as u64), + ty::TyArray(elem, n) => (elem, n.val.unwrap_u64() as u64), ty::TySlice(elem) => { match self { @@ -115,6 +115,29 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } } + pub fn read_field( + &self, + base: Value, + field: mir::Field, + base_ty: Ty<'tcx>, + ) -> EvalResult<'tcx, Option<(Value, Ty<'tcx>)>> { + let base_layout = self.layout_of(base_ty)?; + let field_index = field.index(); + let field = base_layout.field(self, field_index)?; + let offset = base_layout.fields.offset(field_index); + match base { + // the field covers the entire type + Value::ByValPair(..) | + Value::ByVal(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some((base, field.ty))), + // split fat pointers, 2 element tuples, ... + Value::ByValPair(a, b) if base_layout.fields.count() == 2 => { + let val = [a, b][field_index]; + Ok(Some((Value::ByVal(val), field.ty))) + }, + _ => Ok(None), + } + } + fn try_read_place_projection( &mut self, proj: &mir::PlaceProjection<'tcx>, @@ -126,23 +149,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { }; let base_ty = self.place_ty(&proj.base); match proj.elem { - Field(field, _) => { - let base_layout = self.layout_of(base_ty)?; - let field_index = field.index(); - let field = base_layout.field(&self, field_index)?; - let offset = base_layout.fields.offset(field_index); - match base { - // the field covers the entire type - Value::ByValPair(..) | - Value::ByVal(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some(base)), - // split fat pointers, 2 element tuples, ... - Value::ByValPair(a, b) if base_layout.fields.count() == 2 => { - let val = [a, b][field_index]; - Ok(Some(Value::ByVal(val))) - }, - _ => Ok(None), - } - }, + Field(field, _) => Ok(self.read_field(base, field, base_ty)?.map(|(f, _)| f)), // The NullablePointer cases should work fine, need to take care for normal enums Downcast(..) | Subslice { .. } | diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index 606bda51edb..c18cf6d9f96 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -45,8 +45,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { // Branch to the `otherwise` case by default, if no match is found. let mut target_block = targets[targets.len() - 1]; - for (index, const_int) in values.iter().enumerate() { - let prim = PrimVal::Bytes(const_int.to_u128_unchecked()); + for (index, &const_int) in values.iter().enumerate() { + let prim = PrimVal::Bytes(const_int); if discr_prim.to_bytes()? == prim.to_bytes()? { target_block = targets[index]; break; diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 38b8ffc6b9c..1f7f1237ba7 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -314,7 +314,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { output.push('['); self.push_type_name(inner_type, output); write!(output, "; {}", - len.val.to_const_int().unwrap().to_u64().unwrap()).unwrap(); + len.val.unwrap_u64()).unwrap(); output.push(']'); }, ty::TySlice(inner_type) => { diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index e6ebdd3d6c1..11dded1d3f0 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -17,6 +17,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::maps::Providers; use rustc_const_math::{ConstInt, ConstUsize}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -303,7 +304,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match self_ty.sty { _ if is_copy => builder.copy_shim(), ty::TyArray(ty, len) => { - let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + let len = len.val.unwrap_u64(); builder.array_shim(dest, src, ty, len) } ty::TyClosure(def_id, substs) => { @@ -443,7 +444,12 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { ty: func_ty, literal: Literal::Value { value: tcx.mk_const(ty::Const { - val: ConstVal::Function(self.def_id, substs), + val: if tcx.sess.opts.debugging_opts.miri { + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(self.def_id, substs) + }, ty: func_ty }), }, @@ -501,13 +507,20 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { } fn make_usize(&self, value: u64) -> Box> { - let value = ConstUsize::new(value, self.tcx.sess.target.usize_ty).unwrap(); box Constant { span: self.span, ty: self.tcx.types.usize, literal: Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::Usize(value)), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))) + } else { + let value = ConstUsize::new( + value, + self.tcx.sess.target.usize_ty, + ).unwrap(); + ConstVal::Integral(ConstInt::Usize(value)) + }, ty: self.tcx.types.usize, }) } @@ -739,8 +752,12 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty, literal: Literal::Value { value: tcx.mk_const(ty::Const { - val: ConstVal::Function(def_id, - Substs::identity_for_item(tcx, def_id)), + val: if tcx.sess.opts.debugging_opts.miri { + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(def_id, Substs::identity_for_item(tcx, def_id)) + }, ty }), }, diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 04ebaa031fe..ec3edb1e068 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -80,6 +80,7 @@ use transform::simplify; use transform::no_landing_pads::no_landing_pads; use dataflow::{do_dataflow, DebugFormatted, state_for_location}; use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals}; +use rustc::mir::interpret::{Value, PrimVal}; pub struct StateTransform; @@ -181,7 +182,11 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { ty: self.tcx.types.u32, literal: Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::U32(state_disc)), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(state_disc.into()))) + } else { + ConstVal::Integral(ConstInt::U32(state_disc)) + }, ty: self.tcx.types.u32 }), }, @@ -534,7 +539,7 @@ fn insert_switch<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let switch = TerminatorKind::SwitchInt { discr: Operand::Copy(transform.make_field(transform.state_field, tcx.types.u32)), switch_ty: tcx.types.u32, - values: Cow::from(cases.iter().map(|&(i, _)| ConstInt::U32(i)).collect::>()), + values: Cow::from(cases.iter().map(|&(i, _)| i.into()).collect::>()), targets: cases.iter().map(|&(_, d)| d).chain(once(default_block)).collect(), }; diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 64c702b99cd..b8a0e0f8907 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -207,6 +207,13 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { return false; } + // Do not inline {u,i}128 lang items, trans const eval depends + // on detecting calls to these lang items and intercepting them + if tcx.is_binop_lang_item(callsite.callee).is_some() { + debug!(" not inlining 128bit integer lang item"); + return false; + } + let trans_fn_attrs = tcx.trans_fn_attrs(callsite.callee); let hinted = match trans_fn_attrs.inline { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 8f5831270d6..88618122e4f 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -690,7 +690,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { _ => false } } else if let ty::TyArray(_, len) = ty.sty { - len.val.to_const_int().unwrap().to_u64().unwrap() == 0 && + len.val.unwrap_u64() == 0 && self.mode == Mode::Fn } else { false diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 41089f567bd..ca7f573b58a 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -40,10 +40,10 @@ impl MirPass for SimplifyBranches { TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant { literal: Literal::Value { ref value }, .. }), ref values, ref targets, .. } => { - if let Some(ref constint) = value.val.to_const_int() { + if let Some(constint) = value.val.to_u128() { let (otherwise, targets) = targets.split_last().unwrap(); let mut ret = TerminatorKind::Goto { target: *otherwise }; - for (v, t) in values.iter().zip(targets.iter()) { + for (&v, t) in values.iter().zip(targets.iter()) { if v == constint { ret = TerminatorKind::Goto { target: *t }; break; diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index e2feb0ed390..77ef2c20117 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -11,13 +11,14 @@ use std::fmt; use rustc::hir; use rustc::mir::*; -use rustc::middle::const_val::{ConstInt, ConstVal}; +use rustc::middle::const_val::ConstVal; use rustc::middle::lang_items; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Kind, Substs}; use rustc::ty::util::IntTypeExt; use rustc_data_structures::indexed_vec::Idx; use util::patch::MirPatch; +use rustc::mir::interpret::{Value, PrimVal}; use std::{iter, u32}; @@ -425,7 +426,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> variant_path, &adt.variants[variant_index], substs); - values.push(discr); + values.push(discr.to_u128().unwrap()); if let Unwind::To(unwind) = unwind { // We can't use the half-ladder from the original // drop ladder, because this breaks the @@ -480,7 +481,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> fn adt_switch_block(&mut self, adt: &'tcx ty::AdtDef, blocks: Vec, - values: &[ConstInt], + values: &[u128], succ: BasicBlock, unwind: Unwind) -> BasicBlock { @@ -803,7 +804,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.complete_drop(Some(DropFlagMode::Deep), succ, unwind) } ty::TyArray(ety, size) => self.open_drop_for_array( - ety, size.val.to_const_int().and_then(|v| v.to_u64())), + ety, size.val.to_u128().map(|i| i as u64)), ty::TySlice(ety) => self.open_drop_for_array(ety, None), _ => bug!("open drop from non-ADT `{:?}`", ty) @@ -949,7 +950,11 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> ty: self.tcx().types.usize, literal: Literal::Value { value: self.tcx().mk_const(ty::Const { - val: ConstVal::Integral(self.tcx().const_usize(val)), + val: if self.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.into()))) + } else { + ConstVal::Integral(self.tcx().const_usize(val)) + }, ty: self.tcx().types.usize }) } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index b93b759fdf8..8153c3c8493 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -129,6 +129,9 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { } fn check_const_eval(&self, expr: &'gcx hir::Expr) { + if self.tcx.sess.opts.debugging_opts.miri { + return; + } if let Err(err) = self.const_cx().eval(expr) { match err.kind { UnimplementedConstVal(_) => {} @@ -220,23 +223,24 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { self.check_const_eval(lit); } PatKind::Range(ref start, ref end, RangeEnd::Excluded) => { - match self.const_cx().compare_lit_exprs(p.span, start, end) { - Ok(Ordering::Less) => {} - Ok(Ordering::Equal) | - Ok(Ordering::Greater) => { + match self.const_cx().compare_lit_exprs(start, end) { + Ok(Some(Ordering::Less)) => {} + Ok(Some(Ordering::Equal)) | + Ok(Some(Ordering::Greater)) => { span_err!(self.tcx.sess, start.span, E0579, "lower range bound must be less than upper"); } + Ok(None) => bug!("ranges must be char or int"), Err(ErrorReported) => {} } } PatKind::Range(ref start, ref end, RangeEnd::Included) => { - match self.const_cx().compare_lit_exprs(p.span, start, end) { - Ok(Ordering::Less) | - Ok(Ordering::Equal) => {} - Ok(Ordering::Greater) => { + match self.const_cx().compare_lit_exprs(start, end) { + Ok(Some(Ordering::Less)) | + Ok(Some(Ordering::Equal)) => {} + Ok(Some(Ordering::Greater)) => { let mut err = struct_span_err!( self.tcx.sess, start.span, @@ -252,6 +256,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { } err.emit(); } + Ok(None) => bug!("ranges must be char or int"), Err(ErrorReported) => {} } } @@ -308,7 +313,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { self.promotable = false; } - if self.in_fn && self.promotable { + if self.in_fn && self.promotable && !self.tcx.sess.opts.debugging_opts.miri { match self.const_cx().eval(ex) { Ok(_) => {} Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) | diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 3708f6f6ec4..314b8c59df5 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -195,7 +195,7 @@ pub fn unsized_info<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>, let (source, target) = cx.tcx.struct_lockstep_tails(source, target); match (&source.sty, &target.sty) { (&ty::TyArray(_, len), &ty::TySlice(_)) => { - C_usize(cx, len.val.to_const_int().unwrap().to_u64().unwrap()) + C_usize(cx, len.val.unwrap_u64()) } (&ty::TyDynamic(..), &ty::TyDynamic(..)) => { // For now, upcasts are limited to changes in marker diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 2c430d03c96..0fe425fb7ea 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -276,7 +276,7 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let upper_bound = match array_or_slice_type.sty { ty::TyArray(_, len) => { - len.val.to_const_int().unwrap().to_u64().unwrap() as c_longlong + len.val.unwrap_u64() as c_longlong } _ => -1 }; diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 6490d109f29..a88eb9ae354 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -97,7 +97,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ty::TyArray(inner_type, len) => { output.push('['); push_debuginfo_type_name(cx, inner_type, true, output); - output.push_str(&format!("; {}", len.val.to_const_int().unwrap().to_u64().unwrap())); + output.push_str(&format!("; {}", len.val.unwrap_u64())); output.push(']'); }, ty::TySlice(inner_type) => { diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index f683703ce6d..c88e39d7824 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -17,6 +17,7 @@ use rustc::middle::const_val::ConstVal; use rustc::mir::{self, Location, TerminatorKind, Literal}; use rustc::mir::visit::{Visitor, PlaceContext}; use rustc::mir::traversal; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::ty; use rustc::ty::layout::LayoutOf; use type_of::LayoutLlvmExt; @@ -109,15 +110,26 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { block: mir::BasicBlock, kind: &mir::TerminatorKind<'tcx>, location: Location) { - match *kind { + let check = match *kind { mir::TerminatorKind::Call { func: mir::Operand::Constant(box mir::Constant { literal: Literal::Value { - value: &ty::Const { val: ConstVal::Function(def_id, _), .. }, .. + value: &ty::Const { val, ty }, .. }, .. }), ref args, .. - } if Some(def_id) == self.fx.cx.tcx.lang_items().box_free_fn() => { + } => match val { + ConstVal::Function(def_id, _) => Some((def_id, args)), + ConstVal::Value(Value::ByVal(PrimVal::Undef)) => match ty.sty { + ty::TyFnDef(did, _) => Some((did, args)), + _ => None, + }, + _ => None, + } + _ => None, + }; + if let Some((def_id, args)) = check { + if Some(def_id) == self.cx.ccx.tcx().lang_items().box_free_fn() { // box_free(x) shares with `drop x` the property that it // is not guaranteed to be statically dominated by the // definition of x, so x must always be in an alloca. @@ -125,7 +137,6 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { self.visit_place(place, PlaceContext::Drop, location); } } - _ => {} } self.super_terminator_kind(block, kind, location); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index bb2a7840fae..239300c1ecf 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -10,7 +10,7 @@ use llvm::{self, ValueRef, BasicBlockRef}; use rustc::middle::lang_items; -use rustc::middle::const_val::{ConstEvalErr, ConstInt, ErrKind}; +use rustc::middle::const_val::{ConstEvalErr, ErrKind}; use rustc::ty::{self, TypeFoldable}; use rustc::ty::layout::{self, LayoutOf}; use rustc::traits; @@ -196,17 +196,18 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { if switch_ty == bx.tcx().types.bool { let lltrue = llblock(self, targets[0]); let llfalse = llblock(self, targets[1]); - if let [ConstInt::U8(0)] = values[..] { + if let [0] = values[..] { bx.cond_br(discr.immediate(), llfalse, lltrue); } else { + assert_eq!(&values[..], &[1]); bx.cond_br(discr.immediate(), lltrue, llfalse); } } else { let (otherwise, targets) = targets.split_last().unwrap(); let switch = bx.switch(discr.immediate(), llblock(self, *otherwise), values.len()); - for (value, target) in values.iter().zip(targets) { - let val = Const::from_constint(bx.cx, value); + for (&value, target) in values.iter().zip(targets) { + let val = Const::from_bytes(bx.cx, value, switch_ty); let llbb = llblock(self, *target); bx.add_case(switch, val.llval, llbb) } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index c853230b15a..5bd5f19a57c 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -16,6 +16,7 @@ use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; use rustc::traits; use rustc::mir; +use rustc::mir::interpret::{Value as MiriValue, PrimVal}; use rustc::mir::tcx::PlaceTy; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::layout::{self, LayoutOf, Size}; @@ -38,6 +39,7 @@ use value::Value; use syntax_pos::Span; use syntax::ast; +use syntax::symbol::Symbol; use std::fmt; use std::ptr; @@ -81,12 +83,46 @@ impl<'a, 'tcx> Const<'tcx> { Const { llval: llval, ty: ty } } + pub fn from_bytes(ccx: &CrateContext<'a, 'tcx>, b: u128, ty: Ty<'tcx>) -> Const<'tcx> { + let llval = match ty.sty { + ty::TyInt(ast::IntTy::I128) | + ty::TyUint(ast::UintTy::U128) => C_uint_big(Type::i128(ccx), b), + ty::TyInt(i) => C_int(Type::int_from_ty(ccx, i), b as i128 as i64), + ty::TyUint(u) => C_uint(Type::uint_from_ty(ccx, u), b as u64), + ty::TyBool => { + assert!(b <= 1); + C_bool(ccx, b == 1) + }, + ty::TyChar => { + assert_eq!(b as u32 as u128, b); + let c = b as u32; + assert!(::std::char::from_u32(c).is_some()); + C_uint(Type::char(ccx), c as u64) + }, + ty::TyFloat(fty) => { + let llty = ccx.layout_of(ty).llvm_type(ccx); + let bits = match fty { + ast::FloatTy::F32 => C_u32(ccx, b as u32), + ast::FloatTy::F64 => C_u64(ccx, b as u64), + }; + consts::bitcast(bits, llty) + }, + ty::TyAdt(adt, _) if adt.is_enum() => { + use rustc::ty::util::IntTypeExt; + Const::from_bytes(ccx, b, adt.repr.discr_type().to_ty(ccx.tcx())).llval + }, + _ => bug!("from_bytes({}, {})", b, ty), + }; + Const { llval, ty } + } + /// Translate ConstVal into a LLVM constant value. pub fn from_constval(cx: &CodegenCx<'a, 'tcx>, cv: &ConstVal, ty: Ty<'tcx>) -> Const<'tcx> { let llty = cx.layout_of(ty).llvm_type(cx); + trace!("from_constval: {:#?}: {}", cv, ty); let val = match *cv { ConstVal::Float(v) => { let bits = match v.ty { @@ -108,7 +144,41 @@ impl<'a, 'tcx> Const<'tcx> { ConstVal::Unevaluated(..) => { bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv) } - ConstVal::Value(_) => unimplemented!(), + ConstVal::Value(MiriValue::ByRef(..)) => unimplemented!("{:#?}:{}", cv, ty), + ConstVal::Value(MiriValue::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len))) => { + match ty.sty { + ty::TyRef(_, ref tam) => match tam.ty.sty { + ty::TyStr => {}, + _ => unimplemented!("non-str fat pointer: {:?}: {:?}", ptr, ty), + }, + _ => unimplemented!("non-str fat pointer: {:?}: {:?}", ptr, ty), + } + let alloc = ccx + .tcx() + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .expect("miri alloc not found"); + assert_eq!(len as usize as u128, len); + let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)]; + let s = ::std::str::from_utf8(slice) + .expect("non utf8 str from miri"); + C_str_slice(ccx, Symbol::intern(s).as_str()) + }, + ConstVal::Value(MiriValue::ByValPair(..)) => unimplemented!(), + ConstVal::Value(MiriValue::ByVal(PrimVal::Bytes(b))) => + return Const::from_bytes(ccx, b, ty), + ConstVal::Value(MiriValue::ByVal(PrimVal::Undef)) => C_undef(llty), + ConstVal::Value(MiriValue::ByVal(PrimVal::Ptr(ptr))) => { + let alloc = ccx + .tcx() + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .expect("miri alloc not found"); + let data = &alloc.bytes[(ptr.offset as usize)..]; + consts::addr_of(ccx, C_bytes(ccx, data), ccx.align_of(ty), "byte_str") + } }; assert!(!ty.has_erasable_regions()); @@ -239,7 +309,7 @@ impl<'tcx> ConstPlace<'tcx> { pub fn len<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> ValueRef { match self.ty.sty { ty::TyArray(_, n) => { - C_usize(cx, n.val.to_const_int().unwrap().to_u64().unwrap()) + C_usize(cx, n.val.unwrap_u64()) } ty::TySlice(_) | ty::TyStr => { assert!(self.llextra != ptr::null_mut()); @@ -316,7 +386,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let tcx = self.cx.tcx; let mut bb = mir::START_BLOCK; - // Make sure to evaluate all statemenets to + // Make sure to evaluate all statements to // report as many errors as we possibly can. let mut failure = Ok(()); @@ -392,6 +462,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { _ => span_bug!(span, "calling {:?} (of type {}) in constant", func, fn_ty) }; + trace!("trans const fn call {:?}, {:?}, {:#?}", func, fn_ty, args); let mut arg_vals = IndexVec::with_capacity(args.len()); for arg in args { @@ -419,7 +490,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } _ => span_bug!(span, "{:?} in constant", terminator.kind) } - } else if let Some((op, is_checked)) = self.is_binop_lang_item(def_id) { + } else if let Some((op, is_checked)) = tcx.is_binop_lang_item(def_id) { (||{ assert_eq!(arg_vals.len(), 2); let rhs = arg_vals.pop().unwrap()?; @@ -470,37 +541,6 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } } - fn is_binop_lang_item(&mut self, def_id: DefId) -> Option<(mir::BinOp, bool)> { - let tcx = self.cx.tcx; - let items = tcx.lang_items(); - let def_id = Some(def_id); - if items.i128_add_fn() == def_id { Some((mir::BinOp::Add, false)) } - else if items.u128_add_fn() == def_id { Some((mir::BinOp::Add, false)) } - else if items.i128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) } - else if items.u128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) } - else if items.i128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) } - else if items.u128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) } - else if items.i128_div_fn() == def_id { Some((mir::BinOp::Div, false)) } - else if items.u128_div_fn() == def_id { Some((mir::BinOp::Div, false)) } - else if items.i128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) } - else if items.u128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) } - else if items.i128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) } - else if items.u128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) } - else if items.i128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) } - else if items.u128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) } - else if items.i128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) } - else if items.u128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) } - else if items.i128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) } - else if items.u128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) } - else if items.i128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) } - else if items.u128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) } - else if items.i128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) } - else if items.u128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) } - else if items.i128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) } - else if items.u128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) } - else { None } - } - fn store(&mut self, dest: &mir::Place<'tcx>, value: Result, ConstEvalErr<'tcx>>, diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 34ac44cec02..b0cb7de824e 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -497,7 +497,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { if let mir::Place::Local(index) = *place { if let LocalRef::Operand(Some(op)) = self.locals[index] { if let ty::TyArray(_, n) = op.layout.ty.sty { - let n = n.val.to_const_int().unwrap().to_u64().unwrap(); + let n = n.val.unwrap_u64(); return common::C_usize(bx.cx, n); } } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index a261c12bcdd..eb02c05fd39 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -413,7 +413,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expected_ty = self.structurally_resolved_type(pat.span, expected); let (inner_ty, slice_ty) = match expected_ty.sty { ty::TyArray(inner_ty, size) => { - let size = size.val.to_const_int().unwrap().to_u64().unwrap(); + let size = size.val.unwrap_u64(); let min_len = before.len() as u64 + after.len() as u64; if slice.is_none() { if min_len != size { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0f59973eab2..26b96493310 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4029,9 +4029,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Ok(count) = count { - let zero_or_one = count.val.to_const_int().and_then(|count| { - count.to_u64().map(|count| count <= 1) - }).unwrap_or(false); + let zero_or_one = count.val.to_u128().map_or(false, |count| count <= 1); if !zero_or_one { // For [foo, ..n] where n > 1, `foo` must have // Copy type: diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 12791107ebb..47a229cbd3b 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -447,10 +447,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::BiBitOr => ("bitor", lang.bitor_trait()), hir::BiShl => ("shl", lang.shl_trait()), hir::BiShr => ("shr", lang.shr_trait()), - hir::BiLt => ("lt", lang.ord_trait()), - hir::BiLe => ("le", lang.ord_trait()), - hir::BiGe => ("ge", lang.ord_trait()), - hir::BiGt => ("gt", lang.ord_trait()), + hir::BiLt => ("lt", lang.partial_ord_trait()), + hir::BiLe => ("le", lang.partial_ord_trait()), + hir::BiGe => ("ge", lang.partial_ord_trait()), + hir::BiGt => ("gt", lang.partial_ord_trait()), hir::BiEq => ("eq", lang.eq_trait()), hir::BiNe => ("ne", lang.eq_trait()), hir::BiAnd | hir::BiOr => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1a7d8bb5678..5ed35e8203c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -37,8 +37,8 @@ use rustc::ty::{ToPredicate, ReprOptions}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::maps::Providers; use rustc::ty::util::IntTypeExt; -use rustc::util::nodemap::FxHashSet; -use util::nodemap::FxHashMap; +use rustc::util::nodemap::{FxHashSet, FxHashMap}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc_const_math::ConstInt; @@ -534,6 +534,18 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match result { Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => Some(x), + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + use syntax::attr::IntType; + Some(match repr_type { + IntType::SignedInt(int_type) => ConstInt::new_signed( + b as i128, int_type, tcx.sess.target.isize_ty).unwrap(), + IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned( + b, uint_type, tcx.sess.target.usize_ty).unwrap(), + }) + } _ => None } } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) { diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index d9bd96b0d76..40385cabf56 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -86,6 +86,7 @@ This API is completely unstable and subject to change. #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] +#![feature(i128_type)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/test/mir-opt/end_region_2.rs b/src/test/mir-opt/end_region_2.rs index d6084d5a6da..3fb5621c8ae 100644 --- a/src/test/mir-opt/end_region_2.rs +++ b/src/test/mir-opt/end_region_2.rs @@ -49,7 +49,7 @@ fn main() { // _3 = &'23_1rs _2; // StorageLive(_5); // _5 = _2; -// switchInt(move _5) -> [0u8: bb5, otherwise: bb4]; +// switchInt(move _5) -> [false: bb5, otherwise: bb4]; // } // bb3: { // ... diff --git a/src/test/mir-opt/end_region_3.rs b/src/test/mir-opt/end_region_3.rs index 46548f1cce9..070bde8e3c3 100644 --- a/src/test/mir-opt/end_region_3.rs +++ b/src/test/mir-opt/end_region_3.rs @@ -51,7 +51,7 @@ fn main() { // _3 = &'26_1rs _1; // StorageLive(_5); // _5 = _1; -// switchInt(move _5) -> [0u8: bb5, otherwise: bb4]; +// switchInt(move _5) -> [false: bb5, otherwise: bb4]; // } // bb3: { // ... diff --git a/src/test/mir-opt/end_region_9.rs b/src/test/mir-opt/end_region_9.rs index 0f1d714cc6f..6d9a27eeeb4 100644 --- a/src/test/mir-opt/end_region_9.rs +++ b/src/test/mir-opt/end_region_9.rs @@ -72,7 +72,7 @@ fn main() { // bb4: { // StorageLive(_7); // _7 = _1; -// switchInt(move _7) -> [0u8: bb6, otherwise: bb5]; +// switchInt(move _7) -> [false: bb6, otherwise: bb5]; // } // bb5: { // _0 = (); diff --git a/src/test/mir-opt/end_region_cyclic.rs b/src/test/mir-opt/end_region_cyclic.rs index 2a82e2675b6..83425a72f45 100644 --- a/src/test/mir-opt/end_region_cyclic.rs +++ b/src/test/mir-opt/end_region_cyclic.rs @@ -103,7 +103,7 @@ fn query() -> bool { true } // _11 = const query() -> [return: bb6, unwind: bb3]; // } // bb6: { -// switchInt(move _11) -> [0u8: bb8, otherwise: bb7]; +// switchInt(move _11) -> [false: bb8, otherwise: bb7]; // } // bb7: { // _0 = (); diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs index 3151c064307..a9eea26f466 100644 --- a/src/test/mir-opt/issue-38669.rs +++ b/src/test/mir-opt/issue-38669.rs @@ -36,7 +36,7 @@ fn main() { // bb3: { // StorageLive(_4); // _4 = _1; -// switchInt(move _4) -> [0u8: bb5, otherwise: bb4]; +// switchInt(move _4) -> [false: bb5, otherwise: bb4]; // } // bb4: { // _0 = (); diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index ba1b54d59f6..596bb4e115d 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -93,7 +93,7 @@ fn main() { // _7 = const guard() -> [return: bb10, unwind: bb1]; // } // bb10: { // end of guard -// switchInt(move _7) -> [0u8: bb11, otherwise: bb2]; +// switchInt(move _7) -> [false: bb11, otherwise: bb2]; // } // bb11: { // to pre_binding2 // falseEdges -> [real: bb5, imaginary: bb5]; @@ -157,7 +157,7 @@ fn main() { // _7 = const guard() -> [return: bb10, unwind: bb1]; // } // bb10: { // end of guard -// switchInt(move _7) -> [0u8: bb11, otherwise: bb2]; +// switchInt(move _7) -> [false: bb11, otherwise: bb2]; // } // bb11: { // to pre_binding2 // falseEdges -> [real: bb6, imaginary: bb5]; @@ -219,7 +219,7 @@ fn main() { // _9 = const guard() -> [return: bb10, unwind: bb1]; // } // bb10: { //end of guard -// switchInt(move _9) -> [0u8: bb11, otherwise: bb2]; +// switchInt(move _9) -> [false: bb11, otherwise: bb2]; // } // bb11: { // to pre_binding2 // falseEdges -> [real: bb5, imaginary: bb5]; @@ -239,8 +239,8 @@ fn main() { // _11 = const guard2(move _12) -> [return: bb14, unwind: bb1]; // } // bb14: { // end of guard2 -// StorageDead(_12); -// switchInt(move _11) -> [0u8: bb15, otherwise: bb3]; +// StorageDead(_11); +// switchInt(move _11) -> [false: bb15, otherwise: bb3]; // } // bb15: { // to pre_binding4 // falseEdges -> [real: bb7, imaginary: bb7]; diff --git a/src/test/mir-opt/nll/region-liveness-basic.rs b/src/test/mir-opt/nll/region-liveness-basic.rs index e9834305550..19d733d4f6b 100644 --- a/src/test/mir-opt/nll/region-liveness-basic.rs +++ b/src/test/mir-opt/nll/region-liveness-basic.rs @@ -41,7 +41,7 @@ fn main() { // | Live variables on entry to bb2[0]: [_1, _3] // _2 = &'_#2r _1[_3]; // | Live variables on entry to bb2[1]: [_2] -// switchInt(const true) -> [0u8: bb4, otherwise: bb3]; +// switchInt(const true) -> [false: bb4, otherwise: bb3]; // } // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs index 35786643648..52d5892e656 100644 --- a/src/test/mir-opt/simplify_if.rs +++ b/src/test/mir-opt/simplify_if.rs @@ -17,7 +17,7 @@ fn main() { // END RUST SOURCE // START rustc.main.SimplifyBranches-initial.before.mir // bb0: { -// switchInt(const false) -> [0u8: bb3, otherwise: bb2]; +// switchInt(const false) -> [false: bb3, otherwise: bb2]; // } // END rustc.main.SimplifyBranches-initial.before.mir // START rustc.main.SimplifyBranches-initial.after.mir diff --git a/src/test/ui/const-eval-overflow-2.rs b/src/test/ui/const-eval-overflow-2.rs index 6b7f631ff4c..885edb55ed8 100644 --- a/src/test/ui/const-eval-overflow-2.rs +++ b/src/test/ui/const-eval-overflow-2.rs @@ -19,8 +19,7 @@ use std::{u8, u16, u32, u64, usize}; const NEG_128: i8 = -128; const NEG_NEG_128: i8 = -NEG_128; -//~^ ERROR constant evaluation error -//~| attempt to negate with overflow +//~^ ERROR E0080 fn main() { match -128i8 { diff --git a/src/test/ui/const-eval-overflow-4.rs b/src/test/ui/const-eval-overflow-4.rs index 4423fdec33a..a1b90f623cd 100644 --- a/src/test/ui/const-eval-overflow-4.rs +++ b/src/test/ui/const-eval-overflow-4.rs @@ -21,8 +21,7 @@ use std::{u8, u16, u32, u64, usize}; const A_I8_T : [u32; (i8::MAX as i8 + 1i8) as usize] - //~^ ERROR constant evaluation error - //~| WARNING constant evaluation error + //~^ ERROR E0080 = [0; (i8::MAX as usize) + 1]; fn main() { diff --git a/src/test/ui/const-eval/issue-43197.rs b/src/test/ui/const-eval/issue-43197.rs index 85ab2a00521..86c5e873df8 100644 --- a/src/test/ui/const-eval/issue-43197.rs +++ b/src/test/ui/const-eval/issue-43197.rs @@ -16,8 +16,6 @@ const fn foo(x: u32) -> u32 { fn main() { const X: u32 = 0-1; //~ ERROR constant evaluation error - //~^ WARN constant evaluation error const Y: u32 = foo(0-1); //~ ERROR constant evaluation error - //~^ WARN constant evaluation error println!("{} {}", X, Y); } diff --git a/src/test/ui/const-expr-addr-operator.rs b/src/test/ui/const-expr-addr-operator.rs index 24d4457f01d..bfd6a409064 100644 --- a/src/test/ui/const-expr-addr-operator.rs +++ b/src/test/ui/const-expr-addr-operator.rs @@ -9,10 +9,11 @@ // except according to those terms. // Encountered while testing #44614. +// must-compile-successfully pub fn main() { // Constant of generic type (int) - const X: &'static u32 = &22; //~ ERROR constant evaluation error + const X: &'static u32 = &22; assert_eq!(0, match &22 { X => 0, _ => 1, diff --git a/src/test/ui/const-fn-error.rs b/src/test/ui/const-fn-error.rs index ac1c2fe5432..dc1526a7079 100644 --- a/src/test/ui/const-fn-error.rs +++ b/src/test/ui/const-fn-error.rs @@ -13,17 +13,18 @@ const X : usize = 2; const fn f(x: usize) -> usize { - let mut sum = 0; //~ ERROR blocks in constant functions are limited - for i in 0..x { //~ ERROR calls in constant functions - //~| ERROR constant function contains unimplemented + let mut sum = 0; + //~^ ERROR E0016 + for i in 0..x { + //~^ ERROR E0015 + //~| ERROR E0019 sum += i; } - sum //~ ERROR E0080 - //~| non-constant path in constant + sum } #[allow(unused_variables)] fn main() { let a : [i32; f(X)]; - //~^ WARNING constant evaluation error: non-constant path + //~^ ERROR E0080 } diff --git a/src/test/ui/const-fn-error.stderr b/src/test/ui/const-fn-error.stderr index e738a5e4ff3..26c238992ab 100644 --- a/src/test/ui/const-fn-error.stderr +++ b/src/test/ui/const-fn-error.stderr @@ -1,3 +1,4 @@ +<<<<<<< HEAD warning: constant evaluation error: non-constant path in constant expression --> $DIR/const-fn-error.rs:27:19 | @@ -10,6 +11,12 @@ error[E0016]: blocks in constant functions are limited to items and tail express --> $DIR/const-fn-error.rs:16:19 | LL | let mut sum = 0; //~ ERROR blocks in constant functions are limited +======= +error[E0016]: blocks in constant functions are limited to items and tail expressions + --> $DIR/const-fn-error.rs:16:19 + | +16 | let mut sum = 0; +>>>>>>> Produce instead of pointers | ^ error[E0015]: calls in constant functions are limited to constant functions, struct and enum constructors @@ -25,6 +32,7 @@ LL | for i in 0..x { //~ ERROR calls in constant functions | ^^^^ error[E0080]: constant evaluation error +<<<<<<< HEAD --> $DIR/const-fn-error.rs:21:5 | LL | sum //~ ERROR E0080 @@ -35,6 +43,12 @@ note: for constant expression here | LL | let a : [i32; f(X)]; | ^^^^^^^^^^^ +======= + --> $DIR/const-fn-error.rs:28:19 + | +28 | let a : [i32; f(X)]; + | ^^^^ miri failed: machine error: Cannot evaluate within constants: "calling non-const fn `>::into_iter`" +>>>>>>> Produce instead of pointers error: aborting due to 4 previous errors diff --git a/src/test/ui/const-len-underflow-separate-spans.rs b/src/test/ui/const-len-underflow-separate-spans.rs index 823cc988947..7582d0efa81 100644 --- a/src/test/ui/const-len-underflow-separate-spans.rs +++ b/src/test/ui/const-len-underflow-separate-spans.rs @@ -15,9 +15,8 @@ const ONE: usize = 1; const TWO: usize = 2; const LEN: usize = ONE - TWO; -//~^ ERROR constant evaluation error [E0080] -//~| WARN attempt to subtract with overflow fn main() { let a: [i8; LEN] = unimplemented!(); +//~^ ERROR E0080 } diff --git a/src/test/ui/const-pattern-not-const-evaluable.rs b/src/test/ui/const-pattern-not-const-evaluable.rs index 263c0bdc64c..09b24d1ffa2 100644 --- a/src/test/ui/const-pattern-not-const-evaluable.rs +++ b/src/test/ui/const-pattern-not-const-evaluable.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// must-compile-successfully + #![feature(const_fn)] #[derive(PartialEq, Eq)] @@ -20,8 +22,6 @@ use Cake::*; struct Pair(A, B); const BOO: Pair = Pair(Marmor, BlackForest); -//~^ ERROR: constant evaluation error [E0080] -//~| unimplemented constant expression: tuple struct constructors const FOO: Cake = BOO.1; const fn foo() -> Cake { diff --git a/src/test/ui/feature-gate-const-indexing.rs b/src/test/ui/feature-gate-const-indexing.rs index 0d61878cd80..eb5f746774c 100644 --- a/src/test/ui/feature-gate-const-indexing.rs +++ b/src/test/ui/feature-gate-const-indexing.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// must-compile-successfully fn main() { const ARR: [i32; 6] = [42, 43, 44, 45, 46, 47]; const IDX: usize = 3; const VAL: i32 = ARR[IDX]; - const BLUB: [i32; (ARR[0] - 41) as usize] = [5]; //~ ERROR constant evaluation error + const BLUB: [i32; (ARR[0] - 41) as usize] = [5]; } diff --git a/src/test/ui/issue-38875/issue_38875.rs b/src/test/ui/issue-38875/issue_38875.rs index 42e3c05a38c..24cd20a84a9 100644 --- a/src/test/ui/issue-38875/issue_38875.rs +++ b/src/test/ui/issue-38875/issue_38875.rs @@ -9,6 +9,7 @@ // except according to those terms. // aux-build:issue_38875_b.rs +// must-compile-successfully extern crate issue_38875_b; diff --git a/src/test/ui/union/union-const-eval.rs b/src/test/ui/union/union-const-eval.rs index a4c969ba20c..aeafb45e6a5 100644 --- a/src/test/ui/union/union-const-eval.rs +++ b/src/test/ui/union/union-const-eval.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// must-compile-successfully + union U { a: usize, b: usize, @@ -16,9 +18,6 @@ union U { const C: U = U { a: 10 }; fn main() { - unsafe { - let a: [u8; C.a]; // OK - let b: [u8; C.b]; //~ ERROR constant evaluation error - //~| WARNING constant evaluation error - } + let a: [u8; unsafe { C.a }]; + let b: [u8; unsafe { C.b }]; } -- cgit 1.4.1-3-g733a5 From fe557eee7de236e767a81a123c5de9b52d5e9a2a Mon Sep 17 00:00:00 2001 From: Maxim Nazarenko Date: Thu, 8 Mar 2018 23:15:39 +0200 Subject: another rewrite based on @nikomatsakis texthg --- src/libcore/cell.rs | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 8accbc204c1..61b0aead22f 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1161,27 +1161,43 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// The `UnsafeCell` type is the only legal way to obtain aliasable data that is considered /// mutable. In general, transmuting an `&T` type into an `&mut T` is considered undefined behavior. /// -/// The compiler makes optimizations based on the knowledge that `&T` is not mutably aliased or -/// mutated, and that `&mut T` is unique. When building abstractions like `Cell`, `RefCell`, -/// `Mutex`, etc, you need to turn these optimizations off. `UnsafeCell` is the only legal way -/// to do this. When `UnsafeCell` itself is immutably aliased, it is still safe to obtain -/// a mutable reference to its interior and/or to mutate the interior. However, the abstraction -/// designer must ensure that any active mutable references to the interior obtained this way does -/// not co-exist with other active references to the interior, either mutable or not. This is often -/// done via runtime checks. Naturally, several active immutable references to the interior can -/// co-exits with each other (but not with a mutable reference). +/// If you have a reference `&SomeStruct`, then normally in Rust all fields of `SomeStruct` are +/// immutable. The compiler makes optimizations based on the knowledge that `&T` is not mutably +/// aliased or mutated, and that `&mut T` is unique. `UnsafeCel` is the only core language +/// feature to work around this restriction. All other types that allow internal mutability, such as +/// `Cell` and `RefCell` use `UnsafeCell` to wrap their internal data. /// -/// To put it in other words, if a mutable reference to the contents is active, no other references -/// can be active at the same time, and if an immutable reference to the contents is active, then -/// only other immutable reference may be active. +/// The `UnsafeCell` API itself is technically very simple: it gives you a raw pointer `*mut T` to +/// its contents. It is up to _you_ as the abstraction designer to use that raw pointer correctly. +/// +/// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious: +/// +/// - If you create a safe reference with lifetime `'a` (either a `&T` or `&mut T` reference) that +/// is accessible by safe code (for example, because you returned it), then you must not access +/// the data in any way that contradicts that reference for the remainder of `'a`. For example, that +/// means that if you take the `*mut T` from an `UnsafeCell` and case it to an `&T`, then until +/// that reference's lifetime expires, the data in `T` must remain immutable (modulo any +/// `UnsafeCell` data found within `T`, of course). Similarly, if you create an `&mut T` reference +/// that is released to safe code, then you must not access the data within the `UnsafeCell` until +/// that reference expires. +/// +/// - At all times, you must avoid data races, meaning that if multiple threads have access to +/// the same `UnsafeCell`, then any writes must have a proper happens-before relation to all other +/// accesses (or use atomics). +/// +/// To assist with proper design, the following scenarios are explicitly declared legal +/// for single-threaded code: +/// +/// 1. A `&T` reference can be released to safe code and there it can co-exit with other `&T` +/// references, but not with a `&mut T` +/// +/// 2. A `&mut T` reference may be released to safe code, provided neither other `&mut T` nor `&T` +/// co-exist with it. A `&mut T` must always be unique. /// /// Note that while mutating or mutably aliasing the contents of an `& UnsafeCell` is /// okay (provided you enforce the invariants some other way), it is still undefined behavior /// to have multiple `&mut UnsafeCell` aliases. /// -/// -/// Types like `Cell` and `RefCell` use this type to wrap their internal data. -/// /// # Examples /// /// ``` -- cgit 1.4.1-3-g733a5 From fbcd2f5a6a23c48416e6a948d8733f1c225acab3 Mon Sep 17 00:00:00 2001 From: Maxim Nazarenko Date: Thu, 8 Mar 2018 23:16:31 +0200 Subject: tidy. Again --- src/libcore/cell.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 61b0aead22f..98f08676722 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1167,7 +1167,7 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// feature to work around this restriction. All other types that allow internal mutability, such as /// `Cell` and `RefCell` use `UnsafeCell` to wrap their internal data. /// -/// The `UnsafeCell` API itself is technically very simple: it gives you a raw pointer `*mut T` to +/// The `UnsafeCell` API itself is technically very simple: it gives you a raw pointer `*mut T` to /// its contents. It is up to _you_ as the abstraction designer to use that raw pointer correctly. /// /// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious: @@ -1182,7 +1182,7 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// that reference expires. /// /// - At all times, you must avoid data races, meaning that if multiple threads have access to -/// the same `UnsafeCell`, then any writes must have a proper happens-before relation to all other +/// the same `UnsafeCell`, then any writes must have a proper happens-before relation to all other /// accesses (or use atomics). /// /// To assist with proper design, the following scenarios are explicitly declared legal -- cgit 1.4.1-3-g733a5 From 55be28367413e01262e4fb72d4af36cee368b65d Mon Sep 17 00:00:00 2001 From: Maxim Nazarenko Date: Thu, 8 Mar 2018 23:26:27 +0200 Subject: and again :( --- src/libcore/cell.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 98f08676722..4cfc34b86d0 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1176,10 +1176,10 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// is accessible by safe code (for example, because you returned it), then you must not access /// the data in any way that contradicts that reference for the remainder of `'a`. For example, that /// means that if you take the `*mut T` from an `UnsafeCell` and case it to an `&T`, then until -/// that reference's lifetime expires, the data in `T` must remain immutable (modulo any +/// that reference's lifetime expires, the data in `T` must remain immutable (modulo any /// `UnsafeCell` data found within `T`, of course). Similarly, if you create an `&mut T` reference /// that is released to safe code, then you must not access the data within the `UnsafeCell` until -/// that reference expires. +/// that reference expires. /// /// - At all times, you must avoid data races, meaning that if multiple threads have access to /// the same `UnsafeCell`, then any writes must have a proper happens-before relation to all other @@ -1189,7 +1189,7 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// for single-threaded code: /// /// 1. A `&T` reference can be released to safe code and there it can co-exit with other `&T` -/// references, but not with a `&mut T` +/// references, but not with a `&mut T` /// /// 2. A `&mut T` reference may be released to safe code, provided neither other `&mut T` nor `&T` /// co-exist with it. A `&mut T` must always be unique. -- cgit 1.4.1-3-g733a5 From 679e410b11848ef3d9544c08bdb942ae3bc15a46 Mon Sep 17 00:00:00 2001 From: 1011X <1011XXXXX@gmail.com> Date: Thu, 8 Mar 2018 22:55:54 -0500 Subject: declare ascii test module in core --- src/libcore/tests/lib.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libcore') diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 0049ed66a10..939afdcb982 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -52,6 +52,7 @@ extern crate test; mod any; mod array; +mod ascii; mod atomic; mod cell; mod char; -- cgit 1.4.1-3-g733a5 From f2a8556df455c37b64d7e7df1454fc156f6be342 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 9 Mar 2018 11:31:04 -0800 Subject: Update stdsimd module Pulls in a redesigned `std::simd` module as well as a replacement for the `is_target_feature_detected!` macro --- src/libcore/lib.rs | 2 ++ src/stdsimd | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 1efd605112d..448e49ffebd 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -74,7 +74,9 @@ #![feature(concat_idents)] #![feature(const_fn)] #![feature(custom_attribute)] +#![feature(doc_cfg)] #![feature(doc_spotlight)] +#![feature(fn_must_use)] #![feature(fundamental)] #![feature(i128_type)] #![feature(inclusive_range_syntax)] diff --git a/src/stdsimd b/src/stdsimd index 678cbd325c8..ab9356f2af6 160000 --- a/src/stdsimd +++ b/src/stdsimd @@ -1 +1 @@ -Subproject commit 678cbd325c84070c9dbe4303969fbd2734c0b4ee +Subproject commit ab9356f2af650815d339d77306f0d09c44d531ad -- cgit 1.4.1-3-g733a5 From 994bfd414138e623f315f4273841b9f006ac72ee Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 26 Feb 2018 09:07:16 -0800 Subject: Update Cargo submodule Required moving all fulldeps tests depending on `rand` to different locations as now there's multiple `rand` crates that can't be implicitly linked against. --- src/Cargo.lock | 702 ++++++++++----------- src/bootstrap/builder.rs | 4 +- src/liballoc/Cargo.toml | 2 +- src/liballoc/tests/binary_heap.rs | 83 ++- src/liballoc/tests/slice.rs | 165 +++++ src/libcore/Cargo.toml | 3 + src/libcore/tests/lib.rs | 1 + src/libcore/tests/num/flt2dec/mod.rs | 1 + src/libcore/tests/num/flt2dec/random.rs | 160 +++++ src/libcore/tests/slice.rs | 71 ++- src/libstd/Cargo.toml | 2 +- src/libstd/tests/env.rs | 95 +++ .../run-pass-fulldeps/binary-heap-panic-safe.rs | 101 --- src/test/run-pass-fulldeps/env.rs | 99 --- src/test/run-pass-fulldeps/flt2dec.rs | 163 ----- src/test/run-pass-fulldeps/sort-unstable.rs | 83 --- .../run-pass-fulldeps/vector-sort-panic-safe.rs | 181 ------ src/tools/cargo | 2 +- src/tools/tidy/src/deps.rs | 2 + 19 files changed, 926 insertions(+), 994 deletions(-) create mode 100644 src/libcore/tests/num/flt2dec/random.rs create mode 100644 src/libstd/tests/env.rs delete mode 100644 src/test/run-pass-fulldeps/binary-heap-panic-safe.rs delete mode 100644 src/test/run-pass-fulldeps/env.rs delete mode 100644 src/test/run-pass-fulldeps/flt2dec.rs delete mode 100644 src/test/run-pass-fulldeps/sort-unstable.rs delete mode 100644 src/test/run-pass-fulldeps/vector-sort-panic-safe.rs (limited to 'src/libcore') diff --git a/src/Cargo.lock b/src/Cargo.lock index 646ddf1a744..3252fda970b 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -28,7 +28,7 @@ name = "alloc" version = "0.0.0" dependencies = [ "core 0.0.0", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "std_unicode 0.0.0", ] @@ -39,7 +39,7 @@ dependencies = [ "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "libc 0.0.0", ] @@ -81,7 +81,7 @@ name = "atty" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -93,8 +93,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -103,8 +103,8 @@ name = "backtrace-sys" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -131,16 +131,16 @@ name = "bootstrap" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -158,8 +158,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "build-manifest" version = "0.1.0" dependencies = [ - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -177,48 +177,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cargo" -version = "0.26.0" +version = "0.27.0" dependencies = [ "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "cargotest 0.1.0", - "core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crates-io 0.15.0", + "core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crates-io 0.16.0", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto-hash 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "git2-curl 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "home 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ignore 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ignore 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "jobserver 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -227,9 +227,9 @@ name = "cargo_metadata" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -239,25 +239,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cargotest" -version = "0.1.0" -dependencies = [ - "cargo 0.26.0", - "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -266,7 +250,7 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -279,7 +263,7 @@ name = "chrono" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -308,9 +292,9 @@ dependencies = [ "compiletest_rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -329,11 +313,11 @@ dependencies = [ "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -349,11 +333,11 @@ dependencies = [ "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -361,7 +345,7 @@ name = "cmake" version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -377,14 +361,14 @@ name = "commoncrypto-sys" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "compiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -393,16 +377,16 @@ name = "compiletest" version = "0.0.0" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -414,11 +398,11 @@ dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -429,41 +413,39 @@ version = "0.1.0" [[package]] name = "core" version = "0.0.0" +dependencies = [ + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "core-foundation" -version = "0.4.6" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "core-foundation-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "core-foundation-sys" -version = "0.4.6" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crates-io" -version = "0.15.0" +version = "0.16.0" dependencies = [ "curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "crossbeam" version = "0.3.2" @@ -502,14 +484,13 @@ dependencies = [ [[package]] name = "crypto-hash" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -519,11 +500,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "socket2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -532,10 +513,10 @@ name = "curl-sys" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -552,7 +533,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.12.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -574,9 +555,9 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -619,7 +600,7 @@ name = "enum_primitive" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -637,19 +618,19 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "env_logger" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -704,7 +685,7 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -721,7 +702,7 @@ name = "flate2" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -752,7 +733,7 @@ name = "fs2" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -782,26 +763,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "git2" -version = "0.6.11" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "git2-curl" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -811,29 +792,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "globset" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "graphviz" version = "0.0.0" -[[package]] -name = "hamcrest" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "handlebars" version = "0.29.1" @@ -843,16 +815,11 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "hex" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "hex" version = "0.3.1" @@ -895,18 +862,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ignore" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "globset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "globset 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -931,7 +899,7 @@ dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "xz2 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -967,8 +935,8 @@ name = "jobserver" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -983,9 +951,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1003,10 +971,10 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1025,6 +993,11 @@ name = "lazycell" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lazycell" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.0.0" @@ -1034,21 +1007,21 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.36" +version = "0.2.39" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libgit2-sys" -version = "0.6.19" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1058,9 +1031,9 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1069,8 +1042,8 @@ name = "libz-sys" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1108,9 +1081,9 @@ name = "lzma-sys" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1126,7 +1099,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "handlebars 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1135,12 +1108,12 @@ dependencies = [ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1150,7 +1123,7 @@ name = "memchr" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1158,7 +1131,7 @@ name = "memchr" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1171,8 +1144,8 @@ name = "miniz-sys" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1181,7 +1154,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1191,7 +1164,7 @@ name = "miow" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "socket2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1203,7 +1176,7 @@ dependencies = [ "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "compiletest_rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1212,14 +1185,12 @@ version = "0.1.0" [[package]] name = "net2" -version = "0.2.31" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1234,7 +1205,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1245,68 +1216,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num" -version = "0.1.41" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-complex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-bigint" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-complex" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-iter" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "num-rational" -version = "0.1.40" +name = "num-traits" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.1.41" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1314,7 +1259,7 @@ name = "num_cpus" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1324,14 +1269,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl" -version = "0.9.23" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1341,11 +1286,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl-sys" -version = "0.9.24" +version = "0.9.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1401,8 +1346,8 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1444,7 +1389,7 @@ dependencies = [ name = "profiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -1514,11 +1459,22 @@ dependencies = [ [[package]] name = "rand" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1537,9 +1493,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1577,12 +1533,12 @@ dependencies = [ [[package]] name = "regex" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1597,6 +1553,14 @@ name = "regex-syntax" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "regex-syntax" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "remote-test-client" version = "0.1.0" @@ -1605,14 +1569,23 @@ version = "0.1.0" name = "remote-test-server" version = "0.1.0" +[[package]] +name = "remove_dir_all" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rls" version = "0.126.0" dependencies = [ - "cargo 0.26.0", + "cargo 0.27.0", "cargo_metadata 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "clippy_lints 0.0.186 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.12 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1629,10 +1602,10 @@ dependencies = [ "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustfmt-nightly 0.3.8", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1660,8 +1633,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1675,8 +1648,8 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1789,7 +1762,7 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.5" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1839,7 +1812,7 @@ name = "rustc_back" version = "0.0.0" dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax 0.0.0", ] @@ -1893,7 +1866,7 @@ version = "0.0.0" dependencies = [ "ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "arena 0.0.0", - "env_logger 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", @@ -1927,7 +1900,7 @@ dependencies = [ "rustc_data_structures 0.0.0", "serialize 0.0.0", "syntax_pos 0.0.0", - "termcolor 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1937,7 +1910,7 @@ version = "0.0.0" dependencies = [ "graphviz 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "serialize 0.0.0", @@ -1962,8 +1935,8 @@ version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "build_helper 0.1.0", - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", ] @@ -2100,15 +2073,15 @@ name = "rustc_trans" version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "jobserver 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_apfloat 0.0.0", "rustc_back 0.0.0", @@ -2123,7 +2096,7 @@ dependencies = [ "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2174,7 +2147,7 @@ name = "rustdoc" version = "0.0.0" dependencies = [ "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2199,14 +2172,14 @@ dependencies = [ "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2223,7 +2196,7 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2232,7 +2205,7 @@ dependencies = [ [[package]] name = "scoped-tls" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2259,7 +2232,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2268,7 +2241,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2278,26 +2251,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.27" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.27" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive_internals 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive_internals" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2305,18 +2279,18 @@ name = "serde_ignored" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2329,7 +2303,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2350,11 +2324,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "socket2" -version = "0.3.0" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2377,7 +2351,7 @@ dependencies = [ "panic_abort 0.0.0", "panic_unwind 0.0.0", "profiler_builtins 0.0.0", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_asan 0.0.0", "rustc_lsan 0.0.0", "rustc_msan 0.0.0", @@ -2410,7 +2384,7 @@ dependencies = [ [[package]] name = "syn" -version = "0.12.13" +version = "0.12.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2474,7 +2448,7 @@ name = "syntex_errors" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2496,7 +2470,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2511,17 +2485,18 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tempdir" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2539,10 +2514,10 @@ dependencies = [ [[package]] name = "termcolor" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "wincolor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2550,7 +2525,7 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2577,7 +2552,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2601,9 +2576,9 @@ dependencies = [ name = "tidy" version = "0.1.0" dependencies = [ - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2611,7 +2586,7 @@ name = "time" version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2629,7 +2604,7 @@ name = "toml" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2640,10 +2615,15 @@ dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ucd-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-bidi" version = "0.3.4" @@ -2707,7 +2687,7 @@ dependencies = [ [[package]] name = "url" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2720,8 +2700,8 @@ name = "url_serde" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2760,10 +2740,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "walkdir" -version = "2.0.1" +version = "2.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2797,11 +2778,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wincolor" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2822,7 +2802,7 @@ name = "xattr" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2855,7 +2835,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b" "checksum cargo_metadata 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20d6fb2b5574726329c85cdba0df0347fddfec3cf9c8b588f9931708280f5643" -"checksum cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0" +"checksum cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fedf677519ac9e865c4ff43ef8f930773b37ed6e6ea61b6b83b400a7b5787f49" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" "checksum clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "110d43e343eb29f4f51c1db31beb879d546db27998577e5715270a54bcf41d3f" @@ -2864,14 +2844,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" "checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" "checksum compiletest_rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6c5aafb5d4a77c6b5fa384fe93c7a9a3561bd88c4b8b8e45187cf5e779b1badc" -"checksum core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8047f547cd6856d45b1cdd75ef8d2f21f3d0e4bf1dab0a0041b0ae9a5dda9c0e" -"checksum core-foundation-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "152195421a2e6497a8179195672e9d4ee8e45ed8c465b626f1606d27a08ebcd5" -"checksum crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be" +"checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980" +"checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-epoch 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "59796cc6cbbdc6bb319161349db0c3250ec73ec7fcb763a51065ec4e2e158552" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crypto-hash 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34903878eec1694faf53cae8473a088df333181de421d4d3d48061d6559fe602" +"checksum crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4" "checksum curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b70fd6394677d3c0e239ff4be6f2b3176e171ffd1c23ffdc541e78dea2b8bb5e" "checksum curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f46e49c7125131f5afaded06944d6888b55cbdf8eba05dae73c954019b907961" "checksum derive-new 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "92f8b8e1d6c8a5f5ea0849a0e4c55941576115c62d3fc425e96918bbbeb3d3c2" @@ -2885,7 +2864,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" -"checksum env_logger 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f3cc21490995c841d68e00276eba02071ebb269ec24011d5728bd00eabd39e31" +"checksum env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f0628f04f7c26ebccf40d7fc2c1cf92236c05ec88cf2132641cc956812312f0f" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "checksum error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6930e04918388a9a2e41d518c25cf679ccafe26733fb4127dbf21993f2575d46" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" @@ -2900,19 +2879,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "118b49cac82e04121117cbd3121ede3147e885627d82c4546b87c702debb90c1" "checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" -"checksum git2 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ee5b4bb7cd2a44e6e5ee3a26ba6a9ca10d4ce2771cdc3839bbc54b47b7d1be84" -"checksum git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "68676bc784bf0bef83278898929bf64a251e87c0340723d0b93fa096c9c5bf8e" +"checksum git2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4813cd7ad02e53275e6e51aaaf21c30f9ef500b579ad7a54a92f6091a7ac296" +"checksum git2-curl 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "27245f4c3a65ab19fd1ab5b52659bd60ed0ce8d0d129202c4737044d1d21db29" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum globset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "464627f948c3190ae3d04b1bc6d7dca2f785bda0ac01278e6db129ad383dbeb6" -"checksum hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf088f042a467089e9baa4972f57f9247e42a0cc549ba264c7a04fbb8ecb89d4" +"checksum globset 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e96ab92362c06811385ae9a34d2698e8a1160745e0c78fbb434a44c8de3fabc" "checksum handlebars 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04af2006ea09d985fef82b81e0eb25337e51b691c76403332378a53d521edc" -"checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" "checksum hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "459d3cf58137bb02ad4adeef5036377ff59f066dbb82517b7192e3a5462a2abc" "checksum home 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f25ae61099d8f3fee8b483df0bd4ecccf4b2731897aad40d50eca1b641fe6db" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "61bb90bdd39e3af69b0172dfc6130f6cd6332bf040fbb9bdd4401d37adbd48b8" -"checksum ignore 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bb2f0238094bd1b41800fb6eb9b16fdd5e9832ed6053ed91409f0cd5bf28dcfd" +"checksum ignore 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "245bea0ba52531a3739cb8ba99f8689eda13d7faf8c36b6a73ce4421aab42588" "checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053" "checksum itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3f2be4da1690a039e9ae5fd575f706a63ad5a2120f161b1d653c9da3930dd21" "checksum itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b07332223953b5051bceb67e8c4700aa65291535568e1f12408c43c4a42c0394" @@ -2925,8 +2902,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b" -"checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121" -"checksum libgit2-sys 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6eeae66e7b1c995de45cb4e65c5ab438a96a7b4077e448645d4048dc753ad357" +"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" +"checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff" +"checksum libgit2-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1ecbd6428006c321c29b6c8a895f0d90152f1cf4fd8faab69fc436a3d9594f63" "checksum libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0db4ec23611747ef772db1c4d650f8bd762f07b461727ec998f953c614024b75" "checksum libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "87f737ad6cc6fd6eefe3d9dc5412f1573865bded441300904d2f42269e140f16" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" @@ -2941,22 +2919,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9224c91f82b3c47cf53dcf78dfaa20d6888fbcc5d272d5f2fcdf8a697f3c987d" -"checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09" +"checksum net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0" "checksum nibble_vec 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "62e678237a4c70c5f2b917cefd7d080dfbf800421f06e8a59d4e28ef5130fd9e" "checksum nix 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "47e49f6982987135c5e9620ab317623e723bd06738fd85377e8d55f57c8b6487" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" -"checksum num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4083e14b542ea3eb9b5f33ff48bd373a92d78687e74f4cc0a30caeb754f0ca" -"checksum num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "bdc1494b5912f088f260b775799468d9b9209ac60885d8186a547a0476289e23" -"checksum num-complex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "58de7b4bf7cf5dbecb635a5797d489864eadd03b107930cbccf9e0fd7428b47c" -"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" -"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" -"checksum num-rational 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "0c7cb72a95250d8a370105c828f388932373e0e94414919891a0f945222310fe" -"checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070" +"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +"checksum num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f8d26da319fb45674985c78f1d1caf99aa4941f785d384a2ae36d0740bc3e2fe" +"checksum num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "4b226df12c5a59b63569dd57fafb926d91b385dfce33d8074a412411b689d593" +"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +"checksum num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3c2bd9b9d21e48e956b763c9f37134dc62d9e95da6edb3f672cacb6caf3cd3" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c281318d992e4432cfa799969467003d05921582a7489a8325e37f8a450d5113" -"checksum openssl 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)" = "169a4b9160baf9b9b1ab975418c673686638995ba921683a7f1e01470dcb8854" +"checksum openssl 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1636c9f1d78af9cbcc50e523bfff4a30274108aad5e86761afd4d31e4e184fa7" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" -"checksum openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "14ba54ac7d5a4eabd1d5f2c1fdeb7e7c14debfa669d94b983d01b465e767ba9e" +"checksum openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdc5c4a02e69ce65046f1763a0181107038e02176233acb0b3351d7cc588f9" "checksum os_pipe 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "998bfbb3042e715190fe2a41abfa047d7e8cb81374d2977d7f100eacd8619cb1" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3e7f7c9857874e54afeb950eebeae662b1e51a2493666d2ea4c0a5d91dcf0412" @@ -2973,15 +2949,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" "checksum racer 2.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "034f1c4528581c40a60e96875467c03315868084e08ff4ceb46a00f7be3b16b4" "checksum radix_trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "211c49b6a9995cac0fd1dd9ca60b42cf3a51e151a12eb954b3a9e75513426ee8" -"checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1" +"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" +"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" "checksum rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "485541959c8ecc49865526fe6c4de9653dd6e60d829d6edf0be228167b60372d" "checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" "checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" -"checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa" +"checksum regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a62bf8bb734ab90b7f234b681b01af396e5d39b028906c210dc04fa1d5e9e5b3" "checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" "checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e" +"checksum regex-syntax 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48d7391e7e90e06eaf3aefbe4652464153ecfec64806f3bf77ffc59638a63e77" +"checksum remove_dir_all 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5d2f806b0fcdabd98acd380dc8daef485e22bcb7cddc811d1337967f2528cf5" "checksum rls-analysis 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39461c31c9ec26c2f15821d6aaa349216bf71e24e69550d9f8eeded78dc435e1" "checksum rls-blacklist 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56fb7b8e4850b988fbcf277fbdb1eff36879070d02fc1ca243b559273866973d" "checksum rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bea04462e94b5512a78499837eecb7db182ff082144cd1b4bc32ef5d43de6510" @@ -2994,40 +2973,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e0745fa445ff41c4b6699936cf35ce3ca49502377dd7b3929c829594772c3a7b" "checksum rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82efedabe30f393161e11214a9130edfa01ad476372d1c6f3fec1f8d30488c9d" "checksum rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db9de2e927e280c75b8efab9c5f591ad31082d5d2c4c562c68fdba2ee77286b0" -"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" +"checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637" -"checksum schannel 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "acece75e0f987c48863a6c792ec8b7d6c4177d4a027f8ccc72f849794f437016" -"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" +"checksum schannel 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fbaffce35eb61c5b00846e73128b0cd62717e7c0ec46abbec132370d013975b4" +"checksum scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8674d439c964889e2476f474a3bf198cc9e199e77499960893bac5de7e9218a4" "checksum scopeguard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "59a076157c1e2dc561d8de585151ee6965d910dd4dcb5dabb7ae3e83981a6c57" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" "checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "db99f3919e20faa51bb2996057f5031d8685019b5a06139b1ce761da671b8526" -"checksum serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ba7591cfe93755e89eeecdbcc668885624829b020050e6aec99c2a03bd3fd0" -"checksum serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e03f1c9530c3fb0a0a5c9b826bdd9246a5921ae995d75f512ac917fc4dd55b5" +"checksum serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4763b773978e495252615e814d2ad04773b2c1f85421c7913869a537f35cb406" +"checksum serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "8ab31f00ae5574bb643c196d5e302961c122da1c768604c6d16a35c5d551948a" +"checksum serde_derive_internals 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fc848d073be32cd982380c06587ea1d433bc1a4c4a111de07ec2286a3ddade8" "checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142" -"checksum serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9db7266c7d63a4c4b7fe8719656ccdd51acf1bed6124b174f933b009fb10bcb" +"checksum serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "57781ed845b8e742fc2bf306aba8e3b408fe8c366b900e3769fbc39f49eb8b39" "checksum shared_child 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "099b38928dbe4a0a01fcd8c233183072f14a7d126a34bed05880869be66e14cc" "checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8" "checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" "checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9" -"checksum socket2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf5d5aa364bf61a0d744a293da20381617b6445b89eb524800fab857c5aed2d8" +"checksum socket2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78e4c1cde1adbc6bc4c394da2e7727c916b9b7d0b53d6984c890c65c1f4e6437" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -"checksum syn 0.12.13 (registry+https://github.com/rust-lang/crates.io-index)" = "517f6da31bc53bf080b9a77b29fbd0ff8da2f5a2ebd24c73c2238274a94ac7cb" +"checksum syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)" = "8c5bc2d6ff27891209efa5f63e9de78648d7801f085e4653701a692ce938d6fd" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" "checksum syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e52bffe6202cfb67587784cf23e0ec5bf26d331eef4922a16d5c42e12aa1e9b" "checksum syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "955ef4b16af4c468e4680d1497f873ff288f557d338180649e18f915af5e15ac" "checksum syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde" "checksum tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "1605d3388ceb50252952ffebab4b5dc43017ead7e4481b175961c283bb951195" -"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" +"checksum tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f73eebdb68c14bcb24aef74ea96079830e7fa7b31a6106e42ea7ee887c1e134e" "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" -"checksum termcolor 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9065bced9c3e43453aa3d56f1e98590b8455b341d2fa191a1090c0dd0b242c75" +"checksum termcolor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "56c456352e44f9f91f774ddeeed27c1ec60a2455ed66d692059acfb1d731bda1" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" @@ -3037,6 +3016,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" "checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" "checksum toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6854664bfc6df0360c695480836ee90e2d0c965f06db291d10be9344792d43e8" +"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946" @@ -3045,7 +3025,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa35e768d4daf1d85733418a49fb42e10d7f633e394fccab4ab7aba897053fe2" +"checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" "checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea" "checksum userenv-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d28ea36bbd9192d75bd9fa9b39f96ddb986eaee824adae5d53b6e51919b2f3" "checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" @@ -3053,13 +3033,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b" "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum walkdir 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b6d201f4f8998a837196b6de9c73e35af14c992cbb92c4ab641d2c2dce52de" +"checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a39ee4464208f6430992ff20154216ab2357772ac871d994c51628d60e58b8b0" +"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "5f04de8a1346489a2f9e9bd8526b73d135ec554227b17568456e86aa35b6f3fc" "checksum xz2 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "98df591c3504d014dd791d998123ed00a476c7e26dc6b2e873cb55c6ac9e59fa" diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 22656e5a9da..586216b9a58 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -775,7 +775,9 @@ impl<'a> Builder<'a> { // be resolved because MinGW has the import library. The downside is we // don't get newer functions from Windows, but we don't use any of them // anyway. - cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1"); + if mode != Mode::Tool { + cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1"); + } if self.is_very_verbose() { cargo.arg("-v"); diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index 0a265ee1376..3bf919b0c00 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -12,7 +12,7 @@ core = { path = "../libcore" } std_unicode = { path = "../libstd_unicode" } [dev-dependencies] -rand = "0.3" +rand = "0.4" [[test]] name = "collectionstests" diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs index 06d585f8ea8..5c979d82e55 100644 --- a/src/liballoc/tests/binary_heap.rs +++ b/src/liballoc/tests/binary_heap.rs @@ -8,9 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::panic; +use std::cmp; use std::collections::BinaryHeap; use std::collections::binary_heap::{Drain, PeekMut}; +use std::panic::{self, AssertUnwindSafe}; +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; + +use rand::{thread_rng, Rng}; #[test] fn test_iterator() { @@ -300,3 +304,80 @@ fn assert_covariance() { d } } + +// old binaryheap failed this test +// +// Integrity means that all elements are present after a comparison panics, +// even if the order may not be correct. +// +// Destructors must be called exactly once per element. +#[test] +fn panic_safe() { + static DROP_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; + + #[derive(Eq, PartialEq, Ord, Clone, Debug)] + struct PanicOrd(T, bool); + + impl Drop for PanicOrd { + fn drop(&mut self) { + // update global drop count + DROP_COUNTER.fetch_add(1, Ordering::SeqCst); + } + } + + impl PartialOrd for PanicOrd { + fn partial_cmp(&self, other: &Self) -> Option { + if self.1 || other.1 { + panic!("Panicking comparison"); + } + self.0.partial_cmp(&other.0) + } + } + let mut rng = thread_rng(); + const DATASZ: usize = 32; + const NTEST: usize = 10; + + // don't use 0 in the data -- we want to catch the zeroed-out case. + let data = (1..DATASZ + 1).collect::>(); + + // since it's a fuzzy test, run several tries. + for _ in 0..NTEST { + for i in 1..DATASZ + 1 { + DROP_COUNTER.store(0, Ordering::SeqCst); + + let mut panic_ords: Vec<_> = data.iter() + .filter(|&&x| x != i) + .map(|&x| PanicOrd(x, false)) + .collect(); + let panic_item = PanicOrd(i, true); + + // heapify the sane items + rng.shuffle(&mut panic_ords); + let mut heap = BinaryHeap::from(panic_ords); + let inner_data; + + { + // push the panicking item to the heap and catch the panic + let thread_result = { + let mut heap_ref = AssertUnwindSafe(&mut heap); + panic::catch_unwind(move || { + heap_ref.push(panic_item); + }) + }; + assert!(thread_result.is_err()); + + // Assert no elements were dropped + let drops = DROP_COUNTER.load(Ordering::SeqCst); + assert!(drops == 0, "Must not drop items. drops={}", drops); + inner_data = heap.clone().into_vec(); + drop(heap); + } + let drops = DROP_COUNTER.load(Ordering::SeqCst); + assert_eq!(drops, DATASZ); + + let mut data_sorted = inner_data.into_iter().map(|p| p.0).collect::>(); + data_sorted.sort(); + assert_eq!(data_sorted, data); + } + } +} diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index 1a9d26fd1a2..d9e9d91cea8 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -8,9 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::cell::Cell; use std::cmp::Ordering::{Equal, Greater, Less}; +use std::cmp::Ordering; use std::mem; +use std::panic; use std::rc::Rc; +use std::sync::atomic::Ordering::Relaxed; +use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize}; +use std::thread; use rand::{Rng, thread_rng}; @@ -1341,3 +1347,162 @@ fn test_copy_from_slice_dst_shorter() { let mut dst = [0; 3]; dst.copy_from_slice(&src); } + +const MAX_LEN: usize = 80; + +static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [ + // FIXME #5244: AtomicUsize is not Copy. + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), +]; + +static VERSIONS: AtomicUsize = ATOMIC_USIZE_INIT; + +#[derive(Clone, Eq)] +struct DropCounter { + x: u32, + id: usize, + version: Cell, +} + +impl PartialEq for DropCounter { + fn eq(&self, other: &Self) -> bool { + self.partial_cmp(other) == Some(Ordering::Equal) + } +} + +impl PartialOrd for DropCounter { + fn partial_cmp(&self, other: &Self) -> Option { + self.version.set(self.version.get() + 1); + other.version.set(other.version.get() + 1); + VERSIONS.fetch_add(2, Relaxed); + self.x.partial_cmp(&other.x) + } +} + +impl Ord for DropCounter { + fn cmp(&self, other: &Self) -> Ordering { + self.partial_cmp(other).unwrap() + } +} + +impl Drop for DropCounter { + fn drop(&mut self) { + DROP_COUNTS[self.id].fetch_add(1, Relaxed); + VERSIONS.fetch_sub(self.version.get(), Relaxed); + } +} + +macro_rules! test { + ($input:ident, $func:ident) => { + let len = $input.len(); + + // Work out the total number of comparisons required to sort + // this array... + let mut count = 0usize; + $input.to_owned().$func(|a, b| { count += 1; a.cmp(b) }); + + // ... and then panic on each and every single one. + for panic_countdown in 0..count { + // Refresh the counters. + VERSIONS.store(0, Relaxed); + for i in 0..len { + DROP_COUNTS[i].store(0, Relaxed); + } + + let v = $input.to_owned(); + let _ = thread::spawn(move || { + let mut v = v; + let mut panic_countdown = panic_countdown; + v.$func(|a, b| { + if panic_countdown == 0 { + SILENCE_PANIC.with(|s| s.set(true)); + panic!(); + } + panic_countdown -= 1; + a.cmp(b) + }) + }).join(); + + // Check that the number of things dropped is exactly + // what we expect (i.e. the contents of `v`). + for (i, c) in DROP_COUNTS.iter().enumerate().take(len) { + let count = c.load(Relaxed); + assert!(count == 1, + "found drop count == {} for i == {}, len == {}", + count, i, len); + } + + // Check that the most recent versions of values were dropped. + assert_eq!(VERSIONS.load(Relaxed), 0); + } + } +} + +thread_local!(static SILENCE_PANIC: Cell = Cell::new(false)); + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] // no threads +fn panic_safe() { + let prev = panic::take_hook(); + panic::set_hook(Box::new(move |info| { + if !SILENCE_PANIC.with(|s| s.get()) { + prev(info); + } + })); + + let mut rng = thread_rng(); + + for len in (1..20).chain(70..MAX_LEN) { + for &modulus in &[5, 20, 50] { + for &has_runs in &[false, true] { + let mut input = (0..len) + .map(|id| { + DropCounter { + x: rng.next_u32() % modulus, + id: id, + version: Cell::new(0), + } + }) + .collect::>(); + + if has_runs { + for c in &mut input { + c.x = c.id as u32; + } + + for _ in 0..5 { + let a = rng.gen::() % len; + let b = rng.gen::() % len; + if a < b { + input[a..b].reverse(); + } else { + input.swap(a, b); + } + } + } + + test!(input, sort_by); + test!(input, sort_unstable_by); + } + } + } +} diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index 5af63aa970f..24529f7a9d8 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -16,3 +16,6 @@ path = "../libcore/tests/lib.rs" [[bench]] name = "corebenches" path = "../libcore/benches/lib.rs" + +[dev-dependencies] +rand = "0.4" diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index a9c5683e0ef..d08d6b3215d 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -50,6 +50,7 @@ extern crate core; extern crate test; +extern crate rand; mod any; mod array; diff --git a/src/libcore/tests/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs index ef0178815f9..04567e25e25 100644 --- a/src/libcore/tests/num/flt2dec/mod.rs +++ b/src/libcore/tests/num/flt2dec/mod.rs @@ -23,6 +23,7 @@ mod strategy { mod dragon; mod grisu; } +mod random; pub fn decode_finite(v: T) -> Decoded { match decode(v).1 { diff --git a/src/libcore/tests/num/flt2dec/random.rs b/src/libcore/tests/num/flt2dec/random.rs new file mode 100644 index 00000000000..315ac4d7d99 --- /dev/null +++ b/src/libcore/tests/num/flt2dec/random.rs @@ -0,0 +1,160 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg(not(target_arch = "wasm32"))] + +use std::i16; +use std::mem; +use std::str; + +use core::num::flt2dec::MAX_SIG_DIGITS; +use core::num::flt2dec::strategy::grisu::format_exact_opt; +use core::num::flt2dec::strategy::grisu::format_shortest_opt; +use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded}; + +use rand::{self, Rand, XorShiftRng}; +use rand::distributions::{IndependentSample, Range}; + +pub fn decode_finite(v: T) -> Decoded { + match decode(v).1 { + FullDecoded::Finite(decoded) => decoded, + full_decoded => panic!("expected finite, got {:?} instead", full_decoded) + } +} + + +fn iterate(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize) + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + V: FnMut(usize) -> Decoded { + assert!(k <= 1024); + + let mut npassed = 0; // f(x) = Some(g(x)) + let mut nignored = 0; // f(x) = None + + for i in 0..n { + if (i & 0xfffff) == 0 { + println!("in progress, {:x}/{:x} (ignored={} passed={} failed={})", + i, n, nignored, npassed, i - nignored - npassed); + } + + let decoded = v(i); + let mut buf1 = [0; 1024]; + if let Some((len1, e1)) = f(&decoded, &mut buf1[..k]) { + let mut buf2 = [0; 1024]; + let (len2, e2) = g(&decoded, &mut buf2[..k]); + if e1 == e2 && &buf1[..len1] == &buf2[..len2] { + npassed += 1; + } else { + println!("equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}", + i, n, decoded, str::from_utf8(&buf1[..len1]).unwrap(), e1, + str::from_utf8(&buf2[..len2]).unwrap(), e2); + } + } else { + nignored += 1; + } + } + println!("{}({}): done, ignored={} passed={} failed={}", + func, k, nignored, npassed, n - nignored - npassed); + assert!(nignored + npassed == n, + "{}({}): {} out of {} values returns an incorrect value!", + func, k, n - nignored - npassed, n); + (npassed, nignored) +} + +pub fn f32_random_equivalence_test(f: F, g: G, k: usize, n: usize) + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); + let f32_range = Range::new(0x0000_0001u32, 0x7f80_0000); + iterate("f32_random_equivalence_test", k, n, f, g, |_| { + let i: u32 = f32_range.ind_sample(&mut rng); + let x: f32 = unsafe {mem::transmute(i)}; + decode_finite(x) + }); +} + +pub fn f64_random_equivalence_test(f: F, g: G, k: usize, n: usize) + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); + let f64_range = Range::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000); + iterate("f64_random_equivalence_test", k, n, f, g, |_| { + let i: u64 = f64_range.ind_sample(&mut rng); + let x: f64 = unsafe {mem::transmute(i)}; + decode_finite(x) + }); +} + +pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values, + // so why not simply testing all of them? + // + // this is of course very stressful (and thus should be behind an `#[ignore]` attribute), + // but with `-C opt-level=3 -C lto` this only takes about an hour or so. + + // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e. all finite ranges + let (npassed, nignored) = iterate("f32_exhaustive_equivalence_test", + k, 0x7f7f_ffff, f, g, |i: usize| { + let x: f32 = unsafe {mem::transmute(i as u32 + 1)}; + decode_finite(x) + }); + assert_eq!((npassed, nignored), (2121451881, 17643158)); +} + +#[test] +fn shortest_random_equivalence_test() { + use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); + f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); +} + +#[test] #[ignore] // it is too expensive +fn shortest_f32_exhaustive_equivalence_test() { + // it is hard to directly test the optimality of the output, but we can at least test if + // two different algorithms agree to each other. + // + // this reports the progress and the number of f32 values returned `None`. + // with `--nocapture` (and plenty of time and appropriate rustc flags), this should print: + // `done, ignored=17643158 passed=2121451881 failed=0`. + + use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS); +} + +#[test] #[ignore] // it is too expensive +fn shortest_f64_hard_random_equivalence_test() { + // this again probably has to use appropriate rustc flags. + + use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + f64_random_equivalence_test(format_shortest_opt, fallback, + MAX_SIG_DIGITS, 100_000_000); +} + +#[test] +fn exact_f32_random_equivalence_test() { + use core::num::flt2dec::strategy::dragon::format_exact as fallback; + for k in 1..21 { + f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), + |d, buf| fallback(d, buf, i16::MIN), k, 1_000); + } +} + +#[test] +fn exact_f64_random_equivalence_test() { + use core::num::flt2dec::strategy::dragon::format_exact as fallback; + for k in 1..21 { + f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), + |d, buf| fallback(d, buf, i16::MIN), k, 1_000); + } +} + diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 13740b95802..53fdfa06827 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -10,7 +10,6 @@ use core::result::Result::{Ok, Err}; - #[test] fn test_position() { let b = [1, 2, 3, 5, 5]; @@ -481,3 +480,73 @@ fn test_rotate_right() { assert_eq!(a[(i + 42) % N], i); } } + +#[test] +#[cfg(not(target_arch = "wasm32"))] +fn sort_unstable() { + use core::cmp::Ordering::{Equal, Greater, Less}; + use core::slice::heapsort; + use rand::{Rng, XorShiftRng}; + + let mut v = [0; 600]; + let mut tmp = [0; 600]; + let mut rng = XorShiftRng::new_unseeded(); + + for len in (2..25).chain(500..510) { + let v = &mut v[0..len]; + let tmp = &mut tmp[0..len]; + + for &modulus in &[5, 10, 100, 1000] { + for _ in 0..100 { + for i in 0..len { + v[i] = rng.gen::() % modulus; + } + + // Sort in default order. + tmp.copy_from_slice(v); + tmp.sort_unstable(); + assert!(tmp.windows(2).all(|w| w[0] <= w[1])); + + // Sort in ascending order. + tmp.copy_from_slice(v); + tmp.sort_unstable_by(|a, b| a.cmp(b)); + assert!(tmp.windows(2).all(|w| w[0] <= w[1])); + + // Sort in descending order. + tmp.copy_from_slice(v); + tmp.sort_unstable_by(|a, b| b.cmp(a)); + assert!(tmp.windows(2).all(|w| w[0] >= w[1])); + + // Test heapsort using `<` operator. + tmp.copy_from_slice(v); + heapsort(tmp, |a, b| a < b); + assert!(tmp.windows(2).all(|w| w[0] <= w[1])); + + // Test heapsort using `>` operator. + tmp.copy_from_slice(v); + heapsort(tmp, |a, b| a > b); + assert!(tmp.windows(2).all(|w| w[0] >= w[1])); + } + } + } + + // Sort using a completely random comparison function. + // This will reorder the elements *somehow*, but won't panic. + for i in 0..v.len() { + v[i] = i as i32; + } + v.sort_unstable_by(|_, _| *rng.choose(&[Less, Equal, Greater]).unwrap()); + v.sort_unstable(); + for i in 0..v.len() { + assert_eq!(v[i], i as i32); + } + + // Should not panic. + [0i32; 0].sort_unstable(); + [(); 10].sort_unstable(); + [(); 100].sort_unstable(); + + let mut v = [0xDEADBEEFu64]; + v.sort_unstable(); + assert!(v == [0xDEADBEEF]); +} diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index c1fe4a89d6a..12017598853 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -26,7 +26,7 @@ std_unicode = { path = "../libstd_unicode" } unwind = { path = "../libunwind" } [dev-dependencies] -rand = "0.3" +rand = "0.4" [target.x86_64-apple-darwin.dependencies] rustc_asan = { path = "../librustc_asan" } diff --git a/src/libstd/tests/env.rs b/src/libstd/tests/env.rs new file mode 100644 index 00000000000..d4376523691 --- /dev/null +++ b/src/libstd/tests/env.rs @@ -0,0 +1,95 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate rand; + +use std::env::*; +use std::iter::repeat; +use std::ffi::{OsString, OsStr}; + +use rand::Rng; + +fn make_rand_name() -> OsString { + let mut rng = rand::thread_rng(); + let n = format!("TEST{}", rng.gen_ascii_chars().take(10) + .collect::()); + let n = OsString::from(n); + assert!(var_os(&n).is_none()); + n +} + +fn eq(a: Option, b: Option<&str>) { + assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s)); +} + +#[test] +fn test_set_var() { + let n = make_rand_name(); + set_var(&n, "VALUE"); + eq(var_os(&n), Some("VALUE")); +} + +#[test] +fn test_remove_var() { + let n = make_rand_name(); + set_var(&n, "VALUE"); + remove_var(&n); + eq(var_os(&n), None); +} + +#[test] +fn test_set_var_overwrite() { + let n = make_rand_name(); + set_var(&n, "1"); + set_var(&n, "2"); + eq(var_os(&n), Some("2")); + set_var(&n, ""); + eq(var_os(&n), Some("")); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn test_var_big() { + let mut s = "".to_string(); + let mut i = 0; + while i < 100 { + s.push_str("aaaaaaaaaa"); + i += 1; + } + let n = make_rand_name(); + set_var(&n, &s); + eq(var_os(&n), Some(&s)); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn test_env_set_get_huge() { + let n = make_rand_name(); + let s = repeat("x").take(10000).collect::(); + set_var(&n, &s); + eq(var_os(&n), Some(&s)); + remove_var(&n); + eq(var_os(&n), None); +} + +#[test] +fn test_env_set_var() { + let n = make_rand_name(); + + let mut e = vars_os(); + set_var(&n, "VALUE"); + assert!(!e.any(|(k, v)| { + &*k == &*n && &*v == "VALUE" + })); + + assert!(vars_os().any(|(k, v)| { + &*k == &*n && &*v == "VALUE" + })); +} diff --git a/src/test/run-pass-fulldeps/binary-heap-panic-safe.rs b/src/test/run-pass-fulldeps/binary-heap-panic-safe.rs deleted file mode 100644 index 6139a7d3201..00000000000 --- a/src/test/run-pass-fulldeps/binary-heap-panic-safe.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(rustc_private, std_panic)] - -extern crate rand; - -use rand::{thread_rng, Rng}; -use std::panic::{self, AssertUnwindSafe}; - -use std::collections::BinaryHeap; -use std::cmp; -use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; - -static DROP_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; - -// old binaryheap failed this test -// -// Integrity means that all elements are present after a comparison panics, -// even if the order may not be correct. -// -// Destructors must be called exactly once per element. -fn test_integrity() { - #[derive(Eq, PartialEq, Ord, Clone, Debug)] - struct PanicOrd(T, bool); - - impl Drop for PanicOrd { - fn drop(&mut self) { - // update global drop count - DROP_COUNTER.fetch_add(1, Ordering::SeqCst); - } - } - - impl PartialOrd for PanicOrd { - fn partial_cmp(&self, other: &Self) -> Option { - if self.1 || other.1 { - panic!("Panicking comparison"); - } - self.0.partial_cmp(&other.0) - } - } - let mut rng = thread_rng(); - const DATASZ: usize = 32; - const NTEST: usize = 10; - - // don't use 0 in the data -- we want to catch the zeroed-out case. - let data = (1..DATASZ + 1).collect::>(); - - // since it's a fuzzy test, run several tries. - for _ in 0..NTEST { - for i in 1..DATASZ + 1 { - DROP_COUNTER.store(0, Ordering::SeqCst); - - let mut panic_ords: Vec<_> = data.iter() - .filter(|&&x| x != i) - .map(|&x| PanicOrd(x, false)) - .collect(); - let panic_item = PanicOrd(i, true); - - // heapify the sane items - rng.shuffle(&mut panic_ords); - let mut heap = BinaryHeap::from(panic_ords); - let inner_data; - - { - // push the panicking item to the heap and catch the panic - let thread_result = { - let mut heap_ref = AssertUnwindSafe(&mut heap); - panic::catch_unwind(move || { - heap_ref.push(panic_item); - }) - }; - assert!(thread_result.is_err()); - - // Assert no elements were dropped - let drops = DROP_COUNTER.load(Ordering::SeqCst); - assert!(drops == 0, "Must not drop items. drops={}", drops); - inner_data = heap.clone().into_vec(); - drop(heap); - } - let drops = DROP_COUNTER.load(Ordering::SeqCst); - assert_eq!(drops, DATASZ); - - let mut data_sorted = inner_data.into_iter().map(|p| p.0).collect::>(); - data_sorted.sort(); - assert_eq!(data_sorted, data); - } - } -} - -fn main() { - test_integrity(); -} - diff --git a/src/test/run-pass-fulldeps/env.rs b/src/test/run-pass-fulldeps/env.rs deleted file mode 100644 index cf2ea732ee1..00000000000 --- a/src/test/run-pass-fulldeps/env.rs +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: --test - -#![feature(rustc_private, std_panic)] - -extern crate rand; - -use std::env::*; -use std::iter::repeat; -use std::ffi::{OsString, OsStr}; - -use rand::Rng; - -fn make_rand_name() -> OsString { - let mut rng = rand::thread_rng(); - let n = format!("TEST{}", rng.gen_ascii_chars().take(10) - .collect::()); - let n = OsString::from(n); - assert!(var_os(&n).is_none()); - n -} - -fn eq(a: Option, b: Option<&str>) { - assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s)); -} - -#[test] -fn test_set_var() { - let n = make_rand_name(); - set_var(&n, "VALUE"); - eq(var_os(&n), Some("VALUE")); -} - -#[test] -fn test_remove_var() { - let n = make_rand_name(); - set_var(&n, "VALUE"); - remove_var(&n); - eq(var_os(&n), None); -} - -#[test] -fn test_set_var_overwrite() { - let n = make_rand_name(); - set_var(&n, "1"); - set_var(&n, "2"); - eq(var_os(&n), Some("2")); - set_var(&n, ""); - eq(var_os(&n), Some("")); -} - -#[test] -#[cfg_attr(target_os = "emscripten", ignore)] -fn test_var_big() { - let mut s = "".to_string(); - let mut i = 0; - while i < 100 { - s.push_str("aaaaaaaaaa"); - i += 1; - } - let n = make_rand_name(); - set_var(&n, &s); - eq(var_os(&n), Some(&s)); -} - -#[test] -#[cfg_attr(target_os = "emscripten", ignore)] -fn test_env_set_get_huge() { - let n = make_rand_name(); - let s = repeat("x").take(10000).collect::(); - set_var(&n, &s); - eq(var_os(&n), Some(&s)); - remove_var(&n); - eq(var_os(&n), None); -} - -#[test] -fn test_env_set_var() { - let n = make_rand_name(); - - let mut e = vars_os(); - set_var(&n, "VALUE"); - assert!(!e.any(|(k, v)| { - &*k == &*n && &*v == "VALUE" - })); - - assert!(vars_os().any(|(k, v)| { - &*k == &*n && &*v == "VALUE" - })); -} diff --git a/src/test/run-pass-fulldeps/flt2dec.rs b/src/test/run-pass-fulldeps/flt2dec.rs deleted file mode 100644 index 3db0644d1ef..00000000000 --- a/src/test/run-pass-fulldeps/flt2dec.rs +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags:--test - -#![feature(rustc_private, flt2dec)] - -extern crate core; -extern crate rand; - -use std::i16; -use std::mem; -use std::str; - -use core::num::flt2dec::MAX_SIG_DIGITS; -use core::num::flt2dec::strategy::grisu::format_exact_opt; -use core::num::flt2dec::strategy::grisu::format_shortest_opt; -use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded}; - -use rand::{Rand, XorShiftRng}; -use rand::distributions::{IndependentSample, Range}; -pub fn decode_finite(v: T) -> Decoded { - match decode(v).1 { - FullDecoded::Finite(decoded) => decoded, - full_decoded => panic!("expected finite, got {:?} instead", full_decoded) - } -} - - -fn iterate(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize) - where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), - V: FnMut(usize) -> Decoded { - assert!(k <= 1024); - - let mut npassed = 0; // f(x) = Some(g(x)) - let mut nignored = 0; // f(x) = None - - for i in 0..n { - if (i & 0xfffff) == 0 { - println!("in progress, {:x}/{:x} (ignored={} passed={} failed={})", - i, n, nignored, npassed, i - nignored - npassed); - } - - let decoded = v(i); - let mut buf1 = [0; 1024]; - if let Some((len1, e1)) = f(&decoded, &mut buf1[..k]) { - let mut buf2 = [0; 1024]; - let (len2, e2) = g(&decoded, &mut buf2[..k]); - if e1 == e2 && &buf1[..len1] == &buf2[..len2] { - npassed += 1; - } else { - println!("equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}", - i, n, decoded, str::from_utf8(&buf1[..len1]).unwrap(), e1, - str::from_utf8(&buf2[..len2]).unwrap(), e2); - } - } else { - nignored += 1; - } - } - println!("{}({}): done, ignored={} passed={} failed={}", - func, k, nignored, npassed, n - nignored - npassed); - assert!(nignored + npassed == n, - "{}({}): {} out of {} values returns an incorrect value!", - func, k, n - nignored - npassed, n); - (npassed, nignored) -} - -pub fn f32_random_equivalence_test(f: F, g: G, k: usize, n: usize) - where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { - let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); - let f32_range = Range::new(0x0000_0001u32, 0x7f80_0000); - iterate("f32_random_equivalence_test", k, n, f, g, |_| { - let i: u32 = f32_range.ind_sample(&mut rng); - let x: f32 = unsafe {mem::transmute(i)}; - decode_finite(x) - }); -} - -pub fn f64_random_equivalence_test(f: F, g: G, k: usize, n: usize) - where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { - let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); - let f64_range = Range::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000); - iterate("f64_random_equivalence_test", k, n, f, g, |_| { - let i: u64 = f64_range.ind_sample(&mut rng); - let x: f64 = unsafe {mem::transmute(i)}; - decode_finite(x) - }); -} - -pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) - where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { - // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values, - // so why not simply testing all of them? - // - // this is of course very stressful (and thus should be behind an `#[ignore]` attribute), - // but with `-C opt-level=3 -C lto` this only takes about an hour or so. - - // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e. all finite ranges - let (npassed, nignored) = iterate("f32_exhaustive_equivalence_test", - k, 0x7f7f_ffff, f, g, |i: usize| { - let x: f32 = unsafe {mem::transmute(i as u32 + 1)}; - decode_finite(x) - }); - assert_eq!((npassed, nignored), (2121451881, 17643158)); -} - -#[test] -fn shortest_random_equivalence_test() { - use core::num::flt2dec::strategy::dragon::format_shortest as fallback; - f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); - f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); -} - -#[test] #[ignore] // it is too expensive -fn shortest_f32_exhaustive_equivalence_test() { - // it is hard to directly test the optimality of the output, but we can at least test if - // two different algorithms agree to each other. - // - // this reports the progress and the number of f32 values returned `None`. - // with `--nocapture` (and plenty of time and appropriate rustc flags), this should print: - // `done, ignored=17643158 passed=2121451881 failed=0`. - - use core::num::flt2dec::strategy::dragon::format_shortest as fallback; - f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS); -} - -#[test] #[ignore] // it is too expensive -fn shortest_f64_hard_random_equivalence_test() { - // this again probably has to use appropriate rustc flags. - - use core::num::flt2dec::strategy::dragon::format_shortest as fallback; - f64_random_equivalence_test(format_shortest_opt, fallback, - MAX_SIG_DIGITS, 100_000_000); -} - -#[test] -fn exact_f32_random_equivalence_test() { - use core::num::flt2dec::strategy::dragon::format_exact as fallback; - for k in 1..21 { - f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), - |d, buf| fallback(d, buf, i16::MIN), k, 1_000); - } -} - -#[test] -fn exact_f64_random_equivalence_test() { - use core::num::flt2dec::strategy::dragon::format_exact as fallback; - for k in 1..21 { - f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), - |d, buf| fallback(d, buf, i16::MIN), k, 1_000); - } -} diff --git a/src/test/run-pass-fulldeps/sort-unstable.rs b/src/test/run-pass-fulldeps/sort-unstable.rs deleted file mode 100644 index af8a691aa3e..00000000000 --- a/src/test/run-pass-fulldeps/sort-unstable.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(rustc_private, sort_internals)] - -extern crate core; -extern crate rand; - -use std::cmp::Ordering::{Equal, Greater, Less}; -use core::slice::heapsort; - -use rand::{Rng, XorShiftRng}; - -fn main() { - let mut v = [0; 600]; - let mut tmp = [0; 600]; - let mut rng = XorShiftRng::new_unseeded(); - - for len in (2..25).chain(500..510) { - let v = &mut v[0..len]; - let tmp = &mut tmp[0..len]; - - for &modulus in &[5, 10, 100, 1000] { - for _ in 0..100 { - for i in 0..len { - v[i] = rng.gen::() % modulus; - } - - // Sort in default order. - tmp.copy_from_slice(v); - tmp.sort_unstable(); - assert!(tmp.windows(2).all(|w| w[0] <= w[1])); - - // Sort in ascending order. - tmp.copy_from_slice(v); - tmp.sort_unstable_by(|a, b| a.cmp(b)); - assert!(tmp.windows(2).all(|w| w[0] <= w[1])); - - // Sort in descending order. - tmp.copy_from_slice(v); - tmp.sort_unstable_by(|a, b| b.cmp(a)); - assert!(tmp.windows(2).all(|w| w[0] >= w[1])); - - // Test heapsort using `<` operator. - tmp.copy_from_slice(v); - heapsort(tmp, |a, b| a < b); - assert!(tmp.windows(2).all(|w| w[0] <= w[1])); - - // Test heapsort using `>` operator. - tmp.copy_from_slice(v); - heapsort(tmp, |a, b| a > b); - assert!(tmp.windows(2).all(|w| w[0] >= w[1])); - } - } - } - - // Sort using a completely random comparison function. - // This will reorder the elements *somehow*, but won't panic. - for i in 0..v.len() { - v[i] = i as i32; - } - v.sort_unstable_by(|_, _| *rng.choose(&[Less, Equal, Greater]).unwrap()); - v.sort_unstable(); - for i in 0..v.len() { - assert_eq!(v[i], i as i32); - } - - // Should not panic. - [0i32; 0].sort_unstable(); - [(); 10].sort_unstable(); - [(); 100].sort_unstable(); - - let mut v = [0xDEADBEEFu64]; - v.sort_unstable(); - assert!(v == [0xDEADBEEF]); -} diff --git a/src/test/run-pass-fulldeps/vector-sort-panic-safe.rs b/src/test/run-pass-fulldeps/vector-sort-panic-safe.rs deleted file mode 100644 index adc72aa0ea2..00000000000 --- a/src/test/run-pass-fulldeps/vector-sort-panic-safe.rs +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-emscripten no threads support - -#![feature(rustc_private)] -#![feature(sort_unstable)] - -extern crate rand; - -use rand::{thread_rng, Rng}; -use std::cell::Cell; -use std::cmp::Ordering; -use std::panic; -use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize}; -use std::sync::atomic::Ordering::Relaxed; -use std::thread; - -const MAX_LEN: usize = 80; - -static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [ - // FIXME #5244: AtomicUsize is not Copy. - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), -]; - -static VERSIONS: AtomicUsize = ATOMIC_USIZE_INIT; - -#[derive(Clone, Eq)] -struct DropCounter { - x: u32, - id: usize, - version: Cell, -} - -impl PartialEq for DropCounter { - fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other) == Some(Ordering::Equal) - } -} - -impl PartialOrd for DropCounter { - fn partial_cmp(&self, other: &Self) -> Option { - self.version.set(self.version.get() + 1); - other.version.set(other.version.get() + 1); - VERSIONS.fetch_add(2, Relaxed); - self.x.partial_cmp(&other.x) - } -} - -impl Ord for DropCounter { - fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other).unwrap() - } -} - -impl Drop for DropCounter { - fn drop(&mut self) { - DROP_COUNTS[self.id].fetch_add(1, Relaxed); - VERSIONS.fetch_sub(self.version.get(), Relaxed); - } -} - -macro_rules! test { - ($input:ident, $func:ident) => { - let len = $input.len(); - - // Work out the total number of comparisons required to sort - // this array... - let mut count = 0usize; - $input.to_owned().$func(|a, b| { count += 1; a.cmp(b) }); - - // ... and then panic on each and every single one. - for panic_countdown in 0..count { - // Refresh the counters. - VERSIONS.store(0, Relaxed); - for i in 0..len { - DROP_COUNTS[i].store(0, Relaxed); - } - - let v = $input.to_owned(); - let _ = thread::spawn(move || { - let mut v = v; - let mut panic_countdown = panic_countdown; - v.$func(|a, b| { - if panic_countdown == 0 { - SILENCE_PANIC.with(|s| s.set(true)); - panic!(); - } - panic_countdown -= 1; - a.cmp(b) - }) - }).join(); - - // Check that the number of things dropped is exactly - // what we expect (i.e. the contents of `v`). - for (i, c) in DROP_COUNTS.iter().enumerate().take(len) { - let count = c.load(Relaxed); - assert!(count == 1, - "found drop count == {} for i == {}, len == {}", - count, i, len); - } - - // Check that the most recent versions of values were dropped. - assert_eq!(VERSIONS.load(Relaxed), 0); - } - } -} - -thread_local!(static SILENCE_PANIC: Cell = Cell::new(false)); - -fn main() { - let prev = panic::take_hook(); - panic::set_hook(Box::new(move |info| { - if !SILENCE_PANIC.with(|s| s.get()) { - prev(info); - } - })); - - let mut rng = thread_rng(); - - for len in (1..20).chain(70..MAX_LEN) { - for &modulus in &[5, 20, 50] { - for &has_runs in &[false, true] { - let mut input = (0..len) - .map(|id| { - DropCounter { - x: rng.next_u32() % modulus, - id: id, - version: Cell::new(0), - } - }) - .collect::>(); - - if has_runs { - for c in &mut input { - c.x = c.id as u32; - } - - for _ in 0..5 { - let a = rng.gen::() % len; - let b = rng.gen::() % len; - if a < b { - input[a..b].reverse(); - } else { - input.swap(a, b); - } - } - } - - test!(input, sort_by); - test!(input, sort_unstable_by); - } - } - } -} diff --git a/src/tools/cargo b/src/tools/cargo index 1d6dfea44f9..5f83bb4044f 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 1d6dfea44f97199d5d5c177c7dadcde393eaff9a +Subproject commit 5f83bb4044f32b60d06717c609610f67411fc671 diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 72414c2a53e..22c6af28cea 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -91,6 +91,7 @@ static WHITELIST: &'static [Crate] = &[ Crate("redox_termios"), Crate("regex"), Crate("regex-syntax"), + Crate("remove_dir_all"), Crate("rustc-demangle"), Crate("smallvec"), Crate("stable_deref_trait"), @@ -99,6 +100,7 @@ static WHITELIST: &'static [Crate] = &[ Crate("terminon"), Crate("termion"), Crate("thread_local"), + Crate("ucd-util"), Crate("unicode-width"), Crate("unreachable"), Crate("utf8-ranges"), -- cgit 1.4.1-3-g733a5 From 8654738260e8490f678fcfb07e6abaed337a0926 Mon Sep 17 00:00:00 2001 From: 1011X <1011XXXXX@gmail.com> Date: Mon, 12 Mar 2018 01:04:51 -0400 Subject: include AsciiExt in tests --- src/libcore/tests/ascii.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/ascii.rs b/src/libcore/tests/ascii.rs index dbed5920519..4d43067ad2c 100644 --- a/src/libcore/tests/ascii.rs +++ b/src/libcore/tests/ascii.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use char::from_u32; +use core::char::from_u32; +use std::ascii::AsciiExt; #[test] fn test_is_ascii() { -- cgit 1.4.1-3-g733a5 From 1a16271d1cc64e89f6c0acc7803b9d6fa25bf131 Mon Sep 17 00:00:00 2001 From: 1011X <1011XXXXX@gmail.com> Date: Mon, 12 Mar 2018 03:29:06 -0400 Subject: added ascii_ctypes feature to libcore tests module --- src/libcore/tests/lib.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libcore') diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 971991dce3d..e9d9e4d5c5d 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -10,6 +10,7 @@ #![deny(warnings)] +#![feature(ascii_ctype)] #![feature(box_syntax)] #![feature(core_float)] #![feature(core_private_bignum)] -- cgit 1.4.1-3-g733a5 From bda5a45793b7bf98290b815f80db6ae2e1f867ae Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 Mar 2018 16:01:28 +0100 Subject: Add missing links --- src/libcore/fmt/mod.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 8ad5a9861a0..213b317f632 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -684,18 +684,16 @@ pub trait Octal { /// /// The `Binary` trait should format its output as a number in binary. /// -/// For primitive signed integers (`i8` to `i128`, and `isize`), +/// For primitive signed integers ([`i8`] to [`i128`], and [`isize`]), /// negative values are formatted as the two’s complement representation. /// /// The alternate flag, `#`, adds a `0b` in front of the output. /// /// For more information on formatters, see [the module-level documentation][module]. /// -/// [module]: ../../std/fmt/index.html -/// /// # Examples /// -/// Basic usage with `i32`: +/// Basic usage with [`i32`]: /// /// ``` /// let x = 42; // 42 is '101010' in binary @@ -725,6 +723,12 @@ pub trait Octal { /// /// println!("l as binary is: {:b}", l); /// ``` +/// +/// [module]: ../../std/fmt/index.html +/// [`i8`]: ../../std/primitive.i8.html +/// [`i128`]: ../../std/primitive.i128.html +/// [`isize`]: ../../std/primitive.isize.html +/// [`i32`]: ../../std/primitive.i32.html #[stable(feature = "rust1", since = "1.0.0")] pub trait Binary { /// Formats the value using the given formatter. -- cgit 1.4.1-3-g733a5 From da257b8fecacdb577592032dcaa9e4b5900cab2c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 Mar 2018 22:42:23 +0100 Subject: Add missing examples --- src/libcore/fmt/mod.rs | 136 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 8ad5a9861a0..02a1b9e6a96 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1375,27 +1375,159 @@ impl<'a> Formatter<'a> { } } - /// Optionally specified integer width that the output should be + /// Optionally specified integer width that the output should be. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(i32); + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// if let Some(width) = formatter.width() { + /// // If we received a width, we use it + /// write!(formatter, "{:width$}", &format!("Foo({})", self.0), width = width) + /// } else { + /// // Otherwise we do nothing special + /// write!(formatter, "Foo({})", self.0) + /// } + /// } + /// } + /// + /// assert_eq!(&format!("{:10}", Foo(23)), "Foo(23) "); + /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)"); + /// ``` #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn width(&self) -> Option { self.width } - /// Optionally specified precision for numeric types + /// Optionally specified precision for numeric types. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(f32); + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// if let Some(precision) = formatter.precision() { + /// // If we received a precision, we use it. + /// write!(formatter, "Foo({1:.*})", precision, self.0) + /// } else { + /// // Otherwise we default to 2. + /// write!(formatter, "Foo({:.2})", self.0) + /// } + /// } + /// } + /// + /// assert_eq!(&format!("{:.4}", Foo(23.2)), "Foo(23.2000)"); + /// assert_eq!(&format!("{}", Foo(23.2)), "Foo(23.20)"); + /// ``` #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn precision(&self) -> Option { self.precision } /// Determines if the `+` flag was specified. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(i32); + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// if formatter.sign_plus() { + /// write!(formatter, + /// "Foo({}{})", + /// if self.0 < 0 { '-' } else { '+' }, + /// self.0) + /// } else { + /// write!(formatter, "Foo({})", self.0) + /// } + /// } + /// } + /// + /// assert_eq!(&format!("{:+}", Foo(23)), "Foo(+23)"); + /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)"); + /// ``` #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_plus(&self) -> bool { self.flags & (1 << FlagV1::SignPlus as u32) != 0 } /// Determines if the `-` flag was specified. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(i32); + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// if formatter.sign_minus() { + /// // You want a minus sign? Have one! + /// write!(formatter, "-Foo({})", self.0) + /// } else { + /// write!(formatter, "Foo({})", self.0) + /// } + /// } + /// } + /// + /// assert_eq!(&format!("{:-}", Foo(23)), "-Foo(23)"); + /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)"); + /// ``` #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_minus(&self) -> bool { self.flags & (1 << FlagV1::SignMinus as u32) != 0 } /// Determines if the `#` flag was specified. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(i32); + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// if formatter.alternate() { + /// write!(formatter, "Foo({})", self.0) + /// } else { + /// write!(formatter, "{}", self.0) + /// } + /// } + /// } + /// + /// assert_eq!(&format!("{:#}", Foo(23)), "Foo(23)"); + /// assert_eq!(&format!("{}", Foo(23)), "23"); + /// ``` #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn alternate(&self) -> bool { self.flags & (1 << FlagV1::Alternate as u32) != 0 } /// Determines if the `0` flag was specified. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(i32); + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// assert!(formatter.sign_aware_zero_pad()); + /// assert_eq!(formatter.width(), Some(4)); + /// // We ignore the formatter's options. + /// write!(formatter, "{}", self.0) + /// } + /// } + /// + /// assert_eq!(&format!("{:04}", Foo(23)), "23"); + /// ``` #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_aware_zero_pad(&self) -> bool { self.flags & (1 << FlagV1::SignAwareZeroPad as u32) != 0 -- cgit 1.4.1-3-g733a5 From 4897935e8645e5f1d9d9ef61c78a1cb019c44f89 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 13 Mar 2018 14:08:15 +0100 Subject: Add hexadecimal formatting of integers with fmt::Debug This can be used for integers within a larger types which implements Debug (possibly through derive) but not fmt::UpperHex or fmt::LowerHex. ```rust assert!(format!("{:02x?}", b"Foo\0") == "[46, 6f, 6f, 00]"); assert!(format!("{:02X?}", b"Foo\0") == "[46, 6F, 6F, 00]"); ``` RFC: https://github.com/rust-lang/rfcs/pull/2226 --- src/liballoc/fmt.rs | 2 ++ src/libcore/fmt/mod.rs | 8 +++++++- src/libcore/fmt/num.rs | 8 +++++++- src/libcore/tests/fmt/num.rs | 6 ++++++ src/libfmt_macros/lib.rs | 22 ++++++++++++++++++++-- 5 files changed, 42 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs index a092bfb3b0a..2c4cdef03b0 100644 --- a/src/liballoc/fmt.rs +++ b/src/liballoc/fmt.rs @@ -113,6 +113,8 @@ //! //! * *nothing* ⇒ [`Display`] //! * `?` ⇒ [`Debug`] +//! * `x?` ⇒ [`Debug`] with lower-case hexadecimal integers +//! * `X?` ⇒ [`Debug`] with lower-case hexadecimal integers //! * `o` ⇒ [`Octal`](trait.Octal.html) //! * `x` ⇒ [`LowerHex`](trait.LowerHex.html) //! * `X` ⇒ [`UpperHex`](trait.UpperHex.html) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 8ad5a9861a0..a31be0e216f 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -333,7 +333,7 @@ impl<'a> ArgumentV1<'a> { // flags available in the v1 format of format_args #[derive(Copy, Clone)] -enum FlagV1 { SignPlus, SignMinus, Alternate, SignAwareZeroPad, } +enum FlagV1 { SignPlus, SignMinus, Alternate, SignAwareZeroPad, DebugLowerHex, DebugUpperHex } impl<'a> Arguments<'a> { /// When using the format_args!() macro, this function is used to generate the @@ -1401,6 +1401,12 @@ impl<'a> Formatter<'a> { self.flags & (1 << FlagV1::SignAwareZeroPad as u32) != 0 } + // FIXME: Decide what public API we want for these two flags. + // https://github.com/rust-lang/rust/issues/48584 + fn debug_lower_hex(&self) -> bool { self.flags & (1 << FlagV1::DebugLowerHex as u32) != 0 } + + fn debug_upper_hex(&self) -> bool { self.flags & (1 << FlagV1::DebugUpperHex as u32) != 0 } + /// Creates a [`DebugStruct`] builder designed to assist with creation of /// [`fmt::Debug`] implementations for structs. /// diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index 2992e7cf8db..86f1b5a8f28 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -159,7 +159,13 @@ macro_rules! debug { impl fmt::Debug for $T { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, f) + if f.debug_lower_hex() { + fmt::LowerHex::fmt(self, f) + } else if f.debug_upper_hex() { + fmt::UpperHex::fmt(self, f) + } else { + fmt::Display::fmt(self, f) + } } } } diff --git a/src/libcore/tests/fmt/num.rs b/src/libcore/tests/fmt/num.rs index 4ddedd91004..bc205ec0582 100644 --- a/src/libcore/tests/fmt/num.rs +++ b/src/libcore/tests/fmt/num.rs @@ -150,3 +150,9 @@ fn test_format_int_twos_complement() { assert!(format!("{}", i32::MIN) == "-2147483648"); assert!(format!("{}", i64::MIN) == "-9223372036854775808"); } + +#[test] +fn test_format_debug_hex() { + assert!(format!("{:02x?}", b"Foo\0") == "[46, 6f, 6f, 00]"); + assert!(format!("{:02X?}", b"Foo\0") == "[46, 6F, 6F, 00]"); +} diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 71519ab21fe..0f45f965104 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -108,6 +108,10 @@ pub enum Flag { /// For numbers, this means that the number will be padded with zeroes, /// and the sign (`+` or `-`) will precede them. FlagSignAwareZeroPad, + /// For Debug / `?`, format integers in lower-case hexadecimal. + FlagDebugLowerHex, + /// For Debug / `?`, format integers in upper-case hexadecimal. + FlagDebugUpperHex, } /// A count is used for the precision and width parameters of an integer, and @@ -377,8 +381,22 @@ impl<'a> Parser<'a> { spec.precision = self.count(); } } - // Finally the actual format specifier - if self.consume('?') { + // Optional radix followed by the actual format specifier + if self.consume('x') { + if self.consume('?') { + spec.flags |= 1 << (FlagDebugLowerHex as u32); + spec.ty = "?"; + } else { + spec.ty = "x"; + } + } else if self.consume('X') { + if self.consume('?') { + spec.flags |= 1 << (FlagDebugUpperHex as u32); + spec.ty = "?"; + } else { + spec.ty = "X"; + } + } else if self.consume('?') { spec.ty = "?"; } else { spec.ty = self.word(); -- cgit 1.4.1-3-g733a5 From a9fc3901b07d0494bd3eb9c37b10e63b429714b0 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 21 Jan 2018 16:44:41 +0800 Subject: stabilise feature(never_type) Replace feature(never_type) with feature(exhaustive_patterns). feature(exhaustive_patterns) only covers the pattern-exhaustives checks that used to be covered by feature(never_type) --- src/libcore/cmp.rs | 8 +++---- src/libcore/fmt/mod.rs | 4 ++-- src/libcore/lib.rs | 3 ++- src/librustc/lib.rs | 2 +- src/librustc_lint/lib.rs | 1 + src/librustc_mir/build/matches/simplify.rs | 2 +- src/librustc_mir/hair/pattern/_match.rs | 6 ++--- src/librustc_mir/hair/pattern/check_match.rs | 2 +- src/librustc_mir/lib.rs | 3 ++- src/librustc_typeck/lib.rs | 3 ++- src/libstd/error.rs | 2 +- src/libstd/lib.rs | 3 ++- src/libstd/primitive_docs.rs | 11 ++++----- src/libsyntax/feature_gate.rs | 8 ++----- .../compile-fail/call-fn-never-arg-wrong-type.rs | 2 -- src/test/compile-fail/coerce-to-bang-cast.rs | 2 -- src/test/compile-fail/coerce-to-bang.rs | 1 - .../compile-fail/inhabitedness-infinite-loop.rs | 2 +- src/test/compile-fail/loop-break-value.rs | 2 -- src/test/compile-fail/match-privately-empty.rs | 2 +- src/test/compile-fail/never-assign-dead-code.rs | 2 +- src/test/compile-fail/never-assign-wrong-type.rs | 1 - .../recursive-types-are-not-uninhabited.rs | 2 -- src/test/compile-fail/uninhabited-irrefutable.rs | 2 +- src/test/compile-fail/uninhabited-patterns.rs | 2 +- src/test/compile-fail/unreachable-loop-patterns.rs | 2 +- src/test/compile-fail/unreachable-try-pattern.rs | 2 +- src/test/run-fail/adjust_never.rs | 2 -- src/test/run-fail/call-fn-never-arg.rs | 1 - src/test/run-fail/cast-never.rs | 2 -- src/test/run-fail/never-associated-type.rs | 2 -- src/test/run-fail/never-type-arg.rs | 2 -- .../run-pass/diverging-fallback-control-flow.rs | 2 -- src/test/run-pass/empty-types-in-patterns.rs | 2 +- src/test/run-pass/impl-for-never.rs | 2 -- src/test/run-pass/issue-38972.rs | 25 ------------------- src/test/run-pass/issue-44402.rs | 2 +- src/test/run-pass/loop-break-value.rs | 2 -- src/test/run-pass/mir_calls_to_shims.rs | 1 - src/test/run-pass/never-result.rs | 2 -- src/test/ui/feature-gate-exhaustive-patterns.rs | 18 ++++++++++++++ .../ui/feature-gate-exhaustive-patterns.stderr | 8 +++++++ src/test/ui/feature-gate-never_type.rs | 28 ---------------------- src/test/ui/print_type_sizes/uninhabited.rs | 1 - src/test/ui/reachable/expr_add.rs | 1 - src/test/ui/reachable/expr_add.stderr | 4 ++-- src/test/ui/reachable/expr_array.rs | 3 +-- src/test/ui/reachable/expr_array.stderr | 4 ++-- src/test/ui/reachable/expr_assign.rs | 1 - src/test/ui/reachable/expr_assign.stderr | 6 ++--- src/test/ui/reachable/expr_block.rs | 1 - src/test/ui/reachable/expr_block.stderr | 4 ++-- src/test/ui/reachable/expr_call.rs | 1 - src/test/ui/reachable/expr_call.stderr | 4 ++-- src/test/ui/reachable/expr_cast.rs | 1 - src/test/ui/reachable/expr_cast.stderr | 2 +- src/test/ui/reachable/expr_if.rs | 1 - src/test/ui/reachable/expr_if.stderr | 2 +- src/test/ui/reachable/expr_loop.rs | 1 - src/test/ui/reachable/expr_loop.stderr | 6 ++--- src/test/ui/reachable/expr_match.rs | 1 - src/test/ui/reachable/expr_match.stderr | 6 ++--- src/test/ui/reachable/expr_method.rs | 1 - src/test/ui/reachable/expr_method.stderr | 4 ++-- src/test/ui/reachable/expr_repeat.rs | 1 - src/test/ui/reachable/expr_repeat.stderr | 2 +- src/test/ui/reachable/expr_return.rs | 1 - src/test/ui/reachable/expr_return.stderr | 2 +- src/test/ui/reachable/expr_struct.rs | 1 - src/test/ui/reachable/expr_struct.stderr | 8 +++---- src/test/ui/reachable/expr_tup.rs | 1 - src/test/ui/reachable/expr_tup.stderr | 4 ++-- src/test/ui/reachable/expr_type.rs | 1 - src/test/ui/reachable/expr_type.stderr | 2 +- src/test/ui/reachable/expr_unary.rs | 1 - src/test/ui/reachable/expr_unary.stderr | 6 ++--- src/test/ui/reachable/expr_while.rs | 1 - src/test/ui/reachable/expr_while.stderr | 6 ++--- 78 files changed, 101 insertions(+), 174 deletions(-) delete mode 100644 src/test/run-pass/issue-38972.rs create mode 100644 src/test/ui/feature-gate-exhaustive-patterns.rs create mode 100644 src/test/ui/feature-gate-exhaustive-patterns.stderr delete mode 100644 src/test/ui/feature-gate-never_type.rs (limited to 'src/libcore') diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 6602643dc51..fdb9946469b 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -882,24 +882,24 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.24.0")] impl PartialEq for ! { fn eq(&self, _: &!) -> bool { *self } } - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.24.0")] impl Eq for ! {} - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.24.0")] impl PartialOrd for ! { fn partial_cmp(&self, _: &!) -> Option { *self } } - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.24.0")] impl Ord for ! { fn cmp(&self, _: &!) -> Ordering { *self diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 213b317f632..3706da7c521 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1579,14 +1579,14 @@ macro_rules! fmt_refs { fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp } -#[unstable(feature = "never_type", issue = "35121")] +#[stable(feature = "never_type", since = "1.24.0")] impl Debug for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self } } -#[unstable(feature = "never_type", issue = "35121")] +#[stable(feature = "never_type", since = "1.24.0")] impl Display for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index cefcc5ff03f..a947c9f0b7c 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -85,7 +85,7 @@ #![feature(iterator_repeat_with)] #![feature(lang_items)] #![feature(link_llvm_intrinsics)] -#![feature(never_type)] +#![feature(exhaustive_patterns)] #![feature(no_core)] #![feature(on_unimplemented)] #![feature(optin_builtin_traits)] @@ -103,6 +103,7 @@ #![feature(unwind_attributes)] #![cfg_attr(stage0, allow(unused_attributes))] +#![cfg_attr(stage0, feature(never_type))] #[prelude_import] #[allow(unused)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 77b3a87c0ed..51882385b2e 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -60,7 +60,7 @@ #![feature(match_default_bindings)] #![feature(macro_lifetime_matcher)] #![feature(macro_vis_matcher)] -#![feature(never_type)] +#![feature(exhaustive_patterns)] #![feature(non_exhaustive)] #![feature(nonzero)] #![feature(proc_macro_internals)] diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 235d733b253..cbc1d7c38d6 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -32,6 +32,7 @@ #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] +#![cfg_attr(stage0, feature(never_type))] #[macro_use] extern crate syntax; diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index abea5583546..4e95ee6444d 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -113,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| { i == variant_index || { - self.hir.tcx().features().never_type && + self.hir.tcx().features().exhaustive_patterns && self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs) } }); diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 58aa9b06c64..6f8b1f8e799 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -219,7 +219,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { - if self.tcx.features().never_type { + if self.tcx.features().exhaustive_patterns { self.tcx.is_ty_uninhabited_from(self.module, ty) } else { false @@ -245,7 +245,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { substs: &'tcx ty::subst::Substs<'tcx>) -> bool { - if self.tcx.features().never_type { + if self.tcx.features().exhaustive_patterns { self.tcx.is_enum_variant_uninhabited_from(self.module, variant, substs) } else { false @@ -694,7 +694,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, // test for details. // // FIXME: currently the only way I know of something can - // be a privately-empty enum is when the never_type + // be a privately-empty enum is when the exhaustive_patterns // feature flag is not present, so this is only // needed for that case. diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 69ed4e6064f..d924baaf005 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -222,7 +222,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { let pat_ty = self.tables.node_id_to_type(scrut.hir_id); let module = self.tcx.hir.get_module_parent(scrut.id); if inlined_arms.is_empty() { - let scrutinee_is_uninhabited = if self.tcx.features().never_type { + let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns { self.tcx.is_ty_uninhabited_from(module, pat_ty) } else { self.conservative_is_uninhabited(pat_ty) diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index c31e95fd826..5510e219780 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -32,13 +32,14 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(inclusive_range)] #![feature(macro_vis_matcher)] #![feature(match_default_bindings)] -#![feature(never_type)] +#![feature(exhaustive_patterns)] #![feature(range_contains)] #![feature(rustc_diagnostic_macros)] #![feature(placement_in_syntax)] #![feature(collection_placement)] #![feature(nonzero)] #![feature(underscore_lifetimes)] +#![cfg_attr(stage0, feature(never_type))] extern crate arena; #[macro_use] diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index ea90c35cb8f..a97c6e84eab 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -80,13 +80,14 @@ This API is completely unstable and subject to change. #![feature(crate_visibility_modifier)] #![feature(from_ref)] #![feature(match_default_bindings)] -#![feature(never_type)] +#![feature(exhaustive_patterns)] #![feature(option_filter)] #![feature(quote)] #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] #![feature(i128_type)] +#![cfg_attr(stage0, feature(never_type))] #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/libstd/error.rs b/src/libstd/error.rs index eb5022ad577..347b8224410 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -234,7 +234,7 @@ impl<'a> From> for Box { } } -#[unstable(feature = "never_type", issue = "35121")] +#[stable(feature = "never_type", since = "1.24.0")] impl Error for ! { fn description(&self) -> &str { *self } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index da15941374d..eea0e6b6752 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -282,7 +282,7 @@ #![feature(macro_reexport)] #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] -#![feature(never_type)] +#![feature(exhaustive_patterns)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] @@ -324,6 +324,7 @@ #![feature(doc_spotlight)] #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] +#![cfg_attr(stage0, feature(never_type))] #![default_lib_allocator] diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 358aa2c37df..e6e6be2e453 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -79,7 +79,6 @@ mod prim_bool { } /// write: /// /// ``` -/// #![feature(never_type)] /// # fn foo() -> u32 { /// let x: ! = { /// return 123 @@ -131,13 +130,15 @@ mod prim_bool { } /// [`Result`] which we can unpack like this: /// /// ```ignore (string-from-str-error-type-is-not-never-yet) +/// #[feature(exhaustive_patterns)] /// // NOTE: This does not work today! /// let Ok(s) = String::from_str("hello"); /// ``` /// -/// Since the [`Err`] variant contains a `!`, it can never occur. So we can exhaustively match on -/// [`Result`] by just taking the [`Ok`] variant. This illustrates another behaviour of `!` - -/// it can be used to "delete" certain enum variants from generic types like `Result`. +/// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns` +/// feature is present this means we can exhaustively match on [`Result`] by just taking the +/// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain +/// enum variants from generic types like `Result`. /// /// [`String::from_str`]: str/trait.FromStr.html#tymethod.from_str /// [`Result`]: result/enum.Result.html @@ -154,7 +155,6 @@ mod prim_bool { } /// for example: /// /// ``` -/// # #![feature(never_type)] /// # use std::fmt; /// # trait Debug { /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result; @@ -192,7 +192,6 @@ mod prim_bool { } /// [`Default`]: default/trait.Default.html /// [`default()`]: default/trait.Default.html#tymethod.default /// -#[unstable(feature = "never_type", issue = "35121")] mod prim_never { } #[doc(primitive = "char")] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ec9a15d9f2b..91364fe6ed4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -286,8 +286,8 @@ declare_features! ( // Allows `impl Trait` in function arguments. (active, universal_impl_trait, "1.23.0", Some(34511), None), - // The `!` type - (active, never_type, "1.13.0", Some(35121), None), + // Allows exhaustive pattern matching on types that contain uninhabited types. + (active, exhaustive_patterns, "1.13.0", None, None), // Allows all literals in attribute lists and values of key-value pairs. (active, attr_literals, "1.13.0", Some(34981), None), @@ -1566,10 +1566,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::BareFn(ref bare_fn_ty) => { self.check_abi(bare_fn_ty.abi, ty.span); } - ast::TyKind::Never => { - gate_feature_post!(&self, never_type, ty.span, - "The `!` type is experimental"); - }, ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => { gate_feature_post!(&self, dyn_trait, ty.span, "`dyn Trait` syntax is unstable"); diff --git a/src/test/compile-fail/call-fn-never-arg-wrong-type.rs b/src/test/compile-fail/call-fn-never-arg-wrong-type.rs index 583befed1e8..c2f157cd35c 100644 --- a/src/test/compile-fail/call-fn-never-arg-wrong-type.rs +++ b/src/test/compile-fail/call-fn-never-arg-wrong-type.rs @@ -10,8 +10,6 @@ // Test that we can't pass other types for ! -#![feature(never_type)] - fn foo(x: !) -> ! { x } diff --git a/src/test/compile-fail/coerce-to-bang-cast.rs b/src/test/compile-fail/coerce-to-bang-cast.rs index 0d5bf6cd68c..8b3a9ed092d 100644 --- a/src/test/compile-fail/coerce-to-bang-cast.rs +++ b/src/test/compile-fail/coerce-to-bang-cast.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] - fn foo(x: usize, y: !, z: usize) { } #[deny(coerce_never)] diff --git a/src/test/compile-fail/coerce-to-bang.rs b/src/test/compile-fail/coerce-to-bang.rs index b804bb2981b..b365f142a9b 100644 --- a/src/test/compile-fail/coerce-to-bang.rs +++ b/src/test/compile-fail/coerce-to-bang.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] #![deny(coerce_never)] fn foo(x: usize, y: !, z: usize) { } diff --git a/src/test/compile-fail/inhabitedness-infinite-loop.rs b/src/test/compile-fail/inhabitedness-infinite-loop.rs index 91b85d7510a..b9741e0add6 100644 --- a/src/test/compile-fail/inhabitedness-infinite-loop.rs +++ b/src/test/compile-fail/inhabitedness-infinite-loop.rs @@ -10,7 +10,7 @@ // error-pattern:reached recursion limit -#![feature(never_type)] +#![feature(exhaustive_patterns)] struct Foo<'a, T: 'a> { ph: std::marker::PhantomData, diff --git a/src/test/compile-fail/loop-break-value.rs b/src/test/compile-fail/loop-break-value.rs index 938f7fba2a0..5ef46bb27fd 100644 --- a/src/test/compile-fail/loop-break-value.rs +++ b/src/test/compile-fail/loop-break-value.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] - fn main() { let val: ! = loop { break break; }; //~^ ERROR mismatched types diff --git a/src/test/compile-fail/match-privately-empty.rs b/src/test/compile-fail/match-privately-empty.rs index 3affb1c03e9..e18c7d77ce3 100644 --- a/src/test/compile-fail/match-privately-empty.rs +++ b/src/test/compile-fail/match-privately-empty.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] +#![feature(exhaustive_patterns)] mod private { pub struct Private { diff --git a/src/test/compile-fail/never-assign-dead-code.rs b/src/test/compile-fail/never-assign-dead-code.rs index 1e0cc0f5357..4e987d1ddce 100644 --- a/src/test/compile-fail/never-assign-dead-code.rs +++ b/src/test/compile-fail/never-assign-dead-code.rs @@ -10,7 +10,7 @@ // Test that an assignment of type ! makes the rest of the block dead code. -#![feature(never_type, rustc_attrs)] +#![feature(rustc_attrs)] #![warn(unused)] #[rustc_error] diff --git a/src/test/compile-fail/never-assign-wrong-type.rs b/src/test/compile-fail/never-assign-wrong-type.rs index c0dd2cab749..8c2de7d68d3 100644 --- a/src/test/compile-fail/never-assign-wrong-type.rs +++ b/src/test/compile-fail/never-assign-wrong-type.rs @@ -10,7 +10,6 @@ // Test that we can't use another type in place of ! -#![feature(never_type)] #![deny(warnings)] fn main() { diff --git a/src/test/compile-fail/recursive-types-are-not-uninhabited.rs b/src/test/compile-fail/recursive-types-are-not-uninhabited.rs index f8d6c3de2ab..fa936697072 100644 --- a/src/test/compile-fail/recursive-types-are-not-uninhabited.rs +++ b/src/test/compile-fail/recursive-types-are-not-uninhabited.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//#![feature(never_type)] - struct R<'a> { r: &'a R<'a>, } diff --git a/src/test/compile-fail/uninhabited-irrefutable.rs b/src/test/compile-fail/uninhabited-irrefutable.rs index 4755fdd4fd5..72b0afa6bd3 100644 --- a/src/test/compile-fail/uninhabited-irrefutable.rs +++ b/src/test/compile-fail/uninhabited-irrefutable.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] +#![feature(exhaustive_patterns)] mod foo { pub struct SecretlyEmpty { diff --git a/src/test/compile-fail/uninhabited-patterns.rs b/src/test/compile-fail/uninhabited-patterns.rs index 4c894b0bdd3..9f943f08232 100644 --- a/src/test/compile-fail/uninhabited-patterns.rs +++ b/src/test/compile-fail/uninhabited-patterns.rs @@ -11,7 +11,7 @@ #![feature(box_patterns)] #![feature(slice_patterns)] #![feature(box_syntax)] -#![feature(never_type)] +#![feature(exhaustive_patterns)] #![deny(unreachable_patterns)] mod foo { diff --git a/src/test/compile-fail/unreachable-loop-patterns.rs b/src/test/compile-fail/unreachable-loop-patterns.rs index 6147692658f..dca79bdfb87 100644 --- a/src/test/compile-fail/unreachable-loop-patterns.rs +++ b/src/test/compile-fail/unreachable-loop-patterns.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] +#![feature(exhaustive_patterns)] #![deny(unreachable_patterns)] fn main() { diff --git a/src/test/compile-fail/unreachable-try-pattern.rs b/src/test/compile-fail/unreachable-try-pattern.rs index 46ea4a06a3b..0caf7d51234 100644 --- a/src/test/compile-fail/unreachable-try-pattern.rs +++ b/src/test/compile-fail/unreachable-try-pattern.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type, rustc_attrs)] +#![feature(exhaustive_patterns, rustc_attrs)] #![warn(unreachable_code)] #![warn(unreachable_patterns)] diff --git a/src/test/run-fail/adjust_never.rs b/src/test/run-fail/adjust_never.rs index ccdb1ca15bb..7a4b5e59eeb 100644 --- a/src/test/run-fail/adjust_never.rs +++ b/src/test/run-fail/adjust_never.rs @@ -10,8 +10,6 @@ // Test that a variable of type ! can coerce to another type. -#![feature(never_type)] - // error-pattern:explicit fn main() { let x: ! = panic!(); diff --git a/src/test/run-fail/call-fn-never-arg.rs b/src/test/run-fail/call-fn-never-arg.rs index 95101e70db9..56454586bb9 100644 --- a/src/test/run-fail/call-fn-never-arg.rs +++ b/src/test/run-fail/call-fn-never-arg.rs @@ -12,7 +12,6 @@ // error-pattern:wowzers! -#![feature(never_type)] #![allow(unreachable_code)] fn foo(x: !) -> ! { diff --git a/src/test/run-fail/cast-never.rs b/src/test/run-fail/cast-never.rs index acd002494f4..0155332c51d 100644 --- a/src/test/run-fail/cast-never.rs +++ b/src/test/run-fail/cast-never.rs @@ -10,8 +10,6 @@ // Test that we can explicitly cast ! to another type -#![feature(never_type)] - // error-pattern:explicit fn main() { let x: ! = panic!(); diff --git a/src/test/run-fail/never-associated-type.rs b/src/test/run-fail/never-associated-type.rs index 345674f3f52..d9b8461a1d0 100644 --- a/src/test/run-fail/never-associated-type.rs +++ b/src/test/run-fail/never-associated-type.rs @@ -10,8 +10,6 @@ // Test that we can use ! as an associated type. -#![feature(never_type)] - // error-pattern:kapow! trait Foo { diff --git a/src/test/run-fail/never-type-arg.rs b/src/test/run-fail/never-type-arg.rs index 826ca3a08c0..0fe10d43910 100644 --- a/src/test/run-fail/never-type-arg.rs +++ b/src/test/run-fail/never-type-arg.rs @@ -12,8 +12,6 @@ // error-pattern:oh no! -#![feature(never_type)] - struct Wub; impl PartialEq for Wub { diff --git a/src/test/run-pass/diverging-fallback-control-flow.rs b/src/test/run-pass/diverging-fallback-control-flow.rs index 723a98bcdfa..a96f98b9efd 100644 --- a/src/test/run-pass/diverging-fallback-control-flow.rs +++ b/src/test/run-pass/diverging-fallback-control-flow.rs @@ -14,8 +14,6 @@ // These represent current behavior, but are pretty dubious. I would // like to revisit these and potentially change them. --nmatsakis -#![feature(never_type)] - trait BadDefault { fn default() -> Self; } diff --git a/src/test/run-pass/empty-types-in-patterns.rs b/src/test/run-pass/empty-types-in-patterns.rs index 033b185a0ef..87db4401929 100644 --- a/src/test/run-pass/empty-types-in-patterns.rs +++ b/src/test/run-pass/empty-types-in-patterns.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] +#![feature(exhaustive_patterns)] #![feature(slice_patterns)] #![allow(unreachable_patterns)] #![allow(unreachable_code)] diff --git a/src/test/run-pass/impl-for-never.rs b/src/test/run-pass/impl-for-never.rs index 794f5969bff..cf54e1c3bd5 100644 --- a/src/test/run-pass/impl-for-never.rs +++ b/src/test/run-pass/impl-for-never.rs @@ -10,8 +10,6 @@ // Test that we can call static methods on ! both directly and when it appears in a generic -#![feature(never_type)] - trait StringifyType { fn stringify_type() -> &'static str; } diff --git a/src/test/run-pass/issue-38972.rs b/src/test/run-pass/issue-38972.rs deleted file mode 100644 index d5df84e0fb0..00000000000 --- a/src/test/run-pass/issue-38972.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// This issue tracks a regression (a new warning) without -// feature(never_type). When we make that the default, please -// remove this test. - -enum Foo { } - -fn make_foo() -> Option { None } - -#[deny(warnings)] -fn main() { - match make_foo() { - None => {}, - Some(_) => {} - } -} diff --git a/src/test/run-pass/issue-44402.rs b/src/test/run-pass/issue-44402.rs index 244aa65a3d5..a5a0a5a5794 100644 --- a/src/test/run-pass/issue-44402.rs +++ b/src/test/run-pass/issue-44402.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] +#![feature(exhaustive_patterns)] // Regression test for inhabitedness check. The old // cache used to cause us to incorrectly decide diff --git a/src/test/run-pass/loop-break-value.rs b/src/test/run-pass/loop-break-value.rs index 39053769b24..ffdd99ebf6e 100644 --- a/src/test/run-pass/loop-break-value.rs +++ b/src/test/run-pass/loop-break-value.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] - #[allow(unused)] fn never_returns() { loop { diff --git a/src/test/run-pass/mir_calls_to_shims.rs b/src/test/run-pass/mir_calls_to_shims.rs index 9641ed28293..dda7a46f325 100644 --- a/src/test/run-pass/mir_calls_to_shims.rs +++ b/src/test/run-pass/mir_calls_to_shims.rs @@ -11,7 +11,6 @@ // ignore-wasm32-bare compiled with panic=abort by default #![feature(fn_traits)] -#![feature(never_type)] use std::panic; diff --git a/src/test/run-pass/never-result.rs b/src/test/run-pass/never-result.rs index 5c0af392f44..8aa2a13ed8c 100644 --- a/src/test/run-pass/never-result.rs +++ b/src/test/run-pass/never-result.rs @@ -10,8 +10,6 @@ // Test that we can extract a ! through pattern matching then use it as several different types. -#![feature(never_type)] - fn main() { let x: Result = Ok(123); match x { diff --git a/src/test/ui/feature-gate-exhaustive-patterns.rs b/src/test/ui/feature-gate-exhaustive-patterns.rs new file mode 100644 index 00000000000..477dd1b38eb --- /dev/null +++ b/src/test/ui/feature-gate-exhaustive-patterns.rs @@ -0,0 +1,18 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() -> Result { + Ok(123) +} + +fn main() { + let Ok(_x) = foo(); //~ ERROR refutable pattern in local binding +} + diff --git a/src/test/ui/feature-gate-exhaustive-patterns.stderr b/src/test/ui/feature-gate-exhaustive-patterns.stderr new file mode 100644 index 00000000000..43a4adf9373 --- /dev/null +++ b/src/test/ui/feature-gate-exhaustive-patterns.stderr @@ -0,0 +1,8 @@ +error[E0005]: refutable pattern in local binding: `Err(_)` not covered + --> $DIR/feature-gate-exhaustive-patterns.rs:16:9 + | +16 | let Ok(_x) = foo(); //~ ERROR refutable pattern in local binding + | ^^^^^^ pattern `Err(_)` not covered + +error: aborting due to previous error + diff --git a/src/test/ui/feature-gate-never_type.rs b/src/test/ui/feature-gate-never_type.rs deleted file mode 100644 index 11b9f412957..00000000000 --- a/src/test/ui/feature-gate-never_type.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that ! errors when used in illegal positions with feature(never_type) disabled - -trait Foo { - type Wub; -} - -type Ma = (u32, !, i32); //~ ERROR type is experimental -type Meeshka = Vec; //~ ERROR type is experimental -type Mow = &fn(!) -> !; //~ ERROR type is experimental -type Skwoz = &mut !; //~ ERROR type is experimental - -impl Foo for Meeshka { - type Wub = !; //~ ERROR type is experimental -} - -fn main() { -} - diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs index 4d0396903e5..7e8eff02c20 100644 --- a/src/test/ui/print_type_sizes/uninhabited.rs +++ b/src/test/ui/print_type_sizes/uninhabited.rs @@ -11,7 +11,6 @@ // compile-flags: -Z print-type-sizes // must-compile-successfully -#![feature(never_type)] #![feature(start)] #[start] diff --git a/src/test/ui/reachable/expr_add.rs b/src/test/ui/reachable/expr_add.rs index dd43c58de6d..3e39b75d8c0 100644 --- a/src/test/ui/reachable/expr_add.rs +++ b/src/test/ui/reachable/expr_add.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] #![allow(unused_variables)] #![deny(unreachable_code)] diff --git a/src/test/ui/reachable/expr_add.stderr b/src/test/ui/reachable/expr_add.stderr index d3e1da0e718..f49a781ce33 100644 --- a/src/test/ui/reachable/expr_add.stderr +++ b/src/test/ui/reachable/expr_add.stderr @@ -1,11 +1,11 @@ error: unreachable expression - --> $DIR/expr_add.rs:27:13 + --> $DIR/expr_add.rs:26:13 | LL | let x = Foo + return; //~ ERROR unreachable | ^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/expr_add.rs:13:9 + --> $DIR/expr_add.rs:12:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_array.rs b/src/test/ui/reachable/expr_array.rs index 31229668796..323a5752e22 100644 --- a/src/test/ui/reachable/expr_array.rs +++ b/src/test/ui/reachable/expr_array.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] #![feature(type_ascription)] fn a() { @@ -21,7 +20,7 @@ fn a() { } fn b() { - // the `array is unreachable: + // the array is unreachable: let x: [usize; 2] = [22, return]; //~ ERROR unreachable } diff --git a/src/test/ui/reachable/expr_array.stderr b/src/test/ui/reachable/expr_array.stderr index 3257514ea50..78ac76a6137 100644 --- a/src/test/ui/reachable/expr_array.stderr +++ b/src/test/ui/reachable/expr_array.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_array.rs:20:34 + --> $DIR/expr_array.rs:19:34 | LL | let x: [usize; 2] = [return, 22]; //~ ERROR unreachable | ^^ @@ -11,7 +11,7 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable expression - --> $DIR/expr_array.rs:25:25 + --> $DIR/expr_array.rs:24:25 | LL | let x: [usize; 2] = [22, return]; //~ ERROR unreachable | ^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_assign.rs b/src/test/ui/reachable/expr_assign.rs index e6fb46a5bac..73083af34d9 100644 --- a/src/test/ui/reachable/expr_assign.rs +++ b/src/test/ui/reachable/expr_assign.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] fn foo() { // No error here. diff --git a/src/test/ui/reachable/expr_assign.stderr b/src/test/ui/reachable/expr_assign.stderr index 15dcf2c2401..628bfbf6217 100644 --- a/src/test/ui/reachable/expr_assign.stderr +++ b/src/test/ui/reachable/expr_assign.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_assign.rs:20:5 + --> $DIR/expr_assign.rs:19:5 | LL | x = return; //~ ERROR unreachable | ^^^^^^^^^^ @@ -11,13 +11,13 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable expression - --> $DIR/expr_assign.rs:30:14 + --> $DIR/expr_assign.rs:29:14 | LL | *p = return; //~ ERROR unreachable | ^^^^^^ error: unreachable expression - --> $DIR/expr_assign.rs:36:15 + --> $DIR/expr_assign.rs:35:15 | LL | *{return; &mut i} = 22; //~ ERROR unreachable | ^^^^^^ diff --git a/src/test/ui/reachable/expr_block.rs b/src/test/ui/reachable/expr_block.rs index 57b5d3cabce..93bce43f76d 100644 --- a/src/test/ui/reachable/expr_block.rs +++ b/src/test/ui/reachable/expr_block.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] fn a() { // Here the tail expression is considered unreachable: diff --git a/src/test/ui/reachable/expr_block.stderr b/src/test/ui/reachable/expr_block.stderr index a0cef6449f7..5f5696aadb3 100644 --- a/src/test/ui/reachable/expr_block.stderr +++ b/src/test/ui/reachable/expr_block.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_block.rs:21:9 + --> $DIR/expr_block.rs:20:9 | LL | 22 //~ ERROR unreachable | ^^ @@ -11,7 +11,7 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable statement - --> $DIR/expr_block.rs:36:9 + --> $DIR/expr_block.rs:35:9 | LL | println!("foo"); | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_call.rs b/src/test/ui/reachable/expr_call.rs index 86b95aad9c2..2772dd429d1 100644 --- a/src/test/ui/reachable/expr_call.rs +++ b/src/test/ui/reachable/expr_call.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] fn foo(x: !, y: usize) { } diff --git a/src/test/ui/reachable/expr_call.stderr b/src/test/ui/reachable/expr_call.stderr index 455e5ab3653..414d29ec2a7 100644 --- a/src/test/ui/reachable/expr_call.stderr +++ b/src/test/ui/reachable/expr_call.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_call.rs:23:17 + --> $DIR/expr_call.rs:22:17 | LL | foo(return, 22); //~ ERROR unreachable | ^^ @@ -11,7 +11,7 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable expression - --> $DIR/expr_call.rs:28:5 + --> $DIR/expr_call.rs:27:5 | LL | bar(return); //~ ERROR unreachable | ^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_cast.rs b/src/test/ui/reachable/expr_cast.rs index 76b00c00ad9..88846b63841 100644 --- a/src/test/ui/reachable/expr_cast.rs +++ b/src/test/ui/reachable/expr_cast.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] #![feature(type_ascription)] fn a() { diff --git a/src/test/ui/reachable/expr_cast.stderr b/src/test/ui/reachable/expr_cast.stderr index 8c37759aa46..458334e2af9 100644 --- a/src/test/ui/reachable/expr_cast.stderr +++ b/src/test/ui/reachable/expr_cast.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_cast.rs:20:13 + --> $DIR/expr_cast.rs:19:13 | LL | let x = {return} as !; //~ ERROR unreachable | ^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_if.rs b/src/test/ui/reachable/expr_if.rs index 2a265e772f3..d2fb1044e48 100644 --- a/src/test/ui/reachable/expr_if.rs +++ b/src/test/ui/reachable/expr_if.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] fn foo() { if {return} { diff --git a/src/test/ui/reachable/expr_if.stderr b/src/test/ui/reachable/expr_if.stderr index c14cdbfc2bc..6e8afd1c5be 100644 --- a/src/test/ui/reachable/expr_if.stderr +++ b/src/test/ui/reachable/expr_if.stderr @@ -1,5 +1,5 @@ error: unreachable statement - --> $DIR/expr_if.rs:38:5 + --> $DIR/expr_if.rs:37:5 | LL | println!("But I am."); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_loop.rs b/src/test/ui/reachable/expr_loop.rs index 3ed4b2dcf0c..533cdac0968 100644 --- a/src/test/ui/reachable/expr_loop.rs +++ b/src/test/ui/reachable/expr_loop.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] fn a() { loop { return; } diff --git a/src/test/ui/reachable/expr_loop.stderr b/src/test/ui/reachable/expr_loop.stderr index 7f834567de3..a51ef293acf 100644 --- a/src/test/ui/reachable/expr_loop.stderr +++ b/src/test/ui/reachable/expr_loop.stderr @@ -1,5 +1,5 @@ error: unreachable statement - --> $DIR/expr_loop.rs:19:5 + --> $DIR/expr_loop.rs:18:5 | LL | println!("I am dead."); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(unreachable_code)] = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: unreachable statement - --> $DIR/expr_loop.rs:31:5 + --> $DIR/expr_loop.rs:30:5 | LL | println!("I am dead."); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | println!("I am dead."); = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: unreachable statement - --> $DIR/expr_loop.rs:41:5 + --> $DIR/expr_loop.rs:40:5 | LL | println!("I am dead."); | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_match.rs b/src/test/ui/reachable/expr_match.rs index d2b96e51a95..193edd77435 100644 --- a/src/test/ui/reachable/expr_match.rs +++ b/src/test/ui/reachable/expr_match.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] fn a() { // The match is considered unreachable here, because the `return` diff --git a/src/test/ui/reachable/expr_match.stderr b/src/test/ui/reachable/expr_match.stderr index d4cf21cef28..dfc1417f3d2 100644 --- a/src/test/ui/reachable/expr_match.stderr +++ b/src/test/ui/reachable/expr_match.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_match.rs:20:5 + --> $DIR/expr_match.rs:19:5 | LL | match {return} { } //~ ERROR unreachable | ^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable statement - --> $DIR/expr_match.rs:25:5 + --> $DIR/expr_match.rs:24:5 | LL | println!("I am dead"); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | println!("I am dead"); = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: unreachable statement - --> $DIR/expr_match.rs:35:5 + --> $DIR/expr_match.rs:34:5 | LL | println!("I am dead"); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_method.rs b/src/test/ui/reachable/expr_method.rs index 8be71e464b2..7dabb307097 100644 --- a/src/test/ui/reachable/expr_method.rs +++ b/src/test/ui/reachable/expr_method.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] struct Foo; diff --git a/src/test/ui/reachable/expr_method.stderr b/src/test/ui/reachable/expr_method.stderr index b9348b5d481..6d67bfcd54a 100644 --- a/src/test/ui/reachable/expr_method.stderr +++ b/src/test/ui/reachable/expr_method.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_method.rs:26:21 + --> $DIR/expr_method.rs:25:21 | LL | Foo.foo(return, 22); //~ ERROR unreachable | ^^ @@ -11,7 +11,7 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable expression - --> $DIR/expr_method.rs:31:5 + --> $DIR/expr_method.rs:30:5 | LL | Foo.bar(return); //~ ERROR unreachable | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_repeat.rs b/src/test/ui/reachable/expr_repeat.rs index 47ee2ba62b8..fd9fca413a7 100644 --- a/src/test/ui/reachable/expr_repeat.rs +++ b/src/test/ui/reachable/expr_repeat.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] #![feature(type_ascription)] fn a() { diff --git a/src/test/ui/reachable/expr_repeat.stderr b/src/test/ui/reachable/expr_repeat.stderr index 90cc3183c72..36393de90b7 100644 --- a/src/test/ui/reachable/expr_repeat.stderr +++ b/src/test/ui/reachable/expr_repeat.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_repeat.rs:20:25 + --> $DIR/expr_repeat.rs:19:25 | LL | let x: [usize; 2] = [return; 2]; //~ ERROR unreachable | ^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_return.rs b/src/test/ui/reachable/expr_return.rs index fac1116dc68..9bbbe6f9099 100644 --- a/src/test/ui/reachable/expr_return.rs +++ b/src/test/ui/reachable/expr_return.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] #![feature(type_ascription)] fn a() { diff --git a/src/test/ui/reachable/expr_return.stderr b/src/test/ui/reachable/expr_return.stderr index 3876da6541d..2dcc50944c5 100644 --- a/src/test/ui/reachable/expr_return.stderr +++ b/src/test/ui/reachable/expr_return.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_return.rs:21:22 + --> $DIR/expr_return.rs:20:22 | LL | let x = {return {return {return;}}}; //~ ERROR unreachable | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_struct.rs b/src/test/ui/reachable/expr_struct.rs index b5acd395be6..66414f6084b 100644 --- a/src/test/ui/reachable/expr_struct.rs +++ b/src/test/ui/reachable/expr_struct.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] #![feature(type_ascription)] struct Foo { diff --git a/src/test/ui/reachable/expr_struct.stderr b/src/test/ui/reachable/expr_struct.stderr index 43985bbbb5c..3f0ecb20479 100644 --- a/src/test/ui/reachable/expr_struct.stderr +++ b/src/test/ui/reachable/expr_struct.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_struct.rs:25:13 + --> $DIR/expr_struct.rs:24:13 | LL | let x = Foo { a: 22, b: 33, ..return }; //~ ERROR unreachable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,19 +11,19 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable expression - --> $DIR/expr_struct.rs:30:33 + --> $DIR/expr_struct.rs:29:33 | LL | let x = Foo { a: return, b: 33, ..return }; //~ ERROR unreachable | ^^ error: unreachable expression - --> $DIR/expr_struct.rs:35:39 + --> $DIR/expr_struct.rs:34:39 | LL | let x = Foo { a: 22, b: return, ..return }; //~ ERROR unreachable | ^^^^^^ error: unreachable expression - --> $DIR/expr_struct.rs:40:13 + --> $DIR/expr_struct.rs:39:13 | LL | let x = Foo { a: 22, b: return }; //~ ERROR unreachable | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_tup.rs b/src/test/ui/reachable/expr_tup.rs index 089020bf385..e2c10090248 100644 --- a/src/test/ui/reachable/expr_tup.rs +++ b/src/test/ui/reachable/expr_tup.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] #![feature(type_ascription)] fn a() { diff --git a/src/test/ui/reachable/expr_tup.stderr b/src/test/ui/reachable/expr_tup.stderr index ff9aa666d8e..d372373ced0 100644 --- a/src/test/ui/reachable/expr_tup.stderr +++ b/src/test/ui/reachable/expr_tup.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_tup.rs:20:38 + --> $DIR/expr_tup.rs:19:38 | LL | let x: (usize, usize) = (return, 2); //~ ERROR unreachable | ^ @@ -11,7 +11,7 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable expression - --> $DIR/expr_tup.rs:25:29 + --> $DIR/expr_tup.rs:24:29 | LL | let x: (usize, usize) = (2, return); //~ ERROR unreachable | ^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_type.rs b/src/test/ui/reachable/expr_type.rs index 29c59d5304f..2381ea2ac7a 100644 --- a/src/test/ui/reachable/expr_type.rs +++ b/src/test/ui/reachable/expr_type.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] #![feature(type_ascription)] fn a() { diff --git a/src/test/ui/reachable/expr_type.stderr b/src/test/ui/reachable/expr_type.stderr index d6b9f75edf1..9b165d6b3ee 100644 --- a/src/test/ui/reachable/expr_type.stderr +++ b/src/test/ui/reachable/expr_type.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_type.rs:20:13 + --> $DIR/expr_type.rs:19:13 | LL | let x = {return}: !; //~ ERROR unreachable | ^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_unary.rs b/src/test/ui/reachable/expr_unary.rs index ad12cb876fe..524784934c7 100644 --- a/src/test/ui/reachable/expr_unary.rs +++ b/src/test/ui/reachable/expr_unary.rs @@ -13,7 +13,6 @@ #![allow(dead_code)] #![deny(unreachable_code)] #![deny(coerce_never)] -#![feature(never_type)] fn foo() { let x: ! = ! { return; 22 }; //~ ERROR unreachable diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr index b09721e5957..1239701cabd 100644 --- a/src/test/ui/reachable/expr_unary.stderr +++ b/src/test/ui/reachable/expr_unary.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_unary.rs:19:28 + --> $DIR/expr_unary.rs:18:28 | LL | let x: ! = ! { return; 22 }; //~ ERROR unreachable | ^^ @@ -11,7 +11,7 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: cannot coerce `{integer}` to ! - --> $DIR/expr_unary.rs:19:28 + --> $DIR/expr_unary.rs:18:28 | LL | let x: ! = ! { return; 22 }; //~ ERROR unreachable | ^^ @@ -25,7 +25,7 @@ LL | #![deny(coerce_never)] = note: for more information, see issue #46325 error[E0600]: cannot apply unary operator `!` to type `!` - --> $DIR/expr_unary.rs:19:16 + --> $DIR/expr_unary.rs:18:16 | LL | let x: ! = ! { return; 22 }; //~ ERROR unreachable | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_while.rs b/src/test/ui/reachable/expr_while.rs index 7dcd609fbc8..79fa69a9289 100644 --- a/src/test/ui/reachable/expr_while.rs +++ b/src/test/ui/reachable/expr_while.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] fn foo() { while {return} { diff --git a/src/test/ui/reachable/expr_while.stderr b/src/test/ui/reachable/expr_while.stderr index cd093906615..90c35bfaa7a 100644 --- a/src/test/ui/reachable/expr_while.stderr +++ b/src/test/ui/reachable/expr_while.stderr @@ -1,5 +1,5 @@ error: unreachable statement - --> $DIR/expr_while.rs:19:9 + --> $DIR/expr_while.rs:18:9 | LL | println!("Hello, world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(unreachable_code)] = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: unreachable statement - --> $DIR/expr_while.rs:33:9 + --> $DIR/expr_while.rs:32:9 | LL | println!("I am dead."); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | println!("I am dead."); = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: unreachable statement - --> $DIR/expr_while.rs:35:5 + --> $DIR/expr_while.rs:34:5 | LL | println!("I am, too."); | ^^^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 32ddb30715f73498477262c992d1152cf10ca631 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 21 Jan 2018 18:30:04 +0800 Subject: Fix version number --- src/libcore/cmp.rs | 8 ++++---- src/libcore/fmt/mod.rs | 4 ++-- src/libstd/error.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index fdb9946469b..3923b652afc 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -882,24 +882,24 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - #[stable(feature = "never_type", since = "1.24.0")] + #[stable(feature = "never_type", since = "1.25.0")] impl PartialEq for ! { fn eq(&self, _: &!) -> bool { *self } } - #[stable(feature = "never_type", since = "1.24.0")] + #[stable(feature = "never_type", since = "1.25.0")] impl Eq for ! {} - #[stable(feature = "never_type", since = "1.24.0")] + #[stable(feature = "never_type", since = "1.25.0")] impl PartialOrd for ! { fn partial_cmp(&self, _: &!) -> Option { *self } } - #[stable(feature = "never_type", since = "1.24.0")] + #[stable(feature = "never_type", since = "1.25.0")] impl Ord for ! { fn cmp(&self, _: &!) -> Ordering { *self diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 3706da7c521..40b88ded27d 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1579,14 +1579,14 @@ macro_rules! fmt_refs { fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp } -#[stable(feature = "never_type", since = "1.24.0")] +#[stable(feature = "never_type", since = "1.25.0")] impl Debug for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self } } -#[stable(feature = "never_type", since = "1.24.0")] +#[stable(feature = "never_type", since = "1.25.0")] impl Display for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 347b8224410..1743dfbfb7b 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -234,7 +234,7 @@ impl<'a> From> for Box { } } -#[stable(feature = "never_type", since = "1.24.0")] +#[stable(feature = "never_type", since = "1.25.0")] impl Error for ! { fn description(&self) -> &str { *self } } -- cgit 1.4.1-3-g733a5 From a704624ef5830541acb9912146fa28305b9a920c Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Thu, 1 Mar 2018 01:41:10 +0800 Subject: change never_type stabilisation version --- src/libcore/cmp.rs | 8 ++++---- src/libcore/fmt/mod.rs | 4 ++-- src/libstd/error.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 3923b652afc..67445daa436 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -882,24 +882,24 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - #[stable(feature = "never_type", since = "1.25.0")] + #[stable(feature = "never_type", since = "1.26.0")] impl PartialEq for ! { fn eq(&self, _: &!) -> bool { *self } } - #[stable(feature = "never_type", since = "1.25.0")] + #[stable(feature = "never_type", since = "1.26.0")] impl Eq for ! {} - #[stable(feature = "never_type", since = "1.25.0")] + #[stable(feature = "never_type", since = "1.26.0")] impl PartialOrd for ! { fn partial_cmp(&self, _: &!) -> Option { *self } } - #[stable(feature = "never_type", since = "1.25.0")] + #[stable(feature = "never_type", since = "1.26.0")] impl Ord for ! { fn cmp(&self, _: &!) -> Ordering { *self diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 40b88ded27d..2456b5b6654 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1579,14 +1579,14 @@ macro_rules! fmt_refs { fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp } -#[stable(feature = "never_type", since = "1.25.0")] +#[stable(feature = "never_type", since = "1.26.0")] impl Debug for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self } } -#[stable(feature = "never_type", since = "1.25.0")] +#[stable(feature = "never_type", since = "1.26.0")] impl Display for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 1743dfbfb7b..f8dbe193fed 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -234,7 +234,7 @@ impl<'a> From> for Box { } } -#[stable(feature = "never_type", since = "1.25.0")] +#[stable(feature = "never_type", since = "1.26.0")] impl Error for ! { fn description(&self) -> &str { *self } } -- cgit 1.4.1-3-g733a5 From 918ef671b04398560d8860363736ba120825e6fe Mon Sep 17 00:00:00 2001 From: boats Date: Wed, 14 Mar 2018 15:57:25 -0700 Subject: Pin and Unpin in libcore. --- src/libcore/marker.rs | 10 +++++ src/libcore/mem.rs | 111 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 119 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 98e0f71eb93..7b67404db5d 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -565,3 +565,13 @@ unsafe impl Freeze for *const T {} unsafe impl Freeze for *mut T {} unsafe impl<'a, T: ?Sized> Freeze for &'a T {} unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} + +/// Types which can be moved out of a `Pin`. +/// +/// The `Unpin` trait is used to control the behavior of the [`Pin`] type. If a +/// type implements `Unpin`, it is safe to move a value of that type out of the +/// `Pin` pointer. +/// +/// This trait is automatically implemented for almost every type. +#[unstable(feature = "pin", issue = "0")] +pub unsafe auto trait Unpin {} diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 21a0beccbf6..792d71732e6 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -20,9 +20,9 @@ use cmp; use fmt; use hash; use intrinsics; -use marker::{Copy, PhantomData, Sized}; +use marker::{Copy, PhantomData, Sized, Unpin, Unsize}; use ptr; -use ops::{Deref, DerefMut}; +use ops::{Deref, DerefMut, CoerceUnsized}; #[stable(feature = "rust1", since = "1.0.0")] pub use intrinsics::transmute; @@ -1105,3 +1105,110 @@ impl ::hash::Hash for ManuallyDrop { pub unsafe fn unreachable() -> ! { intrinsics::unreachable() } + +/// A pinned reference. +/// +/// A pinned reference is a lot like a mutable reference, except that it is not +/// safe to move a value out of a pinned reference unless the type of that +/// value implements the `Unpin` trait. +#[unstable(feature = "pin", issue = "0")] +pub struct Pin<'a, T: ?Sized + 'a> { + inner: &'a mut T, +} + +#[unstable(feature = "pin", issue = "0")] +impl<'a, T: ?Sized + Unpin> Pin<'a, T> { + /// Construct a new `Pin` around a reference to some data of a type that + /// implements `Unpin`. + #[unstable(feature = "pin", issue = "0")] + pub fn new(reference: &'a mut T) -> Pin<'a, T> { + Pin { inner: reference } + } +} + + +#[unstable(feature = "pin", issue = "0")] +impl<'a, T: ?Sized> Pin<'a, T> { + /// Construct a new `Pin` around a reference to some data of a type that + /// may or may not implement `Unpin`. + /// + /// This constructor is unsafe because we do not know what will happen with + /// that data after the reference ends. If you cannot guarantee that the + /// data will never move again, calling this constructor is invalid. + #[unstable(feature = "pin", issue = "0")] + pub unsafe fn new_unchecked(reference: &'a mut T) -> Pin<'a, T> { + Pin { inner: reference } + } + + /// Borrow a Pin for a shorter lifetime than it already has. + #[unstable(feature = "pin", issue = "0")] + pub fn borrow<'b>(this: &'b mut Pin<'a, T>) -> Pin<'b, T> { + Pin { inner: this.inner } + } + + /// Get a mutable reference to the data inside of this `Pin`. + /// + /// This function is unsafe. You must guarantee that you will never move + /// the data out of the mutable reference you receive when you call this + /// function. + #[unstable(feature = "pin", issue = "0")] + pub unsafe fn get_mut<'b>(this: &'b mut Pin<'a, T>) -> &'b mut T { + this.inner + } + + /// Construct a new pin by mapping the interior value. + /// + /// For example, if you wanted to get a `Pin` of a field of something, you + /// could use this to get access to that field in one line of code. + /// + /// This function is unsafe. You must guarantee that the data you return + /// will not move so long as the argument value does not move (for example, + /// because it is one of the fields of that value), and also that you do + /// not move out of the argument you receive to the interior function. + #[unstable(feature = "pin", issue = "0")] + pub unsafe fn map<'b, U, F>(this: &'b mut Pin<'a, T>, f: F) -> Pin<'b, U> where + F: FnOnce(&mut T) -> &mut U + { + Pin { inner: f(this.inner) } + } +} + +#[unstable(feature = "pin", issue = "0")] +impl<'a, T: ?Sized> Deref for Pin<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + &*self.inner + } +} + +#[unstable(feature = "pin", issue = "0")] +impl<'a, T: ?Sized + Unpin> DerefMut for Pin<'a, T> { + fn deref_mut(&mut self) -> &mut T { + self.inner + } +} + +#[unstable(feature = "pin", issue = "0")] +impl<'a, T: fmt::Debug + ?Sized> fmt::Debug for Pin<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[unstable(feature = "pin", issue = "0")] +impl<'a, T: fmt::Display + ?Sized> fmt::Display for Pin<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +#[unstable(feature = "pin", issue = "0")] +impl<'a, T: ?Sized> fmt::Pointer for Pin<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Pointer::fmt(&(&*self.inner as *const T), f) + } +} + +#[unstable(feature = "pin", issue = "0")] +impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for Pin<'a, T> {} -- cgit 1.4.1-3-g733a5 From 6d8a1739805fa81b6baa8c86efc3e79920ecb306 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sat, 10 Feb 2018 21:01:49 -0800 Subject: Reword E0044 and message for `!Send` types - Reword E0044 help. - Change error message for types that don't implement `Send` --- src/libcore/marker.rs | 5 ++++- src/librustc_typeck/check/mod.rs | 7 ++++--- src/test/compile-fail/builtin-superkinds-double-superkind.rs | 6 ++++-- src/test/compile-fail/closure-bounds-subtype.rs | 2 +- src/test/compile-fail/extern-types-not-sync-send.rs | 2 +- src/test/compile-fail/issue-16538.rs | 2 +- src/test/compile-fail/issue-17718-static-sync.rs | 2 +- src/test/compile-fail/issue-43733-2.rs | 4 ++-- src/test/compile-fail/issue-7364.rs | 2 +- src/test/compile-fail/kindck-send-object.rs | 2 +- src/test/compile-fail/kindck-send-object1.rs | 2 +- src/test/compile-fail/kindck-send-object2.rs | 3 ++- src/test/compile-fail/mutable-enum-indirect.rs | 3 ++- src/test/compile-fail/mutexguard-sync.rs | 3 ++- src/test/compile-fail/no_share-enum.rs | 2 +- src/test/compile-fail/no_share-struct.rs | 2 +- src/test/compile-fail/not-sync.rs | 12 ++++++------ src/test/compile-fail/phantom-oibit.rs | 6 ++++-- .../compile-fail/typeck-default-trait-impl-negation-sync.rs | 6 +++--- src/test/compile-fail/typeck-unsafe-always-share.rs | 8 ++++---- src/test/ui/error-codes/E0044.rs | 8 ++++++-- src/test/ui/error-codes/E0044.stderr | 12 ++++-------- src/test/ui/fmt/send-sync.rs | 4 ++-- src/test/ui/fmt/send-sync.stderr | 8 ++++---- src/test/ui/generator/not-send-sync.rs | 4 ++-- src/test/ui/generator/not-send-sync.stderr | 4 ++-- 26 files changed, 66 insertions(+), 55 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 98e0f71eb93..fd57491fcc7 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -343,7 +343,10 @@ pub trait Copy : Clone { /// [transmute]: ../../std/mem/fn.transmute.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sync"] -#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"] +#[rustc_on_unimplemented( + message="`{Self}` cannot be shared between threads safely", + label="`{Self}` cannot be shared between threads safely" +)] pub unsafe auto trait Sync { // Empty } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 19085ff039e..92c6e3ffed2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1222,9 +1222,10 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item if !generics.types.is_empty() { let mut err = struct_span_err!(tcx.sess, item.span, E0044, "foreign items may not have type parameters"); - span_help!(&mut err, item.span, - "consider using specialization instead of \ - type parameters"); + // FIXME: once we start storing spans for type arguments, turn this into a + // suggestion. + err.help("use specialization instead of type parameters by replacing them \ + with concrete types like `u32`"); err.emit(); } diff --git a/src/test/compile-fail/builtin-superkinds-double-superkind.rs b/src/test/compile-fail/builtin-superkinds-double-superkind.rs index 8d5d8e8dc9b..261881d880b 100644 --- a/src/test/compile-fail/builtin-superkinds-double-superkind.rs +++ b/src/test/compile-fail/builtin-superkinds-double-superkind.rs @@ -13,9 +13,11 @@ trait Foo : Send+Sync { } -impl Foo for (T,) { } //~ ERROR `T: std::marker::Send` is not satisfied +impl Foo for (T,) { } +//~^ ERROR the trait bound `T: std::marker::Send` is not satisfied in `(T,)` [E0277] -impl Foo for (T,T) { } //~ ERROR `T: std::marker::Sync` is not satisfied +impl Foo for (T,T) { } +//~^ ERROR `T` cannot be shared between threads safely [E0277] impl Foo for (T,T,T) { } // (ok) diff --git a/src/test/compile-fail/closure-bounds-subtype.rs b/src/test/compile-fail/closure-bounds-subtype.rs index d3339c4845a..db26535b004 100644 --- a/src/test/compile-fail/closure-bounds-subtype.rs +++ b/src/test/compile-fail/closure-bounds-subtype.rs @@ -21,7 +21,7 @@ fn give_any(f: F) where F: FnOnce() { fn give_owned(f: F) where F: FnOnce() + Send { take_any(f); - take_const_owned(f); //~ ERROR `F: std::marker::Sync` is not satisfied + take_const_owned(f); //~ ERROR `F` cannot be shared between threads safely [E0277] } fn main() {} diff --git a/src/test/compile-fail/extern-types-not-sync-send.rs b/src/test/compile-fail/extern-types-not-sync-send.rs index 2f00cf812e4..6a7a515ba5f 100644 --- a/src/test/compile-fail/extern-types-not-sync-send.rs +++ b/src/test/compile-fail/extern-types-not-sync-send.rs @@ -21,7 +21,7 @@ fn assert_send() { } fn main() { assert_sync::(); - //~^ ERROR the trait bound `A: std::marker::Sync` is not satisfied + //~^ ERROR `A` cannot be shared between threads safely [E0277] assert_send::(); //~^ ERROR the trait bound `A: std::marker::Send` is not satisfied diff --git a/src/test/compile-fail/issue-16538.rs b/src/test/compile-fail/issue-16538.rs index 08c3f7a7c15..7df445c676c 100644 --- a/src/test/compile-fail/issue-16538.rs +++ b/src/test/compile-fail/issue-16538.rs @@ -21,7 +21,7 @@ mod Y { } static foo: *const Y::X = Y::foo(Y::x as *const Y::X); -//~^ ERROR `*const usize: std::marker::Sync` is not satisfied +//~^ ERROR `*const usize` cannot be shared between threads safely [E0277] //~| ERROR cannot refer to other statics by value, use the address-of operator or a constant instead //~| ERROR E0015 diff --git a/src/test/compile-fail/issue-17718-static-sync.rs b/src/test/compile-fail/issue-17718-static-sync.rs index 790329cd2e4..c5349d4e82b 100644 --- a/src/test/compile-fail/issue-17718-static-sync.rs +++ b/src/test/compile-fail/issue-17718-static-sync.rs @@ -17,6 +17,6 @@ impl !Sync for Foo {} static FOO: usize = 3; static BAR: Foo = Foo; -//~^ ERROR: `Foo: std::marker::Sync` is not satisfied +//~^ ERROR: `Foo` cannot be shared between threads safely [E0277] fn main() {} diff --git a/src/test/compile-fail/issue-43733-2.rs b/src/test/compile-fail/issue-43733-2.rs index 0fd31454596..a5ba9ef9bd3 100644 --- a/src/test/compile-fail/issue-43733-2.rs +++ b/src/test/compile-fail/issue-43733-2.rs @@ -33,7 +33,7 @@ impl Key { use std::thread::__FastLocalKeyInner as Key; static __KEY: Key<()> = Key::new(); -//~^ ERROR `std::cell::UnsafeCell>: std::marker::Sync` is not satisfied -//~| ERROR `std::cell::Cell: std::marker::Sync` is not satisfied +//~^ ERROR `std::cell::UnsafeCell>` cannot be shared between threads +//~| ERROR `std::cell::Cell` cannot be shared between threads safely [E0277] fn main() {} diff --git a/src/test/compile-fail/issue-7364.rs b/src/test/compile-fail/issue-7364.rs index 16138c992ff..801a1301ad7 100644 --- a/src/test/compile-fail/issue-7364.rs +++ b/src/test/compile-fail/issue-7364.rs @@ -15,6 +15,6 @@ use std::cell::RefCell; // Regression test for issue 7364 static boxed: Box> = box RefCell::new(0); //~^ ERROR allocations are not allowed in statics -//~| ERROR `std::cell::RefCell: std::marker::Sync` is not satisfied +//~| ERROR `std::cell::RefCell` cannot be shared between threads safely [E0277] fn main() { } diff --git a/src/test/compile-fail/kindck-send-object.rs b/src/test/compile-fail/kindck-send-object.rs index bd0e5642b9c..a84eae0bfda 100644 --- a/src/test/compile-fail/kindck-send-object.rs +++ b/src/test/compile-fail/kindck-send-object.rs @@ -20,7 +20,7 @@ trait Message : Send { } fn object_ref_with_static_bound_not_ok() { assert_send::<&'static (Dummy+'static)>(); - //~^ ERROR : std::marker::Sync` is not satisfied + //~^ ERROR `Dummy + 'static` cannot be shared between threads safely [E0277] } fn box_object_with_no_bound_not_ok<'a>() { diff --git a/src/test/compile-fail/kindck-send-object1.rs b/src/test/compile-fail/kindck-send-object1.rs index da56fccde2d..66865bbcc7e 100644 --- a/src/test/compile-fail/kindck-send-object1.rs +++ b/src/test/compile-fail/kindck-send-object1.rs @@ -18,7 +18,7 @@ trait Dummy { } // careful with object types, who knows what they close over... fn test51<'a>() { assert_send::<&'a Dummy>(); - //~^ ERROR : std::marker::Sync` is not satisfied + //~^ ERROR `Dummy + 'a` cannot be shared between threads safely [E0277] } fn test52<'a>() { assert_send::<&'a (Dummy+Sync)>(); diff --git a/src/test/compile-fail/kindck-send-object2.rs b/src/test/compile-fail/kindck-send-object2.rs index e52a6e12efc..51bc587d74f 100644 --- a/src/test/compile-fail/kindck-send-object2.rs +++ b/src/test/compile-fail/kindck-send-object2.rs @@ -14,7 +14,8 @@ fn assert_send() { } trait Dummy { } fn test50() { - assert_send::<&'static Dummy>(); //~ ERROR : std::marker::Sync` is not satisfied + assert_send::<&'static Dummy>(); + //~^ ERROR `Dummy + 'static` cannot be shared between threads safely [E0277] } fn test53() { diff --git a/src/test/compile-fail/mutable-enum-indirect.rs b/src/test/compile-fail/mutable-enum-indirect.rs index cafcabe6279..9107745b0e9 100644 --- a/src/test/compile-fail/mutable-enum-indirect.rs +++ b/src/test/compile-fail/mutable-enum-indirect.rs @@ -24,5 +24,6 @@ fn bar(_: T) {} fn main() { let x = Foo::A(NoSync); - bar(&x); //~ ERROR `NoSync: std::marker::Sync` is not satisfied + bar(&x); + //~^ ERROR `NoSync` cannot be shared between threads safely [E0277] } diff --git a/src/test/compile-fail/mutexguard-sync.rs b/src/test/compile-fail/mutexguard-sync.rs index 861714720c5..2d4b50eb7b2 100644 --- a/src/test/compile-fail/mutexguard-sync.rs +++ b/src/test/compile-fail/mutexguard-sync.rs @@ -18,5 +18,6 @@ fn main() { let m = Mutex::new(Cell::new(0i32)); let guard = m.lock().unwrap(); - test_sync(guard); //~ ERROR the trait bound + test_sync(guard); + //~^ ERROR `std::cell::Cell` cannot be shared between threads safely [E0277] } diff --git a/src/test/compile-fail/no_share-enum.rs b/src/test/compile-fail/no_share-enum.rs index ae9a25a95b4..77a7012b3b0 100644 --- a/src/test/compile-fail/no_share-enum.rs +++ b/src/test/compile-fail/no_share-enum.rs @@ -22,5 +22,5 @@ fn bar(_: T) {} fn main() { let x = Foo::A(NoSync); bar(x); - //~^ ERROR `NoSync: std::marker::Sync` is not satisfied + //~^ ERROR `NoSync` cannot be shared between threads safely [E0277] } diff --git a/src/test/compile-fail/no_share-struct.rs b/src/test/compile-fail/no_share-struct.rs index d64d37a2f6c..34e43e9f2aa 100644 --- a/src/test/compile-fail/no_share-struct.rs +++ b/src/test/compile-fail/no_share-struct.rs @@ -20,5 +20,5 @@ fn bar(_: T) {} fn main() { let x = Foo { a: 5 }; bar(x); - //~^ ERROR `Foo: std::marker::Sync` is not satisfied + //~^ ERROR `Foo` cannot be shared between threads safely [E0277] } diff --git a/src/test/compile-fail/not-sync.rs b/src/test/compile-fail/not-sync.rs index 12c29279178..a383244f415 100644 --- a/src/test/compile-fail/not-sync.rs +++ b/src/test/compile-fail/not-sync.rs @@ -16,17 +16,17 @@ fn test() {} fn main() { test::>(); - //~^ ERROR `std::cell::Cell: std::marker::Sync` is not satisfied + //~^ ERROR `std::cell::Cell` cannot be shared between threads safely [E0277] test::>(); - //~^ ERROR `std::cell::RefCell: std::marker::Sync` is not satisfied + //~^ ERROR `std::cell::RefCell` cannot be shared between threads safely [E0277] test::>(); - //~^ ERROR `std::rc::Rc: std::marker::Sync` is not satisfied + //~^ ERROR `std::rc::Rc` cannot be shared between threads safely [E0277] test::>(); - //~^ ERROR `std::rc::Weak: std::marker::Sync` is not satisfied + //~^ ERROR `std::rc::Weak` cannot be shared between threads safely [E0277] test::>(); - //~^ ERROR `std::sync::mpsc::Receiver: std::marker::Sync` is not satisfied + //~^ ERROR `std::sync::mpsc::Receiver` cannot be shared between threads safely [E0277] test::>(); - //~^ ERROR `std::sync::mpsc::Sender: std::marker::Sync` is not satisfied + //~^ ERROR `std::sync::mpsc::Sender` cannot be shared between threads safely [E0277] } diff --git a/src/test/compile-fail/phantom-oibit.rs b/src/test/compile-fail/phantom-oibit.rs index e36c4835ca1..51e7d5da98f 100644 --- a/src/test/compile-fail/phantom-oibit.rs +++ b/src/test/compile-fail/phantom-oibit.rs @@ -28,11 +28,13 @@ struct Nested(T); fn is_zen(_: T) {} fn not_sync(x: Guard) { - is_zen(x) //~ error: `T: std::marker::Sync` is not satisfied + is_zen(x) + //~^ ERROR `T` cannot be shared between threads safely [E0277] } fn nested_not_sync(x: Nested>) { - is_zen(x) //~ error: `T: std::marker::Sync` is not satisfied + is_zen(x) + //~^ ERROR `T` cannot be shared between threads safely [E0277] } fn main() {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-negation-sync.rs b/src/test/compile-fail/typeck-default-trait-impl-negation-sync.rs index cdf787a60ad..c829ba3dcc3 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-negation-sync.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-negation-sync.rs @@ -43,11 +43,11 @@ fn is_sync() {} fn main() { is_sync::(); is_sync::(); - //~^ ERROR `MyNotSync: std::marker::Sync` is not satisfied + //~^ ERROR `MyNotSync` cannot be shared between threads safely [E0277] is_sync::(); - //~^ ERROR `std::cell::UnsafeCell: std::marker::Sync` is not satisfied + //~^ ERROR `std::cell::UnsafeCell` cannot be shared between threads safely [E0277] is_sync::(); - //~^ ERROR `Managed: std::marker::Sync` is not satisfied + //~^ ERROR `Managed` cannot be shared between threads safely [E0277] } diff --git a/src/test/compile-fail/typeck-unsafe-always-share.rs b/src/test/compile-fail/typeck-unsafe-always-share.rs index f0172777cda..fcfc8574b21 100644 --- a/src/test/compile-fail/typeck-unsafe-always-share.rs +++ b/src/test/compile-fail/typeck-unsafe-always-share.rs @@ -27,16 +27,16 @@ fn test(s: T) {} fn main() { let us = UnsafeCell::new(MySync{u: UnsafeCell::new(0)}); test(us); - //~^ ERROR `std::cell::UnsafeCell>: std::marker::Sync` is not satisfied + //~^ ERROR `std::cell::UnsafeCell>` cannot be shared between threads safely let uns = UnsafeCell::new(NoSync); test(uns); - //~^ ERROR `std::cell::UnsafeCell: std::marker::Sync` is not satisfied + //~^ ERROR `std::cell::UnsafeCell` cannot be shared between threads safely [E0277] let ms = MySync{u: uns}; test(ms); - //~^ ERROR `std::cell::UnsafeCell: std::marker::Sync` is not satisfied + //~^ ERROR `std::cell::UnsafeCell` cannot be shared between threads safely [E0277] test(NoSync); - //~^ ERROR `NoSync: std::marker::Sync` is not satisfied + //~^ ERROR `NoSync` cannot be shared between threads safely [E0277] } diff --git a/src/test/ui/error-codes/E0044.rs b/src/test/ui/error-codes/E0044.rs index 48fe2300031..4d20edea5fe 100644 --- a/src/test/ui/error-codes/E0044.rs +++ b/src/test/ui/error-codes/E0044.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,7 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern { fn some_func(x: T); } //~ ERROR E0044 +extern { + fn sqrt(f: T) -> T; + //~^ ERROR foreign items may not have type parameters [E0044] + //~| HELP use specialization instead of type parameters by replacing them with concrete types +} fn main() { } diff --git a/src/test/ui/error-codes/E0044.stderr b/src/test/ui/error-codes/E0044.stderr index b823f3717b3..12324e771d3 100644 --- a/src/test/ui/error-codes/E0044.stderr +++ b/src/test/ui/error-codes/E0044.stderr @@ -1,14 +1,10 @@ error[E0044]: foreign items may not have type parameters - --> $DIR/E0044.rs:11:10 + --> $DIR/E0044.rs:12:5 | -LL | extern { fn some_func(x: T); } //~ ERROR E0044 - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | fn sqrt(f: T) -> T; + | ^^^^^^^^^^^^^^^^^^^^^^ | -help: consider using specialization instead of type parameters - --> $DIR/E0044.rs:11:10 - | -LL | extern { fn some_func(x: T); } //~ ERROR E0044 - | ^^^^^^^^^^^^^^^^^^^^^^ + = help: use specialization instead of type parameters by replacing them with concrete types like `u32` error: aborting due to previous error diff --git a/src/test/ui/fmt/send-sync.rs b/src/test/ui/fmt/send-sync.rs index 3f13fd2e491..424919a0eba 100644 --- a/src/test/ui/fmt/send-sync.rs +++ b/src/test/ui/fmt/send-sync.rs @@ -15,6 +15,6 @@ fn main() { // `Cell` is not `Sync`, so `&Cell` is neither `Sync` nor `Send`, // `std::fmt::Arguments` used to forget this... let c = std::cell::Cell::new(42); - send(format_args!("{:?}", c)); //~ ERROR Sync` is not satisfied - sync(format_args!("{:?}", c)); //~ ERROR Sync` is not satisfied + send(format_args!("{:?}", c)); //~ ERROR E0277 + sync(format_args!("{:?}", c)); //~ ERROR E0277 } diff --git a/src/test/ui/fmt/send-sync.stderr b/src/test/ui/fmt/send-sync.stderr index 0943b64c5c0..113a2a480aa 100644 --- a/src/test/ui/fmt/send-sync.stderr +++ b/src/test/ui/fmt/send-sync.stderr @@ -1,7 +1,7 @@ -error[E0277]: the trait bound `*mut std::ops::Fn() + 'static: std::marker::Sync` is not satisfied in `[std::fmt::ArgumentV1<'_>]` +error[E0277]: `*mut std::ops::Fn() + 'static` cannot be shared between threads safely --> $DIR/send-sync.rs:18:5 | -LL | send(format_args!("{:?}", c)); //~ ERROR Sync` is not satisfied +LL | send(format_args!("{:?}", c)); //~ ERROR E0277 | ^^^^ `*mut std::ops::Fn() + 'static` cannot be shared between threads safely | = help: within `[std::fmt::ArgumentV1<'_>]`, the trait `std::marker::Sync` is not implemented for `*mut std::ops::Fn() + 'static` @@ -18,10 +18,10 @@ note: required by `send` LL | fn send(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `*mut std::ops::Fn() + 'static: std::marker::Sync` is not satisfied in `std::fmt::Arguments<'_>` +error[E0277]: `*mut std::ops::Fn() + 'static` cannot be shared between threads safely --> $DIR/send-sync.rs:19:5 | -LL | sync(format_args!("{:?}", c)); //~ ERROR Sync` is not satisfied +LL | sync(format_args!("{:?}", c)); //~ ERROR E0277 | ^^^^ `*mut std::ops::Fn() + 'static` cannot be shared between threads safely | = help: within `std::fmt::Arguments<'_>`, the trait `std::marker::Sync` is not implemented for `*mut std::ops::Fn() + 'static` diff --git a/src/test/ui/generator/not-send-sync.rs b/src/test/ui/generator/not-send-sync.rs index 0419758d8ea..f0df05ebfdf 100644 --- a/src/test/ui/generator/not-send-sync.rs +++ b/src/test/ui/generator/not-send-sync.rs @@ -17,14 +17,14 @@ fn main() { fn assert_send(_: T) {} assert_sync(|| { - //~^ ERROR: Sync` is not satisfied + //~^ ERROR: E0277 let a = Cell::new(2); yield; }); let a = Cell::new(2); assert_send(|| { - //~^ ERROR: Sync` is not satisfied + //~^ ERROR: E0277 drop(&a); yield; }); diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr index 6ca583bf16d..669e0d26cf0 100644 --- a/src/test/ui/generator/not-send-sync.stderr +++ b/src/test/ui/generator/not-send-sync.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `std::cell::Cell: std::marker::Sync` is not satisfied +error[E0277]: `std::cell::Cell` cannot be shared between threads safely --> $DIR/not-send-sync.rs:26:5 | LL | assert_send(|| { @@ -13,7 +13,7 @@ note: required by `main::assert_send` LL | fn assert_send(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `std::cell::Cell: std::marker::Sync` is not satisfied in `[generator@$DIR/not-send-sync.rs:19:17: 23:6 {std::cell::Cell, ()}]` +error[E0277]: `std::cell::Cell` cannot be shared between threads safely --> $DIR/not-send-sync.rs:19:5 | LL | assert_sync(|| { -- cgit 1.4.1-3-g733a5 From fe1975448cf180a39393104a7b424291975998d4 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 11 Feb 2018 13:39:32 -0800 Subject: Suggest using `move` when trying to share `...::channel::{Receiver, Sender}` Extend `rustc_on_unimplemented` to match on ADT without evaluating type arguments. --- src/libcore/marker.rs | 8 ++++++++ src/librustc/traits/error_reporting.rs | 31 +++++++++++++++++-------------- src/test/ui/closure-move-sync.rs | 32 ++++++++++++++++++++++++++++++++ src/test/ui/closure-move-sync.stderr | 24 ++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 14 deletions(-) create mode 100644 src/test/ui/closure-move-sync.rs create mode 100644 src/test/ui/closure-move-sync.stderr (limited to 'src/libcore') diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index fd57491fcc7..51d2e29e6b1 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -344,6 +344,14 @@ pub trait Copy : Clone { #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sync"] #[rustc_on_unimplemented( + on( + _Self="std::sync::mpsc::Receiver", + label="`{Self}` cannot be shared safely, if using a closure consider marking it `move`" + ), + on( + _Self="std::sync::mpsc::Sender", + label="`{Self}` cannot be shared safely, if using a closure consider marking it `move`" + ), message="`{Self}` cannot be shared between threads safely", label="`{Self}` cannot be shared between threads safely" )] diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index cd2d0d7e2a0..9cdab856b05 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -338,18 +338,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .unwrap_or(trait_ref.def_id()); let trait_ref = *trait_ref.skip_binder(); - let desugaring; - let method; let mut flags = vec![]; - let direct = match obligation.cause.code { + match obligation.cause.code { ObligationCauseCode::BuiltinDerivedObligation(..) | - ObligationCauseCode::ImplDerivedObligation(..) => false, - _ => true - }; - if direct { - // this is a "direct", user-specified, rather than derived, - // obligation. - flags.push(("direct".to_string(), None)); + ObligationCauseCode::ImplDerivedObligation(..) => {} + _ => { + // this is a "direct", user-specified, rather than derived, + // obligation. + flags.push(("direct".to_string(), None)); + } } if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code { @@ -359,21 +356,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // // Currently I'm leaving it for what I need for `try`. if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) { - method = self.tcx.item_name(item); + let method = self.tcx.item_name(item); flags.push(("from_method".to_string(), None)); flags.push(("from_method".to_string(), Some(method.to_string()))); } } if let Some(k) = obligation.cause.span.compiler_desugaring_kind() { - desugaring = k.as_symbol().as_str(); + let desugaring = k.as_symbol().as_str(); flags.push(("from_desugaring".to_string(), None)); flags.push(("from_desugaring".to_string(), Some(desugaring.to_string()))); } let generics = self.tcx.generics_of(def_id); let self_ty = trait_ref.self_ty(); - let self_ty_str = self_ty.to_string(); - flags.push(("_Self".to_string(), Some(self_ty_str.clone()))); + // This is also included through the generics list as `Self`, + // but the parser won't allow you to use it + flags.push(("_Self".to_string(), Some(self_ty.to_string()))); + if let Some(def) = self_ty.ty_adt_def() { + // We also want to be able to select self's original + // signature with no type arguments resolved + flags.push(("_Self".to_string(), Some(self.tcx.type_of(def.did).to_string()))); + } for param in generics.types.iter() { let name = param.name.as_str().to_string(); diff --git a/src/test/ui/closure-move-sync.rs b/src/test/ui/closure-move-sync.rs new file mode 100644 index 00000000000..e096e7ca3a0 --- /dev/null +++ b/src/test/ui/closure-move-sync.rs @@ -0,0 +1,32 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::thread; +use std::sync::mpsc::channel; + +fn bar() { + let (send, recv) = channel(); + let t = thread::spawn(|| { + recv.recv().unwrap(); + //~^^ ERROR `std::sync::mpsc::Receiver<()>` cannot be shared between threads safely + }); + + send.send(()); + + t.join().unwrap(); +} + +fn foo() { + let (tx, _rx) = channel(); + thread::spawn(|| tx.send(()).unwrap()); + //~^ ERROR `std::sync::mpsc::Sender<()>` cannot be shared between threads safely +} + +fn main() {} diff --git a/src/test/ui/closure-move-sync.stderr b/src/test/ui/closure-move-sync.stderr new file mode 100644 index 00000000000..fc53deeeef7 --- /dev/null +++ b/src/test/ui/closure-move-sync.stderr @@ -0,0 +1,24 @@ +error[E0277]: `std::sync::mpsc::Receiver<()>` cannot be shared between threads safely + --> $DIR/closure-move-sync.rs:16:13 + | +16 | let t = thread::spawn(|| { + | ^^^^^^^^^^^^^ `std::sync::mpsc::Receiver<()>` cannot be shared safely, if using a closure consider marking it `move` + | + = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Receiver<()>` + = note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Receiver<()>` + = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:16:27: 19:6 recv:&std::sync::mpsc::Receiver<()>]` + = note: required by `std::thread::spawn` + +error[E0277]: `std::sync::mpsc::Sender<()>` cannot be shared between threads safely + --> $DIR/closure-move-sync.rs:28:5 + | +28 | thread::spawn(|| tx.send(()).unwrap()); + | ^^^^^^^^^^^^^ `std::sync::mpsc::Sender<()>` cannot be shared safely, if using a closure consider marking it `move` + | + = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender<()>` + = note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Sender<()>` + = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:28:19: 28:42 tx:&std::sync::mpsc::Sender<()>]` + = note: required by `std::thread::spawn` + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From cb5667eaa53c45f1cdf69f367f8cd749b0499ce1 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Mon, 19 Feb 2018 00:15:12 -0800 Subject: Make hint clearer, with the potential of being wrong --- src/libcore/marker.rs | 4 ++-- src/test/ui/closure-move-sync.stderr | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 51d2e29e6b1..d78453cc900 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -346,11 +346,11 @@ pub trait Copy : Clone { #[rustc_on_unimplemented( on( _Self="std::sync::mpsc::Receiver", - label="`{Self}` cannot be shared safely, if using a closure consider marking it `move`" + label="`{Self}` cannot be shared safely, consider marking the closure `move`" ), on( _Self="std::sync::mpsc::Sender", - label="`{Self}` cannot be shared safely, if using a closure consider marking it `move`" + label="`{Self}` cannot be shared safely, consider marking the closure `move`" ), message="`{Self}` cannot be shared between threads safely", label="`{Self}` cannot be shared between threads safely" diff --git a/src/test/ui/closure-move-sync.stderr b/src/test/ui/closure-move-sync.stderr index fc53deeeef7..4b59ef8a437 100644 --- a/src/test/ui/closure-move-sync.stderr +++ b/src/test/ui/closure-move-sync.stderr @@ -2,7 +2,7 @@ error[E0277]: `std::sync::mpsc::Receiver<()>` cannot be shared between threads s --> $DIR/closure-move-sync.rs:16:13 | 16 | let t = thread::spawn(|| { - | ^^^^^^^^^^^^^ `std::sync::mpsc::Receiver<()>` cannot be shared safely, if using a closure consider marking it `move` + | ^^^^^^^^^^^^^ `std::sync::mpsc::Receiver<()>` cannot be shared safely, consider marking the closure `move` | = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Receiver<()>` = note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Receiver<()>` @@ -13,7 +13,7 @@ error[E0277]: `std::sync::mpsc::Sender<()>` cannot be shared between threads saf --> $DIR/closure-move-sync.rs:28:5 | 28 | thread::spawn(|| tx.send(()).unwrap()); - | ^^^^^^^^^^^^^ `std::sync::mpsc::Sender<()>` cannot be shared safely, if using a closure consider marking it `move` + | ^^^^^^^^^^^^^ `std::sync::mpsc::Sender<()>` cannot be shared safely, consider marking the closure `move` | = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender<()>` = note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Sender<()>` -- cgit 1.4.1-3-g733a5 From bfc66daef9d1bdc52000cf8c079ea8572699f6c0 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 25 Feb 2018 13:18:29 -0800 Subject: Review comment: remove mention of `move` closure --- src/libcore/marker.rs | 18 ++++++++++-------- src/test/ui/closure-move-sync.stderr | 9 +++++---- 2 files changed, 15 insertions(+), 12 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index d78453cc900..53b1d1cd12d 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -344,18 +344,20 @@ pub trait Copy : Clone { #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sync"] #[rustc_on_unimplemented( - on( - _Self="std::sync::mpsc::Receiver", - label="`{Self}` cannot be shared safely, consider marking the closure `move`" - ), - on( - _Self="std::sync::mpsc::Sender", - label="`{Self}` cannot be shared safely, consider marking the closure `move`" - ), message="`{Self}` cannot be shared between threads safely", label="`{Self}` cannot be shared between threads safely" )] pub unsafe auto trait Sync { + // FIXME(estebank): once support to add notes in `rustc_on_unimplemented` + // lands in beta, and it has been extended to check whether a closure is + // anywhere in the requirement chain, extend it as such (#48534): + // ``` + // on( + // closure, + // note="`{Self}` cannot be shared safely, consider marking the closure `move`" + // ), + // ``` + // Empty } diff --git a/src/test/ui/closure-move-sync.stderr b/src/test/ui/closure-move-sync.stderr index 4b59ef8a437..abf07d2cef5 100644 --- a/src/test/ui/closure-move-sync.stderr +++ b/src/test/ui/closure-move-sync.stderr @@ -1,8 +1,8 @@ error[E0277]: `std::sync::mpsc::Receiver<()>` cannot be shared between threads safely --> $DIR/closure-move-sync.rs:16:13 | -16 | let t = thread::spawn(|| { - | ^^^^^^^^^^^^^ `std::sync::mpsc::Receiver<()>` cannot be shared safely, consider marking the closure `move` +LL | let t = thread::spawn(|| { + | ^^^^^^^^^^^^^ `std::sync::mpsc::Receiver<()>` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Receiver<()>` = note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Receiver<()>` @@ -12,8 +12,8 @@ error[E0277]: `std::sync::mpsc::Receiver<()>` cannot be shared between threads s error[E0277]: `std::sync::mpsc::Sender<()>` cannot be shared between threads safely --> $DIR/closure-move-sync.rs:28:5 | -28 | thread::spawn(|| tx.send(()).unwrap()); - | ^^^^^^^^^^^^^ `std::sync::mpsc::Sender<()>` cannot be shared safely, consider marking the closure `move` +LL | thread::spawn(|| tx.send(()).unwrap()); + | ^^^^^^^^^^^^^ `std::sync::mpsc::Sender<()>` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender<()>` = note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Sender<()>` @@ -22,3 +22,4 @@ error[E0277]: `std::sync::mpsc::Sender<()>` cannot be shared between threads saf error: aborting due to 2 previous errors +If you want more information on this error, try using "rustc --explain E0277" -- cgit 1.4.1-3-g733a5 From 4647156985404f07dc2e61eed6f2e24770b339a9 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Thu, 15 Mar 2018 12:35:56 +0800 Subject: replace `convert::Infallible` with `!` --- src/libcore/convert.rs | 21 +-------------------- src/libcore/num/mod.rs | 18 +++++------------- src/libstd/error.rs | 9 --------- 3 files changed, 6 insertions(+), 42 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index d3a83dc795c..a45f1ceab5a 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -48,25 +48,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use fmt; - -/// A type used as the error type for implementations of fallible conversion -/// traits in cases where conversions cannot actually fail. -/// -/// Because `Infallible` has no variants, a value of this type can never exist. -/// It is used only to satisfy trait signatures that expect an error type, and -/// signals to both the compiler and the user that the error case is impossible. -#[unstable(feature = "try_from", issue = "33417")] -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum Infallible {} - -#[unstable(feature = "try_from", issue = "33417")] -impl fmt::Display for Infallible { - fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { - match *self { - } - } -} /// A cheap reference-to-reference conversion. Used to convert a value to a /// reference value within generic code. /// @@ -438,7 +419,7 @@ impl TryInto for T where U: TryFrom // with an uninhabited error type. #[unstable(feature = "try_from", issue = "33417")] impl TryFrom for T where T: From { - type Error = Infallible; + type Error = !; fn try_from(value: U) -> Result { Ok(T::from(value)) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 09ab7060d37..faeb87cf944 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -12,7 +12,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use convert::{Infallible, TryFrom}; +use convert::TryFrom; use fmt; use intrinsics; use ops; @@ -3595,20 +3595,12 @@ impl fmt::Display for TryFromIntError { } } -#[unstable(feature = "try_from", issue = "33417")] -impl From for TryFromIntError { - fn from(infallible: Infallible) -> TryFromIntError { - match infallible { - } - } -} - // no possible bounds violation macro_rules! try_from_unbounded { ($source:ty, $($target:ty),*) => {$( #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { - type Error = Infallible; + type Error = !; #[inline] fn try_from(value: $source) -> Result { @@ -3719,7 +3711,7 @@ try_from_lower_bounded!(isize, usize); #[cfg(target_pointer_width = "16")] mod ptr_try_from_impls { use super::TryFromIntError; - use convert::{Infallible, TryFrom}; + use convert::TryFrom; try_from_upper_bounded!(usize, u8); try_from_unbounded!(usize, u16, u32, u64, u128); @@ -3745,7 +3737,7 @@ mod ptr_try_from_impls { #[cfg(target_pointer_width = "32")] mod ptr_try_from_impls { use super::TryFromIntError; - use convert::{Infallible, TryFrom}; + use convert::TryFrom; try_from_upper_bounded!(usize, u8, u16); try_from_unbounded!(usize, u32, u64, u128); @@ -3771,7 +3763,7 @@ mod ptr_try_from_impls { #[cfg(target_pointer_width = "64")] mod ptr_try_from_impls { use super::TryFromIntError; - use convert::{Infallible, TryFrom}; + use convert::TryFrom; try_from_upper_bounded!(usize, u8, u16, u32); try_from_unbounded!(usize, u64, u128); diff --git a/src/libstd/error.rs b/src/libstd/error.rs index f8dbe193fed..79bb6af168f 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -56,7 +56,6 @@ use any::TypeId; use borrow::Cow; use cell; use char; -use convert; use core::array; use fmt::{self, Debug, Display}; use mem::transmute; @@ -371,14 +370,6 @@ impl Error for char::ParseCharError { } } -#[unstable(feature = "try_from", issue = "33417")] -impl Error for convert::Infallible { - fn description(&self) -> &str { - match *self { - } - } -} - // copied from any.rs impl Error + 'static { /// Returns true if the boxed type is the same as `T` -- cgit 1.4.1-3-g733a5 From b5913f2e7695ad247078619bf4c6a6d3dc4dece5 Mon Sep 17 00:00:00 2001 From: kennytm Date: Sun, 28 Jan 2018 03:09:36 +0800 Subject: Stabilize `inclusive_range` library feature. Stabilize std::ops::RangeInclusive and std::ops::RangeInclusiveTo. --- src/liballoc/lib.rs | 1 - src/liballoc/range.rs | 4 ++-- src/liballoc/string.rs | 8 ++++---- src/libcore/iter/range.rs | 12 ++++-------- src/libcore/ops/mod.rs | 2 +- src/libcore/ops/range.rs | 24 +++++++++--------------- src/libcore/slice/mod.rs | 4 ++-- src/libcore/str/mod.rs | 24 ++++++------------------ src/libcore/tests/lib.rs | 1 - src/librustc/lib.rs | 1 - src/librustc_mir/lib.rs | 1 - src/librustc_trans/lib.rs | 1 - src/libstd/lib.rs | 1 - src/test/compile-fail/range_inclusive_gate.rs | 21 --------------------- src/test/compile-fail/range_traits-1.rs | 2 -- src/test/compile-fail/range_traits-6.rs | 2 -- src/test/compile-fail/range_traits-7.rs | 2 +- src/test/parse-fail/range_inclusive.rs | 2 +- src/test/parse-fail/range_inclusive_dotdotdot.rs | 2 +- src/test/parse-fail/range_inclusive_gate.rs | 2 +- src/test/run-pass/range_inclusive.rs | 2 +- 21 files changed, 33 insertions(+), 86 deletions(-) delete mode 100644 src/test/compile-fail/range_inclusive_gate.rs (limited to 'src/libcore') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 3f306784558..cbfec554604 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -98,7 +98,6 @@ #![feature(fundamental)] #![feature(generic_param_attrs)] #![feature(i128_type)] -#![feature(inclusive_range)] #![feature(iter_rfold)] #![feature(lang_items)] #![feature(needs_allocator)] diff --git a/src/liballoc/range.rs b/src/liballoc/range.rs index f862da0d61e..b03abc85180 100644 --- a/src/liballoc/range.rs +++ b/src/liballoc/range.rs @@ -103,7 +103,7 @@ impl RangeArgument for Range { } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl RangeArgument for RangeInclusive { fn start(&self) -> Bound<&T> { Included(&self.start) @@ -113,7 +113,7 @@ impl RangeArgument for RangeInclusive { } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl RangeArgument for RangeToInclusive { fn start(&self) -> Bound<&T> { Unbounded diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 370fb6b4e89..185fb61ae9e 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1876,7 +1876,7 @@ impl ops::Index for String { unsafe { str::from_utf8_unchecked(&self.vec) } } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl ops::Index> for String { type Output = str; @@ -1885,7 +1885,7 @@ impl ops::Index> for String { Index::index(&**self, index) } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl ops::Index> for String { type Output = str; @@ -1923,14 +1923,14 @@ impl ops::IndexMut for String { unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) } } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl ops::IndexMut> for String { #[inline] fn index_mut(&mut self, index: ops::RangeInclusive) -> &mut str { IndexMut::index_mut(&mut **self, index) } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl ops::IndexMut> for String { #[inline] fn index_mut(&mut self, index: ops::RangeToInclusive) -> &mut str { diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 9a3fd215dcf..8d1080bb876 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -186,9 +186,7 @@ macro_rules! range_exact_iter_impl { macro_rules! range_incl_exact_iter_impl { ($($t:ty)*) => ($( - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] impl ExactSizeIterator for ops::RangeInclusive<$t> { } )*) } @@ -202,9 +200,7 @@ macro_rules! range_trusted_len_impl { macro_rules! range_incl_trusted_len_impl { ($($t:ty)*) => ($( - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] unsafe impl TrustedLen for ops::RangeInclusive<$t> { } )*) } @@ -328,7 +324,7 @@ impl FusedIterator for ops::RangeFrom {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for ops::RangeFrom {} -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl Iterator for ops::RangeInclusive { type Item = A; @@ -422,7 +418,7 @@ impl Iterator for ops::RangeInclusive { } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl DoubleEndedIterator for ops::RangeInclusive { #[inline] fn next_back(&mut self) -> Option { diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index 70ef4487334..234970a81fa 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -191,7 +191,7 @@ pub use self::index::{Index, IndexMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] pub use self::range::{RangeInclusive, RangeToInclusive}; #[unstable(feature = "try_trait", issue = "42327")] diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 1d9c0f873b3..9bdd8094f61 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -283,7 +283,7 @@ impl> RangeTo { /// # Examples /// /// ``` -/// #![feature(inclusive_range,inclusive_range_syntax)] +/// #![feature(inclusive_range_syntax)] /// /// assert_eq!((3..=5), std::ops::RangeInclusive { start: 3, end: 5 }); /// assert_eq!(3 + 4 + 5, (3..=5).sum()); @@ -293,21 +293,17 @@ impl> RangeTo { /// assert_eq!(arr[1..=2], [ 1,2 ]); // RangeInclusive /// ``` #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeInclusive { /// The lower bound of the range (inclusive). - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] pub start: Idx, /// The upper bound of the range (inclusive). - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] pub end: Idx, } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl fmt::Debug for RangeInclusive { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "{:?}..={:?}", self.start, self.end) @@ -385,7 +381,7 @@ impl> RangeInclusive { /// The `..=end` syntax is a `RangeToInclusive`: /// /// ``` -/// #![feature(inclusive_range,inclusive_range_syntax)] +/// #![feature(inclusive_range_syntax)] /// assert_eq!((..=5), std::ops::RangeToInclusive{ end: 5 }); /// ``` /// @@ -417,16 +413,14 @@ impl> RangeInclusive { /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html #[derive(Copy, Clone, PartialEq, Eq, Hash)] -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeToInclusive { /// The upper bound of the range (inclusive) - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] pub end: Idx, } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl fmt::Debug for RangeToInclusive { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "..={:?}", self.end) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 19fe4dd36b6..0f1b7cb8fcc 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1039,7 +1039,7 @@ impl SliceIndex<[T]> for ops::RangeFull { } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl SliceIndex<[T]> for ops::RangeInclusive { type Output = [T]; @@ -1080,7 +1080,7 @@ impl SliceIndex<[T]> for ops::RangeInclusive { } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl SliceIndex<[T]> for ops::RangeToInclusive { type Output = [T]; diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index e225c9522bc..9cf862bd936 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1779,9 +1779,7 @@ mod traits { } } - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] impl ops::Index> for str { type Output = str; @@ -1791,9 +1789,7 @@ mod traits { } } - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] impl ops::Index> for str { type Output = str; @@ -1803,18 +1799,14 @@ mod traits { } } - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] impl ops::IndexMut> for str { #[inline] fn index_mut(&mut self, index: ops::RangeInclusive) -> &mut str { index.index_mut(self) } } - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] impl ops::IndexMut> for str { #[inline] fn index_mut(&mut self, index: ops::RangeToInclusive) -> &mut str { @@ -1997,9 +1989,7 @@ mod traits { } } - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] impl SliceIndex for ops::RangeInclusive { type Output = str; #[inline] @@ -2042,9 +2032,7 @@ mod traits { - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] impl SliceIndex for ops::RangeToInclusive { type Output = str; #[inline] diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 5bd5bca19c4..8f01fbeb30e 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -23,7 +23,6 @@ #![feature(fmt_internals)] #![feature(iterator_step_by)] #![feature(i128_type)] -#![feature(inclusive_range)] #![feature(inclusive_range_syntax)] #![feature(iterator_try_fold)] #![feature(iterator_flatten)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 51882385b2e..149ea96b636 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -54,7 +54,6 @@ #![feature(fs_read_write)] #![feature(i128)] #![feature(i128_type)] -#![feature(inclusive_range)] #![feature(inclusive_range_syntax)] #![cfg_attr(windows, feature(libc))] #![feature(match_default_bindings)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 5510e219780..31eb203eefe 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -29,7 +29,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(fs_read_write)] #![feature(i128_type)] #![feature(inclusive_range_syntax)] -#![feature(inclusive_range)] #![feature(macro_vis_matcher)] #![feature(match_default_bindings)] #![feature(exhaustive_patterns)] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 39eb38658fe..a9334461825 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -26,7 +26,6 @@ #![allow(unused_attributes)] #![feature(i128_type)] #![feature(i128)] -#![feature(inclusive_range)] #![feature(inclusive_range_syntax)] #![feature(libc)] #![feature(quote)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index eea0e6b6752..c71a562b0d1 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -271,7 +271,6 @@ #![feature(heap_api)] #![feature(i128)] #![feature(i128_type)] -#![feature(inclusive_range)] #![feature(int_error_internals)] #![feature(integer_atomics)] #![feature(into_cow)] diff --git a/src/test/compile-fail/range_inclusive_gate.rs b/src/test/compile-fail/range_inclusive_gate.rs deleted file mode 100644 index 5b063dc1137..00000000000 --- a/src/test/compile-fail/range_inclusive_gate.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Make sure that #![feature(inclusive_range)] is required. - -#![feature(inclusive_range_syntax)] -// #![feature(inclusive_range)] - -pub fn main() { - let _: std::ops::RangeInclusive<_> = { use std::intrinsics; 1 } ..= { use std::intrinsics; 2 }; - //~^ ERROR use of unstable library feature 'inclusive_range' - //~| ERROR core_intrinsics - //~| ERROR core_intrinsics -} diff --git a/src/test/compile-fail/range_traits-1.rs b/src/test/compile-fail/range_traits-1.rs index f1ea8b04e5a..7645dbb1a6d 100644 --- a/src/test/compile-fail/range_traits-1.rs +++ b/src/test/compile-fail/range_traits-1.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(inclusive_range)] - use std::ops::*; #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] diff --git a/src/test/compile-fail/range_traits-6.rs b/src/test/compile-fail/range_traits-6.rs index 7c62711feae..f9510b5061c 100644 --- a/src/test/compile-fail/range_traits-6.rs +++ b/src/test/compile-fail/range_traits-6.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(inclusive_range)] - use std::ops::*; #[derive(Copy, Clone)] //~ ERROR Copy diff --git a/src/test/compile-fail/range_traits-7.rs b/src/test/compile-fail/range_traits-7.rs index b6fec773a77..871b55b85cf 100644 --- a/src/test/compile-fail/range_traits-7.rs +++ b/src/test/compile-fail/range_traits-7.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs, inclusive_range)] +#![feature(rustc_attrs)] use std::ops::*; diff --git a/src/test/parse-fail/range_inclusive.rs b/src/test/parse-fail/range_inclusive.rs index cc32b9903b5..6c6caa1e649 100644 --- a/src/test/parse-fail/range_inclusive.rs +++ b/src/test/parse-fail/range_inclusive.rs @@ -10,7 +10,7 @@ // Make sure that inclusive ranges with no end point don't parse. -#![feature(inclusive_range_syntax, inclusive_range)] +#![feature(inclusive_range_syntax)] pub fn main() { for _ in 1..= {} //~ERROR inclusive range with no end diff --git a/src/test/parse-fail/range_inclusive_dotdotdot.rs b/src/test/parse-fail/range_inclusive_dotdotdot.rs index a4c36a2f0ba..8a24038638b 100644 --- a/src/test/parse-fail/range_inclusive_dotdotdot.rs +++ b/src/test/parse-fail/range_inclusive_dotdotdot.rs @@ -12,7 +12,7 @@ // Make sure that inclusive ranges with `...` syntax don't parse. -#![feature(inclusive_range_syntax, inclusive_range)] +#![feature(inclusive_range_syntax)] use std::ops::RangeToInclusive; diff --git a/src/test/parse-fail/range_inclusive_gate.rs b/src/test/parse-fail/range_inclusive_gate.rs index 6b6afc504e1..c8c84000e41 100644 --- a/src/test/parse-fail/range_inclusive_gate.rs +++ b/src/test/parse-fail/range_inclusive_gate.rs @@ -12,7 +12,7 @@ // Make sure that #![feature(inclusive_range_syntax)] is required. -// #![feature(inclusive_range_syntax, inclusive_range)] +// #![feature(inclusive_range_syntax)] macro_rules! m { () => { for _ in 1..=10 {} } //~ ERROR inclusive range syntax is experimental diff --git a/src/test/run-pass/range_inclusive.rs b/src/test/run-pass/range_inclusive.rs index 71e11804052..29947860ff6 100644 --- a/src/test/run-pass/range_inclusive.rs +++ b/src/test/run-pass/range_inclusive.rs @@ -10,7 +10,7 @@ // Test inclusive range syntax. -#![feature(inclusive_range_syntax, inclusive_range, iterator_step_by)] +#![feature(inclusive_range_syntax, iterator_step_by)] use std::ops::{RangeInclusive, RangeToInclusive}; -- cgit 1.4.1-3-g733a5 From 92d1f8d8e4be62e6f4dc32bc57f9d44f53117ec9 Mon Sep 17 00:00:00 2001 From: kennytm Date: Sun, 28 Jan 2018 03:19:29 +0800 Subject: Stabilize `inclusive_range_syntax` language feature. Stabilize the syntax `a..=b` and `..=b`. --- .../language-features/inclusive-range-syntax.md | 20 ------ src/liballoc/tests/lib.rs | 2 +- src/libcore/lib.rs | 2 +- src/libcore/ops/range.rs | 19 ++---- src/libcore/tests/lib.rs | 2 +- src/librustc/lib.rs | 2 +- src/librustc_incremental/lib.rs | 2 +- src/librustc_mir/lib.rs | 2 +- src/librustc_trans/lib.rs | 2 +- src/libsyntax/diagnostic_list.rs | 4 -- src/libsyntax/feature_gate.rs | 10 +-- .../incremental/hashes/indexing_expressions.rs | 1 - src/test/parse-fail/range_inclusive.rs | 2 - src/test/parse-fail/range_inclusive_dotdotdot.rs | 2 - src/test/parse-fail/range_inclusive_gate.rs | 74 ---------------------- src/test/run-pass/range_inclusive.rs | 2 +- src/test/run-pass/range_inclusive_gate.rs | 3 +- src/test/ui/impossible_range.rs | 2 - src/test/ui/impossible_range.stderr | 4 +- 19 files changed, 19 insertions(+), 138 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/inclusive-range-syntax.md delete mode 100644 src/test/parse-fail/range_inclusive_gate.rs (limited to 'src/libcore') diff --git a/src/doc/unstable-book/src/language-features/inclusive-range-syntax.md b/src/doc/unstable-book/src/language-features/inclusive-range-syntax.md deleted file mode 100644 index 56f58803150..00000000000 --- a/src/doc/unstable-book/src/language-features/inclusive-range-syntax.md +++ /dev/null @@ -1,20 +0,0 @@ -# `inclusive_range_syntax` - -The tracking issue for this feature is: [#28237] - -[#28237]: https://github.com/rust-lang/rust/issues/28237 - ------------------------- - -To get a range that goes from 0 to 10 and includes the value 10, you -can write `0..=10`: - -```rust -#![feature(inclusive_range_syntax)] - -fn main() { - for i in 0..=10 { - println!("{}", i); - } -} -``` diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 168dbb2ce9b..f5deecd47e8 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -14,7 +14,7 @@ #![feature(alloc_system)] #![feature(attr_literals)] #![feature(box_syntax)] -#![feature(inclusive_range_syntax)] +#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(collection_placement)] #![feature(const_fn)] #![feature(drain_filter)] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index a947c9f0b7c..9aebe2e4ee4 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -79,7 +79,7 @@ #![feature(fn_must_use)] #![feature(fundamental)] #![feature(i128_type)] -#![feature(inclusive_range_syntax)] +#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(intrinsics)] #![feature(iterator_flatten)] #![feature(iterator_repeat_with)] diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 9bdd8094f61..32aa6508805 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -128,7 +128,7 @@ impl> Range { /// The range is empty if either side is incomparable: /// /// ``` - /// #![feature(range_is_empty,inclusive_range_syntax)] + /// #![feature(range_is_empty)] /// /// use std::f32::NAN; /// assert!(!(3.0..5.0).is_empty()); @@ -283,8 +283,6 @@ impl> RangeTo { /// # Examples /// /// ``` -/// #![feature(inclusive_range_syntax)] -/// /// assert_eq!((3..=5), std::ops::RangeInclusive { start: 3, end: 5 }); /// assert_eq!(3 + 4 + 5, (3..=5).sum()); /// @@ -316,7 +314,7 @@ impl> RangeInclusive { /// # Examples /// /// ``` - /// #![feature(range_contains,inclusive_range_syntax)] + /// #![feature(range_contains)] /// /// assert!(!(3..=5).contains(2)); /// assert!( (3..=5).contains(3)); @@ -337,7 +335,7 @@ impl> RangeInclusive { /// # Examples /// /// ``` - /// #![feature(range_is_empty,inclusive_range_syntax)] + /// #![feature(range_is_empty)] /// /// assert!(!(3..=5).is_empty()); /// assert!(!(3..=3).is_empty()); @@ -347,7 +345,7 @@ impl> RangeInclusive { /// The range is empty if either side is incomparable: /// /// ``` - /// #![feature(range_is_empty,inclusive_range_syntax)] + /// #![feature(range_is_empty)] /// /// use std::f32::NAN; /// assert!(!(3.0..=5.0).is_empty()); @@ -358,7 +356,7 @@ impl> RangeInclusive { /// This method returns `true` after iteration has finished: /// /// ``` - /// #![feature(range_is_empty,inclusive_range_syntax)] + /// #![feature(range_is_empty)] /// /// let mut r = 3..=5; /// for _ in r.by_ref() {} @@ -381,7 +379,6 @@ impl> RangeInclusive { /// The `..=end` syntax is a `RangeToInclusive`: /// /// ``` -/// #![feature(inclusive_range_syntax)] /// assert_eq!((..=5), std::ops::RangeToInclusive{ end: 5 }); /// ``` /// @@ -389,8 +386,6 @@ impl> RangeInclusive { /// `for` loop directly. This won't compile: /// /// ```compile_fail,E0277 -/// #![feature(inclusive_range_syntax)] -/// /// // error[E0277]: the trait bound `std::ops::RangeToInclusive<{integer}>: /// // std::iter::Iterator` is not satisfied /// for i in ..=5 { @@ -402,8 +397,6 @@ impl> RangeInclusive { /// array elements up to and including the index indicated by `end`. /// /// ``` -/// #![feature(inclusive_range_syntax)] -/// /// let arr = [0, 1, 2, 3]; /// assert_eq!(arr[ ..=2], [0,1,2 ]); // RangeToInclusive /// assert_eq!(arr[1..=2], [ 1,2 ]); @@ -434,7 +427,7 @@ impl> RangeToInclusive { /// # Examples /// /// ``` - /// #![feature(range_contains,inclusive_range_syntax)] + /// #![feature(range_contains)] /// /// assert!( (..=5).contains(-1_000_000_000)); /// assert!( (..=5).contains(5)); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 8f01fbeb30e..85787f38f06 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -23,7 +23,7 @@ #![feature(fmt_internals)] #![feature(iterator_step_by)] #![feature(i128_type)] -#![feature(inclusive_range_syntax)] +#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(iterator_try_fold)] #![feature(iterator_flatten)] #![feature(conservative_impl_trait)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 149ea96b636..ff2e8ea79d3 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -54,7 +54,7 @@ #![feature(fs_read_write)] #![feature(i128)] #![feature(i128_type)] -#![feature(inclusive_range_syntax)] +#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![cfg_attr(windows, feature(libc))] #![feature(match_default_bindings)] #![feature(macro_lifetime_matcher)] diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 65fbd9d0bf8..d7ccf9d5562 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -18,7 +18,7 @@ #![feature(conservative_impl_trait)] #![feature(fs_read_write)] #![feature(i128_type)] -#![feature(inclusive_range_syntax)] +#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(specialization)] extern crate graphviz; diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 31eb203eefe..ad7a5c94022 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -28,7 +28,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(dyn_trait)] #![feature(fs_read_write)] #![feature(i128_type)] -#![feature(inclusive_range_syntax)] +#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(macro_vis_matcher)] #![feature(match_default_bindings)] #![feature(exhaustive_patterns)] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index a9334461825..f2b76eb57d6 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -26,7 +26,7 @@ #![allow(unused_attributes)] #![feature(i128_type)] #![feature(i128)] -#![feature(inclusive_range_syntax)] +#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(libc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 549ef88afcc..1f87c1b94c5 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -218,8 +218,6 @@ An inclusive range was used with no end. Erroneous code example: ```compile_fail,E0586 -#![feature(inclusive_range_syntax)] - fn main() { let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1]; let x = &tmp[1..=]; // error: inclusive range was used with no end @@ -239,8 +237,6 @@ fn main() { Or put an end to your inclusive range: ``` -#![feature(inclusive_range_syntax)] - fn main() { let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1]; let x = &tmp[1..=3]; // ok! diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 91364fe6ed4..a415117b599 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -268,9 +268,6 @@ declare_features! ( // rustc internal (active, abi_vectorcall, "1.7.0", None, None), - // a..=b and ..=b - (active, inclusive_range_syntax, "1.7.0", Some(28237), None), - // X..Y patterns (active, exclusive_range_pattern, "1.11.0", Some(37854), None), @@ -554,6 +551,8 @@ declare_features! ( (accepted, match_beginning_vert, "1.25.0", Some(44101), None), // Nested groups in `use` (RFC 2128) (accepted, use_nested_groups, "1.25.0", Some(44494), None), + // a..=b and ..=b + (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1592,11 +1591,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, type_ascription, e.span, "type ascription is experimental"); } - ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => { - gate_feature_post!(&self, inclusive_range_syntax, - e.span, - "inclusive range syntax is experimental"); - } ast::ExprKind::InPlace(..) => { gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN); } diff --git a/src/test/incremental/hashes/indexing_expressions.rs b/src/test/incremental/hashes/indexing_expressions.rs index e66e239b33c..fb63aa857aa 100644 --- a/src/test/incremental/hashes/indexing_expressions.rs +++ b/src/test/incremental/hashes/indexing_expressions.rs @@ -23,7 +23,6 @@ #![allow(warnings)] #![feature(rustc_attrs)] #![crate_type="rlib"] -#![feature(inclusive_range_syntax)] // Change simple index --------------------------------------------------------- #[cfg(cfail1)] diff --git a/src/test/parse-fail/range_inclusive.rs b/src/test/parse-fail/range_inclusive.rs index 6c6caa1e649..2aa7d6d6cd7 100644 --- a/src/test/parse-fail/range_inclusive.rs +++ b/src/test/parse-fail/range_inclusive.rs @@ -10,8 +10,6 @@ // Make sure that inclusive ranges with no end point don't parse. -#![feature(inclusive_range_syntax)] - pub fn main() { for _ in 1..= {} //~ERROR inclusive range with no end //~^HELP bounded at the end diff --git a/src/test/parse-fail/range_inclusive_dotdotdot.rs b/src/test/parse-fail/range_inclusive_dotdotdot.rs index 8a24038638b..fa6474717d3 100644 --- a/src/test/parse-fail/range_inclusive_dotdotdot.rs +++ b/src/test/parse-fail/range_inclusive_dotdotdot.rs @@ -12,8 +12,6 @@ // Make sure that inclusive ranges with `...` syntax don't parse. -#![feature(inclusive_range_syntax)] - use std::ops::RangeToInclusive; fn return_range_to() -> RangeToInclusive { diff --git a/src/test/parse-fail/range_inclusive_gate.rs b/src/test/parse-fail/range_inclusive_gate.rs deleted file mode 100644 index c8c84000e41..00000000000 --- a/src/test/parse-fail/range_inclusive_gate.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// gate-test-inclusive_range_syntax - -// Make sure that #![feature(inclusive_range_syntax)] is required. - -// #![feature(inclusive_range_syntax)] - -macro_rules! m { - () => { for _ in 1..=10 {} } //~ ERROR inclusive range syntax is experimental -} - -#[cfg(nope)] -fn f() {} -#[cfg(not(nope))] -fn f() { - for _ in 1..=10 {} //~ ERROR inclusive range syntax is experimental -} - -#[cfg(nope)] -macro_rules! n { () => {} } -#[cfg(not(nope))] -macro_rules! n { - () => { for _ in 1..=10 {} } //~ ERROR inclusive range syntax is experimental -} - -macro_rules! o { - () => {{ - #[cfg(nope)] - fn g() {} - #[cfg(not(nope))] - fn g() { - for _ in 1..=10 {} //~ ERROR inclusive range syntax is experimental - } - - g(); - }} -} - -#[cfg(nope)] -macro_rules! p { () => {} } -#[cfg(not(nope))] -macro_rules! p { - () => {{ - #[cfg(nope)] - fn h() {} - #[cfg(not(nope))] - fn h() { - for _ in 1..=10 {} //~ ERROR inclusive range syntax is experimental - } - - h(); - }} -} - -pub fn main() { - for _ in 1..=10 {} //~ ERROR inclusive range syntax is experimental - for _ in ..=10 {} //~ ERROR inclusive range syntax is experimental - - f(); // not allowed in cfg'ed functions - - m!(); // not allowed in macros - n!(); // not allowed in cfg'ed macros - o!(); // not allowed in macros that output cfgs - p!(); // not allowed in cfg'ed macros that output cfgs -} diff --git a/src/test/run-pass/range_inclusive.rs b/src/test/run-pass/range_inclusive.rs index 29947860ff6..5d46bfab887 100644 --- a/src/test/run-pass/range_inclusive.rs +++ b/src/test/run-pass/range_inclusive.rs @@ -10,7 +10,7 @@ // Test inclusive range syntax. -#![feature(inclusive_range_syntax, iterator_step_by)] +#![feature(iterator_step_by)] use std::ops::{RangeInclusive, RangeToInclusive}; diff --git a/src/test/run-pass/range_inclusive_gate.rs b/src/test/run-pass/range_inclusive_gate.rs index 570087aedbb..6c2731fa5a9 100644 --- a/src/test/run-pass/range_inclusive_gate.rs +++ b/src/test/run-pass/range_inclusive_gate.rs @@ -9,8 +9,7 @@ // except according to those terms. // Test that you only need the syntax gate if you don't mention the structs. - -#![feature(inclusive_range_syntax)] +// (Obsoleted since both features are stabilized) fn main() { let mut count = 0; diff --git a/src/test/ui/impossible_range.rs b/src/test/ui/impossible_range.rs index 5c72c506e6b..073ed867bdb 100644 --- a/src/test/ui/impossible_range.rs +++ b/src/test/ui/impossible_range.rs @@ -10,8 +10,6 @@ // Make sure that invalid ranges generate an error during HIR lowering, not an ICE -#![feature(inclusive_range_syntax)] - pub fn main() { ..; 0..; diff --git a/src/test/ui/impossible_range.stderr b/src/test/ui/impossible_range.stderr index d941b522def..cfeaa53a6bb 100644 --- a/src/test/ui/impossible_range.stderr +++ b/src/test/ui/impossible_range.stderr @@ -1,5 +1,5 @@ error[E0586]: inclusive range with no end - --> $DIR/impossible_range.rs:20:8 + --> $DIR/impossible_range.rs:18:8 | LL | ..=; //~ERROR inclusive range with no end | ^ @@ -7,7 +7,7 @@ LL | ..=; //~ERROR inclusive range with no end = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) error[E0586]: inclusive range with no end - --> $DIR/impossible_range.rs:27:9 + --> $DIR/impossible_range.rs:25:9 | LL | 0..=; //~ERROR inclusive range with no end | ^ -- cgit 1.4.1-3-g733a5 From 939cfa251aeb34b4b1a11396af1a3396792c708d Mon Sep 17 00:00:00 2001 From: kennytm Date: Thu, 15 Mar 2018 02:50:55 +0800 Subject: Keep the fields of RangeInclusive unstable. --- src/liballoc/lib.rs | 1 + src/liballoc/tests/lib.rs | 1 + src/libcore/ops/range.rs | 6 ++++-- src/libcore/tests/lib.rs | 1 + src/librustc/lib.rs | 1 + src/librustc_mir/lib.rs | 1 + src/librustc_trans/lib.rs | 1 + 7 files changed, 10 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index cbfec554604..fb7f114ba1a 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -123,6 +123,7 @@ #![feature(on_unimplemented)] #![feature(exact_chunks)] #![feature(pointer_methods)] +#![feature(inclusive_range_fields)] #![cfg_attr(not(test), feature(fn_traits, placement_new_protocol, swap_with_slice, i128))] #![cfg_attr(test, feature(test, box_heap))] diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index f5deecd47e8..4fea2375558 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -29,6 +29,7 @@ #![feature(unboxed_closures)] #![feature(unicode)] #![feature(exact_chunks)] +#![feature(inclusive_range_fields)] extern crate alloc_system; extern crate std_unicode; diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 32aa6508805..be51f5239b0 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -283,6 +283,8 @@ impl> RangeTo { /// # Examples /// /// ``` +/// #![feature(inclusive_range_fields)] +/// /// assert_eq!((3..=5), std::ops::RangeInclusive { start: 3, end: 5 }); /// assert_eq!(3 + 4 + 5, (3..=5).sum()); /// @@ -294,10 +296,10 @@ impl> RangeTo { #[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeInclusive { /// The lower bound of the range (inclusive). - #[stable(feature = "inclusive_range", since = "1.26.0")] + #[unstable(feature = "inclusive_range_fields", issue = "49022")] pub start: Idx, /// The upper bound of the range (inclusive). - #[stable(feature = "inclusive_range", since = "1.26.0")] + #[unstable(feature = "inclusive_range_fields", issue = "49022")] pub end: Idx, } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 85787f38f06..e53964b5769 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -47,6 +47,7 @@ #![feature(exact_chunks)] #![feature(atomic_nand)] #![feature(reverse_bits)] +#![feature(inclusive_range_fields)] extern crate core; extern crate test; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index ff2e8ea79d3..77259f156e5 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -75,6 +75,7 @@ #![feature(trusted_len)] #![feature(catch_expr)] #![feature(test)] +#![feature(inclusive_range_fields)] #![recursion_limit="512"] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index ad7a5c94022..ff35412ea5b 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -39,6 +39,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(nonzero)] #![feature(underscore_lifetimes)] #![cfg_attr(stage0, feature(never_type))] +#![feature(inclusive_range_fields)] extern crate arena; #[macro_use] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index f2b76eb57d6..9b09dbf5276 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -33,6 +33,7 @@ #![feature(slice_patterns)] #![feature(conservative_impl_trait)] #![feature(optin_builtin_traits)] +#![feature(inclusive_range_fields)] use rustc::dep_graph::WorkProduct; use syntax_pos::symbol::Symbol; -- cgit 1.4.1-3-g733a5 From 6fbdaf42097f2e8fda09692693c7a27acb4c0ef2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 15 Mar 2018 18:04:45 +0100 Subject: unstabilize FusedIterator for Flatten since Flatten is unstable --- src/libcore/iter/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index a6802d606ca..b1b783b47c7 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -2605,7 +2605,7 @@ impl DoubleEndedIterator for Flatten } } -#[stable(feature = "fused", since = "1.26.0")] +#[unstable(feature = "iterator_flatten", issue = "48213")] impl FusedIterator for Flatten where I: FusedIterator, U: Iterator, I::Item: IntoIterator {} -- cgit 1.4.1-3-g733a5 From 81d0ecef2c4ba5ebb36a72f76adbce1b229fb856 Mon Sep 17 00:00:00 2001 From: boats Date: Thu, 15 Mar 2018 16:16:11 -0700 Subject: Pin and PinBox are fundamental. --- src/liballoc/boxed.rs | 1 + src/libcore/mem.rs | 1 + 2 files changed, 2 insertions(+) (limited to 'src/libcore') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 5e5d7b91720..46d3ccb9de5 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -899,6 +899,7 @@ impl Generator for Box /// A pinned, heap allocated reference. #[unstable(feature = "pin", issue = "0")] +#[fundamental] pub struct PinBox { inner: Box, } diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 792d71732e6..e960b5ae758 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1112,6 +1112,7 @@ pub unsafe fn unreachable() -> ! { /// safe to move a value out of a pinned reference unless the type of that /// value implements the `Unpin` trait. #[unstable(feature = "pin", issue = "0")] +#[fundamental] pub struct Pin<'a, T: ?Sized + 'a> { inner: &'a mut T, } -- cgit 1.4.1-3-g733a5 From 15bab452f30ce6cb67a849f13e9de80586a8b180 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Thu, 15 Mar 2018 14:14:48 +0800 Subject: Add From for TryFromIntError --- src/libcore/num/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index faeb87cf944..4583e45bb12 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3595,6 +3595,13 @@ impl fmt::Display for TryFromIntError { } } +#[unstable(feature = "try_from", issue = "33417")] +impl From for TryFromIntError { + fn from(never: !) -> TryFromIntError { + never + } +} + // no possible bounds violation macro_rules! try_from_unbounded { ($source:ty, $($target:ty),*) => {$( -- cgit 1.4.1-3-g733a5 From 9e6268191205c42bc7958d949fa48811d60857f9 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sat, 17 Mar 2018 10:32:29 +0900 Subject: Remove core::fmt::num::Decimal Before ebf9e1aaf6, it was used for Display::fmt, but ebf9e1aaf6 replaced that with a faster implementation, and nothing else uses it. --- src/libcore/fmt/num.rs | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index 2992e7cf8db..57e3b849ae1 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -107,10 +107,6 @@ struct Binary; #[derive(Clone, PartialEq)] struct Octal; -/// A decimal (base 10) radix -#[derive(Clone, PartialEq)] -struct Decimal; - /// A hexadecimal (base 16) radix, formatted with lower-case characters #[derive(Clone, PartialEq)] struct LowerHex; @@ -136,7 +132,6 @@ macro_rules! radix { radix! { Binary, 2, "0b", x @ 0 ... 1 => b'0' + x } radix! { Octal, 8, "0o", x @ 0 ... 7 => b'0' + x } -radix! { Decimal, 10, "", x @ 0 ... 9 => b'0' + x } radix! { LowerHex, 16, "0x", x @ 0 ... 9 => b'0' + x, x @ 10 ... 15 => b'a' + (x - 10) } radix! { UpperHex, 16, "0x", x @ 0 ... 9 => b'0' + x, -- cgit 1.4.1-3-g733a5 From 38cbdcd0b1791e68c9485d8db6e81cf2d6765572 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sat, 17 Mar 2018 10:42:32 +0900 Subject: Use an uninitialized buffer in GenericRadix::fmt_int, like in Display::fmt for numeric types The code using a slice of that buffer is only ever going to use bytes that are subsequently initialized. --- src/libcore/fmt/num.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index 2992e7cf8db..c3843cae27a 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -65,7 +65,7 @@ trait GenericRadix { // characters for a base 2 number. let zero = T::zero(); let is_nonnegative = x >= zero; - let mut buf = [0; 128]; + let mut buf: [u8; 128] = unsafe { mem::uninitialized() }; let mut curr = buf.len(); let base = T::from_u8(self.base()); if is_nonnegative { -- cgit 1.4.1-3-g733a5 From b910d6b93cdbe075b157621432d271e6afcaa20f Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sat, 17 Mar 2018 09:45:03 +0900 Subject: Use associated consts for GenericRadix base and prefix --- src/libcore/fmt/num.rs | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index 2992e7cf8db..6378358c2dd 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -49,15 +49,13 @@ doit! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize } #[doc(hidden)] trait GenericRadix { /// The number of digits. - fn base(&self) -> u8; + const BASE: u8; /// A radix-specific prefix string. - fn prefix(&self) -> &'static str { - "" - } + const PREFIX: &'static str; /// Converts an integer to corresponding radix digit. - fn digit(&self, x: u8) -> u8; + fn digit(x: u8) -> u8; /// Format an integer using the radix using a formatter. fn fmt_int(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result { @@ -67,14 +65,14 @@ trait GenericRadix { let is_nonnegative = x >= zero; let mut buf = [0; 128]; let mut curr = buf.len(); - let base = T::from_u8(self.base()); + let base = T::from_u8(Self::BASE); if is_nonnegative { // Accumulate each digit of the number from the least significant // to the most significant figure. for byte in buf.iter_mut().rev() { - let n = x % base; // Get the current place value. - x = x / base; // Deaccumulate the number. - *byte = self.digit(n.to_u8()); // Store the digit in the buffer. + let n = x % base; // Get the current place value. + x = x / base; // Deaccumulate the number. + *byte = Self::digit(n.to_u8()); // Store the digit in the buffer. curr -= 1; if x == zero { // No more digits left to accumulate. @@ -84,9 +82,9 @@ trait GenericRadix { } else { // Do the same as above, but accounting for two's complement. for byte in buf.iter_mut().rev() { - let n = zero - (x % base); // Get the current place value. - x = x / base; // Deaccumulate the number. - *byte = self.digit(n.to_u8()); // Store the digit in the buffer. + let n = zero - (x % base); // Get the current place value. + x = x / base; // Deaccumulate the number. + *byte = Self::digit(n.to_u8()); // Store the digit in the buffer. curr -= 1; if x == zero { // No more digits left to accumulate. @@ -95,7 +93,7 @@ trait GenericRadix { } } let buf = unsafe { str::from_utf8_unchecked(&buf[curr..]) }; - f.pad_integral(is_nonnegative, self.prefix(), buf) + f.pad_integral(is_nonnegative, Self::PREFIX, buf) } } @@ -122,12 +120,12 @@ struct UpperHex; macro_rules! radix { ($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => { impl GenericRadix for $T { - fn base(&self) -> u8 { $base } - fn prefix(&self) -> &'static str { $prefix } - fn digit(&self, x: u8) -> u8 { + const BASE: u8 = $base; + const PREFIX: &'static str = $prefix; + fn digit(x: u8) -> u8 { match x { $($x => $conv,)+ - x => panic!("number not in the range 0..{}: {}", self.base() - 1, x), + x => panic!("number not in the range 0..{}: {}", Self::BASE - 1, x), } } } -- cgit 1.4.1-3-g733a5 From c5f020a64014d461ce997ea6e2e801f17aa44b08 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 17 Mar 2018 10:40:49 +0100 Subject: Make the deprecated unstable SipHasher24 type private. It is still used by the deprecated *stable* `SipHasher` type. --- src/libcore/hash/mod.rs | 2 +- src/libcore/hash/sip.rs | 45 ++++++------------------------------------- src/libcore/tests/hash/sip.rs | 12 ++++++------ 3 files changed, 13 insertions(+), 46 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 15545a04b64..90d9ab3644a 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -101,7 +101,7 @@ pub use self::sip::SipHasher; #[unstable(feature = "sip_hash_13", issue = "34767")] #[allow(deprecated)] -pub use self::sip::{SipHasher13, SipHasher24}; +pub use self::sip::SipHasher13; mod sip; diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index 4e4d9b3f1e2..7790118fbde 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -38,7 +38,7 @@ pub struct SipHasher13 { #[rustc_deprecated(since = "1.13.0", reason = "use `std::collections::hash_map::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] -pub struct SipHasher24 { +struct SipHasher24 { hasher: Hasher, } @@ -156,7 +156,9 @@ impl SipHasher { #[rustc_deprecated(since = "1.13.0", reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher { - SipHasher(SipHasher24::new_with_keys(key0, key1)) + SipHasher(SipHasher24 { + hasher: Hasher::new_with_keys(key0, key1) + }) } } @@ -182,28 +184,6 @@ impl SipHasher13 { } } -impl SipHasher24 { - /// Creates a new `SipHasher24` with the two initial keys set to 0. - #[inline] - #[unstable(feature = "sip_hash_13", issue = "34767")] - #[rustc_deprecated(since = "1.13.0", - reason = "use `std::collections::hash_map::DefaultHasher` instead")] - pub fn new() -> SipHasher24 { - SipHasher24::new_with_keys(0, 0) - } - - /// Creates a `SipHasher24` that is keyed off the provided keys. - #[inline] - #[unstable(feature = "sip_hash_13", issue = "34767")] - #[rustc_deprecated(since = "1.13.0", - reason = "use `std::collections::hash_map::DefaultHasher` instead")] - pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher24 { - SipHasher24 { - hasher: Hasher::new_with_keys(key0, key1) - } - } -} - impl Hasher { #[inline] fn new_with_keys(key0: u64, key1: u64) -> Hasher { @@ -271,12 +251,12 @@ impl Hasher { impl super::Hasher for SipHasher { #[inline] fn write(&mut self, msg: &[u8]) { - self.0.write(msg) + self.0.hasher.write(msg) } #[inline] fn finish(&self) -> u64 { - self.0.finish() + self.0.hasher.finish() } } @@ -293,19 +273,6 @@ impl super::Hasher for SipHasher13 { } } -#[unstable(feature = "sip_hash_13", issue = "34767")] -impl super::Hasher for SipHasher24 { - #[inline] - fn write(&mut self, msg: &[u8]) { - self.hasher.write(msg) - } - - #[inline] - fn finish(&self) -> u64 { - self.hasher.finish() - } -} - impl super::Hasher for Hasher { // see short_write comment for explanation #[inline] diff --git a/src/libcore/tests/hash/sip.rs b/src/libcore/tests/hash/sip.rs index c6dd41798f2..bad858011e9 100644 --- a/src/libcore/tests/hash/sip.rs +++ b/src/libcore/tests/hash/sip.rs @@ -11,7 +11,7 @@ #![allow(deprecated)] use core::hash::{Hash, Hasher}; -use core::hash::{SipHasher, SipHasher13, SipHasher24}; +use core::hash::{SipHasher, SipHasher13}; use core::{slice, mem}; // Hash just the bytes of the slice, without length prefix @@ -224,14 +224,14 @@ fn test_siphash_2_4() { let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08; let mut buf = Vec::new(); let mut t = 0; - let mut state_inc = SipHasher24::new_with_keys(k0, k1); + let mut state_inc = SipHasher::new_with_keys(k0, k1); while t < 64 { let vec = u8to64_le!(vecs[t], 0); - let out = hash_with(SipHasher24::new_with_keys(k0, k1), &Bytes(&buf)); + let out = hash_with(SipHasher::new_with_keys(k0, k1), &Bytes(&buf)); assert_eq!(vec, out); - let full = hash_with(SipHasher24::new_with_keys(k0, k1), &Bytes(&buf)); + let full = hash_with(SipHasher::new_with_keys(k0, k1), &Bytes(&buf)); let i = state_inc.finish(); assert_eq!(full, i); @@ -322,13 +322,13 @@ fn test_hash_no_concat_alias() { #[test] fn test_write_short_works() { let test_usize = 0xd0c0b0a0usize; - let mut h1 = SipHasher24::new(); + let mut h1 = SipHasher::new(); h1.write_usize(test_usize); h1.write(b"bytes"); h1.write(b"string"); h1.write_u8(0xFFu8); h1.write_u8(0x01u8); - let mut h2 = SipHasher24::new(); + let mut h2 = SipHasher::new(); h2.write(unsafe { slice::from_raw_parts(&test_usize as *const _ as *const u8, mem::size_of::()) -- cgit 1.4.1-3-g733a5 From e09dbbc39eeecbf6a8122d86297a1e8701aca26b Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 17 Mar 2018 10:05:23 +0100 Subject: Add an example of lossy decoding to str::Utf8Error docs --- src/libcore/str/mod.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 9cf862bd936..1185b7acaae 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -165,6 +165,37 @@ Section: Creating a string /// /// [`String`]: ../../std/string/struct.String.html#method.from_utf8 /// [`&str`]: ../../std/str/fn.from_utf8.html +/// +/// # Examples +/// +/// This error type’s methods can be used to create functionality +/// similar to `String::from_utf8_lossy` without allocating heap memory: +/// +/// ``` +/// fn from_utf8_lossy(mut input: &[u8], mut push: F) where F: FnMut(&str) { +/// loop { +/// match ::std::str::from_utf8(input) { +/// Ok(valid) => { +/// push(valid); +/// break +/// } +/// Err(error) => { +/// let (valid, after_valid) = input.split_at(error.valid_up_to()); +/// unsafe { +/// push(::std::str::from_utf8_unchecked(valid)) +/// } +/// push("\u{FFFD}"); +/// +/// if let Some(invalid_sequence_length) = error.error_len() { +/// input = &after_valid[invalid_sequence_length..] +/// } else { +/// break +/// } +/// } +/// } +/// } +/// } +/// ``` #[derive(Copy, Eq, PartialEq, Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Utf8Error { -- cgit 1.4.1-3-g733a5 From 89ecb0d5424f4eb72de70c0b7b0c3fb819273728 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 17 Mar 2018 11:07:50 +0100 Subject: Mark deprecated unstable SipHasher13 as a doc-hidden impl detail of HashMap. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It stays in libcore rather than being private in HashMap’s module because it shares code with the deprecated *stable* `SipHasher` type. --- src/libcore/hash/mod.rs | 3 ++- src/libcore/hash/sip.rs | 11 ++++++----- src/libcore/tests/lib.rs | 2 +- src/libstd/lib.rs | 3 +-- 4 files changed, 10 insertions(+), 9 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 90d9ab3644a..ab714645675 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -99,8 +99,9 @@ use mem; #[allow(deprecated)] pub use self::sip::SipHasher; -#[unstable(feature = "sip_hash_13", issue = "34767")] +#[unstable(feature = "hashmap_internals", issue = "0")] #[allow(deprecated)] +#[doc(hidden)] pub use self::sip::SipHasher13; mod sip; diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index 7790118fbde..e3bdecdc4b1 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -23,10 +23,11 @@ use mem; /// (eg. `collections::HashMap` uses it by default). /// /// See: -#[unstable(feature = "sip_hash_13", issue = "34767")] +#[unstable(feature = "hashmap_internals", issue = "0")] #[rustc_deprecated(since = "1.13.0", reason = "use `std::collections::hash_map::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] +#[doc(hidden)] pub struct SipHasher13 { hasher: Hasher, } @@ -34,7 +35,7 @@ pub struct SipHasher13 { /// An implementation of SipHash 2-4. /// /// See: -#[unstable(feature = "sip_hash_13", issue = "34767")] +#[unstable(feature = "hashmap_internals", issue = "0")] #[rustc_deprecated(since = "1.13.0", reason = "use `std::collections::hash_map::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] @@ -165,7 +166,7 @@ impl SipHasher { impl SipHasher13 { /// Creates a new `SipHasher13` with the two initial keys set to 0. #[inline] - #[unstable(feature = "sip_hash_13", issue = "34767")] + #[unstable(feature = "hashmap_internals", issue = "0")] #[rustc_deprecated(since = "1.13.0", reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new() -> SipHasher13 { @@ -174,7 +175,7 @@ impl SipHasher13 { /// Creates a `SipHasher13` that is keyed off the provided keys. #[inline] - #[unstable(feature = "sip_hash_13", issue = "34767")] + #[unstable(feature = "hashmap_internals", issue = "0")] #[rustc_deprecated(since = "1.13.0", reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 { @@ -260,7 +261,7 @@ impl super::Hasher for SipHasher { } } -#[unstable(feature = "sip_hash_13", issue = "34767")] +#[unstable(feature = "hashmap_internals", issue = "0")] impl super::Hasher for SipHasher13 { #[inline] fn write(&mut self, msg: &[u8]) { diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index e53964b5769..1c876fa0bd7 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -21,6 +21,7 @@ #![feature(fixed_size_array)] #![feature(flt2dec)] #![feature(fmt_internals)] +#![feature(hashmap_internals)] #![feature(iterator_step_by)] #![feature(i128_type)] #![cfg_attr(stage0, feature(inclusive_range_syntax))] @@ -35,7 +36,6 @@ #![feature(range_is_empty)] #![feature(raw)] #![feature(refcell_replace_swap)] -#![feature(sip_hash_13)] #![feature(slice_patterns)] #![feature(sort_internals)] #![feature(specialization)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 70a1f82c9a1..62bef4bc499 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -267,7 +267,7 @@ #![feature(fn_traits)] #![feature(fnbox)] #![feature(generic_param_attrs)] -#![feature(hashmap_hasher)] +#![feature(hashmap_internals)] #![feature(heap_api)] #![feature(i128)] #![feature(i128_type)] @@ -298,7 +298,6 @@ #![feature(raw)] #![feature(rustc_attrs)] #![feature(stdsimd)] -#![feature(sip_hash_13)] #![feature(slice_bytes)] #![feature(slice_concat_ext)] #![feature(slice_internals)] -- cgit 1.4.1-3-g733a5 From 5bef034b198c58fd02a9e8a584a24fd516dc969c Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Sat, 17 Mar 2018 14:05:24 +0100 Subject: Bring back the phrase 'borrowing as' for what Borrow does. --- src/libcore/borrow.rs | 47 ++++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 25 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index c0f1989f879..0014bddb55c 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -12,7 +12,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -/// A trait identifying how borrowed data behaves. +/// A trait for borrowing data. /// /// In Rust, it is common to provide different representations of a type for /// different use cases. For instance, storage location and management for a @@ -24,40 +24,37 @@ /// [`str`]. This requires keeping additional information unnecessary for a /// simple, immutable string. /// -/// These types signal that they are a specialized representation of a basic -/// type `T` by implementing `Borrow`. The method `borrow` provides a way -/// to convert a reference to the type into a reference to this basic type -/// `T`. +/// These types provide access to the underlying data through references +/// to the type of that data. They are said to be ‘borrowed as’ that type. +/// For instance, a [`Box`] can be borrowed as `T` while a [`String`] +/// can be borrowed as `str`. +/// +/// Types express that they can be borrowed as some type `T` by implementing +/// `Borrow`, providing a reference to a `T` in the trait’s +/// [`borrow`] method. A type is free to borrow as several different types. +/// If it wishes to mutably borrow as the type – allowing the underlying data +/// to be modified, it can additionally implement [`BorrowMut`]. /// /// Further, when providing implementations for additional traits, it needs /// to be considered whether they should behave identical to those of the /// underlying type as a consequence of acting as a representation of that -/// underlying type. -/// -/// Generic code typically uses `Borrow` when it not only needs access -/// to a reference of the underlying type but relies on the identical -/// behavior of these additional trait implementations. These traits are -/// likely to appear as additional trait bounds. +/// underlying type. Generic code typically uses `Borrow` when it relies +/// on the identical behavior of these additional trait implementations. +/// These traits will likely appear as additional trait bounds. /// /// If generic code merely needs to work for all types that can /// provide a reference to related type `T`, it is often better to use /// [`AsRef`] as more types can safely implement it. /// -/// If a type implementing `Borrow` also wishes to allow mutable access -/// to the underlying type `T`, it can do so by implementing the companion -/// trait [`BorrowMut`]. -/// -/// Note also that it is perfectly fine for a single type to have multiple -/// implementations of `Borrow` for different `T`s. In fact, a blanket -/// implementation lets every type be at least a borrow of itself. -/// /// [`AsRef`]: ../../std/convert/trait.AsRef.html -/// [`BorrowMut`]: trait.BorrowMut.html +/// [`BorrowMut`]: trait.BorrowMut.html /// [`Box`]: ../../std/boxed/struct.Box.html /// [`Mutex`]: ../../std/sync/struct.Mutex.html /// [`Rc`]: ../../std/rc/struct.Rc.html /// [`str`]: ../../std/primitive.str.html /// [`String`]: ../../std/string/struct.String.html +/// [`borrow`]: #tymethod.borrow +/// /// /// # Examples /// @@ -113,10 +110,10 @@ /// `str` is available. /// /// Instead, the `get` method is generic over the type of the underlying key -/// data, called `Q` in the method signature above. It states that `K` is a -/// representation of `Q` by requiring that `K: Borrow`. By additionally -/// requiring `Q: Hash + Eq`, it demands that `K` and `Q` have -/// implementations of the `Hash` and `Eq` traits that produce identical +/// data, called `Q` in the method signature above. It states that `K` +/// borrows as a `Q` by requiring that `K: Borrow`. By additionally +/// requiring `Q: Hash + Eq`, it signals the requirement that `K` and `Q` +/// have implementations of the `Hash` and `Eq` traits that produce identical /// results. /// /// The implementation of `get` relies in particular on identical @@ -141,7 +138,7 @@ /// ``` /// /// Because two equal values need to produce the same hash value, the -/// implementation of `Hash` needs to reflect that, too: +/// implementation of `Hash` needs to ignore ASCII case, too: /// /// ``` /// # use std::hash::{Hash, Hasher}; -- cgit 1.4.1-3-g733a5 From d664b8954e83e74870a90b871161942d6e827aa6 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Sat, 17 Mar 2018 14:09:45 +0100 Subject: Rewrite the documentation for BorrowMut. --- src/libcore/borrow.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 0014bddb55c..7470512e2b2 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -191,7 +191,11 @@ pub trait Borrow { /// A trait for mutably borrowing data. /// -/// Similar to `Borrow`, but for mutable borrows. +/// As a companion to [`Borrow`] this trait allows a type to borrow as +/// an underlying type by providing a mutable reference. See [`Borrow`] +/// for more information on borrowing as another type. +/// +/// [`Borrow`]: trait.Borrow.html #[stable(feature = "rust1", since = "1.0.0")] pub trait BorrowMut : Borrow { /// Mutably borrows from an owned value. -- cgit 1.4.1-3-g733a5 From 7278e37d38226734dabf07b4453580868847edf6 Mon Sep 17 00:00:00 2001 From: Niv Kaminer Date: Sat, 9 Dec 2017 22:16:54 +0200 Subject: update FIXME(#6393) to point to issue 43234 (tracking issue for non-lexical lifetimes) --- src/libcore/iter/mod.rs | 2 +- src/librustc_mir/util/elaborate_drops.rs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index b1b783b47c7..1e8476d3880 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -1872,7 +1872,7 @@ impl Iterator for Peekable { #[inline] fn nth(&mut self, n: usize) -> Option { - // FIXME(#6393): merge these when borrow-checking gets better. + // FIXME(#43234): merge these when borrow-checking gets better. if n == 0 { match self.peeked.take() { Some(v) => v, diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index e95126c8a1a..19f33ef5d45 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -177,7 +177,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> }); } DropStyle::Conditional => { - let unwind = self.unwind; // FIXME(#6393) + let unwind = self.unwind; // FIXME(#43234) let succ = self.succ; let drop_bb = self.complete_drop(Some(DropFlagMode::Deep), succ, unwind); self.elaborator.patch().patch_terminator(bb, TerminatorKind::Goto { @@ -268,7 +268,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> // Clear the "master" drop flag at the end. This is needed // because the "master" drop protects the ADT's discriminant, // which is invalidated after the ADT is dropped. - let (succ, unwind) = (self.succ, self.unwind); // FIXME(#6393) + let (succ, unwind) = (self.succ, self.unwind); // FIXME(#43234) ( self.drop_flag_reset_block(DropFlagMode::Shallow, succ, unwind), unwind.map(|unwind| { @@ -344,7 +344,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let interior = self.place.clone().deref(); let interior_path = self.elaborator.deref_subpath(self.path); - let succ = self.succ; // FIXME(#6393) + let succ = self.succ; // FIXME(#43234) let unwind = self.unwind; let succ = self.box_free_block(ty, succ, unwind); let unwind_succ = self.unwind.map(|unwind| { @@ -717,7 +717,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> ptr_based) }); - let succ = self.succ; // FIXME(#6393) + let succ = self.succ; // FIXME(#43234) let loop_block = self.drop_loop( succ, cur, @@ -798,7 +798,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.open_drop_for_adt(def, substs) } ty::TyDynamic(..) => { - let unwind = self.unwind; // FIXME(#6393) + let unwind = self.unwind; // FIXME(#43234) let succ = self.succ; self.complete_drop(Some(DropFlagMode::Deep), succ, unwind) } @@ -849,7 +849,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> fn elaborated_drop_block<'a>(&mut self) -> BasicBlock { debug!("elaborated_drop_block({:?})", self); - let unwind = self.unwind; // FIXME(#6393) + let unwind = self.unwind; // FIXME(#43234) let succ = self.succ; let blk = self.drop_block(succ, unwind); self.elaborate_drop(blk); @@ -882,7 +882,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> args: vec![Operand::Move(self.place.clone())], destination: Some((unit_temp, target)), cleanup: None - }; // FIXME(#6393) + }; // FIXME(#43234) let free_block = self.new_block(unwind, call); let block_start = Location { block: free_block, statement_index: 0 }; -- cgit 1.4.1-3-g733a5 From e1b9bf07022d18fb44aeb3dd3870952f1bc17619 Mon Sep 17 00:00:00 2001 From: Niv Kaminer Date: Sat, 17 Mar 2018 11:04:33 +0200 Subject: update FIXME(#23442) to point to issue 45742 (Blanket impl of AsRef for Deref) --- src/libcore/convert.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index d3a83dc795c..2206910c93f 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -382,7 +382,7 @@ impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a mut T where T: AsRef } } -// FIXME (#23442): replace the above impls for &/&mut with the following more general one: +// FIXME (#45742): replace the above impls for &/&mut with the following more general one: // // As lifts over Deref // impl AsRef for D where D::Target: AsRef { // fn as_ref(&self) -> &U { @@ -399,7 +399,7 @@ impl<'a, T: ?Sized, U: ?Sized> AsMut for &'a mut T where T: AsMut } } -// FIXME (#23442): replace the above impl for &mut with the following more general one: +// FIXME (#45742): replace the above impl for &mut with the following more general one: // // AsMut lifts over DerefMut // impl AsMut for D where D::Target: AsMut { // fn as_mut(&mut self) -> &mut U { -- cgit 1.4.1-3-g733a5 From f40877feeb17c538a73fe6294d48af123251a8c5 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 16 Feb 2018 10:39:24 +0100 Subject: Add 12 num::NonZero* types for each primitive integer RFC: https://github.com/rust-lang/rfcs/pull/2307 --- src/libcore/nonzero.rs | 2 +- src/libcore/num/mod.rs | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 1 + src/libstd/num.rs | 11 +++++++ 4 files changed, 100 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 2c966eb3b57..c6a1dab5617 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -62,7 +62,7 @@ impl_zeroable_for_integer_types! { /// NULL or 0 that might allow certain optimizations. #[lang = "non_zero"] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] -pub struct NonZero(T); +pub struct NonZero(pub(crate) T); impl NonZero { /// Creates an instance of NonZero with the provided value. diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 09ab7060d37..d3556ef742b 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -15,9 +15,96 @@ use convert::{Infallible, TryFrom}; use fmt; use intrinsics; +use nonzero::NonZero; use ops; use str::FromStr; +macro_rules! impl_nonzero_fmt { + ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { + $( + #[$stability] + impl fmt::$Trait for $Ty { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.get().fmt(f) + } + } + )+ + } +} + +macro_rules! nonzero_integers { + ( #[$stability: meta] $( $Ty: ident($Int: ty); )+ ) => { + $( + /// An integer that is known not to equal zero. + /// + /// This may enable some memory layout optimization such as: + /// + /// ```rust + /// # #![feature(nonzero)] + /// use std::mem::size_of; + /// assert_eq!(size_of::>(), size_of::()); + /// ``` + #[$stability] + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] + pub struct $Ty(NonZero<$Int>); + + impl $Ty { + /// Create a non-zero without checking the value. + /// + /// # Safety + /// + /// The value must not be zero. + #[$stability] + #[inline] + pub const unsafe fn new_unchecked(n: $Int) -> Self { + $Ty(NonZero(n)) + } + + /// Create a non-zero if the given value is not zero. + #[$stability] + #[inline] + pub fn new(n: $Int) -> Option { + if n != 0 { + Some($Ty(NonZero(n))) + } else { + None + } + } + + /// Returns the value as a primitive type. + #[$stability] + #[inline] + pub fn get(self) -> $Int { + self.0 .0 + } + + } + + impl_nonzero_fmt! { + #[$stability] + (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty + } + )+ + } +} + +nonzero_integers! { + #[unstable(feature = "nonzero", issue = "27730")] + NonZeroU8(u8); NonZeroI8(i8); + NonZeroU16(u16); NonZeroI16(i16); + NonZeroU32(u32); NonZeroI32(i32); + NonZeroU64(u64); NonZeroI64(i64); + NonZeroUsize(usize); NonZeroIsize(isize); +} + +nonzero_integers! { + // Change this to `#[unstable(feature = "i128", issue = "35118")]` + // if other NonZero* integer types are stabilizied before 128-bit integers + #[unstable(feature = "nonzero", issue = "27730")] + NonZeroU128(u128); NonZeroI128(i128); +} + /// Provides intentionally-wrapped arithmetic on `T`. /// /// Operations like `+` on `u32` values is intended to never overflow, diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 70a1f82c9a1..5c0a83fde10 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -282,6 +282,7 @@ #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] #![feature(exhaustive_patterns)] +#![feature(nonzero)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] diff --git a/src/libstd/num.rs b/src/libstd/num.rs index a2c133954a3..5e0406ca220 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -21,6 +21,17 @@ pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError} #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::Wrapping; +#[unstable(feature = "nonzero", issue = "27730")] +pub use core::num::{ + NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, + NonZeroU64, NonZeroI64, NonZeroUsize, NonZeroIsize, +}; + +// Change this to `#[unstable(feature = "i128", issue = "35118")]` +// if other NonZero* integer types are stabilizied before 128-bit integers +#[unstable(feature = "nonzero", issue = "27730")] +pub use core::num::{NonZeroU128, NonZeroI128}; + #[cfg(test)] use fmt; #[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem}; -- cgit 1.4.1-3-g733a5 From 67f46ce1122121849890ad51c35f0eb6ded14b6f Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 16 Feb 2018 11:02:06 +0100 Subject: Use num::NonZero* instead of NonZero<_> in rustc and tests --- src/libcore/tests/nonzero.rs | 14 +++++----- src/librustc/ty/subst.rs | 6 ++--- .../obligation_forest/node_index.rs | 6 ++--- src/librustc_mir/dataflow/move_paths/mod.rs | 6 ++--- src/test/run-pass/enum-null-pointer-opt.rs | 9 +++---- src/test/run-pass/issue-23433.rs | 2 +- src/test/ui/print_type_sizes/niche-filling.rs | 31 ++++++++-------------- src/test/ui/print_type_sizes/niche-filling.stdout | 10 ++++--- 8 files changed, 38 insertions(+), 46 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/nonzero.rs b/src/libcore/tests/nonzero.rs index a795dd57504..9eaf7529dd3 100644 --- a/src/libcore/tests/nonzero.rs +++ b/src/libcore/tests/nonzero.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::nonzero::NonZero; +use core::num::NonZeroU32; use core::option::Option; use core::option::Option::{Some, None}; use std::mem::size_of; @@ -16,28 +16,28 @@ use std::mem::size_of; #[test] fn test_create_nonzero_instance() { let _a = unsafe { - NonZero::new_unchecked(21) + NonZeroU32::new_unchecked(21) }; } #[test] fn test_size_nonzero_in_option() { - assert_eq!(size_of::>(), size_of::>>()); + assert_eq!(size_of::(), size_of::>()); } #[test] fn test_match_on_nonzero_option() { let a = Some(unsafe { - NonZero::new_unchecked(42) + NonZeroU32::new_unchecked(42) }); match a { Some(val) => assert_eq!(val.get(), 42), - None => panic!("unexpected None while matching on Some(NonZero(_))") + None => panic!("unexpected None while matching on Some(NonZeroU32(_))") } - match unsafe { Some(NonZero::new_unchecked(43)) } { + match unsafe { Some(NonZeroU32::new_unchecked(43)) } { Some(val) => assert_eq!(val.get(), 43), - None => panic!("unexpected None while matching on Some(NonZero(_))") + None => panic!("unexpected None while matching on Some(NonZeroU32(_))") } } diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index a301049fe1c..e7b58ae1564 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -19,11 +19,11 @@ use syntax_pos::{Span, DUMMY_SP}; use rustc_data_structures::accumulate_vec::AccumulateVec; use core::intrinsics; -use core::nonzero::NonZero; use std::fmt; use std::iter; use std::marker::PhantomData; use std::mem; +use std::num::NonZeroUsize; /// An entity in the Rust typesystem, which can be one of /// several kinds (only types and lifetimes for now). @@ -32,7 +32,7 @@ use std::mem; /// indicate the type (`Ty` or `Region`) it points to. #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct Kind<'tcx> { - ptr: NonZero, + ptr: NonZeroUsize, marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>)> } @@ -63,7 +63,7 @@ impl<'tcx> UnpackedKind<'tcx> { Kind { ptr: unsafe { - NonZero::new_unchecked(ptr | tag) + NonZeroUsize::new_unchecked(ptr | tag) }, marker: PhantomData } diff --git a/src/librustc_data_structures/obligation_forest/node_index.rs b/src/librustc_data_structures/obligation_forest/node_index.rs index a72cc6b57ea..37512e4bcd5 100644 --- a/src/librustc_data_structures/obligation_forest/node_index.rs +++ b/src/librustc_data_structures/obligation_forest/node_index.rs @@ -8,18 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::nonzero::NonZero; +use std::num::NonZeroU32; use std::u32; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct NodeIndex { - index: NonZero, + index: NonZeroU32, } impl NodeIndex { pub fn new(value: usize) -> NodeIndex { assert!(value < (u32::MAX as usize)); - NodeIndex { index: NonZero::new((value as u32) + 1).unwrap() } + NodeIndex { index: NonZeroU32::new((value as u32) + 1).unwrap() } } pub fn get(self) -> usize { diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 7b6ebc6fba8..9f6cf8c036e 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -29,17 +29,17 @@ mod abs_domain; // (which is likely to yield a subtle off-by-one error). pub(crate) mod indexes { use std::fmt; - use core::nonzero::NonZero; + use std::num::NonZeroUsize; use rustc_data_structures::indexed_vec::Idx; macro_rules! new_index { ($Index:ident, $debug_name:expr) => { #[derive(Copy, Clone, PartialEq, Eq, Hash)] - pub struct $Index(NonZero); + pub struct $Index(NonZeroUsize); impl Idx for $Index { fn new(idx: usize) -> Self { - $Index(NonZero::new(idx + 1).unwrap()) + $Index(NonZeroUsize::new(idx + 1).unwrap()) } fn index(self) -> usize { self.0.get() - 1 diff --git a/src/test/run-pass/enum-null-pointer-opt.rs b/src/test/run-pass/enum-null-pointer-opt.rs index e296aff2782..12f17a1575e 100644 --- a/src/test/run-pass/enum-null-pointer-opt.rs +++ b/src/test/run-pass/enum-null-pointer-opt.rs @@ -10,10 +10,9 @@ #![feature(nonzero, core)] -extern crate core; - -use core::nonzero::NonZero; use std::mem::size_of; +use std::num::NonZeroUsize; +use std::ptr::NonNull; use std::rc::Rc; use std::sync::Arc; @@ -59,8 +58,8 @@ fn main() { assert_eq!(size_of::<[Box; 1]>(), size_of::; 1]>>()); // Should apply to NonZero - assert_eq!(size_of::>(), size_of::>>()); - assert_eq!(size_of::>(), size_of::>>()); + assert_eq!(size_of::(), size_of::>()); + assert_eq!(size_of::>(), size_of::>>()); // Should apply to types that use NonZero internally assert_eq!(size_of::>(), size_of::>>()); diff --git a/src/test/run-pass/issue-23433.rs b/src/test/run-pass/issue-23433.rs index 7af732f561d..9547b2f08a6 100644 --- a/src/test/run-pass/issue-23433.rs +++ b/src/test/run-pass/issue-23433.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Don't fail if we encounter a NonZero<*T> where T is an unsized type +// Don't fail if we encounter a NonNull where T is an unsized type use std::ptr::NonNull; diff --git a/src/test/ui/print_type_sizes/niche-filling.rs b/src/test/ui/print_type_sizes/niche-filling.rs index 7f234e243e9..875883a2cca 100644 --- a/src/test/ui/print_type_sizes/niche-filling.rs +++ b/src/test/ui/print_type_sizes/niche-filling.rs @@ -14,7 +14,7 @@ // This file illustrates how niche-filling enums are handled, // modelled after cases like `Option<&u32>`, `Option` and such. // -// It uses NonZero directly, rather than `&_` or `Unique<_>`, because +// It uses NonZeroU32 rather than `&_` or `Unique<_>`, because // the test is not set up to deal with target-dependent pointer width. // // It avoids using u64/i64 because on some targets that is only 4-byte @@ -25,8 +25,7 @@ #![feature(nonzero)] #![allow(dead_code)] -extern crate core; -use core::nonzero::{NonZero, Zeroable}; +use std::num::NonZeroU32; pub enum MyOption { None, Some(T) } @@ -36,7 +35,7 @@ impl Default for MyOption { pub enum EmbeddedDiscr { None, - Record { pre: u8, val: NonZero, post: u16 }, + Record { pre: u8, val: NonZeroU32, post: u16 }, } impl Default for EmbeddedDiscr { @@ -44,32 +43,24 @@ impl Default for EmbeddedDiscr { } #[derive(Default)] -pub struct IndirectNonZero { +pub struct IndirectNonZero { pre: u8, - nested: NestedNonZero, + nested: NestedNonZero, post: u16, } -pub struct NestedNonZero { +pub struct NestedNonZero { pre: u8, - val: NonZero, + val: NonZeroU32, post: u16, } -impl Default for NestedNonZero { +impl Default for NestedNonZero { fn default() -> Self { - NestedNonZero { pre: 0, val: NonZero::new(T::one()).unwrap(), post: 0 } + NestedNonZero { pre: 0, val: NonZeroU32::new(1).unwrap(), post: 0 } } } -pub trait One { - fn one() -> Self; -} - -impl One for u32 { - fn one() -> Self { 1 } -} - pub enum Enum4 { One(A), Two(B), @@ -79,9 +70,9 @@ pub enum Enum4 { #[start] fn start(_: isize, _: *const *const u8) -> isize { - let _x: MyOption> = Default::default(); + let _x: MyOption = Default::default(); let _y: EmbeddedDiscr = Default::default(); - let _z: MyOption> = Default::default(); + let _z: MyOption = Default::default(); let _a: MyOption = Default::default(); let _b: MyOption = Default::default(); let _c: MyOption = Default::default(); diff --git a/src/test/ui/print_type_sizes/niche-filling.stdout b/src/test/ui/print_type_sizes/niche-filling.stdout index 0f53e7722dd..79f9ef5a231 100644 --- a/src/test/ui/print_type_sizes/niche-filling.stdout +++ b/src/test/ui/print_type_sizes/niche-filling.stdout @@ -1,9 +1,9 @@ -print-type-size type: `IndirectNonZero`: 12 bytes, alignment: 4 bytes +print-type-size type: `IndirectNonZero`: 12 bytes, alignment: 4 bytes print-type-size field `.nested`: 8 bytes print-type-size field `.post`: 2 bytes print-type-size field `.pre`: 1 bytes print-type-size end padding: 1 bytes -print-type-size type: `MyOption>`: 12 bytes, alignment: 4 bytes +print-type-size type: `MyOption`: 12 bytes, alignment: 4 bytes print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 12 bytes print-type-size field `.0`: 12 bytes @@ -14,7 +14,7 @@ print-type-size field `.val`: 4 bytes print-type-size field `.post`: 2 bytes print-type-size field `.pre`: 1 bytes print-type-size end padding: 1 bytes -print-type-size type: `NestedNonZero`: 8 bytes, alignment: 4 bytes +print-type-size type: `NestedNonZero`: 8 bytes, alignment: 4 bytes print-type-size field `.val`: 4 bytes print-type-size field `.post`: 2 bytes print-type-size field `.pre`: 1 bytes @@ -32,12 +32,14 @@ print-type-size type: `MyOption`: 4 bytes, alignment: 4 bytes print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes -print-type-size type: `MyOption>`: 4 bytes, alignment: 4 bytes +print-type-size type: `MyOption`: 4 bytes, alignment: 4 bytes print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes print-type-size type: `core::nonzero::NonZero`: 4 bytes, alignment: 4 bytes print-type-size field `.0`: 4 bytes +print-type-size type: `std::num::NonZeroU32`: 4 bytes, alignment: 4 bytes +print-type-size field `.0`: 4 bytes print-type-size type: `Enum4<(), (), (), MyOption>`: 2 bytes, alignment: 1 bytes print-type-size variant `One`: 0 bytes print-type-size field `.0`: 0 bytes -- cgit 1.4.1-3-g733a5 From 22f7a0295828c0d75b5487d89343e722b406dd5f Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 16 Feb 2018 11:14:35 +0100 Subject: Deprecate core::nonzero in favor of ptr::NonNull and num::NonZero* --- src/libcore/nonzero.rs | 5 ++++- src/libcore/num/mod.rs | 4 +++- src/libcore/ptr.rs | 11 +++++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index c6a1dab5617..59aaef9d66a 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -10,8 +10,11 @@ //! Exposes the NonZero lang item which provides optimization hints. #![unstable(feature = "nonzero", - reason = "needs an RFC to flesh out the design", + reason = "deprecated", issue = "27730")] +#![rustc_deprecated(reason = "use `std::ptr::NonNull` or `std::num::NonZero*` instead", + since = "1.26.0")] +#![allow(deprecated)] use ops::CoerceUnsized; diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index d3556ef742b..84f6ab9b764 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -15,7 +15,7 @@ use convert::{Infallible, TryFrom}; use fmt; use intrinsics; -use nonzero::NonZero; +#[allow(deprecated)] use nonzero::NonZero; use ops; use str::FromStr; @@ -46,9 +46,11 @@ macro_rules! nonzero_integers { /// assert_eq!(size_of::>(), size_of::()); /// ``` #[$stability] + #[allow(deprecated)] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct $Ty(NonZero<$Int>); + #[allow(deprecated)] impl $Ty { /// Create a non-zero without checking the value. /// diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 6270e5892b3..834a2ed09f7 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -23,7 +23,7 @@ use fmt; use hash; use marker::{PhantomData, Unsize}; use mem; -use nonzero::NonZero; +#[allow(deprecated)] use nonzero::NonZero; use cmp::Ordering::{self, Less, Equal, Greater}; @@ -2285,6 +2285,7 @@ impl PartialOrd for *mut T { #[unstable(feature = "ptr_internals", issue = "0", reason = "use NonNull instead and consider PhantomData \ (if you also use #[may_dangle]), Send, and/or Sync")] +#[allow(deprecated)] pub struct Unique { pointer: NonZero<*const T>, // NOTE: this marker has no consequences for variance, but is necessary @@ -2332,6 +2333,7 @@ impl Unique { } #[unstable(feature = "ptr_internals", issue = "0")] +#[allow(deprecated)] impl Unique { /// Creates a new `Unique`. /// @@ -2392,6 +2394,7 @@ impl fmt::Pointer for Unique { } #[unstable(feature = "ptr_internals", issue = "0")] +#[allow(deprecated)] impl<'a, T: ?Sized> From<&'a mut T> for Unique { fn from(reference: &'a mut T) -> Self { Unique { pointer: NonZero::from(reference), _marker: PhantomData } @@ -2399,6 +2402,7 @@ impl<'a, T: ?Sized> From<&'a mut T> for Unique { } #[unstable(feature = "ptr_internals", issue = "0")] +#[allow(deprecated)] impl<'a, T: ?Sized> From<&'a T> for Unique { fn from(reference: &'a T) -> Self { Unique { pointer: NonZero::from(reference), _marker: PhantomData } @@ -2436,7 +2440,7 @@ pub type Shared = NonNull; /// provide a public API that follows the normal shared XOR mutable rules of Rust. #[stable(feature = "nonnull", since = "1.25.0")] pub struct NonNull { - pointer: NonZero<*const T>, + #[allow(deprecated)] pointer: NonZero<*const T>, } /// `NonNull` pointers are not `Send` because the data they reference may be aliased. @@ -2463,6 +2467,7 @@ impl NonNull { } } +#[allow(deprecated)] impl NonNull { /// Creates a new `NonNull`. /// @@ -2581,6 +2586,7 @@ impl From> for NonNull { } #[stable(feature = "nonnull", since = "1.25.0")] +#[allow(deprecated)] impl<'a, T: ?Sized> From<&'a mut T> for NonNull { fn from(reference: &'a mut T) -> Self { NonNull { pointer: NonZero::from(reference) } @@ -2588,6 +2594,7 @@ impl<'a, T: ?Sized> From<&'a mut T> for NonNull { } #[stable(feature = "nonnull", since = "1.25.0")] +#[allow(deprecated)] impl<'a, T: ?Sized> From<&'a T> for NonNull { fn from(reference: &'a T) -> Self { NonNull { pointer: NonZero::from(reference) } -- cgit 1.4.1-3-g733a5 From 6d682c9adc12c5aee1bac37afa15f01b420be8ee Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 16 Feb 2018 11:45:44 +0100 Subject: Stop using deprecated NonZero APIs These will eventually be removed (though the NonZero lang item will likely stay). --- src/libcore/ptr.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 834a2ed09f7..4ab0ceb7967 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2341,17 +2341,21 @@ impl Unique { /// /// `ptr` must be non-null. pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { - Unique { pointer: NonZero::new_unchecked(ptr), _marker: PhantomData } + Unique { pointer: NonZero(ptr as _), _marker: PhantomData } } /// Creates a new `Unique` if `ptr` is non-null. pub fn new(ptr: *mut T) -> Option { - NonZero::new(ptr as *const T).map(|nz| Unique { pointer: nz, _marker: PhantomData }) + if !ptr.is_null() { + Some(Unique { pointer: NonZero(ptr as _), _marker: PhantomData }) + } else { + None + } } /// Acquires the underlying `*mut` pointer. pub fn as_ptr(self) -> *mut T { - self.pointer.get() as *mut T + self.pointer.0 as *mut T } /// Dereferences the content. @@ -2397,7 +2401,7 @@ impl fmt::Pointer for Unique { #[allow(deprecated)] impl<'a, T: ?Sized> From<&'a mut T> for Unique { fn from(reference: &'a mut T) -> Self { - Unique { pointer: NonZero::from(reference), _marker: PhantomData } + Unique { pointer: NonZero(reference as _), _marker: PhantomData } } } @@ -2405,7 +2409,7 @@ impl<'a, T: ?Sized> From<&'a mut T> for Unique { #[allow(deprecated)] impl<'a, T: ?Sized> From<&'a T> for Unique { fn from(reference: &'a T) -> Self { - Unique { pointer: NonZero::from(reference), _marker: PhantomData } + Unique { pointer: NonZero(reference as _), _marker: PhantomData } } } @@ -2476,19 +2480,23 @@ impl NonNull { /// `ptr` must be non-null. #[stable(feature = "nonnull", since = "1.25.0")] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { - NonNull { pointer: NonZero::new_unchecked(ptr) } + NonNull { pointer: NonZero(ptr as _) } } /// Creates a new `NonNull` if `ptr` is non-null. #[stable(feature = "nonnull", since = "1.25.0")] pub fn new(ptr: *mut T) -> Option { - NonZero::new(ptr as *const T).map(|nz| NonNull { pointer: nz }) + if !ptr.is_null() { + Some(NonNull { pointer: NonZero(ptr as _) }) + } else { + None + } } /// Acquires the underlying `*mut` pointer. #[stable(feature = "nonnull", since = "1.25.0")] pub fn as_ptr(self) -> *mut T { - self.pointer.get() as *mut T + self.pointer.0 as *mut T } /// Dereferences the content. @@ -2589,7 +2597,7 @@ impl From> for NonNull { #[allow(deprecated)] impl<'a, T: ?Sized> From<&'a mut T> for NonNull { fn from(reference: &'a mut T) -> Self { - NonNull { pointer: NonZero::from(reference) } + NonNull { pointer: NonZero(reference as _) } } } @@ -2597,6 +2605,6 @@ impl<'a, T: ?Sized> From<&'a mut T> for NonNull { #[allow(deprecated)] impl<'a, T: ?Sized> From<&'a T> for NonNull { fn from(reference: &'a T) -> Self { - NonNull { pointer: NonZero::from(reference) } + NonNull { pointer: NonZero(reference as _) } } } -- cgit 1.4.1-3-g733a5 From 7cf1f18cb9209156108e3871e11cb5d63f7f1cf1 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 16 Feb 2018 19:28:13 +0100 Subject: Test NonZero in a const item in a pattern. (This was buggy before https://github.com/rust-lang/rust/pull/46882) --- src/libcore/tests/nonzero.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/tests/nonzero.rs b/src/libcore/tests/nonzero.rs index 9eaf7529dd3..8d39298bac3 100644 --- a/src/libcore/tests/nonzero.rs +++ b/src/libcore/tests/nonzero.rs @@ -98,3 +98,26 @@ fn test_match_option_string() { None => panic!("unexpected None while matching on Some(String { ... })") } } + +mod atom { + use core::num::NonZeroU32; + + #[derive(PartialEq, Eq)] + pub struct Atom { + index: NonZeroU32, // private + } + pub const FOO_ATOM: Atom = Atom { index: unsafe { NonZeroU32::new_unchecked(7) } }; +} + +macro_rules! atom { + ("foo") => { atom::FOO_ATOM } +} + +#[test] +fn test_match_nonzero_const_pattern() { + match atom!("foo") { + // Using as a pattern is supported by the compiler: + atom!("foo") => {} + _ => panic!("Expected the const item as a pattern to match.") + } +} -- cgit 1.4.1-3-g733a5 From 73c053786dde55059932b9ebcd4a40edf89eae15 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 8 Mar 2018 16:55:51 +0100 Subject: Remove deprecated unstable ptr::Shared type alias. It has been deprecated for about one release cycle. --- src/libcore/cell.rs | 5 ++--- src/libcore/ptr.rs | 5 ----- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 36618e86968..c8ee166fee3 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -146,13 +146,12 @@ //! //! ``` //! #![feature(core_intrinsics)] -//! #![feature(shared)] //! use std::cell::Cell; -//! use std::ptr::Shared; +//! use std::ptr::NonNull; //! use std::intrinsics::abort; //! //! struct Rc { -//! ptr: Shared> +//! ptr: NonNull> //! } //! //! struct RcBox { diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 4ab0ceb7967..cebd5989e96 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2420,11 +2420,6 @@ impl<'a, T: ?Sized> From> for Unique { } } -/// Previous name of `NonNull`. -#[rustc_deprecated(since = "1.25.0", reason = "renamed to `NonNull`")] -#[unstable(feature = "shared", issue = "27730")] -pub type Shared = NonNull; - /// `*mut T` but non-zero and covariant. /// /// This is often the correct thing to use when building data structures using -- cgit 1.4.1-3-g733a5 From 13d94d666e037162808174f0bedbd5db9d65c7fe Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Sun, 18 Mar 2018 13:05:00 +0100 Subject: Fix formatting. --- src/libcore/borrow.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 7470512e2b2..f45a32d4b94 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -55,7 +55,6 @@ /// [`String`]: ../../std/string/struct.String.html /// [`borrow`]: #tymethod.borrow /// -/// /// # Examples /// /// As a data collection, [`HashMap`] owns both keys and values. If @@ -163,7 +162,6 @@ /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// [`String`]: ../../std/string/struct.String.html /// [`str`]: ../../std/primitive.str.html -/// #[stable(feature = "rust1", since = "1.0.0")] pub trait Borrow { /// Immutably borrows from an owned value. -- cgit 1.4.1-3-g733a5 From a23f685296b2edd59acc998411340184b958ec82 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sun, 18 Mar 2018 16:58:38 +0100 Subject: num::NonZero* types now have their own tracking issue: #49137 Fixes #27730 --- src/libcore/nonzero.rs | 7 +------ src/libcore/num/mod.rs | 4 ++-- src/libstd/num.rs | 4 ++-- 3 files changed, 5 insertions(+), 10 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 59aaef9d66a..19836d98844 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -9,9 +9,7 @@ // except according to those terms. //! Exposes the NonZero lang item which provides optimization hints. -#![unstable(feature = "nonzero", - reason = "deprecated", - issue = "27730")] +#![unstable(feature = "nonzero", reason = "deprecated", issue = "49137")] #![rustc_deprecated(reason = "use `std::ptr::NonNull` or `std::num::NonZero*` instead", since = "1.26.0")] #![allow(deprecated)] @@ -70,9 +68,6 @@ pub struct NonZero(pub(crate) T); impl NonZero { /// Creates an instance of NonZero with the provided value. /// You must indeed ensure that the value is actually "non-zero". - #[unstable(feature = "nonzero", - reason = "needs an RFC to flesh out the design", - issue = "27730")] #[inline] pub const unsafe fn new_unchecked(inner: T) -> Self { NonZero(inner) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 84f6ab9b764..2ffcb9e95e2 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -92,7 +92,7 @@ macro_rules! nonzero_integers { } nonzero_integers! { - #[unstable(feature = "nonzero", issue = "27730")] + #[unstable(feature = "nonzero", issue = "49137")] NonZeroU8(u8); NonZeroI8(i8); NonZeroU16(u16); NonZeroI16(i16); NonZeroU32(u32); NonZeroI32(i32); @@ -103,7 +103,7 @@ nonzero_integers! { nonzero_integers! { // Change this to `#[unstable(feature = "i128", issue = "35118")]` // if other NonZero* integer types are stabilizied before 128-bit integers - #[unstable(feature = "nonzero", issue = "27730")] + #[unstable(feature = "nonzero", issue = "49137")] NonZeroU128(u128); NonZeroI128(i128); } diff --git a/src/libstd/num.rs b/src/libstd/num.rs index 5e0406ca220..0c618370ac2 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -21,7 +21,7 @@ pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError} #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::Wrapping; -#[unstable(feature = "nonzero", issue = "27730")] +#[unstable(feature = "nonzero", issue = "49137")] pub use core::num::{ NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroUsize, NonZeroIsize, @@ -29,7 +29,7 @@ pub use core::num::{ // Change this to `#[unstable(feature = "i128", issue = "35118")]` // if other NonZero* integer types are stabilizied before 128-bit integers -#[unstable(feature = "nonzero", issue = "27730")] +#[unstable(feature = "nonzero", issue = "49137")] pub use core::num::{NonZeroU128, NonZeroI128}; #[cfg(test)] use fmt; -- cgit 1.4.1-3-g733a5 From 2797aaca77fe5c454f3a3ada84b06912b2f74b9f Mon Sep 17 00:00:00 2001 From: boats Date: Sun, 18 Mar 2018 15:05:45 -0700 Subject: Update tracking issue. --- src/liballoc/boxed.rs | 24 ++++++++++++------------ src/libcore/marker.rs | 2 +- src/libcore/mem.rs | 28 ++++++++++++++-------------- 3 files changed, 27 insertions(+), 27 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 46d3ccb9de5..0e71cc59d94 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -898,22 +898,22 @@ impl Generator for Box } /// A pinned, heap allocated reference. -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] #[fundamental] pub struct PinBox { inner: Box, } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl PinBox { /// Allocate memory on the heap, move the data into it and pin it. - #[unstable(feature = "pin", issue = "0")] + #[unstable(feature = "pin", issue = "49150")] pub fn new(data: T) -> PinBox { PinBox { inner: Box::new(data) } } } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl PinBox { /// Get a pinned reference to the data in this PinBox. pub fn as_pin<'a>(&'a mut self) -> Pin<'a, T> { @@ -937,21 +937,21 @@ impl PinBox { } } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl From> for PinBox { fn from(boxed: Box) -> PinBox { PinBox { inner: boxed } } } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl From> for Box { fn from(pinned: PinBox) -> Box { pinned.inner } } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl Deref for PinBox { type Target = T; @@ -960,28 +960,28 @@ impl Deref for PinBox { } } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl DerefMut for PinBox { fn deref_mut(&mut self) -> &mut T { &mut *self.inner } } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl fmt::Display for PinBox { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&*self.inner, f) } } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl fmt::Debug for PinBox { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&*self.inner, f) } } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl fmt::Pointer for PinBox { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // It's not possible to extract the inner Uniq directly from the Box, @@ -991,5 +991,5 @@ impl fmt::Pointer for PinBox { } } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl, U: ?Sized> CoerceUnsized> for PinBox {} diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 7b67404db5d..9d7f8abff15 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -573,5 +573,5 @@ unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} /// `Pin` pointer. /// /// This trait is automatically implemented for almost every type. -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] pub unsafe auto trait Unpin {} diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index e960b5ae758..b2467c948b4 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1111,24 +1111,24 @@ pub unsafe fn unreachable() -> ! { /// A pinned reference is a lot like a mutable reference, except that it is not /// safe to move a value out of a pinned reference unless the type of that /// value implements the `Unpin` trait. -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] #[fundamental] pub struct Pin<'a, T: ?Sized + 'a> { inner: &'a mut T, } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl<'a, T: ?Sized + Unpin> Pin<'a, T> { /// Construct a new `Pin` around a reference to some data of a type that /// implements `Unpin`. - #[unstable(feature = "pin", issue = "0")] + #[unstable(feature = "pin", issue = "49150")] pub fn new(reference: &'a mut T) -> Pin<'a, T> { Pin { inner: reference } } } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl<'a, T: ?Sized> Pin<'a, T> { /// Construct a new `Pin` around a reference to some data of a type that /// may or may not implement `Unpin`. @@ -1136,13 +1136,13 @@ impl<'a, T: ?Sized> Pin<'a, T> { /// This constructor is unsafe because we do not know what will happen with /// that data after the reference ends. If you cannot guarantee that the /// data will never move again, calling this constructor is invalid. - #[unstable(feature = "pin", issue = "0")] + #[unstable(feature = "pin", issue = "49150")] pub unsafe fn new_unchecked(reference: &'a mut T) -> Pin<'a, T> { Pin { inner: reference } } /// Borrow a Pin for a shorter lifetime than it already has. - #[unstable(feature = "pin", issue = "0")] + #[unstable(feature = "pin", issue = "49150")] pub fn borrow<'b>(this: &'b mut Pin<'a, T>) -> Pin<'b, T> { Pin { inner: this.inner } } @@ -1152,7 +1152,7 @@ impl<'a, T: ?Sized> Pin<'a, T> { /// This function is unsafe. You must guarantee that you will never move /// the data out of the mutable reference you receive when you call this /// function. - #[unstable(feature = "pin", issue = "0")] + #[unstable(feature = "pin", issue = "49150")] pub unsafe fn get_mut<'b>(this: &'b mut Pin<'a, T>) -> &'b mut T { this.inner } @@ -1166,7 +1166,7 @@ impl<'a, T: ?Sized> Pin<'a, T> { /// will not move so long as the argument value does not move (for example, /// because it is one of the fields of that value), and also that you do /// not move out of the argument you receive to the interior function. - #[unstable(feature = "pin", issue = "0")] + #[unstable(feature = "pin", issue = "49150")] pub unsafe fn map<'b, U, F>(this: &'b mut Pin<'a, T>, f: F) -> Pin<'b, U> where F: FnOnce(&mut T) -> &mut U { @@ -1174,7 +1174,7 @@ impl<'a, T: ?Sized> Pin<'a, T> { } } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl<'a, T: ?Sized> Deref for Pin<'a, T> { type Target = T; @@ -1183,33 +1183,33 @@ impl<'a, T: ?Sized> Deref for Pin<'a, T> { } } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl<'a, T: ?Sized + Unpin> DerefMut for Pin<'a, T> { fn deref_mut(&mut self) -> &mut T { self.inner } } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl<'a, T: fmt::Debug + ?Sized> fmt::Debug for Pin<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl<'a, T: fmt::Display + ?Sized> fmt::Display for Pin<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&**self, f) } } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl<'a, T: ?Sized> fmt::Pointer for Pin<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&(&*self.inner as *const T), f) } } -#[unstable(feature = "pin", issue = "0")] +#[unstable(feature = "pin", issue = "49150")] impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for Pin<'a, T> {} -- cgit 1.4.1-3-g733a5 From 612c4a95bce4c4dc0cddc5ab374fcb262039aede Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Tue, 6 Mar 2018 23:17:49 -0500 Subject: Impl Integer methods for Wrapping Wrapping now implements: count_ones, count_zeros, leading_zeros, trailing_zeros, rotate_left, rotate_right, swap_bytes, from_be, from_le, to_be, to_le, and pow where T is: u8, u16, u32, u64, usize, i8, i16, i32, i64, or isize. Docs were written for all these methods, as well as examples. The examples mirror the ones on u8, u16, etc... for consistency. Closes #32463 --- src/libcore/num/wrapping.rs | 299 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index ae1b0b3ce11..6c110aa0523 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -317,11 +317,307 @@ macro_rules! wrapping_impl { } forward_ref_unop! { impl Neg, neg for Wrapping<$t>, #[stable(feature = "wrapping_ref", since = "1.14.0")] } + )*) } wrapping_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } +macro_rules! wrapping_int_impl { + ($($t:ty)*) => ($( + impl Wrapping<$t> { + /// Returns the number of ones in the binary representation of + /// `self`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(wrapping_int_impl)] + /// use std::num::Wrapping; + /// + /// let n: Wrapping = Wrapping(-0b1000_0000); + /// + /// assert_eq!(n.count_ones(), 1); + /// ``` + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn count_ones(self) -> u32 { + self.0.count_ones() + } + + /// Returns the number of zeros in the binary representation of + /// `self`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(wrapping_int_impl)] + /// use std::num::Wrapping; + /// + /// let n: Wrapping = Wrapping(-0b1000_0000); + /// + /// assert_eq!(n.count_zeros(), 7); + /// ``` + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn count_zeros(self) -> u32 { + self.0.count_zeros() + } + + /// Returns the number of leading zeros in the binary representation + /// of `self`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(wrapping_int_impl)] + /// use std::num::Wrapping; + /// + /// let n: Wrapping = Wrapping(-1); + /// + /// assert_eq!(n.leading_zeros(), 0); + /// ``` + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn leading_zeros(self) -> u32 { + self.0.leading_zeros() + } + + /// Returns the number of trailing zeros in the binary representation + /// of `self`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(wrapping_int_impl)] + /// use std::num::Wrapping; + /// + /// let n: Wrapping = Wrapping(-4); + /// + /// assert_eq!(n.trailing_zeros(), 2); + /// ``` + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn trailing_zeros(self) -> u32 { + self.0.trailing_zeros() + } + + /// Shifts the bits to the left by a specified amount, `n`, + /// wrapping the truncated bits to the end of the resulting + /// integer. + /// + /// Please note this isn't the same operation as `>>`! + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(wrapping_int_impl)] + /// use std::num::Wrapping; + /// + /// let n: Wrapping = Wrapping(0x0123456789ABCDEF); + /// let m: Wrapping = Wrapping(-0x76543210FEDCBA99); + /// + /// assert_eq!(n.rotate_left(32), m); + /// ``` + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn rotate_left(self, n: u32) -> Self { + Wrapping(self.0.rotate_left(n)) + } + + /// Shifts the bits to the right by a specified amount, `n`, + /// wrapping the truncated bits to the beginning of the resulting + /// integer. + /// + /// Please note this isn't the same operation as `<<`! + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(wrapping_int_impl)] + /// use std::num::Wrapping; + /// + /// let n: Wrapping = Wrapping(0x0123456789ABCDEF); + /// let m: Wrapping = Wrapping(-0xFEDCBA987654322); + /// + /// assert_eq!(n.rotate_right(4), m); + /// ``` + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn rotate_right(self, n: u32) -> Self { + Wrapping(self.0.rotate_right(n)) + } + + /// Reverses the byte order of the integer. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(wrapping_int_impl)] + /// use std::num::Wrapping; + /// + /// let n: Wrapping = Wrapping(0b0000000_01010101); + /// assert_eq!(n, Wrapping(85)); + /// + /// let m = n.swap_bytes(); + /// + /// assert_eq!(m, Wrapping(0b01010101_00000000)); + /// assert_eq!(m, Wrapping(21760)); + /// ``` + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn swap_bytes(self) -> Self { + Wrapping(self.0.swap_bytes()) + } + + /// Converts an integer from big endian to the target's endianness. + /// + /// On big endian this is a no-op. On little endian the bytes are + /// swapped. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(wrapping_int_impl)] + /// use std::num::Wrapping; + /// + /// let n: Wrapping = Wrapping(0x0123456789ABCDEF); + /// + /// if cfg!(target_endian = "big") { + /// assert_eq!(Wrapping::::from_be(n), n); + /// } else { + /// assert_eq!(Wrapping::::from_be(n), n.swap_bytes()); + /// } + /// ``` + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn from_be(x: Self) -> Self { + Wrapping(<$t>::from_be(x.0)) + } + + /// Converts an integer from little endian to the target's endianness. + /// + /// On little endian this is a no-op. On big endian the bytes are + /// swapped. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(wrapping_int_impl)] + /// use std::num::Wrapping; + /// + /// let n: Wrapping = Wrapping(0x0123456789ABCDEF); + /// + /// if cfg!(target_endian = "little") { + /// assert_eq!(Wrapping::::from_le(n), n); + /// } else { + /// assert_eq!(Wrapping::::from_le(n), n.swap_bytes()); + /// } + /// ``` + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn from_le(x: Self) -> Self { + Wrapping(<$t>::from_le(x.0)) + } + + /// Converts `self` to big endian from the target's endianness. + /// + /// On big endian this is a no-op. On little endian the bytes are + /// swapped. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(wrapping_int_impl)] + /// use std::num::Wrapping; + /// + /// let n: Wrapping = Wrapping(0x0123456789ABCDEF); + /// + /// if cfg!(target_endian = "big") { + /// assert_eq!(n.to_be(), n); + /// } else { + /// assert_eq!(n.to_be(), n.swap_bytes()); + /// } + /// ``` + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn to_be(self) -> Self { + Wrapping(self.0.to_be()) + } + + /// Converts `self` to little endian from the target's endianness. + /// + /// On little endian this is a no-op. On big endian the bytes are + /// swapped. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(wrapping_int_impl)] + /// use std::num::Wrapping; + /// + /// let n: Wrapping = Wrapping(0x0123456789ABCDEF); + /// + /// if cfg!(target_endian = "little") { + /// assert_eq!(n.to_le(), n); + /// } else { + /// assert_eq!(n.to_le(), n.swap_bytes()); + /// } + /// ``` + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn to_le(self) -> Self { + Wrapping(self.0.to_le()) + } + + /// Raises self to the power of `exp`, using exponentiation by + /// squaring. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(wrapping_int_impl)] + /// use std::num::Wrapping; + /// + /// let x: Wrapping = Wrapping(2); // or any other integer type + /// + /// assert_eq!(x.pow(4), Wrapping(16)); + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn pow(self, exp: u32) -> Self { + Wrapping(self.0.pow(exp)) + } + } + )*) +} + +wrapping_int_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } + + mod shift_max { #![allow(non_upper_case_globals)] @@ -355,3 +651,6 @@ mod shift_max { pub const u64: u32 = i64; pub use self::platform::usize; } + + + -- cgit 1.4.1-3-g733a5 From 5258af398aced119ad5ac40192fa131a2f2827d4 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Thu, 8 Mar 2018 02:31:15 -0500 Subject: Make Wrapping::pow use wrapping_pow, add example --- src/libcore/num/wrapping.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index 6c110aa0523..fb79ddd0951 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -606,10 +606,23 @@ macro_rules! wrapping_int_impl { /// let x: Wrapping = Wrapping(2); // or any other integer type /// /// assert_eq!(x.pow(4), Wrapping(16)); + /// ``` + /// + /// Results that are too large are wrapped: + /// + /// ``` + /// #![feature(wrapping_int_impl)] + /// use std::num::Wrapping; + /// + /// // 5 ^ 4 = 625, which is too big for a u8 + /// let x: Wrapping = Wrapping(5); + /// + /// assert_eq!(x.pow(4).0, 113); + /// ``` #[inline] #[unstable(feature = "wrapping_int_impl", issue = "32463")] pub fn pow(self, exp: u32) -> Self { - Wrapping(self.0.pow(exp)) + Wrapping(self.0.wrapping_pow(exp)) } } )*) @@ -651,6 +664,3 @@ mod shift_max { pub const u64: u32 = i64; pub use self::platform::usize; } - - - -- cgit 1.4.1-3-g733a5 From bf101a5759fd0ddab7c9cbb1dc93d22d35f54722 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Thu, 8 Mar 2018 03:30:55 -0500 Subject: Fix trailing whitespace --- src/libcore/num/wrapping.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index fb79ddd0951..826883fdc3f 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -525,7 +525,7 @@ macro_rules! wrapping_int_impl { /// use std::num::Wrapping; /// /// let n: Wrapping = Wrapping(0x0123456789ABCDEF); - /// + /// /// if cfg!(target_endian = "little") { /// assert_eq!(Wrapping::::from_le(n), n); /// } else { -- cgit 1.4.1-3-g733a5 From deae8de673af638537421804b360443af76d55e4 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 19 Mar 2018 14:33:39 +0100 Subject: Clarify AcqRel's docs This implied things that are not true. Fixes #49127 --- src/libcore/sync/atomic.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 25827edee7d..fd6e5140a09 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -205,8 +205,9 @@ pub enum Ordering { /// [`Release`]: http://llvm.org/docs/Atomics.html#release #[stable(feature = "rust1", since = "1.0.0")] Acquire, - /// When coupled with a load, uses [`Acquire`] ordering, and with a store - /// [`Release`] ordering. + /// Has the effects of both [`Acquire`] and [`Release`] together. + /// + /// If you only are concerned about a load or a store, consider using one of those instead. /// /// [`Acquire`]: http://llvm.org/docs/Atomics.html#acquire /// [`Release`]: http://llvm.org/docs/Atomics.html#release -- cgit 1.4.1-3-g733a5 From 2b64799365a43bf8685cb9750d9e887c006c1f22 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 Mar 2018 19:41:22 +0100 Subject: Make Atomic doc examples specific to each type --- src/libcore/sync/atomic.rs | 765 ++++++++++++++++++++++++--------------------- 1 file changed, 401 insertions(+), 364 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 25827edee7d..fe5ed5d4942 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -948,6 +948,7 @@ macro_rules! atomic_int { $stable_from:meta, $stable_nand:meta, $s_int_type:expr, $int_ref:expr, + $extra_feature:expr, $int_type:ident $atomic_type:ident $atomic_init:ident) => { /// An integer type which can be safely shared between threads. /// @@ -959,12 +960,7 @@ macro_rules! atomic_int { /// ). For more about the differences between atomic types and /// non-atomic types, please see the [module-level documentation]. /// - /// Please note that examples are shared between atomic variants of - /// primitive integer types, so it's normal that they are all - /// demonstrating [`AtomicIsize`]. - /// /// [module-level documentation]: index.html - /// [`AtomicIsize`]: struct.AtomicIsize.html #[$stable] pub struct $atomic_type { v: UnsafeCell<$int_type>, @@ -1001,395 +997,426 @@ macro_rules! atomic_int { unsafe impl Sync for $atomic_type {} impl $atomic_type { - /// Creates a new atomic integer. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::AtomicIsize; - /// - /// let atomic_forty_two = AtomicIsize::new(42); - /// ``` - #[inline] - #[$stable] - pub const fn new(v: $int_type) -> Self { - $atomic_type {v: UnsafeCell::new(v)} + doc_comment! { + concat!("Creates a new atomic integer. + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::", stringify!($atomic_type), "; + +let atomic_forty_two = ", stringify!($atomic_type), "::new(42); +```"), + #[inline] + #[$stable] + pub const fn new(v: $int_type) -> Self { + $atomic_type {v: UnsafeCell::new(v)} + } } - /// Returns a mutable reference to the underlying integer. - /// - /// This is safe because the mutable reference guarantees that no other threads are - /// concurrently accessing the atomic data. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let mut some_isize = AtomicIsize::new(10); - /// assert_eq!(*some_isize.get_mut(), 10); - /// *some_isize.get_mut() = 5; - /// assert_eq!(some_isize.load(Ordering::SeqCst), 5); - /// ``` - #[inline] - #[$stable_access] - pub fn get_mut(&mut self) -> &mut $int_type { - unsafe { &mut *self.v.get() } + doc_comment! { + concat!("Returns a mutable reference to the underlying integer. + +This is safe because the mutable reference guarantees that no other threads are +concurrently accessing the atomic data. + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let mut some_var = ", stringify!($atomic_type), "::new(10); +assert_eq!(*some_var.get_mut(), 10); +*some_var.get_mut() = 5; +assert_eq!(some_var.load(Ordering::SeqCst), 5); +```"), + #[inline] + #[$stable_access] + pub fn get_mut(&mut self) -> &mut $int_type { + unsafe { &mut *self.v.get() } + } } - /// Consumes the atomic and returns the contained value. - /// - /// This is safe because passing `self` by value guarantees that no other threads are - /// concurrently accessing the atomic data. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::AtomicIsize; - /// - /// let some_isize = AtomicIsize::new(5); - /// assert_eq!(some_isize.into_inner(), 5); - /// ``` - #[inline] - #[$stable_access] - pub fn into_inner(self) -> $int_type { - self.v.into_inner() + doc_comment! { + concat!("Consumes the atomic and returns the contained value. + +This is safe because passing `self` by value guarantees that no other threads are +concurrently accessing the atomic data. + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::", stringify!($atomic_type), "; + +let some_var = ", stringify!($atomic_type), "::new(5); +assert_eq!(some_var.into_inner(), 5); +```"), + #[inline] + #[$stable_access] + pub fn into_inner(self) -> $int_type { + self.v.into_inner() + } } - /// Loads a value from the atomic integer. - /// - /// `load` takes an [`Ordering`] argument which describes the memory ordering of this - /// operation. - /// - /// # Panics - /// - /// Panics if `order` is [`Release`] or [`AcqRel`]. - /// - /// [`Ordering`]: enum.Ordering.html - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let some_isize = AtomicIsize::new(5); - /// - /// assert_eq!(some_isize.load(Ordering::Relaxed), 5); - /// ``` - #[inline] - #[$stable] - pub fn load(&self, order: Ordering) -> $int_type { - unsafe { atomic_load(self.v.get(), order) } + doc_comment! { + concat!("Loads a value from the atomic integer. + +`load` takes an [`Ordering`] argument which describes the memory ordering of this operation. + +# Panics + +Panics if `order` is [`Release`] or [`AcqRel`]. + +[`Ordering`]: enum.Ordering.html +[`Release`]: enum.Ordering.html#variant.Release +[`AcqRel`]: enum.Ordering.html#variant.AcqRel + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let some_var = ", stringify!($atomic_type), "::new(5); + +assert_eq!(some_var.load(Ordering::Relaxed), 5); +```"), + #[inline] + #[$stable] + pub fn load(&self, order: Ordering) -> $int_type { + unsafe { atomic_load(self.v.get(), order) } + } } - /// Stores a value into the atomic integer. - /// - /// `store` takes an [`Ordering`] argument which describes the memory ordering of this - /// operation. - /// - /// [`Ordering`]: enum.Ordering.html - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let some_isize = AtomicIsize::new(5); - /// - /// some_isize.store(10, Ordering::Relaxed); - /// assert_eq!(some_isize.load(Ordering::Relaxed), 10); - /// ``` - /// - /// # Panics - /// - /// Panics if `order` is [`Acquire`] or [`AcqRel`]. - /// - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - #[inline] - #[$stable] - pub fn store(&self, val: $int_type, order: Ordering) { - unsafe { atomic_store(self.v.get(), val, order); } + doc_comment! { + concat!("Stores a value into the atomic integer. + +`store` takes an [`Ordering`] argument which describes the memory ordering of this operation. + +[`Ordering`]: enum.Ordering.html + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let some_var = ", stringify!($atomic_type), "::new(5); + +some_var.store(10, Ordering::Relaxed); +assert_eq!(some_var.load(Ordering::Relaxed), 10); +``` + +# Panics + +Panics if `order` is [`Acquire`] or [`AcqRel`]. + +[`Acquire`]: enum.Ordering.html#variant.Acquire +[`AcqRel`]: enum.Ordering.html#variant.AcqRel"), + #[inline] + #[$stable] + pub fn store(&self, val: $int_type, order: Ordering) { + unsafe { atomic_store(self.v.get(), val, order); } + } } - /// Stores a value into the atomic integer, returning the previous value. - /// - /// `swap` takes an [`Ordering`] argument which describes the memory ordering of this - /// operation. - /// - /// [`Ordering`]: enum.Ordering.html - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let some_isize = AtomicIsize::new(5); - /// - /// assert_eq!(some_isize.swap(10, Ordering::Relaxed), 5); - /// ``` - #[inline] - #[$stable] - pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type { - unsafe { atomic_swap(self.v.get(), val, order) } + doc_comment! { + concat!("Stores a value into the atomic integer, returning the previous value. + +`swap` takes an [`Ordering`] argument which describes the memory ordering of this operation. + +[`Ordering`]: enum.Ordering.html + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let some_var = ", stringify!($atomic_type), "::new(5); + +assert_eq!(some_var.swap(10, Ordering::Relaxed), 5); +```"), + #[inline] + #[$stable] + pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { atomic_swap(self.v.get(), val, order) } + } } - /// Stores a value into the atomic integer if the current value is the same as the - /// `current` value. - /// - /// The return value is always the previous value. If it is equal to `current`, then the - /// value was updated. - /// - /// `compare_and_swap` also takes an [`Ordering`] argument which describes the memory - /// ordering of this operation. - /// - /// [`Ordering`]: enum.Ordering.html - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let some_isize = AtomicIsize::new(5); - /// - /// assert_eq!(some_isize.compare_and_swap(5, 10, Ordering::Relaxed), 5); - /// assert_eq!(some_isize.load(Ordering::Relaxed), 10); - /// - /// assert_eq!(some_isize.compare_and_swap(6, 12, Ordering::Relaxed), 10); - /// assert_eq!(some_isize.load(Ordering::Relaxed), 10); - /// ``` - #[inline] - #[$stable] - pub fn compare_and_swap(&self, - current: $int_type, - new: $int_type, - order: Ordering) -> $int_type { - match self.compare_exchange(current, - new, - order, - strongest_failure_ordering(order)) { - Ok(x) => x, - Err(x) => x, + doc_comment! { + concat!("Stores a value into the atomic integer if the current value is the same as +the `current` value. + +The return value is always the previous value. If it is equal to `current`, then the +value was updated. + +`compare_and_swap` also takes an [`Ordering`] argument which describes the memory +ordering of this operation. + +[`Ordering`]: enum.Ordering.html + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let some_var = ", stringify!($atomic_type), "::new(5); + +assert_eq!(some_var.compare_and_swap(5, 10, Ordering::Relaxed), 5); +assert_eq!(some_var.load(Ordering::Relaxed), 10); + +assert_eq!(some_var.compare_and_swap(6, 12, Ordering::Relaxed), 10); +assert_eq!(some_var.load(Ordering::Relaxed), 10); +```"), + #[inline] + #[$stable] + pub fn compare_and_swap(&self, + current: $int_type, + new: $int_type, + order: Ordering) -> $int_type { + match self.compare_exchange(current, + new, + order, + strongest_failure_ordering(order)) { + Ok(x) => x, + Err(x) => x, + } } } - /// Stores a value into the atomic integer if the current value is the same as the - /// `current` value. - /// - /// The return value is a result indicating whether the new value was written and - /// containing the previous value. On success this value is guaranteed to be equal to - /// `current`. - /// - /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory - /// ordering of this operation. The first describes the required ordering if - /// the operation succeeds while the second describes the required ordering when - /// the operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and - /// must be equivalent or weaker than the success ordering. - /// - /// [`Ordering`]: enum.Ordering.html - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let some_isize = AtomicIsize::new(5); - /// - /// assert_eq!(some_isize.compare_exchange(5, 10, - /// Ordering::Acquire, - /// Ordering::Relaxed), - /// Ok(5)); - /// assert_eq!(some_isize.load(Ordering::Relaxed), 10); - /// - /// assert_eq!(some_isize.compare_exchange(6, 12, - /// Ordering::SeqCst, - /// Ordering::Acquire), - /// Err(10)); - /// assert_eq!(some_isize.load(Ordering::Relaxed), 10); - /// ``` - #[inline] - #[$stable_cxchg] - pub fn compare_exchange(&self, - current: $int_type, - new: $int_type, - success: Ordering, - failure: Ordering) -> Result<$int_type, $int_type> { - unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) } + doc_comment! { + concat!("Stores a value into the atomic integer if the current value is the same as +the `current` value. + +The return value is a result indicating whether the new value was written and +containing the previous value. On success this value is guaranteed to be equal to +`current`. + +`compare_exchange` takes two [`Ordering`] arguments to describe the memory +ordering of this operation. The first describes the required ordering if +the operation succeeds while the second describes the required ordering when +the operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and +must be equivalent or weaker than the success ordering. + +[`Ordering`]: enum.Ordering.html +[`Release`]: enum.Ordering.html#variant.Release +[`AcqRel`]: enum.Ordering.html#variant.AcqRel + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let some_var = ", stringify!($atomic_type), "::new(5); + +assert_eq!(some_var.compare_exchange(5, 10, + Ordering::Acquire, + Ordering::Relaxed), + Ok(5)); +assert_eq!(some_var.load(Ordering::Relaxed), 10); + +assert_eq!(some_var.compare_exchange(6, 12, + Ordering::SeqCst, + Ordering::Acquire), + Err(10)); +assert_eq!(some_var.load(Ordering::Relaxed), 10); +```"), + #[inline] + #[$stable_cxchg] + pub fn compare_exchange(&self, + current: $int_type, + new: $int_type, + success: Ordering, + failure: Ordering) -> Result<$int_type, $int_type> { + unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) } + } } - /// Stores a value into the atomic integer if the current value is the same as the - /// `current` value. - /// - /// Unlike [`compare_exchange`], this function is allowed to spuriously fail even - /// when the comparison succeeds, which can result in more efficient code on some - /// platforms. The return value is a result indicating whether the new value was - /// written and containing the previous value. - /// - /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory - /// ordering of this operation. The first describes the required ordering if the - /// operation succeeds while the second describes the required ordering when the - /// operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and - /// must be equivalent or weaker than the success ordering. - /// - /// [`compare_exchange`]: #method.compare_exchange - /// [`Ordering`]: enum.Ordering.html - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let val = AtomicIsize::new(4); - /// - /// let mut old = val.load(Ordering::Relaxed); - /// loop { - /// let new = old * 2; - /// match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) { - /// Ok(_) => break, - /// Err(x) => old = x, - /// } - /// } - /// ``` - #[inline] - #[$stable_cxchg] - pub fn compare_exchange_weak(&self, - current: $int_type, - new: $int_type, - success: Ordering, - failure: Ordering) -> Result<$int_type, $int_type> { - unsafe { - atomic_compare_exchange_weak(self.v.get(), current, new, success, failure) + doc_comment! { + concat!("Stores a value into the atomic integer if the current value is the same as +the `current` value. + +Unlike [`compare_exchange`], this function is allowed to spuriously fail even +when the comparison succeeds, which can result in more efficient code on some +platforms. The return value is a result indicating whether the new value was +written and containing the previous value. + +`compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory +ordering of this operation. The first describes the required ordering if the +operation succeeds while the second describes the required ordering when the +operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and +must be equivalent or weaker than the success ordering. + +[`compare_exchange`]: #method.compare_exchange +[`Ordering`]: enum.Ordering.html +[`Release`]: enum.Ordering.html#variant.Release +[`AcqRel`]: enum.Ordering.html#variant.AcqRel + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let val = ", stringify!($atomic_type), "::new(4); + +let mut old = val.load(Ordering::Relaxed); +loop { + let new = old * 2; + match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) { + Ok(_) => break, + Err(x) => old = x, + } +} +```"), + #[inline] + #[$stable_cxchg] + pub fn compare_exchange_weak(&self, + current: $int_type, + new: $int_type, + success: Ordering, + failure: Ordering) -> Result<$int_type, $int_type> { + unsafe { + atomic_compare_exchange_weak(self.v.get(), current, new, success, failure) + } } } - /// Adds to the current value, returning the previous value. - /// - /// This operation wraps around on overflow. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let foo = AtomicIsize::new(0); - /// assert_eq!(foo.fetch_add(10, Ordering::SeqCst), 0); - /// assert_eq!(foo.load(Ordering::SeqCst), 10); - /// ``` - #[inline] - #[$stable] - pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type { - unsafe { atomic_add(self.v.get(), val, order) } + doc_comment! { + concat!("Adds to the current value, returning the previous value. + +This operation wraps around on overflow. + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(0); +assert_eq!(foo.fetch_add(10, Ordering::SeqCst), 0); +assert_eq!(foo.load(Ordering::SeqCst), 10); +```"), + #[inline] + #[$stable] + pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { atomic_add(self.v.get(), val, order) } + } } - /// Subtracts from the current value, returning the previous value. - /// - /// This operation wraps around on overflow. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let foo = AtomicIsize::new(0); - /// assert_eq!(foo.fetch_sub(10, Ordering::SeqCst), 0); - /// assert_eq!(foo.load(Ordering::SeqCst), -10); - /// ``` - #[inline] - #[$stable] - pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type { - unsafe { atomic_sub(self.v.get(), val, order) } + doc_comment! { + concat!("Subtracts from the current value, returning the previous value. + +This operation wraps around on overflow. + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(20); +assert_eq!(foo.fetch_sub(10, Ordering::SeqCst), 20); +assert_eq!(foo.load(Ordering::SeqCst), 10); +```"), + #[inline] + #[$stable] + pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { atomic_sub(self.v.get(), val, order) } + } } - /// Bitwise "and" with the current value. - /// - /// Performs a bitwise "and" operation on the current value and the argument `val`, and - /// sets the new value to the result. - /// - /// Returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let foo = AtomicIsize::new(0b101101); - /// assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101); - /// assert_eq!(foo.load(Ordering::SeqCst), 0b100001); - #[inline] - #[$stable] - pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type { - unsafe { atomic_and(self.v.get(), val, order) } + doc_comment! { + concat!("Bitwise \"and\" with the current value. + +Performs a bitwise \"and\" operation on the current value and the argument `val`, and +sets the new value to the result. + +Returns the previous value. + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(0b101101); +assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101); +assert_eq!(foo.load(Ordering::SeqCst), 0b100001); +```"), + #[inline] + #[$stable] + pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { atomic_and(self.v.get(), val, order) } + } } - /// Bitwise "nand" with the current value. - /// - /// Performs a bitwise "nand" operation on the current value and the argument `val`, and - /// sets the new value to the result. - /// - /// Returns the previous value. - /// - /// # Examples - /// - /// ``` - /// #![feature(atomic_nand)] - /// - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let foo = AtomicIsize::new(0xf731); - /// assert_eq!(foo.fetch_nand(0x137f, Ordering::SeqCst), 0xf731); - /// assert_eq!(foo.load(Ordering::SeqCst), !(0xf731 & 0x137f)); - #[inline] - #[$stable_nand] - pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type { - unsafe { atomic_nand(self.v.get(), val, order) } + doc_comment! { + concat!("Bitwise \"nand\" with the current value. + +Performs a bitwise \"nand\" operation on the current value and the argument `val`, and +sets the new value to the result. + +Returns the previous value. + +# Examples + +``` +", $extra_feature, "#![feature(atomic_nand)] + +use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(0x13); +assert_eq!(foo.fetch_nand(0x31, Ordering::SeqCst), 0x13); +assert_eq!(foo.load(Ordering::SeqCst), !(0x13 & 0x31)); +```"), + #[inline] + #[$stable_nand] + pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { atomic_nand(self.v.get(), val, order) } + } } - /// Bitwise "or" with the current value. - /// - /// Performs a bitwise "or" operation on the current value and the argument `val`, and - /// sets the new value to the result. - /// - /// Returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let foo = AtomicIsize::new(0b101101); - /// assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101); - /// assert_eq!(foo.load(Ordering::SeqCst), 0b111111); - #[inline] - #[$stable] - pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type { - unsafe { atomic_or(self.v.get(), val, order) } + doc_comment! { + concat!("Bitwise \"or\" with the current value. + +Performs a bitwise \"or\" operation on the current value and the argument `val`, and +sets the new value to the result. + +Returns the previous value. + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(0b101101); +assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101); +assert_eq!(foo.load(Ordering::SeqCst), 0b111111); +```"), + #[inline] + #[$stable] + pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { atomic_or(self.v.get(), val, order) } + } } - /// Bitwise "xor" with the current value. - /// - /// Performs a bitwise "xor" operation on the current value and the argument `val`, and - /// sets the new value to the result. - /// - /// Returns the previous value. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::{AtomicIsize, Ordering}; - /// - /// let foo = AtomicIsize::new(0b101101); - /// assert_eq!(foo.fetch_xor(0b110011, Ordering::SeqCst), 0b101101); - /// assert_eq!(foo.load(Ordering::SeqCst), 0b011110); - #[inline] - #[$stable] - pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type { - unsafe { atomic_xor(self.v.get(), val, order) } + doc_comment! { + concat!("Bitwise \"xor\" with the current value. + +Performs a bitwise \"xor\" operation on the current value and the argument `val`, and +sets the new value to the result. + +Returns the previous value. + +# Examples + +``` +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(0b101101); +assert_eq!(foo.fetch_xor(0b110011, Ordering::SeqCst), 0b101101); +assert_eq!(foo.load(Ordering::SeqCst), 0b011110); +```"), + #[inline] + #[$stable] + pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { atomic_xor(self.v.get(), val, order) } + } } } } @@ -1404,6 +1431,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "atomic_nand", issue = "13226"), "i8", "../../../std/primitive.i8.html", + "#![feature(integer_atomics)]\n\n", i8 AtomicI8 ATOMIC_I8_INIT } #[cfg(target_has_atomic = "8")] @@ -1415,6 +1443,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "atomic_nand", issue = "13226"), "u8", "../../../std/primitive.u8.html", + "#![feature(integer_atomics)]\n\n", u8 AtomicU8 ATOMIC_U8_INIT } #[cfg(target_has_atomic = "16")] @@ -1426,6 +1455,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "atomic_nand", issue = "13226"), "i16", "../../../std/primitive.i16.html", + "#![feature(integer_atomics)]\n\n", i16 AtomicI16 ATOMIC_I16_INIT } #[cfg(target_has_atomic = "16")] @@ -1437,6 +1467,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "atomic_nand", issue = "13226"), "u16", "../../../std/primitive.u16.html", + "#![feature(integer_atomics)]\n\n", u16 AtomicU16 ATOMIC_U16_INIT } #[cfg(target_has_atomic = "32")] @@ -1448,6 +1479,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "atomic_nand", issue = "13226"), "i32", "../../../std/primitive.i32.html", + "#![feature(integer_atomics)]\n\n", i32 AtomicI32 ATOMIC_I32_INIT } #[cfg(target_has_atomic = "32")] @@ -1459,6 +1491,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "atomic_nand", issue = "13226"), "u32", "../../../std/primitive.u32.html", + "#![feature(integer_atomics)]\n\n", u32 AtomicU32 ATOMIC_U32_INIT } #[cfg(target_has_atomic = "64")] @@ -1470,6 +1503,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "atomic_nand", issue = "13226"), "i64", "../../../std/primitive.i64.html", + "#![feature(integer_atomics)]\n\n", i64 AtomicI64 ATOMIC_I64_INIT } #[cfg(target_has_atomic = "64")] @@ -1481,6 +1515,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "atomic_nand", issue = "13226"), "u64", "../../../std/primitive.u64.html", + "#![feature(integer_atomics)]\n\n", u64 AtomicU64 ATOMIC_U64_INIT } #[cfg(target_has_atomic = "ptr")] @@ -1492,6 +1527,7 @@ atomic_int!{ stable(feature = "atomic_from", since = "1.23.0"), unstable(feature = "atomic_nand", issue = "13226"), "isize", "../../../std/primitive.isize.html", + "", isize AtomicIsize ATOMIC_ISIZE_INIT } #[cfg(target_has_atomic = "ptr")] @@ -1503,6 +1539,7 @@ atomic_int!{ stable(feature = "atomic_from", since = "1.23.0"), unstable(feature = "atomic_nand", issue = "13226"), "usize", "../../../std/primitive.usize.html", + "", usize AtomicUsize ATOMIC_USIZE_INIT } -- cgit 1.4.1-3-g733a5 From 7c90189e1331cea3eac0ab0e8959f664cffba1ae Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 24 Feb 2018 22:21:33 +0300 Subject: Stabilize slice patterns without `..` Merge `feature(advanced_slice_patterns)` into `feature(slice_patterns)` --- .../language-features/advanced-slice-patterns.md | 35 --------------- .../src/language-features/slice-patterns.md | 28 ++++++------ src/liballoc/lib.rs | 1 - src/libcore/benches/lib.rs | 1 - src/libcore/tests/lib.rs | 1 + src/librustc/benches/lib.rs | 1 - src/librustc_apfloat/lib.rs | 2 +- src/librustc_const_eval/lib.rs | 1 - src/librustc_lint/lib.rs | 1 - src/librustc_trans/lib.rs | 2 +- src/librustc_trans_utils/lib.rs | 1 - src/librustc_typeck/diagnostics.rs | 6 --- src/librustc_typeck/lib.rs | 2 +- src/librustdoc/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 16 +++---- src/libsyntax/parse/parser.rs | 2 +- .../borrowck/borrowck-describe-lvalue.rs | 1 - .../borrowck-match-binding-is-assignment.rs | 2 - .../borrowck/borrowck-move-out-from-array.rs | 3 +- .../borrowck/borrowck-vec-pattern-element-loan.rs | 1 - src/test/compile-fail/issue-12369.rs | 1 - src/test/compile-fail/issue-13482-2.rs | 2 - src/test/compile-fail/issue-13482.rs | 2 - src/test/compile-fail/issue-15381.rs | 2 - src/test/compile-fail/issue-41255.rs | 1 - src/test/compile-fail/issue-6804.rs | 1 - .../compile-fail/match-byte-array-patterns-2.rs | 2 - src/test/compile-fail/match-byte-array-patterns.rs | 2 +- src/test/compile-fail/match-ref-ice.rs | 1 - src/test/compile-fail/match-slice-patterns.rs | 2 +- src/test/compile-fail/match-vec-fixed.rs | 1 - src/test/compile-fail/match-vec-mismatch-2.rs | 2 - src/test/compile-fail/match-vec-unreachable.rs | 1 - src/test/compile-fail/move-out-of-slice-1.rs | 2 +- .../regions-pattern-typing-issue-19552.rs | 2 - .../uninhabited-matches-feature-gated.rs | 2 - src/test/compile-fail/uninhabited-patterns.rs | 2 +- src/test/mir-opt/uniform_array_move_out.rs | 3 +- .../run-pass-fulldeps/auxiliary/roman_numerals.rs | 1 - src/test/run-pass/destructure-array-1.rs | 3 -- src/test/run-pass/dynamic-drop.rs | 3 +- src/test/run-pass/ignore-all-the-things.rs | 11 +++-- src/test/run-pass/issue-13027.rs | 2 - src/test/run-pass/issue-15080.rs | 1 - src/test/run-pass/issue-15104.rs | 1 - src/test/run-pass/issue-16648.rs | 3 -- src/test/run-pass/issue-17877.rs | 1 - src/test/run-pass/issue-37598.rs | 2 +- src/test/run-pass/issue-38002.rs | 2 - src/test/run-pass/issue-46855.rs | 2 - src/test/run-pass/issue-7784.rs | 2 - src/test/run-pass/match-vec-alternatives.rs | 2 - .../rfc-2005-default-binding-mode/slice.rs | 2 +- src/test/run-pass/trailing-comma.rs | 1 - src/test/run-pass/vec-matching-autoslice.rs | 3 -- src/test/run-pass/vec-matching-fixed.rs | 2 - src/test/run-pass/vec-matching-fold.rs | 2 - src/test/run-pass/vec-matching.rs | 2 - src/test/run-pass/vec-tail-matching.rs | 2 - .../ui/borrowck/borrowck-vec-pattern-nesting.rs | 1 - .../borrowck/borrowck-vec-pattern-nesting.stderr | 16 +++---- src/test/ui/error-codes/E0527.rs | 2 - src/test/ui/error-codes/E0527.stderr | 2 +- src/test/ui/error-codes/E0529.rs | 2 - src/test/ui/error-codes/E0529.stderr | 2 +- .../ui/feature-gate-advanced-slice-features.rs | 22 ---------- .../ui/feature-gate-advanced-slice-features.stderr | 19 -------- src/test/ui/feature-gate-slice-patterns.rs | 13 +++++- src/test/ui/feature-gate-slice-patterns.stderr | 50 +++++++++++++++++++--- src/test/ui/mismatched_types/issue-38371.rs | 2 - src/test/ui/mismatched_types/issue-38371.stderr | 8 ++-- src/test/ui/non-exhaustive-pattern-witness.rs | 1 - src/test/ui/non-exhaustive-pattern-witness.stderr | 14 +++--- src/test/ui/pat-slice-old-style.rs | 4 +- src/test/ui/rfc-2005-default-binding-mode/slice.rs | 2 +- 75 files changed, 124 insertions(+), 226 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/advanced-slice-patterns.md delete mode 100644 src/test/ui/feature-gate-advanced-slice-features.rs delete mode 100644 src/test/ui/feature-gate-advanced-slice-features.stderr (limited to 'src/libcore') diff --git a/src/doc/unstable-book/src/language-features/advanced-slice-patterns.md b/src/doc/unstable-book/src/language-features/advanced-slice-patterns.md deleted file mode 100644 index e8256469b14..00000000000 --- a/src/doc/unstable-book/src/language-features/advanced-slice-patterns.md +++ /dev/null @@ -1,35 +0,0 @@ -# `advanced_slice_patterns` - -The tracking issue for this feature is: [#23121] - -[#23121]: https://github.com/rust-lang/rust/issues/23121 - -See also [`slice_patterns`](language-features/slice-patterns.html). - ------------------------- - - -The `advanced_slice_patterns` gate lets you use `..` to indicate any number of -elements inside a pattern matching a slice. This wildcard can only be used once -for a given array. If there's an identifier before the `..`, the result of the -slice will be bound to that name. For example: - -```rust -#![feature(advanced_slice_patterns, slice_patterns)] - -fn is_symmetric(list: &[u32]) -> bool { - match list { - &[] | &[_] => true, - &[x, ref inside.., y] if x == y => is_symmetric(inside), - _ => false - } -} - -fn main() { - let sym = &[0, 1, 4, 2, 4, 1, 0]; - assert!(is_symmetric(sym)); - - let not_sym = &[0, 1, 7, 2, 4, 1, 0]; - assert!(!is_symmetric(not_sym)); -} -``` diff --git a/src/doc/unstable-book/src/language-features/slice-patterns.md b/src/doc/unstable-book/src/language-features/slice-patterns.md index 69857297582..133174268ef 100644 --- a/src/doc/unstable-book/src/language-features/slice-patterns.md +++ b/src/doc/unstable-book/src/language-features/slice-patterns.md @@ -4,25 +4,29 @@ The tracking issue for this feature is: [#23121] [#23121]: https://github.com/rust-lang/rust/issues/23121 -See also -[`advanced_slice_patterns`](language-features/advanced-slice-patterns.html). - ------------------------ - -If you want to match against a slice or array, you can use `&` with the -`slice_patterns` feature: +The `slice_patterns` feature gate lets you use `..` to indicate any number of +elements inside a pattern matching a slice. This wildcard can only be used once +for a given array. If there's an pattern before the `..`, the subslice will be +matched against that pattern. For example: ```rust #![feature(slice_patterns)] +fn is_symmetric(list: &[u32]) -> bool { + match list { + &[] | &[_] => true, + &[x, ref inside.., y] if x == y => is_symmetric(inside), + &[..] => false, + } +} + fn main() { - let v = vec!["match_this", "1"]; + let sym = &[0, 1, 4, 2, 4, 1, 0]; + assert!(is_symmetric(sym)); - match &v[..] { - &["match_this", second] => println!("The second element is {}", second), - _ => {}, - } + let not_sym = &[0, 1, 7, 2, 4, 1, 0]; + assert!(!is_symmetric(not_sym)); } ``` - diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 2727bcaa28a..45bb3885574 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -110,7 +110,6 @@ #![feature(ptr_internals)] #![feature(rustc_attrs)] #![feature(slice_get_slice)] -#![feature(slice_patterns)] #![feature(slice_rsplit)] #![feature(specialization)] #![feature(staged_api)] diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs index 201064e823b..c947b003ccb 100644 --- a/src/libcore/benches/lib.rs +++ b/src/libcore/benches/lib.rs @@ -11,7 +11,6 @@ #![deny(warnings)] #![feature(flt2dec)] -#![feature(slice_patterns)] #![feature(test)] extern crate core; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 1c876fa0bd7..e9a8113ef10 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -37,6 +37,7 @@ #![feature(raw)] #![feature(refcell_replace_swap)] #![feature(slice_patterns)] +#![feature(slice_rotate)] #![feature(sort_internals)] #![feature(specialization)] #![feature(step_trait)] diff --git a/src/librustc/benches/lib.rs b/src/librustc/benches/lib.rs index 24294ec49ce..278e0f9a26e 100644 --- a/src/librustc/benches/lib.rs +++ b/src/librustc/benches/lib.rs @@ -10,7 +10,6 @@ #![deny(warnings)] -#![feature(slice_patterns)] #![feature(test)] extern crate test; diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 3afc2f68400..565658804b0 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -47,7 +47,7 @@ #![forbid(unsafe_code)] #![feature(i128_type)] -#![feature(slice_patterns)] +#![cfg_attr(stage0, feature(slice_patterns))] #![feature(try_from)] // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 459aa9ea488..2b0775e8695 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -20,7 +20,6 @@ #![deny(warnings)] #![feature(rustc_diagnostic_macros)] -#![feature(slice_patterns)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(macro_lifetime_matcher)] diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 8b86c905489..ce896bfb701 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -31,7 +31,6 @@ #![feature(macro_vis_matcher)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] -#![feature(slice_patterns)] #![cfg_attr(stage0, feature(never_type))] #[macro_use] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 3645e728842..337f85a3813 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -30,7 +30,7 @@ #![feature(libc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] -#![feature(slice_patterns)] +#![cfg_attr(stage0, feature(slice_patterns))] #![feature(conservative_impl_trait)] #![feature(optin_builtin_traits)] #![feature(inclusive_range_fields)] diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index 6a3fd21f3a7..0af5f467934 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -24,7 +24,6 @@ #![feature(i128_type)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] -#![feature(slice_patterns)] #![feature(conservative_impl_trait)] extern crate ar; diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 24044fd2d72..f5337118e30 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3559,8 +3559,6 @@ elements in the array being matched. Example of erroneous code: ```compile_fail,E0527 -#![feature(slice_patterns)] - let r = &[1, 2, 3, 4]; match r { &[a, b] => { // error: pattern requires 2 elements but array @@ -3625,8 +3623,6 @@ An array or slice pattern was matched against some other type. Example of erroneous code: ```compile_fail,E0529 -#![feature(slice_patterns)] - let r: f32 = 1.0; match r { [a, b] => { // error: expected an array or slice, found `f32` @@ -3639,8 +3635,6 @@ Ensure that the pattern and the expression being matched on are of consistent types: ``` -#![feature(slice_patterns)] - let r = [1.0, 2.0]; match r { [a, b] => { // ok! diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 964c0021133..9f98932f24b 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -72,7 +72,7 @@ This API is completely unstable and subject to change. #![allow(non_camel_case_types)] -#![feature(advanced_slice_patterns)] +#![cfg_attr(stage0, feature(advanced_slice_patterns))] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(conservative_impl_trait)] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index da52fd5aa37..bec25a98227 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -20,7 +20,7 @@ #![feature(box_syntax)] #![feature(fs_read_write)] #![feature(set_stdio)] -#![feature(slice_patterns)] +#![cfg_attr(stage0, feature(slice_patterns))] #![feature(test)] #![feature(unicode)] #![feature(vec_remove_item)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index fa600cd6860..915396d29fe 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -145,7 +145,6 @@ declare_features! ( // rustc internal (active, rustc_diagnostic_macros, "1.0.0", None, None), (active, rustc_const_unstable, "1.0.0", None, None), - (active, advanced_slice_patterns, "1.0.0", Some(23121), None), (active, box_syntax, "1.0.0", Some(27779), None), (active, placement_in_syntax, "1.0.0", Some(27779), None), (active, unboxed_closures, "1.0.0", Some(29625), None), @@ -474,6 +473,8 @@ declare_features! ( (removed, allocator, "1.0.0", None, None), // Allows the `#[simd]` attribute -- removed in favor of `#[repr(simd)]` (removed, simd, "1.0.0", Some(27731), None), + // Merged into `slice_patterns` + (removed, advanced_slice_patterns, "1.0.0", Some(23121), None), ); declare_features! ( @@ -1655,17 +1656,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_pat(&mut self, pattern: &'a ast::Pat) { match pattern.node { - PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => { - gate_feature_post!(&self, advanced_slice_patterns, - pattern.span, - "multiple-element slice matches anywhere \ - but at the end of a slice (e.g. \ - `[0, ..xs, 0]`) are experimental") - } - PatKind::Slice(..) => { + PatKind::Slice(_, Some(ref subslice), _) => { gate_feature_post!(&self, slice_patterns, - pattern.span, - "slice pattern syntax is experimental"); + subslice.span, + "syntax for subslices in slice patterns is not yet stabilized"); } PatKind::Box(..) => { gate_feature_post!(&self, box_patterns, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index cb5010a638d..6d8975197d5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3618,7 +3618,7 @@ impl<'a> Parser<'a> { slice = Some(P(Pat { id: ast::DUMMY_NODE_ID, node: PatKind::Wild, - span: self.span, + span: self.prev_span, })); before_slice = false; } diff --git a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs index 1d08b807465..fa475949b36 100644 --- a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs +++ b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs @@ -13,7 +13,6 @@ //[mir]compile-flags: -Z borrowck=mir #![feature(slice_patterns)] -#![feature(advanced_slice_patterns)] pub struct Foo { x: u32 diff --git a/src/test/compile-fail/borrowck/borrowck-match-binding-is-assignment.rs b/src/test/compile-fail/borrowck/borrowck-match-binding-is-assignment.rs index 32a573911ec..30047f84041 100644 --- a/src/test/compile-fail/borrowck/borrowck-match-binding-is-assignment.rs +++ b/src/test/compile-fail/borrowck/borrowck-match-binding-is-assignment.rs @@ -13,8 +13,6 @@ // Test that immutable pattern bindings cannot be reassigned. -#![feature(slice_patterns)] - enum E { Foo(isize) } diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-from-array.rs b/src/test/compile-fail/borrowck/borrowck-move-out-from-array.rs index e0116173462..0db31cef0ed 100644 --- a/src/test/compile-fail/borrowck/borrowck-move-out-from-array.rs +++ b/src/test/compile-fail/borrowck/borrowck-move-out-from-array.rs @@ -11,7 +11,8 @@ // revisions: ast mir //[mir]compile-flags: -Z borrowck=mir -#![feature(box_syntax, slice_patterns, advanced_slice_patterns)] +#![feature(box_syntax)] +#![feature(slice_patterns)] fn move_out_from_begin_and_end() { let a = [box 1, box 2]; diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs index eb5d69d49bd..0fd6923326a 100644 --- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs +++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(advanced_slice_patterns)] #![feature(slice_patterns)] fn a<'a>() -> &'a [isize] { diff --git a/src/test/compile-fail/issue-12369.rs b/src/test/compile-fail/issue-12369.rs index 4df1e24dcfb..1b9af393ccc 100644 --- a/src/test/compile-fail/issue-12369.rs +++ b/src/test/compile-fail/issue-12369.rs @@ -9,7 +9,6 @@ // except according to those terms. #![feature(slice_patterns)] -#![allow(unused_variables)] #![deny(unreachable_patterns)] fn main() { diff --git a/src/test/compile-fail/issue-13482-2.rs b/src/test/compile-fail/issue-13482-2.rs index 6885c8d94c6..fe7fbb176cc 100644 --- a/src/test/compile-fail/issue-13482-2.rs +++ b/src/test/compile-fail/issue-13482-2.rs @@ -10,8 +10,6 @@ // compile-flags:-Z verbose -#![feature(slice_patterns)] - fn main() { let x = [1,2]; let y = match x { diff --git a/src/test/compile-fail/issue-13482.rs b/src/test/compile-fail/issue-13482.rs index 82e82df3186..32a63b79a32 100644 --- a/src/test/compile-fail/issue-13482.rs +++ b/src/test/compile-fail/issue-13482.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(slice_patterns)] - fn main() { let x = [1,2]; let y = match x { diff --git a/src/test/compile-fail/issue-15381.rs b/src/test/compile-fail/issue-15381.rs index d0964d2aabe..1cdd803971b 100644 --- a/src/test/compile-fail/issue-15381.rs +++ b/src/test/compile-fail/issue-15381.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(slice_patterns)] - fn main() { let values: Vec = vec![1,2,3,4,5,6,7,8]; diff --git a/src/test/compile-fail/issue-41255.rs b/src/test/compile-fail/issue-41255.rs index ac85e43cf4f..bdd502d4420 100644 --- a/src/test/compile-fail/issue-41255.rs +++ b/src/test/compile-fail/issue-41255.rs @@ -10,7 +10,6 @@ // Matching against float literals should result in a linter error -#![feature(slice_patterns)] #![feature(exclusive_range_pattern)] #![allow(unused)] #![forbid(illegal_floating_point_literal_pattern)] diff --git a/src/test/compile-fail/issue-6804.rs b/src/test/compile-fail/issue-6804.rs index 9191dfa155c..fffa27ab842 100644 --- a/src/test/compile-fail/issue-6804.rs +++ b/src/test/compile-fail/issue-6804.rs @@ -10,7 +10,6 @@ // Matching against NaN should result in a warning -#![feature(slice_patterns)] #![allow(unused)] #![deny(illegal_floating_point_literal_pattern)] diff --git a/src/test/compile-fail/match-byte-array-patterns-2.rs b/src/test/compile-fail/match-byte-array-patterns-2.rs index ad7e931a0ec..abb770df107 100644 --- a/src/test/compile-fail/match-byte-array-patterns-2.rs +++ b/src/test/compile-fail/match-byte-array-patterns-2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(advanced_slice_patterns, slice_patterns)] - fn main() { let buf = &[0, 1, 2, 3]; diff --git a/src/test/compile-fail/match-byte-array-patterns.rs b/src/test/compile-fail/match-byte-array-patterns.rs index 1ff07eae1c9..9db4319b786 100644 --- a/src/test/compile-fail/match-byte-array-patterns.rs +++ b/src/test/compile-fail/match-byte-array-patterns.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(advanced_slice_patterns, slice_patterns)] +#![feature(slice_patterns)] #![deny(unreachable_patterns)] fn main() { diff --git a/src/test/compile-fail/match-ref-ice.rs b/src/test/compile-fail/match-ref-ice.rs index 1cdbba17f65..cb8f8fad532 100644 --- a/src/test/compile-fail/match-ref-ice.rs +++ b/src/test/compile-fail/match-ref-ice.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(slice_patterns)] #![deny(unreachable_patterns)] // The arity of `ref x` is always 1. If the pattern is compared to some non-structural type whose diff --git a/src/test/compile-fail/match-slice-patterns.rs b/src/test/compile-fail/match-slice-patterns.rs index fd4bd1c7b94..a8ec95da3d8 100644 --- a/src/test/compile-fail/match-slice-patterns.rs +++ b/src/test/compile-fail/match-slice-patterns.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(advanced_slice_patterns, slice_patterns)] +#![feature(slice_patterns)] fn check(list: &[Option<()>]) { match list { diff --git a/src/test/compile-fail/match-vec-fixed.rs b/src/test/compile-fail/match-vec-fixed.rs index dd9379c756d..05971d70167 100644 --- a/src/test/compile-fail/match-vec-fixed.rs +++ b/src/test/compile-fail/match-vec-fixed.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(slice_patterns)] #![deny(unreachable_patterns)] fn a() { diff --git a/src/test/compile-fail/match-vec-mismatch-2.rs b/src/test/compile-fail/match-vec-mismatch-2.rs index 375d855d1fd..52c5375f4e7 100644 --- a/src/test/compile-fail/match-vec-mismatch-2.rs +++ b/src/test/compile-fail/match-vec-mismatch-2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(slice_patterns)] - fn main() { match () { [()] => { } diff --git a/src/test/compile-fail/match-vec-unreachable.rs b/src/test/compile-fail/match-vec-unreachable.rs index 472b054b087..d6e3fdbe088 100644 --- a/src/test/compile-fail/match-vec-unreachable.rs +++ b/src/test/compile-fail/match-vec-unreachable.rs @@ -10,7 +10,6 @@ #![feature(slice_patterns)] #![deny(unreachable_patterns)] -#![allow(unused_variables)] fn main() { let x: Vec<(isize, isize)> = Vec::new(); diff --git a/src/test/compile-fail/move-out-of-slice-1.rs b/src/test/compile-fail/move-out-of-slice-1.rs index 9ca9e0984e4..5efbef549dd 100644 --- a/src/test/compile-fail/move-out-of-slice-1.rs +++ b/src/test/compile-fail/move-out-of-slice-1.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(slice_patterns, box_patterns)] +#![feature(box_patterns)] struct A; diff --git a/src/test/compile-fail/regions-pattern-typing-issue-19552.rs b/src/test/compile-fail/regions-pattern-typing-issue-19552.rs index 8e83177090b..3401dd1becd 100644 --- a/src/test/compile-fail/regions-pattern-typing-issue-19552.rs +++ b/src/test/compile-fail/regions-pattern-typing-issue-19552.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(slice_patterns)] - fn assert_static(_t: T) {} fn main() { diff --git a/src/test/compile-fail/uninhabited-matches-feature-gated.rs b/src/test/compile-fail/uninhabited-matches-feature-gated.rs index 0c3ea53a903..1d3f8ff12d8 100644 --- a/src/test/compile-fail/uninhabited-matches-feature-gated.rs +++ b/src/test/compile-fail/uninhabited-matches-feature-gated.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(slice_patterns)] - enum Void {} fn main() { diff --git a/src/test/compile-fail/uninhabited-patterns.rs b/src/test/compile-fail/uninhabited-patterns.rs index 9f943f08232..e130df5c845 100644 --- a/src/test/compile-fail/uninhabited-patterns.rs +++ b/src/test/compile-fail/uninhabited-patterns.rs @@ -9,9 +9,9 @@ // except according to those terms. #![feature(box_patterns)] -#![feature(slice_patterns)] #![feature(box_syntax)] #![feature(exhaustive_patterns)] +#![feature(slice_patterns)] #![deny(unreachable_patterns)] mod foo { diff --git a/src/test/mir-opt/uniform_array_move_out.rs b/src/test/mir-opt/uniform_array_move_out.rs index 482b69a59dd..fa5f62f89f6 100644 --- a/src/test/mir-opt/uniform_array_move_out.rs +++ b/src/test/mir-opt/uniform_array_move_out.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(box_syntax, slice_patterns, advanced_slice_patterns)] +#![feature(box_syntax)] +#![feature(slice_patterns)] fn move_out_from_end() { let a = [box 1, box 2]; diff --git a/src/test/run-pass-fulldeps/auxiliary/roman_numerals.rs b/src/test/run-pass-fulldeps/auxiliary/roman_numerals.rs index 26419a51513..17cf39372c0 100644 --- a/src/test/run-pass-fulldeps/auxiliary/roman_numerals.rs +++ b/src/test/run-pass-fulldeps/auxiliary/roman_numerals.rs @@ -12,7 +12,6 @@ #![crate_type="dylib"] #![feature(plugin_registrar, rustc_private)] -#![feature(slice_patterns)] extern crate syntax; extern crate syntax_pos; diff --git a/src/test/run-pass/destructure-array-1.rs b/src/test/run-pass/destructure-array-1.rs index 0d24f0bd0d7..43271162c18 100644 --- a/src/test/run-pass/destructure-array-1.rs +++ b/src/test/run-pass/destructure-array-1.rs @@ -11,9 +11,6 @@ // Ensure that we can do a destructuring bind of a fixed-size array, // even when the element type has a destructor. - -#![feature(slice_patterns)] - struct D { x: u8 } impl Drop for D { fn drop(&mut self) { } } diff --git a/src/test/run-pass/dynamic-drop.rs b/src/test/run-pass/dynamic-drop.rs index 4d0bd3f3412..1f543f7be0e 100644 --- a/src/test/run-pass/dynamic-drop.rs +++ b/src/test/run-pass/dynamic-drop.rs @@ -13,7 +13,8 @@ // ignore-wasm32-bare compiled with panic=abort by default -#![feature(generators, generator_trait, untagged_unions, slice_patterns, advanced_slice_patterns)] +#![feature(generators, generator_trait, untagged_unions)] +#![feature(slice_patterns)] use std::cell::{Cell, RefCell}; use std::ops::Generator; diff --git a/src/test/run-pass/ignore-all-the-things.rs b/src/test/run-pass/ignore-all-the-things.rs index 711f2dd6c66..c14f3dc7291 100644 --- a/src/test/run-pass/ignore-all-the-things.rs +++ b/src/test/run-pass/ignore-all-the-things.rs @@ -10,7 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(advanced_slice_patterns)] #![feature(slice_patterns)] struct Foo(isize, isize, isize, isize); @@ -20,11 +19,11 @@ pub fn main() { let Foo(..) = Foo(5, 5, 5, 5); let Foo(..) = Foo(5, 5, 5, 5); let Bar{..} = Bar{a: 5, b: 5, c: 5, d: 5}; - //let (..) = (5, 5, 5, 5); - //let Foo(a, b, ..) = Foo(5, 5, 5, 5); - //let Foo(.., d) = Foo(5, 5, 5, 5); - //let (a, b, ..) = (5, 5, 5, 5); - //let (.., c, d) = (5, 5, 5, 5); + let (..) = (5, 5, 5, 5); + let Foo(a, b, ..) = Foo(5, 5, 5, 5); + let Foo(.., d) = Foo(5, 5, 5, 5); + let (a, b, ..) = (5, 5, 5, 5); + let (.., c, d) = (5, 5, 5, 5); let Bar{b: b, ..} = Bar{a: 5, b: 5, c: 5, d: 5}; match [5, 5, 5, 5] { [..] => { } diff --git a/src/test/run-pass/issue-13027.rs b/src/test/run-pass/issue-13027.rs index 14987484711..d28ea94ec1a 100644 --- a/src/test/run-pass/issue-13027.rs +++ b/src/test/run-pass/issue-13027.rs @@ -12,8 +12,6 @@ // Tests that match expression handles overlapped literal and range // properly in the presence of guard function. -#![feature(slice_patterns)] - fn val() -> usize { 1 } static CONST: usize = 1; diff --git a/src/test/run-pass/issue-15080.rs b/src/test/run-pass/issue-15080.rs index 14e00378846..59267f79e26 100644 --- a/src/test/run-pass/issue-15080.rs +++ b/src/test/run-pass/issue-15080.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - #![feature(slice_patterns)] fn main() { diff --git a/src/test/run-pass/issue-15104.rs b/src/test/run-pass/issue-15104.rs index 508360cb701..2878f2795c5 100644 --- a/src/test/run-pass/issue-15104.rs +++ b/src/test/run-pass/issue-15104.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - #![feature(slice_patterns)] fn main() { diff --git a/src/test/run-pass/issue-16648.rs b/src/test/run-pass/issue-16648.rs index e1b94179764..bf272308fa9 100644 --- a/src/test/run-pass/issue-16648.rs +++ b/src/test/run-pass/issue-16648.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(slice_patterns)] - fn main() { let x: (isize, &[isize]) = (2, &[1, 2]); assert_eq!(match x { diff --git a/src/test/run-pass/issue-17877.rs b/src/test/run-pass/issue-17877.rs index 6c87e8d35fb..d3fe0903a1d 100644 --- a/src/test/run-pass/issue-17877.rs +++ b/src/test/run-pass/issue-17877.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - #![feature(slice_patterns)] fn main() { diff --git a/src/test/run-pass/issue-37598.rs b/src/test/run-pass/issue-37598.rs index d32d2fc2954..e97c8d9f417 100644 --- a/src/test/run-pass/issue-37598.rs +++ b/src/test/run-pass/issue-37598.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(advanced_slice_patterns, slice_patterns)] +#![feature(slice_patterns)] fn check(list: &[u8]) { match list { diff --git a/src/test/run-pass/issue-38002.rs b/src/test/run-pass/issue-38002.rs index 489d35e9147..dd6ccec973f 100644 --- a/src/test/run-pass/issue-38002.rs +++ b/src/test/run-pass/issue-38002.rs @@ -10,8 +10,6 @@ // Check that constant ADTs are translated OK, part k of N. -#![feature(slice_patterns)] - enum Bar { C } diff --git a/src/test/run-pass/issue-46855.rs b/src/test/run-pass/issue-46855.rs index d864d55c939..28aa6c731ec 100644 --- a/src/test/run-pass/issue-46855.rs +++ b/src/test/run-pass/issue-46855.rs @@ -10,8 +10,6 @@ // compile-flags: -Zmir-opt-level=1 -#![feature(slice_patterns)] - use std::mem; #[derive(Copy, Clone)] diff --git a/src/test/run-pass/issue-7784.rs b/src/test/run-pass/issue-7784.rs index badc013cd62..8d21594aa12 100644 --- a/src/test/run-pass/issue-7784.rs +++ b/src/test/run-pass/issue-7784.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(advanced_slice_patterns)] #![feature(slice_patterns)] use std::ops::Add; diff --git a/src/test/run-pass/match-vec-alternatives.rs b/src/test/run-pass/match-vec-alternatives.rs index fa609593c24..7d03d9c2abe 100644 --- a/src/test/run-pass/match-vec-alternatives.rs +++ b/src/test/run-pass/match-vec-alternatives.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(advanced_slice_patterns)] #![feature(slice_patterns)] fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str { diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/slice.rs b/src/test/run-pass/rfc-2005-default-binding-mode/slice.rs index 1717d0d54c0..6178f613b4b 100644 --- a/src/test/run-pass/rfc-2005-default-binding-mode/slice.rs +++ b/src/test/run-pass/rfc-2005-default-binding-mode/slice.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(slice_patterns)] #![feature(match_default_bindings)] +#![feature(slice_patterns)] fn slice_pat() { let sl: &[u8] = b"foo"; diff --git a/src/test/run-pass/trailing-comma.rs b/src/test/run-pass/trailing-comma.rs index b9eda084653..02bae5aa455 100644 --- a/src/test/run-pass/trailing-comma.rs +++ b/src/test/run-pass/trailing-comma.rs @@ -10,7 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(advanced_slice_patterns,)] #![feature(slice_patterns)] fn f(_: T,) {} diff --git a/src/test/run-pass/vec-matching-autoslice.rs b/src/test/run-pass/vec-matching-autoslice.rs index 9df777e7af0..7268536a51f 100644 --- a/src/test/run-pass/vec-matching-autoslice.rs +++ b/src/test/run-pass/vec-matching-autoslice.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(slice_patterns)] - pub fn main() { let x = [1, 2, 3]; match x { diff --git a/src/test/run-pass/vec-matching-fixed.rs b/src/test/run-pass/vec-matching-fixed.rs index 1ed6ddc4110..060d152488a 100644 --- a/src/test/run-pass/vec-matching-fixed.rs +++ b/src/test/run-pass/vec-matching-fixed.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(advanced_slice_patterns)] #![feature(slice_patterns)] fn a() { diff --git a/src/test/run-pass/vec-matching-fold.rs b/src/test/run-pass/vec-matching-fold.rs index ac80a4211ad..1a30f875580 100644 --- a/src/test/run-pass/vec-matching-fold.rs +++ b/src/test/run-pass/vec-matching-fold.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(advanced_slice_patterns)] #![feature(slice_patterns)] use std::fmt::Debug; diff --git a/src/test/run-pass/vec-matching.rs b/src/test/run-pass/vec-matching.rs index bd0731a555c..ace418f2160 100644 --- a/src/test/run-pass/vec-matching.rs +++ b/src/test/run-pass/vec-matching.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(advanced_slice_patterns)] #![feature(slice_patterns)] fn a() { diff --git a/src/test/run-pass/vec-tail-matching.rs b/src/test/run-pass/vec-tail-matching.rs index d123eb36a7d..4f31405ead5 100644 --- a/src/test/run-pass/vec-tail-matching.rs +++ b/src/test/run-pass/vec-tail-matching.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - - #![feature(slice_patterns)] struct Foo { diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs index 07b268f1a4b..111968e9c93 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs +++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(advanced_slice_patterns)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(slice_patterns)] diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr index e11702df80a..6673549e239 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr +++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr @@ -1,5 +1,5 @@ error[E0506]: cannot assign to `vec[..]` because it is borrowed - --> $DIR/borrowck-vec-pattern-nesting.rs:21:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:20:13 | LL | [box ref _a, _, _] => { | ------ borrow of `vec[..]` occurs here @@ -8,7 +8,7 @@ LL | vec[0] = box 4; //~ ERROR cannot assign | ^^^^^^^^^^^^^^ assignment to borrowed `vec[..]` occurs here error[E0506]: cannot assign to `vec[..]` because it is borrowed - --> $DIR/borrowck-vec-pattern-nesting.rs:33:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:32:13 | LL | &mut [ref _b..] => { | ------ borrow of `vec[..]` occurs here @@ -17,7 +17,7 @@ LL | vec[0] = box 4; //~ ERROR cannot assign | ^^^^^^^^^^^^^^ assignment to borrowed `vec[..]` occurs here error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:43:14 + --> $DIR/borrowck-vec-pattern-nesting.rs:42:14 | LL | &mut [_a, //~ ERROR cannot move out | ^-- hint: to prevent move, use `ref _a` or `ref mut _a` @@ -30,7 +30,7 @@ LL | | ] => { | |_________^ cannot move out of here error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:56:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:55:13 | LL | let a = vec[0]; //~ ERROR cannot move out | ^^^^^^ @@ -39,7 +39,7 @@ LL | let a = vec[0]; //~ ERROR cannot move out | help: consider using a reference instead: `&vec[0]` error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:64:14 + --> $DIR/borrowck-vec-pattern-nesting.rs:63:14 | LL | &mut [ //~ ERROR cannot move out | ______________^ @@ -50,7 +50,7 @@ LL | | _b] => {} | hint: to prevent move, use `ref _b` or `ref mut _b` error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:69:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:68:13 | LL | let a = vec[0]; //~ ERROR cannot move out | ^^^^^^ @@ -59,7 +59,7 @@ LL | let a = vec[0]; //~ ERROR cannot move out | help: consider using a reference instead: `&vec[0]` error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:77:14 + --> $DIR/borrowck-vec-pattern-nesting.rs:76:14 | LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out | ^--^^--^^--^ @@ -70,7 +70,7 @@ LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out | cannot move out of here error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:81:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:80:13 | LL | let a = vec[0]; //~ ERROR cannot move out | ^^^^^^ diff --git a/src/test/ui/error-codes/E0527.rs b/src/test/ui/error-codes/E0527.rs index 67d222e867e..a90ccec9cf5 100644 --- a/src/test/ui/error-codes/E0527.rs +++ b/src/test/ui/error-codes/E0527.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(slice_patterns)] - fn main() { let r = &[1, 2, 3, 4]; match r { diff --git a/src/test/ui/error-codes/E0527.stderr b/src/test/ui/error-codes/E0527.stderr index 2060f1e69e0..1e764c18587 100644 --- a/src/test/ui/error-codes/E0527.stderr +++ b/src/test/ui/error-codes/E0527.stderr @@ -1,5 +1,5 @@ error[E0527]: pattern requires 2 elements but array has 4 - --> $DIR/E0527.rs:16:10 + --> $DIR/E0527.rs:14:10 | LL | &[a, b] => { | ^^^^^^ expected 4 elements diff --git a/src/test/ui/error-codes/E0529.rs b/src/test/ui/error-codes/E0529.rs index 5262ad7b716..2459054da89 100644 --- a/src/test/ui/error-codes/E0529.rs +++ b/src/test/ui/error-codes/E0529.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(slice_patterns)] - fn main() { let r: f32 = 1.0; match r { diff --git a/src/test/ui/error-codes/E0529.stderr b/src/test/ui/error-codes/E0529.stderr index fcada000790..b2e7ae23fb0 100644 --- a/src/test/ui/error-codes/E0529.stderr +++ b/src/test/ui/error-codes/E0529.stderr @@ -1,5 +1,5 @@ error[E0529]: expected an array or slice, found `f32` - --> $DIR/E0529.rs:16:9 + --> $DIR/E0529.rs:14:9 | LL | [a, b] => { | ^^^^^^ pattern cannot match with input type `f32` diff --git a/src/test/ui/feature-gate-advanced-slice-features.rs b/src/test/ui/feature-gate-advanced-slice-features.rs deleted file mode 100644 index dc9b4e634ab..00000000000 --- a/src/test/ui/feature-gate-advanced-slice-features.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// gate-test-advanced_slice_patterns - -#![feature(slice_patterns)] - -fn main() { - let x = [ 1, 2, 3, 4, 5 ]; - match x { - [ xs.., 4, 5 ] => {} //~ ERROR multiple-element slice matches - [ 1, xs.., 5 ] => {} //~ ERROR multiple-element slice matches - [ 1, 2, xs.. ] => {} // OK without feature gate - } -} diff --git a/src/test/ui/feature-gate-advanced-slice-features.stderr b/src/test/ui/feature-gate-advanced-slice-features.stderr deleted file mode 100644 index 9d9e7554976..00000000000 --- a/src/test/ui/feature-gate-advanced-slice-features.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0658]: multiple-element slice matches anywhere but at the end of a slice (e.g. `[0, ..xs, 0]`) are experimental (see issue #23121) - --> $DIR/feature-gate-advanced-slice-features.rs:18:9 - | -LL | [ xs.., 4, 5 ] => {} //~ ERROR multiple-element slice matches - | ^^^^^^^^^^^^^^ - | - = help: add #![feature(advanced_slice_patterns)] to the crate attributes to enable - -error[E0658]: multiple-element slice matches anywhere but at the end of a slice (e.g. `[0, ..xs, 0]`) are experimental (see issue #23121) - --> $DIR/feature-gate-advanced-slice-features.rs:19:9 - | -LL | [ 1, xs.., 5 ] => {} //~ ERROR multiple-element slice matches - | ^^^^^^^^^^^^^^ - | - = help: add #![feature(advanced_slice_patterns)] to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate-slice-patterns.rs b/src/test/ui/feature-gate-slice-patterns.rs index 625cb2d3515..fd058f65172 100644 --- a/src/test/ui/feature-gate-slice-patterns.rs +++ b/src/test/ui/feature-gate-slice-patterns.rs @@ -8,11 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that slice pattern syntax is gated by `slice_patterns` feature gate +// Test that slice pattern syntax with `..` is gated by `slice_patterns` feature gate fn main() { let x = [1, 2, 3, 4, 5]; match x { - [1, 2, xs..] => {} //~ ERROR slice pattern syntax is experimental + [1, 2, ..] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized + [1, .., 5] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized + [.., 4, 5] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized + } + + let x = [ 1, 2, 3, 4, 5 ]; + match x { + [ xs.., 4, 5 ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized + [ 1, xs.., 5 ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized + [ 1, 2, xs.. ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized } } diff --git a/src/test/ui/feature-gate-slice-patterns.stderr b/src/test/ui/feature-gate-slice-patterns.stderr index 7c216fad933..d560dcd54ee 100644 --- a/src/test/ui/feature-gate-slice-patterns.stderr +++ b/src/test/ui/feature-gate-slice-patterns.stderr @@ -1,11 +1,51 @@ -error[E0658]: slice pattern syntax is experimental (see issue #23121) - --> $DIR/feature-gate-slice-patterns.rs:16:9 +error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) + --> $DIR/feature-gate-slice-patterns.rs:16:16 | -LL | [1, 2, xs..] => {} //~ ERROR slice pattern syntax is experimental - | ^^^^^^^^^^^^ +LL | [1, 2, ..] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized + | ^^ | = help: add #![feature(slice_patterns)] to the crate attributes to enable -error: aborting due to previous error +error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) + --> $DIR/feature-gate-slice-patterns.rs:17:13 + | +LL | [1, .., 5] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized + | ^^ + | + = help: add #![feature(slice_patterns)] to the crate attributes to enable + +error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) + --> $DIR/feature-gate-slice-patterns.rs:18:10 + | +LL | [.., 4, 5] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized + | ^^ + | + = help: add #![feature(slice_patterns)] to the crate attributes to enable + +error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) + --> $DIR/feature-gate-slice-patterns.rs:23:11 + | +LL | [ xs.., 4, 5 ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized + | ^^ + | + = help: add #![feature(slice_patterns)] to the crate attributes to enable + +error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) + --> $DIR/feature-gate-slice-patterns.rs:24:14 + | +LL | [ 1, xs.., 5 ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized + | ^^ + | + = help: add #![feature(slice_patterns)] to the crate attributes to enable + +error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) + --> $DIR/feature-gate-slice-patterns.rs:25:17 + | +LL | [ 1, 2, xs.. ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized + | ^^ + | + = help: add #![feature(slice_patterns)] to the crate attributes to enable + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/mismatched_types/issue-38371.rs b/src/test/ui/mismatched_types/issue-38371.rs index b9b6b05996b..8e613d4edba 100644 --- a/src/test/ui/mismatched_types/issue-38371.rs +++ b/src/test/ui/mismatched_types/issue-38371.rs @@ -7,8 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(slice_patterns)] - struct Foo { } diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr index 1bf1521e39e..dd5da769075 100644 --- a/src/test/ui/mismatched_types/issue-38371.stderr +++ b/src/test/ui/mismatched_types/issue-38371.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-38371.rs:16:8 + --> $DIR/issue-38371.rs:14:8 | LL | fn foo(&foo: Foo) { //~ ERROR mismatched types | ^^^^ expected struct `Foo`, found reference @@ -9,7 +9,7 @@ LL | fn foo(&foo: Foo) { //~ ERROR mismatched types = help: did you mean `foo: &Foo`? error[E0308]: mismatched types - --> $DIR/issue-38371.rs:30:9 + --> $DIR/issue-38371.rs:28:9 | LL | fn agh(&&bar: &u32) { //~ ERROR mismatched types | ^^^^ expected u32, found reference @@ -19,7 +19,7 @@ LL | fn agh(&&bar: &u32) { //~ ERROR mismatched types = help: did you mean `bar: &u32`? error[E0308]: mismatched types - --> $DIR/issue-38371.rs:33:8 + --> $DIR/issue-38371.rs:31:8 | LL | fn bgh(&&bar: u32) { //~ ERROR mismatched types | ^^^^^ expected u32, found reference @@ -28,7 +28,7 @@ LL | fn bgh(&&bar: u32) { //~ ERROR mismatched types found type `&_` error[E0529]: expected an array or slice, found `u32` - --> $DIR/issue-38371.rs:36:9 + --> $DIR/issue-38371.rs:34:9 | LL | fn ugh(&[bar]: &u32) { //~ ERROR expected an array or slice | ^^^^^ pattern cannot match with input type `u32` diff --git a/src/test/ui/non-exhaustive-pattern-witness.rs b/src/test/ui/non-exhaustive-pattern-witness.rs index 0b12a9acbcb..dd14a10a2bc 100644 --- a/src/test/ui/non-exhaustive-pattern-witness.rs +++ b/src/test/ui/non-exhaustive-pattern-witness.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(advanced_slice_patterns)] #![feature(slice_patterns)] struct Foo { diff --git a/src/test/ui/non-exhaustive-pattern-witness.stderr b/src/test/ui/non-exhaustive-pattern-witness.stderr index 7179b4b135a..e364e822ea8 100644 --- a/src/test/ui/non-exhaustive-pattern-witness.stderr +++ b/src/test/ui/non-exhaustive-pattern-witness.stderr @@ -1,41 +1,41 @@ error[E0004]: non-exhaustive patterns: `Foo { first: false, second: Some([_, _, _, _]) }` not covered - --> $DIR/non-exhaustive-pattern-witness.rs:20:11 + --> $DIR/non-exhaustive-pattern-witness.rs:19:11 | LL | match (Foo { first: true, second: None }) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { first: false, second: Some([_, _, _, _]) }` not covered error[E0004]: non-exhaustive patterns: `Red` not covered - --> $DIR/non-exhaustive-pattern-witness.rs:36:11 + --> $DIR/non-exhaustive-pattern-witness.rs:35:11 | LL | match Color::Red { | ^^^^^^^^^^ pattern `Red` not covered error[E0004]: non-exhaustive patterns: `East`, `South` and `West` not covered - --> $DIR/non-exhaustive-pattern-witness.rs:48:11 + --> $DIR/non-exhaustive-pattern-witness.rs:47:11 | LL | match Direction::North { | ^^^^^^^^^^^^^^^^ patterns `East`, `South` and `West` not covered error[E0004]: non-exhaustive patterns: `Second`, `Third`, `Fourth` and 8 more not covered - --> $DIR/non-exhaustive-pattern-witness.rs:59:11 + --> $DIR/non-exhaustive-pattern-witness.rs:58:11 | LL | match ExcessiveEnum::First { | ^^^^^^^^^^^^^^^^^^^^ patterns `Second`, `Third`, `Fourth` and 8 more not covered error[E0004]: non-exhaustive patterns: `CustomRGBA { a: true, .. }` not covered - --> $DIR/non-exhaustive-pattern-witness.rs:67:11 + --> $DIR/non-exhaustive-pattern-witness.rs:66:11 | LL | match Color::Red { | ^^^^^^^^^^ pattern `CustomRGBA { a: true, .. }` not covered error[E0004]: non-exhaustive patterns: `[Second(true), Second(false)]` not covered - --> $DIR/non-exhaustive-pattern-witness.rs:83:11 + --> $DIR/non-exhaustive-pattern-witness.rs:82:11 | LL | match *x { | ^^ pattern `[Second(true), Second(false)]` not covered error[E0004]: non-exhaustive patterns: `((), false)` not covered - --> $DIR/non-exhaustive-pattern-witness.rs:96:11 + --> $DIR/non-exhaustive-pattern-witness.rs:95:11 | LL | match ((), false) { | ^^^^^^^^^^^ pattern `((), false)` not covered diff --git a/src/test/ui/pat-slice-old-style.rs b/src/test/ui/pat-slice-old-style.rs index 4ff1e94b087..65578e76d6d 100644 --- a/src/test/ui/pat-slice-old-style.rs +++ b/src/test/ui/pat-slice-old-style.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(slice_patterns)] - // NB: this test was introduced in #23121 and will have to change when default match binding modes // stabilizes. +#![feature(slice_patterns)] + fn slice_pat(x: &[u8]) { // OLD! match x { diff --git a/src/test/ui/rfc-2005-default-binding-mode/slice.rs b/src/test/ui/rfc-2005-default-binding-mode/slice.rs index 40aa957242c..20ef0624bf9 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/slice.rs +++ b/src/test/ui/rfc-2005-default-binding-mode/slice.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(slice_patterns)] #![feature(match_default_bindings)] +#![feature(slice_patterns)] pub fn main() { let sl: &[u8] = b"foo"; -- cgit 1.4.1-3-g733a5 From 619003d1d414167630331efffe83702f74413be6 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Tue, 20 Mar 2018 05:33:59 -0400 Subject: Implement some trivial size_hints for various iterators This also implements ExactSizeIterator where applicable. Addresses most of the Iterator traits mentioned in #23708. --- src/libcore/char.rs | 5 +++++ src/libcore/iter/traits.rs | 4 ++++ src/libcore/option.rs | 5 +++++ src/librustc/hir/pat_util.rs | 4 ++++ src/librustc/mir/traversal.rs | 26 ++++++++++++++++++++++++++ src/librustc/session/search_paths.rs | 7 +++++++ src/librustc/traits/util.rs | 5 +++++ src/librustc_data_structures/bitvec.rs | 5 +++++ src/librustc_data_structures/graph/mod.rs | 13 +++++++++++++ src/librustc_driver/pretty.rs | 7 +++++++ src/librustc_typeck/check/method/suggest.rs | 7 +++++++ src/librustdoc/clean/mod.rs | 5 +++++ src/libsyntax_ext/format_foreign.rs | 9 +++++++++ 13 files changed, 102 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 1638f9710f5..2f56238a463 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -902,6 +902,11 @@ impl> Iterator for DecodeUtf8 { } }) } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } } #[unstable(feature = "decode_utf8", issue = "33906")] diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 0267fcd3754..5e4622f804a 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -901,6 +901,10 @@ impl Iterator for ResultShunt None => None, } } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } } #[stable(feature = "iter_arith_traits_result", since="1.16.0")] diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 570f745f833..1ca69f3f503 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -1188,6 +1188,11 @@ impl> FromIterator> for Option { None => None, } } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } } let mut adapter = Adapter { iter: iter.into_iter(), found_none: false }; diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index 2bec224362e..1f00a3ab1f5 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -31,6 +31,10 @@ impl Iterator for EnumerateAndAdjust where I: Iterator { (if i < self.gap_pos { i } else { i + self.gap_len }, elem) }) } + + fn size_hint(&self) -> (usize, Option) { + self.enumerate.size_hint() + } } pub trait EnumerateAndAdjustIterator { diff --git a/src/librustc/mir/traversal.rs b/src/librustc/mir/traversal.rs index 74c3408c4c2..666ca5eabe8 100644 --- a/src/librustc/mir/traversal.rs +++ b/src/librustc/mir/traversal.rs @@ -77,8 +77,18 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { None } + + fn size_hint(&self) -> (usize, Option) { + // All the blocks, minus the number of blocks we've visited. + let remaining = self.mir.basic_blocks().len() - self.visited.count(); + + // We will visit all remaining blocks exactly once. + (remaining, Some(remaining)) + } } +impl<'a, 'tcx> ExactSizeIterator for Preorder<'a, 'tcx> {} + /// Postorder traversal of a graph. /// /// Postorder traversal is when each node is visited after all of it's @@ -210,8 +220,18 @@ impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> { next.map(|(bb, _)| (bb, &self.mir[bb])) } + + fn size_hint(&self) -> (usize, Option) { + // All the blocks, minus the number of blocks we've visited. + let remaining = self.mir.basic_blocks().len() - self.visited.count(); + + // We will visit all remaining blocks exactly once. + (remaining, Some(remaining)) + } } +impl<'a, 'tcx> ExactSizeIterator for Postorder<'a, 'tcx> {} + /// Reverse postorder traversal of a graph /// /// Reverse postorder is the reverse order of a postorder traversal. @@ -276,4 +296,10 @@ impl<'a, 'tcx> Iterator for ReversePostorder<'a, 'tcx> { self.blocks.get(self.idx).map(|&bb| (bb, &self.mir[bb])) } + + fn size_hint(&self) -> (usize, Option) { + (self.idx, Some(self.idx)) + } } + +impl<'a, 'tcx> ExactSizeIterator for ReversePostorder<'a, 'tcx> {} diff --git a/src/librustc/session/search_paths.rs b/src/librustc/session/search_paths.rs index 5bbc6841693..d2dca9f6084 100644 --- a/src/librustc/session/search_paths.rs +++ b/src/librustc/session/search_paths.rs @@ -78,4 +78,11 @@ impl<'a> Iterator for Iter<'a> { } } } + + fn size_hint(&self) -> (usize, Option) { + // This iterator will never return more elements than the base iterator; + // but it can ignore all the remaining elements. + let (_, upper) = self.iter.size_hint(); + (0, upper) + } } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 8f7a2405747..9e38911f53c 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -347,6 +347,11 @@ impl<'tcx,I:Iterator>> Iterator for FilterToTraits { } } } + + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.base_iterator.size_hint(); + (0, upper) + } } /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 54565afa4c6..28e3180063c 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -132,6 +132,11 @@ impl<'a> Iterator for BitVectorIter<'a> { self.idx += offset + 1; return Some(self.idx - 1); } + + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } } impl FromIterator for BitVector { diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index 1945b82c031..e2b393071ff 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -334,6 +334,11 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { self.next = edge.next_edge[self.direction.repr]; Some((edge_index, edge)) } + + fn size_hint(&self) -> (usize, Option) { + // At most, all the edges in the graph. + (0, Some(self.graph.len_edges())) + } } pub struct DepthFirstTraversal<'g, N, E> @@ -383,8 +388,16 @@ impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> { } next } + + fn size_hint(&self) -> (usize, Option) { + // We will visit every node in the graph exactly once. + let remaining = self.graph.len_nodes() - self.visited.count(); + (remaining, Some(remaining)) + } } +impl<'g, N: Debug, E: Debug> ExactSizeIterator for DepthFirstTraversal<'g, N, E> {} + impl Edge { pub fn source(&self) -> NodeIndex { self.source diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 4ae6a93d698..c5e7fdb30d3 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -584,6 +584,13 @@ impl<'a, 'hir> Iterator for NodesMatchingUII<'a, 'hir> { &mut NodesMatchingSuffix(ref mut iter) => iter.next(), } } + + fn size_hint(&self) -> (usize, Option) { + match self { + &NodesMatchingDirect(ref iter) => iter.size_hint(), + &NodesMatchingSuffix(ref iter) => iter.size_hint(), + } + } } impl UserIdentifiedItem { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 61afac97d64..a7536980503 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -718,8 +718,15 @@ impl<'a> Iterator for AllTraits<'a> { TraitInfo::new(*info) }) } + + fn size_hint(&self) -> (usize, Option) { + let len = self.borrow.as_ref().unwrap().len() - self.idx; + (len, Some(len)) + } } +impl<'a> ExactSizeIterator for AllTraits<'a> {} + struct UsePlacementFinder<'a, 'tcx: 'a, 'gcx: 'tcx> { target_module: ast::NodeId, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 904c24815cb..a2a0e878fd8 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -602,6 +602,11 @@ impl<'a> Iterator for ListAttributesIter<'a> { None } + + fn size_hint(&self) -> (usize, Option) { + let lower = self.current_list.len(); + (lower, None) + } } pub trait AttributesExt { diff --git a/src/libsyntax_ext/format_foreign.rs b/src/libsyntax_ext/format_foreign.rs index 0476d7d4fcc..e95c6f2e124 100644 --- a/src/libsyntax_ext/format_foreign.rs +++ b/src/libsyntax_ext/format_foreign.rs @@ -272,6 +272,11 @@ pub mod printf { self.s = tail; Some(sub) } + + fn size_hint(&self) -> (usize, Option) { + // Substitutions are at least 2 characters long. + (0, Some(self.s.len() / 2)) + } } enum State { @@ -782,6 +787,10 @@ pub mod shell { None => None, } } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.s.len())) + } } /// Parse the next substitution from the input string. -- cgit 1.4.1-3-g733a5 From 57896abc38f56dce27ca9d4642c18f44be8db620 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Tue, 20 Mar 2018 00:48:41 +0100 Subject: Make resuming generators unsafe instead of the creation of immovable generators. Fixes #47787 --- .../src/language-features/generators.md | 20 ++++++++-------- src/liballoc/boxed.rs | 2 +- src/libcore/ops/generator.rs | 12 ++++++---- src/librustc_mir/diagnostics.rs | 10 ++++---- src/librustc_mir/transform/check_unsafety.rs | 12 ++-------- src/test/run-pass/dynamic-drop.rs | 2 +- src/test/run-pass/generator/conditional-drop.rs | 8 +++---- src/test/run-pass/generator/control-flow.rs | 2 +- src/test/run-pass/generator/drop-env.rs | 4 ++-- src/test/run-pass/generator/issue-44197.rs | 6 +++-- src/test/run-pass/generator/iterator-count.rs | 4 +++- .../run-pass/generator/live-upvar-across-yield.rs | 2 +- src/test/run-pass/generator/nested_generators.rs | 2 +- src/test/run-pass/generator/panic-drops.rs | 4 ++-- src/test/run-pass/generator/panic-safe.rs | 4 ++-- src/test/run-pass/generator/resume-after-return.rs | 4 ++-- src/test/run-pass/generator/smoke.rs | 28 +++++++++++----------- src/test/run-pass/generator/static-generators.rs | 18 +++++++------- src/test/run-pass/generator/xcrate-reachable.rs | 2 +- src/test/run-pass/generator/xcrate.rs | 6 ++--- src/test/ui/generator/borrowing.rs | 2 +- src/test/ui/generator/borrowing.stderr | 10 ++++---- src/test/ui/generator/dropck.rs | 2 +- src/test/ui/generator/sized-yield.rs | 2 +- src/test/ui/generator/sized-yield.stderr | 6 ++--- src/test/ui/generator/unsafe-immovable.rs | 17 ------------- src/test/ui/generator/unsafe-immovable.stderr | 11 --------- src/test/ui/generator/yield-while-iterating.rs | 6 ++--- .../ui/generator/yield-while-local-borrowed.rs | 6 ++--- .../ui/generator/yield-while-ref-reborrowed.rs | 6 ++--- 30 files changed, 96 insertions(+), 124 deletions(-) delete mode 100644 src/test/ui/generator/unsafe-immovable.rs delete mode 100644 src/test/ui/generator/unsafe-immovable.stderr (limited to 'src/libcore') diff --git a/src/doc/unstable-book/src/language-features/generators.md b/src/doc/unstable-book/src/language-features/generators.md index e8e2132dca2..8e888de90a9 100644 --- a/src/doc/unstable-book/src/language-features/generators.md +++ b/src/doc/unstable-book/src/language-features/generators.md @@ -36,11 +36,11 @@ fn main() { return "foo" }; - match generator.resume() { + match unsafe { generator.resume() } { GeneratorState::Yielded(1) => {} _ => panic!("unexpected value from resume"), } - match generator.resume() { + match unsafe { generator.resume() } { GeneratorState::Complete("foo") => {} _ => panic!("unexpected value from resume"), } @@ -69,9 +69,9 @@ fn main() { }; println!("1"); - generator.resume(); + unsafe { generator.resume() }; println!("3"); - generator.resume(); + unsafe { generator.resume() }; println!("5"); } ``` @@ -92,7 +92,7 @@ The `Generator` trait in `std::ops` currently looks like: pub trait Generator { type Yield; type Return; - fn resume(&mut self) -> GeneratorState; + unsafe fn resume(&mut self) -> GeneratorState; } ``` @@ -175,8 +175,8 @@ fn main() { return ret }; - generator.resume(); - generator.resume(); + unsafe { generator.resume() }; + unsafe { generator.resume() }; } ``` @@ -200,7 +200,7 @@ fn main() { type Yield = i32; type Return = &'static str; - fn resume(&mut self) -> GeneratorState { + unsafe fn resume(&mut self) -> GeneratorState { use std::mem; match mem::replace(self, __Generator::Done) { __Generator::Start(s) => { @@ -223,8 +223,8 @@ fn main() { __Generator::Start(ret) }; - generator.resume(); - generator.resume(); + unsafe { generator.resume() }; + unsafe { generator.resume() }; } ``` diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index b776556d59f..a86ab87ec18 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -892,7 +892,7 @@ impl Generator for Box { type Yield = T::Yield; type Return = T::Return; - fn resume(&mut self) -> GeneratorState { + unsafe fn resume(&mut self) -> GeneratorState { (**self).resume() } } diff --git a/src/libcore/ops/generator.rs b/src/libcore/ops/generator.rs index dc7669d195c..4b70c5398be 100644 --- a/src/libcore/ops/generator.rs +++ b/src/libcore/ops/generator.rs @@ -56,11 +56,11 @@ pub enum GeneratorState { /// return "foo" /// }; /// -/// match generator.resume() { +/// match unsafe { generator.resume() } { /// GeneratorState::Yielded(1) => {} /// _ => panic!("unexpected return from resume"), /// } -/// match generator.resume() { +/// match unsafe { generator.resume() } { /// GeneratorState::Complete("foo") => {} /// _ => panic!("unexpected return from resume"), /// } @@ -98,6 +98,10 @@ pub trait Generator { /// generator will continue executing until it either yields or returns, at /// which point this function will return. /// + /// The function is unsafe because it can be used on an immovable generator. + /// After such a call, the immovable generator must not move again, but + /// this is not enforced by the compiler. + /// /// # Return value /// /// The `GeneratorState` enum returned from this function indicates what @@ -116,7 +120,7 @@ pub trait Generator { /// been returned previously. While generator literals in the language are /// guaranteed to panic on resuming after `Complete`, this is not guaranteed /// for all implementations of the `Generator` trait. - fn resume(&mut self) -> GeneratorState; + unsafe fn resume(&mut self) -> GeneratorState; } #[unstable(feature = "generator_trait", issue = "43122")] @@ -125,7 +129,7 @@ impl<'a, T> Generator for &'a mut T { type Yield = T::Yield; type Return = T::Return; - fn resume(&mut self) -> GeneratorState { + unsafe fn resume(&mut self) -> GeneratorState { (**self).resume() } } diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 2000ebea25d..4f36c3888b9 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -2247,7 +2247,7 @@ let mut b = || { yield (); // ...is still in scope here, when the yield occurs. println!("{}", a); }; -b.resume(); +unsafe { b.resume() }; ``` At present, it is not permitted to have a yield that occurs while a @@ -2265,7 +2265,7 @@ let mut b = || { yield (); println!("{}", a); }; -b.resume(); +unsafe { b.resume() }; ``` This is a very simple case, of course. In more complex cases, we may @@ -2283,7 +2283,7 @@ let mut b = || { yield x; // ...when this yield occurs. } }; -b.resume(); +unsafe { b.resume() }; ``` Such cases can sometimes be resolved by iterating "by value" (or using @@ -2298,7 +2298,7 @@ let mut b = || { yield x; // <-- Now yield is OK. } }; -b.resume(); +unsafe { b.resume() }; ``` If taking ownership is not an option, using indices can work too: @@ -2314,7 +2314,7 @@ let mut b = || { yield x; // <-- Now yield is OK. } }; -b.resume(); +unsafe { b.resume() }; // (*) -- Unfortunately, these temporaries are currently required. // See . diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 86d08dec2b9..033fb493d73 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -125,21 +125,13 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { &AggregateKind::Array(..) | &AggregateKind::Tuple | &AggregateKind::Adt(..) => {} - &AggregateKind::Closure(def_id, _) => { + &AggregateKind::Closure(def_id, _) | + &AggregateKind::Generator(def_id, _, _) => { let UnsafetyCheckResult { violations, unsafe_blocks } = self.tcx.unsafety_check_result(def_id); self.register_violations(&violations, &unsafe_blocks); } - &AggregateKind::Generator(def_id, _, interior) => { - let UnsafetyCheckResult { - violations, unsafe_blocks - } = self.tcx.unsafety_check_result(def_id); - self.register_violations(&violations, &unsafe_blocks); - if !interior.movable { - self.require_unsafe("construction of immovable generator") - } - } } } self.super_rvalue(rvalue, location); diff --git a/src/test/run-pass/dynamic-drop.rs b/src/test/run-pass/dynamic-drop.rs index 4d0bd3f3412..abbce16b77c 100644 --- a/src/test/run-pass/dynamic-drop.rs +++ b/src/test/run-pass/dynamic-drop.rs @@ -178,7 +178,7 @@ fn generator(a: &Allocator, run_count: usize) { ); }; for _ in 0..run_count { - gen.resume(); + unsafe { gen.resume(); } } } diff --git a/src/test/run-pass/generator/conditional-drop.rs b/src/test/run-pass/generator/conditional-drop.rs index 8329684e1a3..3d39c46186b 100644 --- a/src/test/run-pass/generator/conditional-drop.rs +++ b/src/test/run-pass/generator/conditional-drop.rs @@ -42,9 +42,9 @@ fn t1() { }; let n = A.load(Ordering::SeqCst); - a.resume(); + unsafe { a.resume() }; assert_eq!(A.load(Ordering::SeqCst), n + 1); - a.resume(); + unsafe { a.resume() }; assert_eq!(A.load(Ordering::SeqCst), n + 1); } @@ -58,8 +58,8 @@ fn t2() { }; let n = A.load(Ordering::SeqCst); - a.resume(); + unsafe { a.resume() }; assert_eq!(A.load(Ordering::SeqCst), n); - a.resume(); + unsafe { a.resume() }; assert_eq!(A.load(Ordering::SeqCst), n + 1); } diff --git a/src/test/run-pass/generator/control-flow.rs b/src/test/run-pass/generator/control-flow.rs index 60a00b4e467..09971410e55 100644 --- a/src/test/run-pass/generator/control-flow.rs +++ b/src/test/run-pass/generator/control-flow.rs @@ -16,7 +16,7 @@ fn finish(mut amt: usize, mut t: T) -> T::Return where T: Generator { loop { - match t.resume() { + match unsafe { t.resume() } { GeneratorState::Yielded(()) => amt = amt.checked_sub(1).unwrap(), GeneratorState::Complete(ret) => { assert_eq!(amt, 0); diff --git a/src/test/run-pass/generator/drop-env.rs b/src/test/run-pass/generator/drop-env.rs index ac42a25899d..ef4dc24472e 100644 --- a/src/test/run-pass/generator/drop-env.rs +++ b/src/test/run-pass/generator/drop-env.rs @@ -37,7 +37,7 @@ fn t1() { }; let n = A.load(Ordering::SeqCst); - drop(foo.resume()); + drop(unsafe { foo.resume() }); assert_eq!(A.load(Ordering::SeqCst), n); drop(foo); assert_eq!(A.load(Ordering::SeqCst), n + 1); @@ -50,7 +50,7 @@ fn t2() { }; let n = A.load(Ordering::SeqCst); - drop(foo.resume()); + drop(unsafe { foo.resume() }); assert_eq!(A.load(Ordering::SeqCst), n + 1); drop(foo); assert_eq!(A.load(Ordering::SeqCst), n + 1); diff --git a/src/test/run-pass/generator/issue-44197.rs b/src/test/run-pass/generator/issue-44197.rs index 7cb80ea8b21..8ce4fc6affa 100644 --- a/src/test/run-pass/generator/issue-44197.rs +++ b/src/test/run-pass/generator/issue-44197.rs @@ -35,6 +35,8 @@ fn bar2(baz: String) -> impl Generator { } fn main() { - assert_eq!(bar(String::new()).resume(), GeneratorState::Yielded(String::new())); - assert_eq!(bar2(String::new()).resume(), GeneratorState::Complete(())); + unsafe { + assert_eq!(bar(String::new()).resume(), GeneratorState::Yielded(String::new())); + assert_eq!(bar2(String::new()).resume(), GeneratorState::Complete(())); + } } diff --git a/src/test/run-pass/generator/iterator-count.rs b/src/test/run-pass/generator/iterator-count.rs index 9afe95f9e86..654b18928c0 100644 --- a/src/test/run-pass/generator/iterator-count.rs +++ b/src/test/run-pass/generator/iterator-count.rs @@ -14,11 +14,13 @@ use std::ops::{GeneratorState, Generator}; struct W(T); +// This impl isn't safe in general, but the generator used in this test is movable +// so it won't cause problems. impl> Iterator for W { type Item = T::Yield; fn next(&mut self) -> Option { - match self.0.resume() { + match unsafe { self.0.resume() } { GeneratorState::Complete(..) => None, GeneratorState::Yielded(v) => Some(v), } diff --git a/src/test/run-pass/generator/live-upvar-across-yield.rs b/src/test/run-pass/generator/live-upvar-across-yield.rs index e34b0b3100c..28e7da232ce 100644 --- a/src/test/run-pass/generator/live-upvar-across-yield.rs +++ b/src/test/run-pass/generator/live-upvar-across-yield.rs @@ -17,5 +17,5 @@ fn main() { let mut a = || { b(yield); }; - a.resume(); + unsafe { a.resume() }; } diff --git a/src/test/run-pass/generator/nested_generators.rs b/src/test/run-pass/generator/nested_generators.rs index f70d4144a3c..29808da85a7 100644 --- a/src/test/run-pass/generator/nested_generators.rs +++ b/src/test/run-pass/generator/nested_generators.rs @@ -20,7 +20,7 @@ fn main() { yield 2; }; - match sub_generator.resume() { + match unsafe { sub_generator.resume() } { GeneratorState::Yielded(x) => { yield x; } diff --git a/src/test/run-pass/generator/panic-drops.rs b/src/test/run-pass/generator/panic-drops.rs index 36e401a54bc..3d7b60ab6b9 100644 --- a/src/test/run-pass/generator/panic-drops.rs +++ b/src/test/run-pass/generator/panic-drops.rs @@ -42,7 +42,7 @@ fn main() { assert_eq!(A.load(Ordering::SeqCst), 0); let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { - foo.resume() + unsafe { foo.resume() } })); assert!(res.is_err()); assert_eq!(A.load(Ordering::SeqCst), 1); @@ -57,7 +57,7 @@ fn main() { assert_eq!(A.load(Ordering::SeqCst), 1); let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { - foo.resume() + unsafe { foo.resume() } })); assert!(res.is_err()); assert_eq!(A.load(Ordering::SeqCst), 1); diff --git a/src/test/run-pass/generator/panic-safe.rs b/src/test/run-pass/generator/panic-safe.rs index 0d5bae7876b..ace5cdde51d 100644 --- a/src/test/run-pass/generator/panic-safe.rs +++ b/src/test/run-pass/generator/panic-safe.rs @@ -24,13 +24,13 @@ fn main() { }; let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { - foo.resume() + unsafe { foo.resume() } })); assert!(res.is_err()); for _ in 0..10 { let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { - foo.resume() + unsafe { foo.resume() } })); assert!(res.is_err()); } diff --git a/src/test/run-pass/generator/resume-after-return.rs b/src/test/run-pass/generator/resume-after-return.rs index 56511dcd53a..06e7615d261 100644 --- a/src/test/run-pass/generator/resume-after-return.rs +++ b/src/test/run-pass/generator/resume-after-return.rs @@ -23,12 +23,12 @@ fn main() { yield; }; - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } - match panic::catch_unwind(move || foo.resume()) { + match panic::catch_unwind(move || unsafe { foo.resume() }) { Ok(_) => panic!("generator successfully resumed"), Err(_) => {} } diff --git a/src/test/run-pass/generator/smoke.rs b/src/test/run-pass/generator/smoke.rs index 8693964665d..7395c8484c1 100644 --- a/src/test/run-pass/generator/smoke.rs +++ b/src/test/run-pass/generator/smoke.rs @@ -24,7 +24,7 @@ fn simple() { } }; - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } @@ -40,7 +40,7 @@ fn return_capture() { a }; - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(ref s) if *s == "foo" => {} s => panic!("bad state: {:?}", s), } @@ -52,11 +52,11 @@ fn simple_yield() { yield; }; - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Yielded(()) => {} s => panic!("bad state: {:?}", s), } - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } @@ -69,11 +69,11 @@ fn yield_capture() { yield b; }; - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Yielded(ref s) if *s == "foo" => {} s => panic!("bad state: {:?}", s), } - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } @@ -86,11 +86,11 @@ fn simple_yield_value() { return String::from("foo") }; - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Yielded(ref s) if *s == "bar" => {} s => panic!("bad state: {:?}", s), } - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(ref s) if *s == "foo" => {} s => panic!("bad state: {:?}", s), } @@ -104,11 +104,11 @@ fn return_after_yield() { return a }; - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Yielded(()) => {} s => panic!("bad state: {:?}", s), } - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(ref s) if *s == "foo" => {} s => panic!("bad state: {:?}", s), } @@ -156,11 +156,11 @@ fn send_and_sync() { fn send_over_threads() { let mut foo = || { yield }; thread::spawn(move || { - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Yielded(()) => {} s => panic!("bad state: {:?}", s), } - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } @@ -169,11 +169,11 @@ fn send_over_threads() { let a = String::from("a"); let mut foo = || { yield a }; thread::spawn(move || { - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Yielded(ref s) if *s == "a" => {} s => panic!("bad state: {:?}", s), } - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } diff --git a/src/test/run-pass/generator/static-generators.rs b/src/test/run-pass/generator/static-generators.rs index 9504414d8b6..ebc070eee09 100644 --- a/src/test/run-pass/generator/static-generators.rs +++ b/src/test/run-pass/generator/static-generators.rs @@ -13,14 +13,14 @@ use std::ops::{Generator, GeneratorState}; fn main() { - let mut generator = unsafe { - static || { - let a = true; - let b = &a; - yield; - assert_eq!(b as *const _, &a as *const _); - } + let mut generator = static || { + let a = true; + let b = &a; + yield; + assert_eq!(b as *const _, &a as *const _); }; - assert_eq!(generator.resume(), GeneratorState::Yielded(())); - assert_eq!(generator.resume(), GeneratorState::Complete(())); + unsafe { + assert_eq!(generator.resume(), GeneratorState::Yielded(())); + assert_eq!(generator.resume(), GeneratorState::Complete(())); + } } diff --git a/src/test/run-pass/generator/xcrate-reachable.rs b/src/test/run-pass/generator/xcrate-reachable.rs index dff5e08b9c2..8eeb0133144 100644 --- a/src/test/run-pass/generator/xcrate-reachable.rs +++ b/src/test/run-pass/generator/xcrate-reachable.rs @@ -17,5 +17,5 @@ extern crate xcrate_reachable as foo; use std::ops::Generator; fn main() { - foo::foo().resume(); + unsafe { foo::foo().resume(); } } diff --git a/src/test/run-pass/generator/xcrate.rs b/src/test/run-pass/generator/xcrate.rs index dc7a6fdef9c..04791d51356 100644 --- a/src/test/run-pass/generator/xcrate.rs +++ b/src/test/run-pass/generator/xcrate.rs @@ -19,18 +19,18 @@ use std::ops::{GeneratorState, Generator}; fn main() { let mut foo = xcrate::foo(); - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } let mut foo = xcrate::bar(3); - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Yielded(3) => {} s => panic!("bad state: {:?}", s), } - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } diff --git a/src/test/ui/generator/borrowing.rs b/src/test/ui/generator/borrowing.rs index de10bdef4ae..e56927d8182 100644 --- a/src/test/ui/generator/borrowing.rs +++ b/src/test/ui/generator/borrowing.rs @@ -15,7 +15,7 @@ use std::ops::Generator; fn main() { let _b = { let a = 3; - (|| yield &a).resume() + unsafe { (|| yield &a).resume() } //~^ ERROR: `a` does not live long enough }; diff --git a/src/test/ui/generator/borrowing.stderr b/src/test/ui/generator/borrowing.stderr index 2a5de3790ad..45d950b5aef 100644 --- a/src/test/ui/generator/borrowing.stderr +++ b/src/test/ui/generator/borrowing.stderr @@ -1,10 +1,10 @@ error[E0597]: `a` does not live long enough - --> $DIR/borrowing.rs:18:20 + --> $DIR/borrowing.rs:18:29 | -LL | (|| yield &a).resume() - | -- ^ borrowed value does not live long enough - | | - | capture occurs here +LL | unsafe { (|| yield &a).resume() } + | -- ^ borrowed value does not live long enough + | | + | capture occurs here LL | //~^ ERROR: `a` does not live long enough LL | }; | - borrowed value only lives until here diff --git a/src/test/ui/generator/dropck.rs b/src/test/ui/generator/dropck.rs index 0b143d7f514..b2240fb225f 100644 --- a/src/test/ui/generator/dropck.rs +++ b/src/test/ui/generator/dropck.rs @@ -23,6 +23,6 @@ fn main() { let _d = ref_.take(); //~ ERROR `ref_` does not live long enough yield; }; - gen.resume(); + unsafe { gen.resume(); } // drops the RefCell and then the Ref, leading to use-after-free } diff --git a/src/test/ui/generator/sized-yield.rs b/src/test/ui/generator/sized-yield.rs index f38ebf8b946..a1c8ca77e41 100644 --- a/src/test/ui/generator/sized-yield.rs +++ b/src/test/ui/generator/sized-yield.rs @@ -17,5 +17,5 @@ fn main() { let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied yield s[..]; }; - gen.resume(); //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + unsafe { gen.resume(); } //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied } diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr index fc99c7e3bd7..957fac172c2 100644 --- a/src/test/ui/generator/sized-yield.stderr +++ b/src/test/ui/generator/sized-yield.stderr @@ -11,10 +11,10 @@ LL | | }; = note: the yield type of a generator must have a statically known size error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied - --> $DIR/sized-yield.rs:20:8 + --> $DIR/sized-yield.rs:20:17 | -LL | gen.resume(); //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied - | ^^^^^^ `str` does not have a constant size known at compile-time +LL | unsafe { gen.resume(); } //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + | ^^^^^^ `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` diff --git a/src/test/ui/generator/unsafe-immovable.rs b/src/test/ui/generator/unsafe-immovable.rs deleted file mode 100644 index 45acbf50931..00000000000 --- a/src/test/ui/generator/unsafe-immovable.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(generators)] - -fn main() { - static || { //~ ERROR: construction of immovable generator requires unsafe - yield; - }; -} diff --git a/src/test/ui/generator/unsafe-immovable.stderr b/src/test/ui/generator/unsafe-immovable.stderr deleted file mode 100644 index b2add55613d..00000000000 --- a/src/test/ui/generator/unsafe-immovable.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0133]: construction of immovable generator requires unsafe function or block - --> $DIR/unsafe-immovable.rs:14:5 - | -LL | / static || { //~ ERROR: construction of immovable generator requires unsafe -LL | | yield; -LL | | }; - | |_____^ construction of immovable generator - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/generator/yield-while-iterating.rs b/src/test/ui/generator/yield-while-iterating.rs index bc53448cb08..b8a67a0e7b6 100644 --- a/src/test/ui/generator/yield-while-iterating.rs +++ b/src/test/ui/generator/yield-while-iterating.rs @@ -43,7 +43,7 @@ fn yield_during_iter_borrowed_slice_2() { println!("{:?}", x); } -fn yield_during_iter_borrowed_slice_3() { +unsafe fn yield_during_iter_borrowed_slice_3() { // OK to take a mutable ref to `x` and yield // up pointers from it: let mut x = vec![22_i32]; @@ -55,7 +55,7 @@ fn yield_during_iter_borrowed_slice_3() { b.resume(); } -fn yield_during_iter_borrowed_slice_4() { +unsafe fn yield_during_iter_borrowed_slice_4() { // ...but not OK to do that while reading // from `x` too let mut x = vec![22_i32]; @@ -68,7 +68,7 @@ fn yield_during_iter_borrowed_slice_4() { b.resume(); } -fn yield_during_range_iter() { +unsafe fn yield_during_range_iter() { // Should be OK. let mut b = || { let v = vec![1,2,3]; diff --git a/src/test/ui/generator/yield-while-local-borrowed.rs b/src/test/ui/generator/yield-while-local-borrowed.rs index 11bd4ed05ca..3dc2650a2ec 100644 --- a/src/test/ui/generator/yield-while-local-borrowed.rs +++ b/src/test/ui/generator/yield-while-local-borrowed.rs @@ -15,7 +15,7 @@ use std::ops::{GeneratorState, Generator}; use std::cell::Cell; -fn borrow_local_inline() { +unsafe fn borrow_local_inline() { // Not OK to yield with a borrow of a temporary. // // (This error occurs because the region shows up in the type of @@ -30,7 +30,7 @@ fn borrow_local_inline() { b.resume(); } -fn borrow_local_inline_done() { +unsafe fn borrow_local_inline_done() { // No error here -- `a` is not in scope at the point of `yield`. let mut b = move || { { @@ -41,7 +41,7 @@ fn borrow_local_inline_done() { b.resume(); } -fn borrow_local() { +unsafe fn borrow_local() { // Not OK to yield with a borrow of a temporary. // // (This error occurs because the region shows up in the type of diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.rs b/src/test/ui/generator/yield-while-ref-reborrowed.rs index b9c963ae740..573dd4377bb 100644 --- a/src/test/ui/generator/yield-while-ref-reborrowed.rs +++ b/src/test/ui/generator/yield-while-ref-reborrowed.rs @@ -13,7 +13,7 @@ use std::ops::{GeneratorState, Generator}; use std::cell::Cell; -fn reborrow_shared_ref(x: &i32) { +unsafe fn reborrow_shared_ref(x: &i32) { // This is OK -- we have a borrow live over the yield, but it's of // data that outlives the generator. let mut b = move || { @@ -24,7 +24,7 @@ fn reborrow_shared_ref(x: &i32) { b.resume(); } -fn reborrow_mutable_ref(x: &mut i32) { +unsafe fn reborrow_mutable_ref(x: &mut i32) { // This is OK -- we have a borrow live over the yield, but it's of // data that outlives the generator. let mut b = move || { @@ -35,7 +35,7 @@ fn reborrow_mutable_ref(x: &mut i32) { b.resume(); } -fn reborrow_mutable_ref_2(x: &mut i32) { +unsafe fn reborrow_mutable_ref_2(x: &mut i32) { // ...but not OK to go on using `x`. let mut b = || { let a = &mut *x; -- cgit 1.4.1-3-g733a5 From 5201e7cf8ac0c78bc8e4f0feb8f97e91b957a19e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 21 Mar 2018 07:31:39 +0100 Subject: document format_args! behavior wrt. Display and Debug --- src/libcore/fmt/mod.rs | 72 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 6 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 3ecd73873c0..0363714c31b 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -406,6 +406,18 @@ impl<'a> Arguments<'a> { /// macro validates the format string at compile-time so usage of the [`write`] /// and [`format`] functions can be safely performed. /// +/// You can use the `Arguments<'a>` that [`format_args!`] returns in `Debug` +/// and `Display` contexts as seen below. The example also shows that `Debug` +/// and `Display` format to the same thing: the interpolated format string +/// in `format_args!`. +/// +/// ```rust +/// let display = format!("{:?}", format_args!("{} foo {:?}", 1, 2)); +/// let debug = format!("{}", format_args!("{} foo {:?}", 1, 2)); +/// assert_eq!("1 foo 2", display); +/// assert_eq!(display, debug); +/// ``` +/// /// [`format_args!`]: ../../std/macro.format_args.html /// [`format`]: ../../std/fmt/fn.format.html /// [`write`]: ../../std/fmt/fn.write.html @@ -1553,10 +1565,12 @@ impl<'a> Formatter<'a> { /// /// ```rust /// use std::fmt; + /// use std::net::Ipv4Addr; /// /// struct Foo { /// bar: i32, /// baz: String, + /// addr: Ipv4Addr, /// } /// /// impl fmt::Debug for Foo { @@ -1564,12 +1578,19 @@ impl<'a> Formatter<'a> { /// fmt.debug_struct("Foo") /// .field("bar", &self.bar) /// .field("baz", &self.baz) + /// .field("addr", &format_args!("{}", self.addr)) /// .finish() /// } /// } /// - /// // prints "Foo { bar: 10, baz: "Hello World" }" - /// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() }); + /// assert_eq!( + /// "Foo { bar: 10, baz: \"Hello World\", addr: 127.0.0.1 }", + /// format!("{:?}", Foo { + /// bar: 10, + /// baz: "Hello World".to_string(), + /// addr: Ipv4Addr::new(127, 0, 0, 1), + /// }) + /// ); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn debug_struct<'b>(&'b mut self, name: &str) -> DebugStruct<'b, 'a> { @@ -1583,20 +1604,24 @@ impl<'a> Formatter<'a> { /// /// ```rust /// use std::fmt; + /// use std::marker::PhantomData; /// - /// struct Foo(i32, String); + /// struct Foo(i32, String, PhantomData); /// - /// impl fmt::Debug for Foo { + /// impl fmt::Debug for Foo { /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { /// fmt.debug_tuple("Foo") /// .field(&self.0) /// .field(&self.1) + /// .field(&format_args!("_")) /// .finish() /// } /// } /// - /// // prints "Foo(10, "Hello World")" - /// println!("{:?}", Foo(10, "Hello World".to_string())); + /// assert_eq!( + /// "Foo(10, \"Hello\", _)", + /// format!("{:?}", Foo(10, "Hello".to_string(), PhantomData::)) + /// ); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn debug_tuple<'b>(&'b mut self, name: &str) -> DebugTuple<'b, 'a> { @@ -1646,6 +1671,41 @@ impl<'a> Formatter<'a> { /// // prints "{10, 11}" /// println!("{:?}", Foo(vec![10, 11])); /// ``` + /// + /// [`format_args!`]: ../../std/macro.format_args.html + /// + /// In this more complex example, we use [`format_args!`] and `.debug_set()` + /// to build a list of match arms: + /// + /// ```rust + /// use std::fmt; + /// + /// struct Arm<'a, L: 'a, R: 'a>(&'a (L, R)); + /// struct Table<'a, K: 'a, V: 'a>(&'a [(K, V)], V); + /// + /// impl<'a, L, R> fmt::Debug for Arm<'a, L, R> + /// where + /// L: 'a + fmt::Debug, R: 'a + fmt::Debug + /// { + /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + /// L::fmt(&(self.0).0, fmt)?; + /// fmt.write_str(" => ")?; + /// R::fmt(&(self.0).1, fmt) + /// } + /// } + /// + /// impl<'a, K, V> fmt::Debug for Table<'a, K, V> + /// where + /// K: 'a + fmt::Debug, V: 'a + fmt::Debug + /// { + /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + /// fmt.debug_set() + /// .entries(self.0.iter().map(Arm)) + /// .entry(&Arm(&(format_args!("_"), &self.1))) + /// .finish() + /// } + /// } + /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn debug_set<'b>(&'b mut self) -> DebugSet<'b, 'a> { builders::debug_set_new(self) -- cgit 1.4.1-3-g733a5 From c09b9f937250db0f51b705a3110f8cffdad083bb Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 17 Mar 2018 12:15:24 +0100 Subject: Deprecate the AsciiExt trait in favor of inherent methods The trait and some of its methods are stable and will remain. Some of the newer methods are unstable and can be removed later. Fixes https://github.com/rust-lang/rust/issues/39658 --- src/libcore/tests/ascii.rs | 3 --- src/libstd/ascii.rs | 17 +++++++++++++++++ src/libstd/sys/windows/process.rs | 1 - src/libstd/sys_common/wtf8.rs | 17 +++++++---------- src/test/run-pass/issue-10683.rs | 2 -- 5 files changed, 24 insertions(+), 16 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/ascii.rs b/src/libcore/tests/ascii.rs index 4d43067ad2c..950222dbcfa 100644 --- a/src/libcore/tests/ascii.rs +++ b/src/libcore/tests/ascii.rs @@ -9,7 +9,6 @@ // except according to those terms. use core::char::from_u32; -use std::ascii::AsciiExt; #[test] fn test_is_ascii() { @@ -143,8 +142,6 @@ macro_rules! assert_all { stringify!($what), b); } } - assert!($str.$what()); - assert!($str.as_bytes().$what()); )+ }}; ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+)) diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 0837ff91c14..6472edb0aa7 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -52,6 +52,7 @@ pub use core::ascii::{EscapeDefault, escape_default}; /// /// [combining character]: https://en.wikipedia.org/wiki/Combining_character #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] pub trait AsciiExt { /// Container type for copied ASCII characters. #[stable(feature = "rust1", since = "1.0.0")] @@ -84,6 +85,7 @@ pub trait AsciiExt { /// [`make_ascii_uppercase`]: #tymethod.make_ascii_uppercase /// [`str::to_uppercase`]: ../primitive.str.html#method.to_uppercase #[stable(feature = "rust1", since = "1.0.0")] + #[allow(deprecated)] fn to_ascii_uppercase(&self) -> Self::Owned; /// Makes a copy of the value in its ASCII lower case equivalent. @@ -104,6 +106,7 @@ pub trait AsciiExt { /// [`make_ascii_lowercase`]: #tymethod.make_ascii_lowercase /// [`str::to_lowercase`]: ../primitive.str.html#method.to_lowercase #[stable(feature = "rust1", since = "1.0.0")] + #[allow(deprecated)] fn to_ascii_lowercase(&self) -> Self::Owned; /// Checks that two values are an ASCII case-insensitive match. @@ -162,6 +165,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_alphabetic(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII uppercase character: @@ -174,6 +178,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_uppercase(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII lowercase character: @@ -186,6 +191,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_lowercase(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII alphanumeric character: @@ -199,6 +205,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_alphanumeric(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII decimal digit: @@ -211,6 +218,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_digit(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII hexadecimal digit: @@ -224,6 +232,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_hexdigit(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII punctuation character: @@ -241,6 +250,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_punctuation(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII graphic character: @@ -253,6 +263,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_graphic(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII whitespace character: @@ -282,6 +293,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_whitespace(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII control character: @@ -294,6 +306,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_control(&self) -> bool { unimplemented!(); } } @@ -354,6 +367,7 @@ macro_rules! delegating_ascii_ctype_methods { } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] impl AsciiExt for u8 { type Owned = u8; @@ -362,6 +376,7 @@ impl AsciiExt for u8 { } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] impl AsciiExt for char { type Owned = char; @@ -370,6 +385,7 @@ impl AsciiExt for char { } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] impl AsciiExt for [u8] { type Owned = Vec; @@ -427,6 +443,7 @@ impl AsciiExt for [u8] { } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] impl AsciiExt for str { type Owned = String; diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index f1ab9c47609..afa8e3e1369 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -10,7 +10,6 @@ #![unstable(feature = "process_internals", issue = "0")] -use ascii::AsciiExt; use collections::BTreeMap; use env::split_paths; use env; diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 9fff8b91f96..78b2bb5fe6e 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -27,7 +27,6 @@ use core::str::next_code_point; -use ascii::*; use borrow::Cow; use char; use fmt; @@ -871,24 +870,22 @@ impl Hash for Wtf8 { } } -impl AsciiExt for Wtf8 { - type Owned = Wtf8Buf; - - fn is_ascii(&self) -> bool { +impl Wtf8 { + pub fn is_ascii(&self) -> bool { self.bytes.is_ascii() } - fn to_ascii_uppercase(&self) -> Wtf8Buf { + pub fn to_ascii_uppercase(&self) -> Wtf8Buf { Wtf8Buf { bytes: self.bytes.to_ascii_uppercase() } } - fn to_ascii_lowercase(&self) -> Wtf8Buf { + pub fn to_ascii_lowercase(&self) -> Wtf8Buf { Wtf8Buf { bytes: self.bytes.to_ascii_lowercase() } } - fn eq_ignore_ascii_case(&self, other: &Wtf8) -> bool { + pub fn eq_ignore_ascii_case(&self, other: &Wtf8) -> bool { self.bytes.eq_ignore_ascii_case(&other.bytes) } - fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() } - fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() } + pub fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() } + pub fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() } } #[cfg(test)] diff --git a/src/test/run-pass/issue-10683.rs b/src/test/run-pass/issue-10683.rs index eb2177202a2..d3ba477fa57 100644 --- a/src/test/run-pass/issue-10683.rs +++ b/src/test/run-pass/issue-10683.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -use std::ascii::AsciiExt; - static NAME: &'static str = "hello world"; fn main() { -- cgit 1.4.1-3-g733a5 From 613fb8bc2c5277b9b9a14bdba3939bb6042d91ec Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 22 Mar 2018 10:06:17 +0100 Subject: document format_args! - fix trailing whitespace --- src/libcore/fmt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 0363714c31b..62994ed15cc 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1682,7 +1682,7 @@ impl<'a> Formatter<'a> { /// /// struct Arm<'a, L: 'a, R: 'a>(&'a (L, R)); /// struct Table<'a, K: 'a, V: 'a>(&'a [(K, V)], V); - /// + /// /// impl<'a, L, R> fmt::Debug for Arm<'a, L, R> /// where /// L: 'a + fmt::Debug, R: 'a + fmt::Debug -- cgit 1.4.1-3-g733a5 From 68e0ea9d47f797f815225e4f2fbd9bb1cde6e19e Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 23 Mar 2018 01:30:23 -0700 Subject: Introduce unsafe offset_from on pointers Adds intrinsics::exact_div to take advantage of the unsafe, which reduces the implementation from ```asm sub rcx, rdx mov rax, rcx sar rax, 63 shr rax, 62 lea rax, [rax + rcx] sar rax, 2 ret ``` down to ```asm sub rcx, rdx sar rcx, 2 mov rax, rcx ret ``` (for `*const i32`) --- src/libcore/intrinsics.rs | 10 ++ src/libcore/ptr.rs | 207 +++++++++++++++++++++++++++++++++ src/librustc_llvm/ffi.rs | 5 + src/librustc_trans/builder.rs | 7 ++ src/librustc_trans/intrinsic.rs | 8 +- src/librustc_typeck/check/intrinsic.rs | 2 +- 6 files changed, 237 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 830ebad0654..3b740adc468 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1314,6 +1314,11 @@ extern "rust-intrinsic" { /// [`std::u32::overflowing_mul`](../../std/primitive.u32.html#method.overflowing_mul) pub fn mul_with_overflow(x: T, y: T) -> (T, bool); + /// Performs an exact division, resulting in undefined behavior where + /// `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` + #[cfg(not(stage0))] + pub fn exact_div(x: T, y: T) -> T; + /// Performs an unchecked division, resulting in undefined behavior /// where y = 0 or x = `T::min_value()` and y = -1 pub fn unchecked_div(x: T, y: T) -> T; @@ -1396,3 +1401,8 @@ extern "rust-intrinsic" { /// Probably will never become stable. pub fn nontemporal_store(ptr: *mut T, val: T); } + +#[cfg(stage0)] +pub unsafe fn exact_div(a: T, b: T) -> T { + unchecked_div(a, b) +} diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 6270e5892b3..cbd45bb6a39 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -700,6 +700,114 @@ impl *const T { } } + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// This function is the inverse of [`offset`]. + /// + /// [`offset`]: #method.offset + /// [`wrapping_offset_from`]: #method.wrapping_offset_from + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and other pointer must be either in bounds or one + /// byte past the end of the same allocated object. + /// + /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. + /// + /// * The distance between the pointers, in bytes, must be an exact multiple + /// of the size of `T` and `T` must not be a Zero-Sized Type ("ZST"). + /// + /// * The distance being in bounds cannot rely on "wrapping around" the address space. + /// + /// The compiler and standard library generally try to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `ptr_into_vec.offset_from(vec.as_ptr())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using [`wrapping_offset_from`] instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_offset_from)] + /// + /// let a = [0; 5]; + /// let ptr1: *const i32 = &a[1]; + /// let ptr2: *const i32 = &a[3]; + /// unsafe { + /// assert_eq!(ptr2.offset_from(ptr1), 2); + /// assert_eq!(ptr1.offset_from(ptr2), -2); + /// assert_eq!(ptr1.offset(2), ptr2); + /// assert_eq!(ptr2.offset(-2), ptr1); + /// } + /// ``` + #[unstable(feature = "ptr_offset_from", issue = "41079")] + #[inline] + pub unsafe fn offset_from(self, other: *const T) -> isize where T: Sized { + let pointee_size = mem::size_of::(); + assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); + + // FIXME: can this be nuw/nsw? + let d = isize::wrapping_sub(self as _, other as _); + intrinsics::exact_div(d, pointee_size as _) + } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// If the address different between the two pointers is not a multiple of + /// `mem::size_of::()` then the result of the division is rounded towards + /// zero. + /// + /// # Panics + /// + /// This function panics if `T` is a zero-sized typed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_wrapping_offset_from)] + /// + /// let a = [0; 5]; + /// let ptr1: *const i32 = &a[1]; + /// let ptr2: *const i32 = &a[3]; + /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); + /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2); + /// assert_eq!(ptr1.wrapping_offset(2), ptr2); + /// assert_eq!(ptr2.wrapping_offset(-2), ptr1); + /// + /// let ptr1: *const i32 = 3 as _; + /// let ptr2: *const i32 = 13 as _; + /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); + /// ``` + #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")] + #[inline] + pub fn wrapping_offset_from(self, other: *const T) -> isize where T: Sized { + let pointee_size = mem::size_of::(); + assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); + + let d = isize::wrapping_sub(self as _, other as _); + d.wrapping_div(pointee_size as _) + } + /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). /// /// `count` is in units of T; e.g. a `count` of 3 represents a pointer @@ -1347,6 +1455,105 @@ impl *mut T { } } + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// This function is the inverse of [`offset`]. + /// + /// [`offset`]: #method.offset-1 + /// [`wrapping_offset_from`]: #method.wrapping_offset_from-1 + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and other pointer must be either in bounds or one + /// byte past the end of the same allocated object. + /// + /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. + /// + /// * The distance between the pointers, in bytes, must be an exact multiple + /// of the size of `T` and `T` must not be a Zero-Sized Type ("ZST"). + /// + /// * The distance being in bounds cannot rely on "wrapping around" the address space. + /// + /// The compiler and standard library generally try to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `ptr_into_vec.offset_from(vec.as_ptr())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// Consider using [`wrapping_offset_from`] instead if these constraints are + /// difficult to satisfy. The only advantage of this method is that it + /// enables more aggressive compiler optimizations. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_offset_from)] + /// + /// let a = [0; 5]; + /// let ptr1: *mut i32 = &mut a[1]; + /// let ptr2: *mut i32 = &mut a[3]; + /// unsafe { + /// assert_eq!(ptr2.offset_from(ptr1), 2); + /// assert_eq!(ptr1.offset_from(ptr2), -2); + /// assert_eq!(ptr1.offset(2), ptr2); + /// assert_eq!(ptr2.offset(-2), ptr1); + /// } + /// ``` + #[unstable(feature = "ptr_offset_from", issue = "41079")] + #[inline] + pub unsafe fn offset_from(self, other: *const T) -> isize where T: Sized { + (self as *const T).offset_from(other) + } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// If the address different between the two pointers is not a multiple of + /// `mem::size_of::()` then the result of the division is rounded towards + /// zero. + /// + /// # Panics + /// + /// This function panics if `T` is a zero-sized typed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_wrapping_offset_from)] + /// + /// let a = [0; 5]; + /// let ptr1: *mut i32 = &mut a[1]; + /// let ptr2: *mut i32 = &mut a[3]; + /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); + /// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2); + /// assert_eq!(ptr1.wrapping_offset(2), ptr2); + /// assert_eq!(ptr2.wrapping_offset(-2), ptr1); + /// + /// let ptr1: *mut i32 = 3 as _; + /// let ptr2: *mut i32 = 13 as _; + /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); + /// ``` + #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")] + #[inline] + pub fn wrapping_offset_from(self, other: *const T) -> isize where T: Sized { + (self as *const T).wrapping_offset_from(other) + } + /// Computes the byte offset that needs to be applied in order to /// make the pointer aligned to `align`. /// If it is not possible to align the pointer, the implementation returns diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index c0cdd212770..403fe4731f1 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -935,6 +935,11 @@ extern "C" { RHS: ValueRef, Name: *const c_char) -> ValueRef; + pub fn LLVMBuildExactUDiv(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; pub fn LLVMBuildSDiv(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 91eabb9998f..5e2d32b3596 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -344,6 +344,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + pub fn exactudiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("exactudiv"); + unsafe { + llvm::LLVMBuildExactUDiv(self.llbuilder, lhs, rhs, noname()) + } + } + pub fn sdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { self.count_insn("sdiv"); unsafe { diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index c3de9e0ffcc..ca5b48be4d5 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -289,7 +289,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" | "bitreverse" | "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" | - "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" => { + "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" => { let ty = arg_tys[0]; match int_type_width_signed(ty, cx) { Some((width, signed)) => @@ -343,6 +343,12 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, "overflowing_add" => bx.add(args[0].immediate(), args[1].immediate()), "overflowing_sub" => bx.sub(args[0].immediate(), args[1].immediate()), "overflowing_mul" => bx.mul(args[0].immediate(), args[1].immediate()), + "exact_div" => + if signed { + bx.exactsdiv(args[0].immediate(), args[1].immediate()) + } else { + bx.exactudiv(args[0].immediate(), args[1].immediate()) + }, "unchecked_div" => if signed { bx.sdiv(args[0].immediate(), args[1].immediate()) diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 99707a4a3c0..a4e9967daa6 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -283,7 +283,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool])), - "unchecked_div" | "unchecked_rem" => + "unchecked_div" | "unchecked_rem" | "exact_div" => (1, vec![param(0), param(0)], param(0)), "unchecked_shl" | "unchecked_shr" => (1, vec![param(0), param(0)], param(0)), -- cgit 1.4.1-3-g733a5 From 00721de714785a8abf95a6403a66a19de6a58fc3 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Mar 2018 11:37:11 +0100 Subject: Mention closures in docs for Clone and Copy --- src/libcore/clone.rs | 5 +++++ src/libcore/marker.rs | 5 +++++ 2 files changed, 10 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 826420a0c00..d25f498b99e 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -63,6 +63,11 @@ /// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d /// implementation of [`clone`] calls [`clone`] on each field. /// +/// ## Closures +/// +/// Closure types automatically implement `Clone` if they capture no value from the environment +/// or if all such captured values implement `Clone` themselves. +/// /// ## How can I implement `Clone`? /// /// Types that are [`Copy`] should have a trivial implementation of `Clone`. More formally: diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index f8a33961811..7d0174a178a 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -166,6 +166,11 @@ pub trait Unsize { /// are allowed to access `x` after the assignment. Under the hood, both a copy and a move /// can result in bits being copied in memory, although this is sometimes optimized away. /// +/// ## Closures +/// +/// Closure types automatically implement `Copy` if they capture no value from the environment +/// or if all such captured values implement `Copy` themselves. +/// /// ## How can I implement `Copy`? /// /// There are two ways to implement `Copy` on your type. The simplest is to use `derive`: -- cgit 1.4.1-3-g733a5 From 8334977dcffbd538fbd1457555ea3d80cc5eb64b Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Sat, 24 Mar 2018 23:35:16 -0400 Subject: Fix incorrect lower bounds --- src/libcore/char.rs | 7 ++++++- src/libcore/iter/traits.rs | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 2f56238a463..4420eff06ed 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -905,7 +905,12 @@ impl> Iterator for DecodeUtf8 { #[inline] fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() + let len = self.iter.len(); + + // A code point is at most 4 bytes long. + let min_code_points = len / 4; + + (min_code_points, Some(len)) } } diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 5e4622f804a..c3aebc4fb23 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -903,7 +903,12 @@ impl Iterator for ResultShunt } fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() + if self.error.is_some() { + (0, Some(0)) + } else { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } } } -- cgit 1.4.1-3-g733a5 From 4a097ea53251e59063cf5bdc9901f0313664f90e Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 24 Mar 2018 20:37:31 -0700 Subject: Documentation and naming improvements --- src/libcore/ptr.rs | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index cbd45bb6a39..3fc8421d3b0 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -669,7 +669,7 @@ impl *const T { /// `mem::size_of::()` then the result of the division is rounded towards /// zero. /// - /// This function returns `None` if `T` is a zero-sized typed. + /// This function returns `None` if `T` is a zero-sized type. /// /// # Examples /// @@ -719,7 +719,7 @@ impl *const T { /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. /// /// * The distance between the pointers, in bytes, must be an exact multiple - /// of the size of `T` and `T` must not be a Zero-Sized Type ("ZST"). + /// of the size of `T`. /// /// * The distance being in bounds cannot rely on "wrapping around" the address space. /// @@ -740,6 +740,10 @@ impl *const T { /// difficult to satisfy. The only advantage of this method is that it /// enables more aggressive compiler optimizations. /// + /// # Panics + /// + /// This function panics if `T` is a Zero-Sized Type ("ZST"). + /// /// # Examples /// /// Basic usage: @@ -759,12 +763,14 @@ impl *const T { /// ``` #[unstable(feature = "ptr_offset_from", issue = "41079")] #[inline] - pub unsafe fn offset_from(self, other: *const T) -> isize where T: Sized { + pub unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized { let pointee_size = mem::size_of::(); assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); - // FIXME: can this be nuw/nsw? - let d = isize::wrapping_sub(self as _, other as _); + // This is the same sequence that Clang emits for pointer subtraction. + // It can be neither `nsw` nor `nuw` because the input is treated as + // unsigned but then the output is treated as signed, so neither works. + let d = isize::wrapping_sub(self as _, origin as _); intrinsics::exact_div(d, pointee_size as _) } @@ -775,9 +781,13 @@ impl *const T { /// `mem::size_of::()` then the result of the division is rounded towards /// zero. /// + /// Though this method is safe for any two pointers, note that its result + /// will be mostly useless if the two pointers aren't into the same allocated + /// object, for example if they point to two different local variables. + /// /// # Panics /// - /// This function panics if `T` is a zero-sized typed. + /// This function panics if `T` is a zero-sized type. /// /// # Examples /// @@ -800,11 +810,11 @@ impl *const T { /// ``` #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")] #[inline] - pub fn wrapping_offset_from(self, other: *const T) -> isize where T: Sized { + pub fn wrapping_offset_from(self, origin: *const T) -> isize where T: Sized { let pointee_size = mem::size_of::(); assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); - let d = isize::wrapping_sub(self as _, other as _); + let d = isize::wrapping_sub(self as _, origin as _); d.wrapping_div(pointee_size as _) } @@ -1424,7 +1434,7 @@ impl *mut T { /// `mem::size_of::()` then the result of the division is rounded towards /// zero. /// - /// This function returns `None` if `T` is a zero-sized typed. + /// This function returns `None` if `T` is a zero-sized type. /// /// # Examples /// @@ -1474,7 +1484,7 @@ impl *mut T { /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. /// /// * The distance between the pointers, in bytes, must be an exact multiple - /// of the size of `T` and `T` must not be a Zero-Sized Type ("ZST"). + /// of the size of `T`. /// /// * The distance being in bounds cannot rely on "wrapping around" the address space. /// @@ -1495,6 +1505,10 @@ impl *mut T { /// difficult to satisfy. The only advantage of this method is that it /// enables more aggressive compiler optimizations. /// + /// # Panics + /// + /// This function panics if `T` is a Zero-Sized Type ("ZST"). + /// /// # Examples /// /// Basic usage: @@ -1514,8 +1528,8 @@ impl *mut T { /// ``` #[unstable(feature = "ptr_offset_from", issue = "41079")] #[inline] - pub unsafe fn offset_from(self, other: *const T) -> isize where T: Sized { - (self as *const T).offset_from(other) + pub unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized { + (self as *const T).offset_from(origin) } /// Calculates the distance between two pointers. The returned value is in @@ -1525,9 +1539,13 @@ impl *mut T { /// `mem::size_of::()` then the result of the division is rounded towards /// zero. /// + /// Though this method is safe for any two pointers, note that its result + /// will be mostly useless if the two pointers aren't into the same allocated + /// object, for example if they point to two different local variables. + /// /// # Panics /// - /// This function panics if `T` is a zero-sized typed. + /// This function panics if `T` is a zero-sized type. /// /// # Examples /// @@ -1550,8 +1568,8 @@ impl *mut T { /// ``` #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")] #[inline] - pub fn wrapping_offset_from(self, other: *const T) -> isize where T: Sized { - (self as *const T).wrapping_offset_from(other) + pub fn wrapping_offset_from(self, origin: *const T) -> isize where T: Sized { + (self as *const T).wrapping_offset_from(origin) } /// Computes the byte offset that needs to be applied in order to -- cgit 1.4.1-3-g733a5 From 62649524b94fb83e2ed472088ea1a0cd87079fd2 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 24 Mar 2018 20:41:20 -0700 Subject: Fix doctest mutability copy-pasta --- src/libcore/ptr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 3fc8421d3b0..0723fa8a23d 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -1516,7 +1516,7 @@ impl *mut T { /// ``` /// #![feature(ptr_offset_from)] /// - /// let a = [0; 5]; + /// let mut a = [0; 5]; /// let ptr1: *mut i32 = &mut a[1]; /// let ptr2: *mut i32 = &mut a[3]; /// unsafe { @@ -1554,7 +1554,7 @@ impl *mut T { /// ``` /// #![feature(ptr_wrapping_offset_from)] /// - /// let a = [0; 5]; + /// let mut a = [0; 5]; /// let ptr1: *mut i32 = &mut a[1]; /// let ptr2: *mut i32 = &mut a[3]; /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); -- cgit 1.4.1-3-g733a5 From a907d9aad20a728e02897f660995b07646658a44 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Sat, 24 Mar 2018 23:45:20 -0400 Subject: Fix syntax error --- src/libcore/char.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 4420eff06ed..b8d1f91c247 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -905,7 +905,7 @@ impl> Iterator for DecodeUtf8 { #[inline] fn size_hint(&self) -> (usize, Option) { - let len = self.iter.len(); + let len = self.0.len(); // A code point is at most 4 bytes long. let min_code_points = len / 4; -- cgit 1.4.1-3-g733a5 From 01af316867dd6477072e0feae2d7cead2229ebfd Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Sun, 25 Mar 2018 00:00:18 -0400 Subject: Fix incorrect copy-pasted code It's late. --- src/libcore/char.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/char.rs b/src/libcore/char.rs index b8d1f91c247..c74b23da39c 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -905,12 +905,12 @@ impl> Iterator for DecodeUtf8 { #[inline] fn size_hint(&self) -> (usize, Option) { - let len = self.0.len(); + let (lower, upper) = self.0.size_hint(); // A code point is at most 4 bytes long. - let min_code_points = len / 4; + let min_code_points = lower / 4; - (min_code_points, Some(len)) + (min_code_points, upper) } } -- cgit 1.4.1-3-g733a5 From f198b0acf512458bdbe5079d12414ff94b03f7ac Mon Sep 17 00:00:00 2001 From: Sean Silva Date: Sat, 24 Mar 2018 22:31:17 -0700 Subject: Fix confusing doc for `scan` The comment "the value passed on to the next iteration" confused me since it sounded more like what Haskell's [scanl](http://hackage.haskell.org/package/base-4.11.0.0/docs/Prelude.html#v:scanl) does where the closure's return value serves as both the "yielded value" *and* the new value of the "state". I tried changing the example to make it clear that the closure's return value is decoupled from the state argument. --- src/libcore/iter/iterator.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 2cfbc092293..31f77f92435 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -974,13 +974,13 @@ pub trait Iterator { /// // each iteration, we'll multiply the state by the element /// *state = *state * x; /// - /// // the value passed on to the next iteration - /// Some(*state) + /// // then, we'll yield the negation of the state + /// Some(-*state) /// }); /// - /// assert_eq!(iter.next(), Some(1)); - /// assert_eq!(iter.next(), Some(2)); - /// assert_eq!(iter.next(), Some(6)); + /// assert_eq!(iter.next(), Some(-1)); + /// assert_eq!(iter.next(), Some(-2)); + /// assert_eq!(iter.next(), Some(-6)); /// assert_eq!(iter.next(), None); /// ``` #[inline] -- cgit 1.4.1-3-g733a5 From 23013c791c70a297b430e9d1c0408493705d36e0 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sun, 25 Mar 2018 14:19:27 +0200 Subject: update wording as per feedback --- src/libcore/sync/atomic.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index fd6e5140a09..c1f6c492e98 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -207,7 +207,9 @@ pub enum Ordering { Acquire, /// Has the effects of both [`Acquire`] and [`Release`] together. /// - /// If you only are concerned about a load or a store, consider using one of those instead. + /// This ordering is only applicable for operations that combine both loads and stores. + /// + /// For loads it uses [`Acquire`] ordering. For stores it uses the [`Release`] ordering. /// /// [`Acquire`]: http://llvm.org/docs/Atomics.html#acquire /// [`Release`]: http://llvm.org/docs/Atomics.html#release -- cgit 1.4.1-3-g733a5 From 0f5b52e4a8d3004ef2d69b2ec7f410d4b2c9494c Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 21 Mar 2018 18:32:44 -0700 Subject: Stabilize conservative_impl_trait --- src/Cargo.lock | 27 +-------- .../language-features/conservative-impl-trait.md | 66 ---------------------- src/libcore/tests/lib.rs | 2 +- src/librustc/diagnostics.rs | 8 --- src/librustc/hir/lowering.rs | 11 ---- src/librustc/lib.rs | 2 +- src/librustc_data_structures/lib.rs | 2 +- src/librustc_errors/lib.rs | 2 +- src/librustc_incremental/lib.rs | 2 +- src/librustc_metadata/lib.rs | 2 +- src/librustc_mir/lib.rs | 2 +- src/librustc_trans/lib.rs | 2 +- src/librustc_trans_utils/lib.rs | 2 +- src/librustc_typeck/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 5 +- src/test/compile-fail/conservative_impl_trait.rs | 1 - .../impl-trait/infinite-impl-trait-issue-38064.rs | 2 - .../must_outlive_least_region_or_bound.rs | 2 - .../impl-trait/needs_least_region_or_bound.rs | 2 - src/test/compile-fail/impl-trait/no-trait.rs | 2 - .../impl-trait/type_parameters_captured.rs | 2 - src/test/compile-fail/impl-trait/where-allowed.rs | 2 +- src/test/compile-fail/issue-32995-2.rs | 1 - src/test/compile-fail/issue-35668.rs | 2 - src/test/compile-fail/issue-36379.rs | 2 +- src/test/compile-fail/private-inferred-type.rs | 1 - src/test/compile-fail/private-type-in-interface.rs | 1 - src/test/incremental/hashes/function_interfaces.rs | 1 - src/test/run-pass/conservative_impl_trait.rs | 2 - .../generator/auxiliary/xcrate-reachable.rs | 2 +- src/test/run-pass/generator/auxiliary/xcrate.rs | 2 +- src/test/run-pass/generator/issue-44197.rs | 2 +- src/test/run-pass/generator/iterator-count.rs | 2 +- src/test/run-pass/generator/xcrate-reachable.rs | 2 +- src/test/run-pass/impl-trait/auto-trait-leak.rs | 2 - src/test/run-pass/impl-trait/auxiliary/xcrate.rs | 2 - src/test/run-pass/impl-trait/equality.rs | 2 +- src/test/run-pass/impl-trait/example-calendar.rs | 3 +- src/test/run-pass/impl-trait/example-st.rs | 2 - src/test/run-pass/impl-trait/issue-42479.rs | 2 - src/test/run-pass/impl-trait/lifetimes.rs | 2 +- src/test/run-pass/in-band-lifetimes.rs | 2 +- src/test/run-pass/issue-36792.rs | 1 - src/test/run-pass/issue-46959.rs | 1 - src/test/rustdoc/issue-43869.rs | 2 - src/test/ui/casts-differing-anon.rs | 2 - src/test/ui/casts-differing-anon.stderr | 2 +- src/test/ui/error-codes/E0657.rs | 1 - src/test/ui/error-codes/E0657.stderr | 4 +- .../ui/feature-gate-conservative_impl_trait.rs | 14 ----- .../ui/feature-gate-conservative_impl_trait.stderr | 11 ---- src/test/ui/impl-trait/auto-trait-leak.rs | 2 - src/test/ui/impl-trait/auto-trait-leak.stderr | 22 ++++---- src/test/ui/impl-trait/equality.rs | 2 +- ...egion-escape-via-bound-contravariant-closure.rs | 1 - .../region-escape-via-bound-contravariant.rs | 1 - src/test/ui/impl-trait/region-escape-via-bound.rs | 1 - .../ui/impl-trait/region-escape-via-bound.stderr | 6 +- src/test/ui/impl_trait_projections.rs | 2 +- src/test/ui/issue-35869.rs | 2 - src/test/ui/issue-35869.stderr | 8 +-- src/test/ui/nested_impl_trait.rs | 2 - src/test/ui/nested_impl_trait.stderr | 12 ++-- src/test/ui/nll/ty-outlives/impl-trait-captures.rs | 1 - .../ui/nll/ty-outlives/impl-trait-captures.stderr | 4 +- src/test/ui/nll/ty-outlives/impl-trait-outlives.rs | 1 - .../ui/nll/ty-outlives/impl-trait-outlives.stderr | 8 +-- src/tools/clippy | 2 +- 68 files changed, 62 insertions(+), 240 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/conservative-impl-trait.md delete mode 100644 src/test/ui/feature-gate-conservative_impl_trait.rs delete mode 100644 src/test/ui/feature-gate-conservative_impl_trait.stderr (limited to 'src/libcore') diff --git a/src/Cargo.lock b/src/Cargo.lock index 371e505e9be..c45f18360b9 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -271,11 +271,11 @@ dependencies = [ [[package]] name = "clippy" -version = "0.0.188" +version = "0.0.189" dependencies = [ "cargo_metadata 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "clippy-mini-macro-test 0.2.0", - "clippy_lints 0.0.188", + "clippy_lints 0.0.189", "compiletest_rs 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -289,29 +289,9 @@ dependencies = [ name = "clippy-mini-macro-test" version = "0.2.0" -[[package]] -name = "clippy_lints" -version = "0.0.188" -dependencies = [ - "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "clippy_lints" version = "0.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1419,7 +1399,7 @@ version = "0.126.0" dependencies = [ "cargo 0.27.0", "cargo_metadata 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy_lints 0.0.189 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy_lints 0.0.189", "env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2638,7 +2618,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" "checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536" -"checksum clippy_lints 0.0.189 (registry+https://github.com/rust-lang/crates.io-index)" = "fef652630bbf8c5e89601220abd000f5057e8fa9db608484b5ebaad98e9bce53" "checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb" "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" "checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" diff --git a/src/doc/unstable-book/src/language-features/conservative-impl-trait.md b/src/doc/unstable-book/src/language-features/conservative-impl-trait.md deleted file mode 100644 index 0be6a321103..00000000000 --- a/src/doc/unstable-book/src/language-features/conservative-impl-trait.md +++ /dev/null @@ -1,66 +0,0 @@ -# `conservative_impl_trait` - -The tracking issue for this feature is: [#34511] - -[#34511]: https://github.com/rust-lang/rust/issues/34511 - ------------------------- - -The `conservative_impl_trait` feature allows a conservative form of abstract -return types. - -Abstract return types allow a function to hide a concrete return type behind a -trait interface similar to trait objects, while still generating the same -statically dispatched code as with concrete types. - -## Examples - -```rust -#![feature(conservative_impl_trait)] - -fn even_iter() -> impl Iterator { - (0..).map(|n| n * 2) -} - -fn main() { - let first_four_even_numbers = even_iter().take(4).collect::>(); - assert_eq!(first_four_even_numbers, vec![0, 2, 4, 6]); -} -``` - -## Background - -In today's Rust, you can write function signatures like: - -````rust,ignore -fn consume_iter_static>(iter: I) { } - -fn consume_iter_dynamic(iter: Box>) { } -```` - -In both cases, the function does not depend on the exact type of the argument. -The type held is "abstract", and is assumed only to satisfy a trait bound. - -* In the `_static` version using generics, each use of the function is - specialized to a concrete, statically-known type, giving static dispatch, - inline layout, and other performance wins. -* In the `_dynamic` version using trait objects, the concrete argument type is - only known at runtime using a vtable. - -On the other hand, while you can write: - -````rust,ignore -fn produce_iter_dynamic() -> Box> { } -```` - -...but you _cannot_ write something like: - -````rust,ignore -fn produce_iter_static() -> Iterator { } -```` - -That is, in today's Rust, abstract return types can only be written using trait -objects, which can be a significant performance penalty. This RFC proposes -"unboxed abstract types" as a way of achieving signatures like -`produce_iter_static`. Like generics, unboxed abstract types guarantee static -dispatch and inline data layout. diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index e9a8113ef10..1c71669abb1 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -27,7 +27,7 @@ #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(iterator_try_fold)] #![feature(iterator_flatten)] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(iter_rfind)] #![feature(iter_rfold)] #![feature(iterator_repeat_with)] diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index e22e2b55703..f95c355012a 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1789,8 +1789,6 @@ allowed as function return types. Erroneous code example: ```compile_fail,E0562 -#![feature(conservative_impl_trait)] - fn main() { let count_to_ten: impl Iterator = 0..10; // error: `impl Trait` not allowed outside of function and inherent method @@ -1804,8 +1802,6 @@ fn main() { Make sure `impl Trait` only appears in return-type position. ``` -#![feature(conservative_impl_trait)] - fn count_to_n(n: usize) -> impl Iterator { 0..n } @@ -2081,8 +2077,6 @@ appear within the `impl Trait` itself. Erroneous code example: ```compile-fail,E0909 -#![feature(conservative_impl_trait)] - use std::cell::Cell; trait Trait<'a> { } @@ -2109,8 +2103,6 @@ type. For example, changing the return type to `impl Trait<'y> + 'x` would work: ``` -#![feature(conservative_impl_trait)] - use std::cell::Cell; trait Trait<'a> { } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2ae102fbef0..536d682566a 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1108,20 +1108,9 @@ impl<'a> LoweringContext<'a> { hir::TyTraitObject(bounds, lifetime_bound) } TyKind::ImplTrait(ref bounds) => { - use syntax::feature_gate::{emit_feature_err, GateIssue}; let span = t.span; match itctx { ImplTraitContext::Existential => { - let has_feature = self.sess.features_untracked().conservative_impl_trait; - if !t.span.allows_unstable() && !has_feature { - emit_feature_err( - &self.sess.parse_sess, - "conservative_impl_trait", - t.span, - GateIssue::Language, - "`impl Trait` in return position is experimental", - ); - } let def_index = self.resolver.definitions().opt_def_index(t.id).unwrap(); let hir_bounds = self.lower_bounds(bounds, itctx); let (lifetimes, lifetime_defs) = diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index d133352de07..1bb903c0627 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -43,7 +43,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(const_fn)] #![cfg_attr(stage0, feature(copy_closures, clone_closures))] #![feature(core_intrinsics)] diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 05bd3ae845f..ff869072871 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -28,7 +28,7 @@ #![feature(unsize)] #![feature(i128_type)] #![feature(i128)] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(specialization)] #![feature(optin_builtin_traits)] #![feature(underscore_lifetimes)] diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index dcbea793ba6..1152c9c574e 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -17,7 +17,7 @@ #![allow(unused_attributes)] #![feature(range_contains)] #![cfg_attr(unix, feature(libc))] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(i128_type)] #![feature(optin_builtin_traits)] diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index d7ccf9d5562..6adb950fe4e 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -15,7 +15,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] #![feature(i128_type)] #![cfg_attr(stage0, feature(inclusive_range_syntax))] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 85099667449..902dd87c574 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -14,7 +14,7 @@ #![deny(warnings)] #![feature(box_patterns)] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] #![feature(i128_type)] #![feature(libc)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index ff35412ea5b..750839f8b00 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -21,7 +21,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(box_patterns)] #![feature(box_syntax)] #![feature(catch_expr)] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(decl_macro)] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 9f654c8ab29..38adc603628 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -31,7 +31,7 @@ #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![cfg_attr(stage0, feature(slice_patterns))] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(optin_builtin_traits)] #![feature(inclusive_range_fields)] diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index 0af5f467934..9e4addd1ed1 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -24,7 +24,7 @@ #![feature(i128_type)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] extern crate ar; extern crate flate2; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 5a7de6b56b5..e466ef39234 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -75,7 +75,7 @@ This API is completely unstable and subject to change. #![cfg_attr(stage0, feature(advanced_slice_patterns))] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(conservative_impl_trait)] +#![cfg_attr(stage0, feature(conservative_impl_trait))] #![cfg_attr(stage0, feature(copy_closures, clone_closures))] #![feature(crate_visibility_modifier)] #![feature(from_ref)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index db900ed6e35..1bb369b551d 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -276,9 +276,6 @@ declare_features! ( // Allows cfg(target_has_atomic = "..."). (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), - // Allows `impl Trait` in function return types. - (active, conservative_impl_trait, "1.12.0", Some(34511), None), - // Allows exhaustive pattern matching on types that contain uninhabited types. (active, exhaustive_patterns, "1.13.0", None, None), @@ -565,6 +562,8 @@ declare_features! ( (accepted, copy_closures, "1.26.0", Some(44490), None), // Allows `impl Trait` in function arguments. (accepted, universal_impl_trait, "1.26.0", Some(34511), None), + // Allows `impl Trait` in function return types. + (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), ); // If you change this, please modify src/doc/unstable-book as well. You must diff --git a/src/test/compile-fail/conservative_impl_trait.rs b/src/test/compile-fail/conservative_impl_trait.rs index 7fb0ec52f29..30895bce357 100644 --- a/src/test/compile-fail/conservative_impl_trait.rs +++ b/src/test/compile-fail/conservative_impl_trait.rs @@ -10,7 +10,6 @@ // #39872, #39553 -#![feature(conservative_impl_trait)] fn will_ice(something: &u32) -> impl Iterator { //~^ ERROR the trait bound `(): std::iter::Iterator` is not satisfied [E0277] } diff --git a/src/test/compile-fail/impl-trait/infinite-impl-trait-issue-38064.rs b/src/test/compile-fail/impl-trait/infinite-impl-trait-issue-38064.rs index abde9689bd6..653ef1723e0 100644 --- a/src/test/compile-fail/impl-trait/infinite-impl-trait-issue-38064.rs +++ b/src/test/compile-fail/impl-trait/infinite-impl-trait-issue-38064.rs @@ -15,8 +15,6 @@ // error-pattern:overflow evaluating the requirement `impl Quux` -#![feature(conservative_impl_trait)] - trait Quux {} fn foo() -> impl Quux { diff --git a/src/test/compile-fail/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/compile-fail/impl-trait/must_outlive_least_region_or_bound.rs index 0eb99ca0fc3..537fc975bcf 100644 --- a/src/test/compile-fail/impl-trait/must_outlive_least_region_or_bound.rs +++ b/src/test/compile-fail/impl-trait/must_outlive_least_region_or_bound.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - use std::fmt::Debug; fn elided(x: &i32) -> impl Copy { x } diff --git a/src/test/compile-fail/impl-trait/needs_least_region_or_bound.rs b/src/test/compile-fail/impl-trait/needs_least_region_or_bound.rs index 2a06580fe60..6c0a0b800ce 100644 --- a/src/test/compile-fail/impl-trait/needs_least_region_or_bound.rs +++ b/src/test/compile-fail/impl-trait/needs_least_region_or_bound.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - use std::fmt::Debug; trait MultiRegionTrait<'a, 'b> {} diff --git a/src/test/compile-fail/impl-trait/no-trait.rs b/src/test/compile-fail/impl-trait/no-trait.rs index ce61c5bf63d..5299ba297d0 100644 --- a/src/test/compile-fail/impl-trait/no-trait.rs +++ b/src/test/compile-fail/impl-trait/no-trait.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - fn f() -> impl 'static {} //~ ERROR at least one trait must be specified fn main() {} diff --git a/src/test/compile-fail/impl-trait/type_parameters_captured.rs b/src/test/compile-fail/impl-trait/type_parameters_captured.rs index c6ff762b905..7c3430ab90e 100644 --- a/src/test/compile-fail/impl-trait/type_parameters_captured.rs +++ b/src/test/compile-fail/impl-trait/type_parameters_captured.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - use std::fmt::Debug; trait Any {} diff --git a/src/test/compile-fail/impl-trait/where-allowed.rs b/src/test/compile-fail/impl-trait/where-allowed.rs index c93bcf7f390..038eacaf110 100644 --- a/src/test/compile-fail/impl-trait/where-allowed.rs +++ b/src/test/compile-fail/impl-trait/where-allowed.rs @@ -10,7 +10,7 @@ //! A simple test for testing many permutations of allowedness of //! impl Trait -#![feature(conservative_impl_trait, dyn_trait)] +#![feature(dyn_trait)] use std::fmt::Debug; // Allowed diff --git a/src/test/compile-fail/issue-32995-2.rs b/src/test/compile-fail/issue-32995-2.rs index 0e917ad95d9..18424fcc9e0 100644 --- a/src/test/compile-fail/issue-32995-2.rs +++ b/src/test/compile-fail/issue-32995-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] #![allow(unused)] fn main() { diff --git a/src/test/compile-fail/issue-35668.rs b/src/test/compile-fail/issue-35668.rs index c9323db054c..17fd77b6df3 100644 --- a/src/test/compile-fail/issue-35668.rs +++ b/src/test/compile-fail/issue-35668.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - fn func<'a, T>(a: &'a [T]) -> impl Iterator { a.iter().map(|a| a*a) //~^ ERROR binary operation `*` cannot be applied to type `&T` diff --git a/src/test/compile-fail/issue-36379.rs b/src/test/compile-fail/issue-36379.rs index 2f513b034c3..b20765815e0 100644 --- a/src/test/compile-fail/issue-36379.rs +++ b/src/test/compile-fail/issue-36379.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, rustc_attrs)] +#![feature(rustc_attrs)] fn _test() -> impl Default { } diff --git a/src/test/compile-fail/private-inferred-type.rs b/src/test/compile-fail/private-inferred-type.rs index 351dc6b776b..5af8b063c16 100644 --- a/src/test/compile-fail/private-inferred-type.rs +++ b/src/test/compile-fail/private-inferred-type.rs @@ -9,7 +9,6 @@ // except according to those terms. #![feature(associated_consts)] -#![feature(conservative_impl_trait)] #![feature(decl_macro)] #![allow(private_in_public)] diff --git a/src/test/compile-fail/private-type-in-interface.rs b/src/test/compile-fail/private-type-in-interface.rs index eb8c40a7dd5..1842790a140 100644 --- a/src/test/compile-fail/private-type-in-interface.rs +++ b/src/test/compile-fail/private-type-in-interface.rs @@ -10,7 +10,6 @@ // aux-build:private-inferred-type.rs -#![feature(conservative_impl_trait)] #![allow(warnings)] extern crate private_inferred_type as ext; diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs index abe0586efcd..6c4e11be1e4 100644 --- a/src/test/incremental/hashes/function_interfaces.rs +++ b/src/test/incremental/hashes/function_interfaces.rs @@ -22,7 +22,6 @@ #![allow(warnings)] -#![feature(conservative_impl_trait)] #![feature(intrinsics)] #![feature(linkage)] #![feature(rustc_attrs)] diff --git a/src/test/run-pass/conservative_impl_trait.rs b/src/test/run-pass/conservative_impl_trait.rs index 30090018e29..14e1ca612c0 100644 --- a/src/test/run-pass/conservative_impl_trait.rs +++ b/src/test/run-pass/conservative_impl_trait.rs @@ -10,8 +10,6 @@ // #39665 -#![feature(conservative_impl_trait)] - fn batches(n: &u32) -> impl Iterator { std::iter::once(n) } diff --git a/src/test/run-pass/generator/auxiliary/xcrate-reachable.rs b/src/test/run-pass/generator/auxiliary/xcrate-reachable.rs index a6a2a2d081e..91e43537cc2 100644 --- a/src/test/run-pass/generator/auxiliary/xcrate-reachable.rs +++ b/src/test/run-pass/generator/auxiliary/xcrate-reachable.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, generators, generator_trait)] +#![feature(generators, generator_trait)] use std::ops::Generator; diff --git a/src/test/run-pass/generator/auxiliary/xcrate.rs b/src/test/run-pass/generator/auxiliary/xcrate.rs index f6878e64fbf..fcfe0b754b6 100644 --- a/src/test/run-pass/generator/auxiliary/xcrate.rs +++ b/src/test/run-pass/generator/auxiliary/xcrate.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generators, generator_trait, conservative_impl_trait)] +#![feature(generators, generator_trait)] use std::ops::Generator; diff --git a/src/test/run-pass/generator/issue-44197.rs b/src/test/run-pass/generator/issue-44197.rs index 8ce4fc6affa..272b7eb7bfd 100644 --- a/src/test/run-pass/generator/issue-44197.rs +++ b/src/test/run-pass/generator/issue-44197.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, generators, generator_trait)] +#![feature(generators, generator_trait)] use std::ops::{ Generator, GeneratorState }; diff --git a/src/test/run-pass/generator/iterator-count.rs b/src/test/run-pass/generator/iterator-count.rs index 654b18928c0..3564ddaa806 100644 --- a/src/test/run-pass/generator/iterator-count.rs +++ b/src/test/run-pass/generator/iterator-count.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generators, generator_trait, conservative_impl_trait)] +#![feature(generators, generator_trait)] use std::ops::{GeneratorState, Generator}; diff --git a/src/test/run-pass/generator/xcrate-reachable.rs b/src/test/run-pass/generator/xcrate-reachable.rs index 8eeb0133144..2fc39ba1869 100644 --- a/src/test/run-pass/generator/xcrate-reachable.rs +++ b/src/test/run-pass/generator/xcrate-reachable.rs @@ -10,7 +10,7 @@ // aux-build:xcrate-reachable.rs -#![feature(conservative_impl_trait, generator_trait)] +#![feature(generator_trait)] extern crate xcrate_reachable as foo; diff --git a/src/test/run-pass/impl-trait/auto-trait-leak.rs b/src/test/run-pass/impl-trait/auto-trait-leak.rs index 011d910c5a5..62fbae7b40c 100644 --- a/src/test/run-pass/impl-trait/auto-trait-leak.rs +++ b/src/test/run-pass/impl-trait/auto-trait-leak.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - // Fast path, main can see the concrete type returned. fn before() -> impl FnMut(i32) { let mut p = Box::new(0); diff --git a/src/test/run-pass/impl-trait/auxiliary/xcrate.rs b/src/test/run-pass/impl-trait/auxiliary/xcrate.rs index e4f525a9826..c27a2dd89d5 100644 --- a/src/test/run-pass/impl-trait/auxiliary/xcrate.rs +++ b/src/test/run-pass/impl-trait/auxiliary/xcrate.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - // NOTE commented out due to issue #45994 //pub fn fourway_add(a: i32) -> impl Fn(i32) -> impl Fn(i32) -> impl Fn(i32) -> i32 { // move |b| move |c| move |d| a + b + c + d diff --git a/src/test/run-pass/impl-trait/equality.rs b/src/test/run-pass/impl-trait/equality.rs index ceed454e5ad..034d3d7c80f 100644 --- a/src/test/run-pass/impl-trait/equality.rs +++ b/src/test/run-pass/impl-trait/equality.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, specialization)] +#![feature(specialization)] trait Foo: std::fmt::Debug + Eq {} diff --git a/src/test/run-pass/impl-trait/example-calendar.rs b/src/test/run-pass/impl-trait/example-calendar.rs index d1e2b471d9a..b1db2030717 100644 --- a/src/test/run-pass/impl-trait/example-calendar.rs +++ b/src/test/run-pass/impl-trait/example-calendar.rs @@ -11,8 +11,7 @@ // revisions: normal nll //[nll] compile-flags: -Znll -Zborrowck=mir -#![feature(conservative_impl_trait, - fn_traits, +#![feature(fn_traits, step_trait, unboxed_closures, copy_closures, diff --git a/src/test/run-pass/impl-trait/example-st.rs b/src/test/run-pass/impl-trait/example-st.rs index e9326ed286a..a06bde7f532 100644 --- a/src/test/run-pass/impl-trait/example-st.rs +++ b/src/test/run-pass/impl-trait/example-st.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - struct State; type Error = (); diff --git a/src/test/run-pass/impl-trait/issue-42479.rs b/src/test/run-pass/impl-trait/issue-42479.rs index 629948a5dc4..df7a6c13092 100644 --- a/src/test/run-pass/impl-trait/issue-42479.rs +++ b/src/test/run-pass/impl-trait/issue-42479.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - use std::iter::once; struct Foo { diff --git a/src/test/run-pass/impl-trait/lifetimes.rs b/src/test/run-pass/impl-trait/lifetimes.rs index c589e23f950..1b50ceefbe1 100644 --- a/src/test/run-pass/impl-trait/lifetimes.rs +++ b/src/test/run-pass/impl-trait/lifetimes.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, underscore_lifetimes)] +#![feature(underscore_lifetimes)] #![allow(warnings)] use std::fmt::Debug; diff --git a/src/test/run-pass/in-band-lifetimes.rs b/src/test/run-pass/in-band-lifetimes.rs index b5b73675ca7..6edd0d686ef 100644 --- a/src/test/run-pass/in-band-lifetimes.rs +++ b/src/test/run-pass/in-band-lifetimes.rs @@ -9,7 +9,7 @@ // except according to those terms. #![allow(warnings)] -#![feature(in_band_lifetimes, conservative_impl_trait)] +#![feature(in_band_lifetimes)] fn foo(x: &'x u8) -> &'x u8 { x } fn foo2(x: &'a u8, y: &u8) -> &'a u8 { x } diff --git a/src/test/run-pass/issue-36792.rs b/src/test/run-pass/issue-36792.rs index faf983f6ecb..f2755ec3f84 100644 --- a/src/test/run-pass/issue-36792.rs +++ b/src/test/run-pass/issue-36792.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] fn foo() -> impl Copy { foo } diff --git a/src/test/run-pass/issue-46959.rs b/src/test/run-pass/issue-46959.rs index 876b8c0a1d3..7f050c055b0 100644 --- a/src/test/run-pass/issue-46959.rs +++ b/src/test/run-pass/issue-46959.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] #![deny(non_camel_case_types)] #[allow(dead_code)] diff --git a/src/test/rustdoc/issue-43869.rs b/src/test/rustdoc/issue-43869.rs index 554c71500cc..a5ed3d892ce 100644 --- a/src/test/rustdoc/issue-43869.rs +++ b/src/test/rustdoc/issue-43869.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - pub fn g() -> impl Iterator { Some(1u8).into_iter() } diff --git a/src/test/ui/casts-differing-anon.rs b/src/test/ui/casts-differing-anon.rs index 74c8ff370f9..05a03d3b179 100644 --- a/src/test/ui/casts-differing-anon.rs +++ b/src/test/ui/casts-differing-anon.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - use std::fmt; fn foo() -> Box { diff --git a/src/test/ui/casts-differing-anon.stderr b/src/test/ui/casts-differing-anon.stderr index acbff4f73c3..dac24af671c 100644 --- a/src/test/ui/casts-differing-anon.stderr +++ b/src/test/ui/casts-differing-anon.stderr @@ -1,5 +1,5 @@ error[E0606]: casting `*mut impl std::fmt::Debug+?Sized` as `*mut impl std::fmt::Debug+?Sized` is invalid - --> $DIR/casts-differing-anon.rs:33:13 + --> $DIR/casts-differing-anon.rs:31:13 | LL | b_raw = f_raw as *mut _; //~ ERROR is invalid | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui/error-codes/E0657.rs b/src/test/ui/error-codes/E0657.rs index 31b3acd86ef..c23aa40ee37 100644 --- a/src/test/ui/error-codes/E0657.rs +++ b/src/test/ui/error-codes/E0657.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![allow(warnings)] -#![feature(conservative_impl_trait)] trait Id {} trait Lt<'a> {} diff --git a/src/test/ui/error-codes/E0657.stderr b/src/test/ui/error-codes/E0657.stderr index f0529142023..737ae3a163a 100644 --- a/src/test/ui/error-codes/E0657.stderr +++ b/src/test/ui/error-codes/E0657.stderr @@ -1,11 +1,11 @@ error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level - --> $DIR/E0657.rs:20:31 + --> $DIR/E0657.rs:19:31 | LL | -> Box Id>> | ^^ error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level - --> $DIR/E0657.rs:29:35 + --> $DIR/E0657.rs:28:35 | LL | -> Box Id>> | ^^ diff --git a/src/test/ui/feature-gate-conservative_impl_trait.rs b/src/test/ui/feature-gate-conservative_impl_trait.rs deleted file mode 100644 index 7a3ae639bfc..00000000000 --- a/src/test/ui/feature-gate-conservative_impl_trait.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn foo() -> impl Fn() { || {} } -//~^ ERROR `impl Trait` in return position is experimental - -fn main() {} diff --git a/src/test/ui/feature-gate-conservative_impl_trait.stderr b/src/test/ui/feature-gate-conservative_impl_trait.stderr deleted file mode 100644 index 5400226450b..00000000000 --- a/src/test/ui/feature-gate-conservative_impl_trait.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: `impl Trait` in return position is experimental (see issue #34511) - --> $DIR/feature-gate-conservative_impl_trait.rs:11:13 - | -LL | fn foo() -> impl Fn() { || {} } - | ^^^^^^^^^ - | - = help: add #![feature(conservative_impl_trait)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/impl-trait/auto-trait-leak.rs b/src/test/ui/impl-trait/auto-trait-leak.rs index 5a6aac43ec7..99a7dd5e785 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.rs +++ b/src/test/ui/impl-trait/auto-trait-leak.rs @@ -10,8 +10,6 @@ // ignore-tidy-linelength -#![feature(conservative_impl_trait)] - use std::cell::Cell; use std::rc::Rc; diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 71ca8675db4..ca639f1076d 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -1,56 +1,56 @@ error[E0277]: the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied in `impl std::ops::Fn<(i32,)>` - --> $DIR/auto-trait-leak.rs:27:5 + --> $DIR/auto-trait-leak.rs:25:5 | LL | send(before()); | ^^^^ `std::rc::Rc>` cannot be sent between threads safely | = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` - = note: required because it appears within the type `[closure@$DIR/auto-trait-leak.rs:21:5: 21:22 p:std::rc::Rc>]` + = note: required because it appears within the type `[closure@$DIR/auto-trait-leak.rs:19:5: 19:22 p:std::rc::Rc>]` = note: required because it appears within the type `impl std::ops::Fn<(i32,)>` note: required by `send` - --> $DIR/auto-trait-leak.rs:24:1 + --> $DIR/auto-trait-leak.rs:22:1 | LL | fn send(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied in `impl std::ops::Fn<(i32,)>` - --> $DIR/auto-trait-leak.rs:30:5 + --> $DIR/auto-trait-leak.rs:28:5 | LL | send(after()); | ^^^^ `std::rc::Rc>` cannot be sent between threads safely | = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` - = note: required because it appears within the type `[closure@$DIR/auto-trait-leak.rs:38:5: 38:22 p:std::rc::Rc>]` + = note: required because it appears within the type `[closure@$DIR/auto-trait-leak.rs:36:5: 36:22 p:std::rc::Rc>]` = note: required because it appears within the type `impl std::ops::Fn<(i32,)>` note: required by `send` - --> $DIR/auto-trait-leak.rs:24:1 + --> $DIR/auto-trait-leak.rs:22:1 | LL | fn send(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0391]: cyclic dependency detected - --> $DIR/auto-trait-leak.rs:44:1 + --> $DIR/auto-trait-leak.rs:42:1 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic reference | note: the cycle begins when processing `cycle1`... - --> $DIR/auto-trait-leak.rs:44:1 + --> $DIR/auto-trait-leak.rs:42:1 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which then requires processing `cycle2::{{impl-Trait}}`... - --> $DIR/auto-trait-leak.rs:52:16 + --> $DIR/auto-trait-leak.rs:50:16 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ note: ...which then requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:52:1 + --> $DIR/auto-trait-leak.rs:50:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which then requires processing `cycle1::{{impl-Trait}}`... - --> $DIR/auto-trait-leak.rs:44:16 + --> $DIR/auto-trait-leak.rs:42:16 | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/equality.rs b/src/test/ui/impl-trait/equality.rs index 9d9d4cef311..b65e477f21f 100644 --- a/src/test/ui/impl-trait/equality.rs +++ b/src/test/ui/impl-trait/equality.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, specialization)] +#![feature(specialization)] trait Foo: Copy + ToString {} diff --git a/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs b/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs index f554efe9036..78ae922c751 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs +++ b/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs @@ -18,7 +18,6 @@ // run-pass #![allow(dead_code)] -#![feature(conservative_impl_trait)] #![feature(in_band_lifetimes)] #![feature(nll)] diff --git a/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs b/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs index 416bdae5178..972461c2ffd 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs +++ b/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs @@ -18,7 +18,6 @@ // run-pass #![allow(dead_code)] -#![feature(conservative_impl_trait)] #![feature(in_band_lifetimes)] #![feature(nll)] diff --git a/src/test/ui/impl-trait/region-escape-via-bound.rs b/src/test/ui/impl-trait/region-escape-via-bound.rs index 38c18ce6104..e73f15606dc 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound.rs +++ b/src/test/ui/impl-trait/region-escape-via-bound.rs @@ -14,7 +14,6 @@ // See https://github.com/rust-lang/rust/issues/46541 for more details. #![allow(dead_code)] -#![feature(conservative_impl_trait)] #![feature(in_band_lifetimes)] #![feature(nll)] diff --git a/src/test/ui/impl-trait/region-escape-via-bound.stderr b/src/test/ui/impl-trait/region-escape-via-bound.stderr index 5659fee9bed..4281a4c10ad 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound.stderr +++ b/src/test/ui/impl-trait/region-escape-via-bound.stderr @@ -1,11 +1,11 @@ error[E0909]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/region-escape-via-bound.rs:27:29 + --> $DIR/region-escape-via-bound.rs:26:29 | LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y> | ^^^^^^^^^^^^^^ | -note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime 'x as defined on the function body at 27:1 - --> $DIR/region-escape-via-bound.rs:27:1 +note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime 'x as defined on the function body at 26:1 + --> $DIR/region-escape-via-bound.rs:26:1 | LL | / fn foo(x: Cell<&'x u32>) -> impl Trait<'y> LL | | //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0909] diff --git a/src/test/ui/impl_trait_projections.rs b/src/test/ui/impl_trait_projections.rs index 05e88bf848d..6a727942271 100644 --- a/src/test/ui/impl_trait_projections.rs +++ b/src/test/ui/impl_trait_projections.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dyn_trait, conservative_impl_trait)] +#![feature(dyn_trait)] use std::fmt::Debug; use std::option; diff --git a/src/test/ui/issue-35869.rs b/src/test/ui/issue-35869.rs index 17ee62aed1b..7bab22edcf6 100644 --- a/src/test/ui/issue-35869.rs +++ b/src/test/ui/issue-35869.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - trait Foo { fn foo(_: fn(u8) -> ()); fn bar(_: Option); diff --git a/src/test/ui/issue-35869.stderr b/src/test/ui/issue-35869.stderr index fa971c111a4..1930dd5bbcb 100644 --- a/src/test/ui/issue-35869.stderr +++ b/src/test/ui/issue-35869.stderr @@ -1,5 +1,5 @@ error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/issue-35869.rs:23:15 + --> $DIR/issue-35869.rs:21:15 | LL | fn foo(_: fn(u8) -> ()); | ------------ type in trait @@ -11,7 +11,7 @@ LL | fn foo(_: fn(u16) -> ()) {} found type `fn(fn(u16))` error[E0053]: method `bar` has an incompatible type for trait - --> $DIR/issue-35869.rs:25:15 + --> $DIR/issue-35869.rs:23:15 | LL | fn bar(_: Option); | ---------- type in trait @@ -23,7 +23,7 @@ LL | fn bar(_: Option) {} found type `fn(std::option::Option)` error[E0053]: method `baz` has an incompatible type for trait - --> $DIR/issue-35869.rs:27:15 + --> $DIR/issue-35869.rs:25:15 | LL | fn baz(_: (u8, u16)); | --------- type in trait @@ -35,7 +35,7 @@ LL | fn baz(_: (u16, u16)) {} found type `fn((u16, u16))` error[E0053]: method `qux` has an incompatible type for trait - --> $DIR/issue-35869.rs:29:17 + --> $DIR/issue-35869.rs:27:17 | LL | fn qux() -> u8; | -- type in trait diff --git a/src/test/ui/nested_impl_trait.rs b/src/test/ui/nested_impl_trait.rs index 0fb1222d797..be0454472dd 100644 --- a/src/test/ui/nested_impl_trait.rs +++ b/src/test/ui/nested_impl_trait.rs @@ -7,8 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait)] - use std::fmt::Debug; fn fine(x: impl Into) -> impl Into { x } diff --git a/src/test/ui/nested_impl_trait.stderr b/src/test/ui/nested_impl_trait.stderr index 10d767db8d3..ee53194e2b4 100644 --- a/src/test/ui/nested_impl_trait.stderr +++ b/src/test/ui/nested_impl_trait.stderr @@ -1,5 +1,5 @@ error[E0666]: nested `impl Trait` is not allowed - --> $DIR/nested_impl_trait.rs:16:56 + --> $DIR/nested_impl_trait.rs:14:56 | LL | fn bad_in_ret_position(x: impl Into) -> impl Into { x } | ----------^^^^^^^^^^- @@ -8,7 +8,7 @@ LL | fn bad_in_ret_position(x: impl Into) -> impl Into { x } | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed - --> $DIR/nested_impl_trait.rs:19:42 + --> $DIR/nested_impl_trait.rs:17:42 | LL | fn bad_in_fn_syntax(x: fn() -> impl Into) {} | ----------^^^^^^^^^^- @@ -17,7 +17,7 @@ LL | fn bad_in_fn_syntax(x: fn() -> impl Into) {} | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed - --> $DIR/nested_impl_trait.rs:23:37 + --> $DIR/nested_impl_trait.rs:21:37 | LL | fn bad_in_arg_position(_: impl Into) { } | ----------^^^^^^^^^^- @@ -26,7 +26,7 @@ LL | fn bad_in_arg_position(_: impl Into) { } | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed - --> $DIR/nested_impl_trait.rs:28:44 + --> $DIR/nested_impl_trait.rs:26:44 | LL | fn bad(x: impl Into) -> impl Into { x } | ----------^^^^^^^^^^- @@ -35,13 +35,13 @@ LL | fn bad(x: impl Into) -> impl Into { x } | outer `impl Trait` error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/nested_impl_trait.rs:19:32 + --> $DIR/nested_impl_trait.rs:17:32 | LL | fn bad_in_fn_syntax(x: fn() -> impl Into) {} | ^^^^^^^^^^^^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/nested_impl_trait.rs:36:42 + --> $DIR/nested_impl_trait.rs:34:42 | LL | fn allowed_in_ret_type() -> impl Fn() -> impl Into { | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.rs b/src/test/ui/nll/ty-outlives/impl-trait-captures.rs index 850cd1e7336..571bd9fd76e 100644 --- a/src/test/ui/nll/ty-outlives/impl-trait-captures.rs +++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.rs @@ -11,7 +11,6 @@ // compile-flags:-Znll -Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(conservative_impl_trait)] trait Foo<'a> { } diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr index bfa58bfc807..92e4f72da3a 100644 --- a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr +++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr @@ -1,11 +1,11 @@ warning: not reporting region error due to -Znll - --> $DIR/impl-trait-captures.rs:22:5 + --> $DIR/impl-trait-captures.rs:21:5 | LL | x | ^ error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/impl-trait-captures.rs:22:5 + --> $DIR/impl-trait-captures.rs:21:5 | LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { | - consider changing the type of `x` to `&ReEarlyBound(0, 'a) T` diff --git a/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs b/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs index 135805a7339..2e0671f1a51 100644 --- a/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs +++ b/src/test/ui/nll/ty-outlives/impl-trait-outlives.rs @@ -11,7 +11,6 @@ // compile-flags:-Znll -Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(conservative_impl_trait)] use std::fmt::Debug; diff --git a/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr b/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr index f29d2233e70..2b90d53774e 100644 --- a/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr +++ b/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr @@ -1,17 +1,17 @@ warning: not reporting region error due to -Znll - --> $DIR/impl-trait-outlives.rs:18:35 + --> $DIR/impl-trait-outlives.rs:17:35 | LL | fn no_region<'a, T>(x: Box) -> impl Debug + 'a | ^^^^^^^^^^^^^^^ warning: not reporting region error due to -Znll - --> $DIR/impl-trait-outlives.rs:34:42 + --> $DIR/impl-trait-outlives.rs:33:42 | LL | fn wrong_region<'a, 'b, T>(x: Box) -> impl Debug + 'a | ^^^^^^^^^^^^^^^ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/impl-trait-outlives.rs:23:5 + --> $DIR/impl-trait-outlives.rs:22:5 | LL | x | ^ @@ -19,7 +19,7 @@ LL | x = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`... error[E0309]: the parameter type `T` may not live long enough - --> $DIR/impl-trait-outlives.rs:39:5 + --> $DIR/impl-trait-outlives.rs:38:5 | LL | x | ^ diff --git a/src/tools/clippy b/src/tools/clippy index 4edd140e57c..eafd0901081 160000 --- a/src/tools/clippy +++ b/src/tools/clippy @@ -1 +1 @@ -Subproject commit 4edd140e57cce900fa930e1439bab469f5bbce46 +Subproject commit eafd09010815da43302ac947afee45b0f5219e6b -- cgit 1.4.1-3-g733a5 From 7ce8191775b44d3773e28d647b5b17ec85508e16 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Fri, 16 Mar 2018 19:51:49 -0500 Subject: Stabilize i128_type --- src/liballoc/benches/lib.rs | 2 +- src/liballoc/lib.rs | 2 +- src/libcore/lib.rs | 2 +- src/libcore/num/mod.rs | 6 ++-- src/libcore/tests/lib.rs | 2 +- src/libproc_macro/lib.rs | 2 +- src/librustc/lib.rs | 2 +- src/librustc_apfloat/lib.rs | 2 +- src/librustc_apfloat/tests/ieee.rs | 2 +- src/librustc_const_eval/lib.rs | 2 +- src/librustc_const_math/lib.rs | 2 +- src/librustc_data_structures/lib.rs | 2 +- src/librustc_errors/lib.rs | 2 +- src/librustc_incremental/lib.rs | 2 +- src/librustc_lint/lib.rs | 2 +- src/librustc_metadata/lib.rs | 2 +- src/librustc_mir/lib.rs | 2 +- src/librustc_resolve/lib.rs | 11 -------- src/librustc_trans/lib.rs | 2 +- src/librustc_trans_utils/lib.rs | 2 +- src/librustc_typeck/lib.rs | 2 +- src/libserialize/lib.rs | 2 +- src/libstd/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 17 ++---------- src/libsyntax/lib.rs | 2 +- src/libsyntax_pos/lib.rs | 2 +- src/test/codegen/unchecked-float-casts.rs | 1 - src/test/mir-opt/lower_128bit_debug_test.rs | 1 - src/test/mir-opt/lower_128bit_test.rs | 1 - src/test/run-pass/float-int-invalid-const-cast.rs | 1 - src/test/run-pass/i128-ffi.rs | 2 -- src/test/run-pass/i128.rs | 2 +- src/test/run-pass/intrinsics-integer.rs | 2 +- src/test/run-pass/issue-38763.rs | 2 -- src/test/run-pass/issue-38987.rs | 1 - .../run-pass/next-power-of-two-overflow-debug.rs | 2 -- .../run-pass/next-power-of-two-overflow-ndebug.rs | 2 -- src/test/run-pass/saturating-float-casts.rs | 2 +- src/test/run-pass/u128-as-f32.rs | 2 +- src/test/run-pass/u128.rs | 2 +- src/test/ui/feature-gate-i128_type.rs | 18 ------------ src/test/ui/feature-gate-i128_type.stderr | 19 ------------- src/test/ui/feature-gate-i128_type2.rs | 8 +++--- src/test/ui/feature-gate-i128_type2.stderr | 32 ---------------------- src/test/ui/lint-ctypes.rs | 2 +- src/test/ui/lint/type-overflow.rs | 2 -- 46 files changed, 37 insertions(+), 147 deletions(-) delete mode 100644 src/test/ui/feature-gate-i128_type.rs delete mode 100644 src/test/ui/feature-gate-i128_type.stderr (limited to 'src/libcore') diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index 2de0ffb4b26..09685d1bb40 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -10,7 +10,7 @@ #![deny(warnings)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(rand)] #![feature(repr_simd)] #![feature(test)] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index f914b1a93a9..19d64d8fea9 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -97,7 +97,7 @@ #![feature(from_ref)] #![feature(fundamental)] #![feature(generic_param_attrs)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(iter_rfold)] #![feature(lang_items)] #![feature(needs_allocator)] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 9aebe2e4ee4..11fecde3951 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -78,7 +78,7 @@ #![feature(doc_spotlight)] #![feature(fn_must_use)] #![feature(fundamental)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(intrinsics)] #![feature(iterator_flatten)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 18e0aa453d8..9ff42a6d4ea 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1635,8 +1635,7 @@ impl i64 { #[lang = "i128"] impl i128 { int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, - 170141183460469231731687303715884105727, "#![feature(i128_type)] -#![feature(i128)] + 170141183460469231731687303715884105727, "#![feature(i128)] # fn main() { ", " # }" } @@ -3493,8 +3492,7 @@ impl u64 { #[lang = "u128"] impl u128 { - uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "#![feature(i128_type)] -#![feature(i128)] + uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "#![feature(i128)] # fn main() { ", " diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 1c71669abb1..0b70f692403 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -23,7 +23,7 @@ #![feature(fmt_internals)] #![feature(hashmap_internals)] #![feature(iterator_step_by)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(iterator_try_fold)] #![feature(iterator_flatten)] diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index d6e679bad48..716a2cc6cbb 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -34,7 +34,7 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(rustc_private)] #![feature(staged_api)] #![feature(lang_items)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 1bb903c0627..061044cdf14 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -53,7 +53,7 @@ #![feature(from_ref)] #![feature(fs_read_write)] #![feature(i128)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![cfg_attr(windows, feature(libc))] #![feature(match_default_bindings)] diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 565658804b0..2ee7bea8476 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -46,8 +46,8 @@ #![deny(warnings)] #![forbid(unsafe_code)] -#![feature(i128_type)] #![cfg_attr(stage0, feature(slice_patterns))] +#![cfg_attr(stage0, feature(i128_type))] #![feature(try_from)] // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. diff --git a/src/librustc_apfloat/tests/ieee.rs b/src/librustc_apfloat/tests/ieee.rs index ff46ee79c31..627d79724b2 100644 --- a/src/librustc_apfloat/tests/ieee.rs +++ b/src/librustc_apfloat/tests/ieee.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #[macro_use] extern crate rustc_apfloat; diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 2b0775e8695..2620448927d 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -23,7 +23,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![feature(macro_lifetime_matcher)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(from_ref)] extern crate arena; diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index 5555e727a95..a53055c7ce7 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -20,7 +20,7 @@ #![deny(warnings)] #![feature(i128)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] extern crate rustc_apfloat; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index ff869072871..01f91e37db8 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -26,7 +26,7 @@ #![feature(unboxed_closures)] #![feature(fn_traits)] #![feature(unsize)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(i128)] #![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(specialization)] diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 1152c9c574e..37ae64cef57 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -18,7 +18,7 @@ #![feature(range_contains)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(stage0, feature(conservative_impl_trait))] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(optin_builtin_traits)] extern crate atty; diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 6adb950fe4e..5a33f566e90 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -17,7 +17,7 @@ #![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(specialization)] diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 4639f7b2d28..d024adad9d0 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -27,7 +27,7 @@ #![cfg_attr(test, feature(test))] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(macro_vis_matcher)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 902dd87c574..4af5ec9ae08 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -16,7 +16,7 @@ #![feature(box_patterns)] #![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(libc)] #![feature(macro_lifetime_matcher)] #![feature(proc_macro_internals)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 750839f8b00..a1f096b2a38 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -27,7 +27,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(decl_macro)] #![feature(dyn_trait)] #![feature(fs_read_write)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(macro_vis_matcher)] #![feature(match_default_bindings)] diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2cb2c76c632..01eda71e9b6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3117,17 +3117,6 @@ impl<'a> Resolver<'a> { self.primitive_type_table.primitive_types .contains_key(&path[0].node.name) => { let prim = self.primitive_type_table.primitive_types[&path[0].node.name]; - match prim { - TyUint(UintTy::U128) | TyInt(IntTy::I128) => { - if !self.session.features_untracked().i128_type { - emit_feature_err(&self.session.parse_sess, - "i128_type", span, GateIssue::Language, - "128-bit type is unstable"); - - } - } - _ => {} - } PathResolution::with_unresolved_segments(Def::PrimTy(prim), path.len() - 1) } PathResult::Module(module) => PathResolution::new(module.def().unwrap()), diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 38adc603628..d89d19db63e 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -24,7 +24,7 @@ #![feature(custom_attribute)] #![feature(fs_read_write)] #![allow(unused_attributes)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(i128)] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(libc)] diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index 9e4addd1ed1..99de124c6e1 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -21,7 +21,7 @@ #![feature(box_syntax)] #![feature(custom_attribute)] #![allow(unused_attributes)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![cfg_attr(stage0, feature(conservative_impl_trait))] diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index e466ef39234..8b3d5af3edd 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -86,7 +86,7 @@ This API is completely unstable and subject to change. #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(never_type))] #[macro_use] extern crate log; diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 2e354252c15..ee952523462 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -23,7 +23,7 @@ Core encoding and decoding interfaces. #![feature(box_syntax)] #![feature(core_intrinsics)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(specialization)] #![cfg_attr(test, feature(test))] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 0b06c5d4d65..3cc5d7b81c3 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -270,7 +270,7 @@ #![feature(hashmap_internals)] #![feature(heap_api)] #![feature(i128)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(int_error_internals)] #![feature(integer_atomics)] #![feature(into_cow)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1bb369b551d..4e3c77d5e46 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -303,9 +303,6 @@ declare_features! ( // `extern "ptx-*" fn()` (active, abi_ptx, "1.15.0", None, None), - // The `i128` type - (active, i128_type, "1.16.0", Some(35118), None), - // The `repr(i128)` annotation for enums (active, repr128, "1.16.0", Some(35118), None), @@ -564,6 +561,8 @@ declare_features! ( (accepted, universal_impl_trait, "1.26.0", Some(34511), None), // Allows `impl Trait` in function return types. (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), + // The `i128` type + (accepted, i128_type, "1.26.0", Some(35118), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1641,18 +1640,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { e.span, "yield syntax is experimental"); } - ast::ExprKind::Lit(ref lit) => { - if let ast::LitKind::Int(_, ref ty) = lit.node { - match *ty { - ast::LitIntType::Signed(ast::IntTy::I128) | - ast::LitIntType::Unsigned(ast::UintTy::U128) => { - gate_feature_post!(&self, i128_type, e.span, - "128-bit integers are not stable"); - } - _ => {} - } - } - } ast::ExprKind::Catch(_) => { gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental"); } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 74f1ee373ec..2218b396685 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -24,7 +24,7 @@ #![feature(rustc_diagnostic_macros)] #![feature(match_default_bindings)] #![feature(non_exhaustive)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(const_atomic_usize_new)] #![feature(rustc_attrs)] diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 5a7b7e9ceca..eb345200f41 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -21,7 +21,7 @@ #![feature(const_fn)] #![feature(custom_attribute)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(optin_builtin_traits)] #![allow(unused_attributes)] #![feature(specialization)] diff --git a/src/test/codegen/unchecked-float-casts.rs b/src/test/codegen/unchecked-float-casts.rs index c2fc2966170..87ebaaeec32 100644 --- a/src/test/codegen/unchecked-float-casts.rs +++ b/src/test/codegen/unchecked-float-casts.rs @@ -14,7 +14,6 @@ // -Z saturating-float-casts is not enabled. #![crate_type = "lib"] -#![feature(i128_type)] // CHECK-LABEL: @f32_to_u32 #[no_mangle] diff --git a/src/test/mir-opt/lower_128bit_debug_test.rs b/src/test/mir-opt/lower_128bit_debug_test.rs index 1752445a141..d7586b1aa4b 100644 --- a/src/test/mir-opt/lower_128bit_debug_test.rs +++ b/src/test/mir-opt/lower_128bit_debug_test.rs @@ -15,7 +15,6 @@ // compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=yes -#![feature(i128_type)] #![feature(const_fn)] static TEST_SIGNED: i128 = const_signed(-222); diff --git a/src/test/mir-opt/lower_128bit_test.rs b/src/test/mir-opt/lower_128bit_test.rs index 4058eaef9b0..341682debeb 100644 --- a/src/test/mir-opt/lower_128bit_test.rs +++ b/src/test/mir-opt/lower_128bit_test.rs @@ -15,7 +15,6 @@ // compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=no -#![feature(i128_type)] #![feature(const_fn)] static TEST_SIGNED: i128 = const_signed(-222); diff --git a/src/test/run-pass/float-int-invalid-const-cast.rs b/src/test/run-pass/float-int-invalid-const-cast.rs index d44f78922c7..f84432abbfa 100644 --- a/src/test/run-pass/float-int-invalid-const-cast.rs +++ b/src/test/run-pass/float-int-invalid-const-cast.rs @@ -10,7 +10,6 @@ // ignore-emscripten no i128 support -#![feature(i128_type)] #![deny(const_err)] use std::{f32, f64}; diff --git a/src/test/run-pass/i128-ffi.rs b/src/test/run-pass/i128-ffi.rs index d989210dd71..edf278cbf64 100644 --- a/src/test/run-pass/i128-ffi.rs +++ b/src/test/run-pass/i128-ffi.rs @@ -15,8 +15,6 @@ // ignore-windows // ignore-32bit -#![feature(i128_type)] - #[link(name = "rust_test_helpers", kind = "static")] extern "C" { fn identity(f: u128) -> u128; diff --git a/src/test/run-pass/i128.rs b/src/test/run-pass/i128.rs index c3e43c92590..baf3b339984 100644 --- a/src/test/run-pass/i128.rs +++ b/src/test/run-pass/i128.rs @@ -12,7 +12,7 @@ // compile-flags: -Z borrowck=compare -#![feature(i128_type, test)] +#![feature(test)] extern crate test; use test::black_box as b; diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs index cdfad51e648..7a8ff1befc7 100644 --- a/src/test/run-pass/intrinsics-integer.rs +++ b/src/test/run-pass/intrinsics-integer.rs @@ -10,7 +10,7 @@ // ignore-emscripten no i128 support -#![feature(intrinsics, i128_type)] +#![feature(intrinsics)] mod rusti { extern "rust-intrinsic" { diff --git a/src/test/run-pass/issue-38763.rs b/src/test/run-pass/issue-38763.rs index 01cc8265a39..e038062ff9a 100644 --- a/src/test/run-pass/issue-38763.rs +++ b/src/test/run-pass/issue-38763.rs @@ -10,8 +10,6 @@ // ignore-emscripten -#![feature(i128_type)] - #[repr(C)] pub struct Foo(i128); diff --git a/src/test/run-pass/issue-38987.rs b/src/test/run-pass/issue-38987.rs index a513476d4a3..31a3b7233d8 100644 --- a/src/test/run-pass/issue-38987.rs +++ b/src/test/run-pass/issue-38987.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(i128_type)] fn main() { let _ = -0x8000_0000_0000_0000_0000_0000_0000_0000i128; diff --git a/src/test/run-pass/next-power-of-two-overflow-debug.rs b/src/test/run-pass/next-power-of-two-overflow-debug.rs index 599c6dfd31d..2135b3f8764 100644 --- a/src/test/run-pass/next-power-of-two-overflow-debug.rs +++ b/src/test/run-pass/next-power-of-two-overflow-debug.rs @@ -12,8 +12,6 @@ // ignore-wasm32-bare compiled with panic=abort by default // ignore-emscripten dies with an LLVM error -#![feature(i128_type)] - use std::panic; fn main() { diff --git a/src/test/run-pass/next-power-of-two-overflow-ndebug.rs b/src/test/run-pass/next-power-of-two-overflow-ndebug.rs index f2312b70be6..b05c1863d90 100644 --- a/src/test/run-pass/next-power-of-two-overflow-ndebug.rs +++ b/src/test/run-pass/next-power-of-two-overflow-ndebug.rs @@ -11,8 +11,6 @@ // compile-flags: -C debug_assertions=no // ignore-emscripten dies with an LLVM error -#![feature(i128_type)] - fn main() { for i in 129..256 { assert_eq!((i as u8).next_power_of_two(), 0); diff --git a/src/test/run-pass/saturating-float-casts.rs b/src/test/run-pass/saturating-float-casts.rs index c8fa49c62a0..d1a0901bb3d 100644 --- a/src/test/run-pass/saturating-float-casts.rs +++ b/src/test/run-pass/saturating-float-casts.rs @@ -11,7 +11,7 @@ // Tests saturating float->int casts. See u128-as-f32.rs for the opposite direction. // compile-flags: -Z saturating-float-casts -#![feature(test, i128, i128_type, stmt_expr_attributes)] +#![feature(test, i128, stmt_expr_attributes)] #![deny(overflowing_literals)] extern crate test; diff --git a/src/test/run-pass/u128-as-f32.rs b/src/test/run-pass/u128-as-f32.rs index 117e520155f..3531a961bef 100644 --- a/src/test/run-pass/u128-as-f32.rs +++ b/src/test/run-pass/u128-as-f32.rs @@ -10,7 +10,7 @@ // ignore-emscripten u128 not supported -#![feature(test, i128, i128_type)] +#![feature(test, i128)] #![deny(overflowing_literals)] extern crate test; diff --git a/src/test/run-pass/u128.rs b/src/test/run-pass/u128.rs index ebd43a86033..d649b3b74d3 100644 --- a/src/test/run-pass/u128.rs +++ b/src/test/run-pass/u128.rs @@ -12,7 +12,7 @@ // compile-flags: -Z borrowck=compare -#![feature(i128_type, test)] +#![feature(test)] extern crate test; use test::black_box as b; diff --git a/src/test/ui/feature-gate-i128_type.rs b/src/test/ui/feature-gate-i128_type.rs deleted file mode 100644 index ddb49a3e5d9..00000000000 --- a/src/test/ui/feature-gate-i128_type.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn test2() { - 0i128; //~ ERROR 128-bit integers are not stable -} - -fn test2_2() { - 0u128; //~ ERROR 128-bit integers are not stable -} - diff --git a/src/test/ui/feature-gate-i128_type.stderr b/src/test/ui/feature-gate-i128_type.stderr deleted file mode 100644 index eb3b29f4f55..00000000000 --- a/src/test/ui/feature-gate-i128_type.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0658]: 128-bit integers are not stable (see issue #35118) - --> $DIR/feature-gate-i128_type.rs:12:5 - | -LL | 0i128; //~ ERROR 128-bit integers are not stable - | ^^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error[E0658]: 128-bit integers are not stable (see issue #35118) - --> $DIR/feature-gate-i128_type.rs:16:5 - | -LL | 0u128; //~ ERROR 128-bit integers are not stable - | ^^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate-i128_type2.rs b/src/test/ui/feature-gate-i128_type2.rs index 8a7d316ed83..cd65b9d9223 100644 --- a/src/test/ui/feature-gate-i128_type2.rs +++ b/src/test/ui/feature-gate-i128_type2.rs @@ -10,20 +10,20 @@ // gate-test-i128_type -fn test1() -> i128 { //~ ERROR 128-bit type is unstable +fn test1() -> i128 { 0 } -fn test1_2() -> u128 { //~ ERROR 128-bit type is unstable +fn test1_2() -> u128 { 0 } fn test3() { - let x: i128 = 0; //~ ERROR 128-bit type is unstable + let x: i128 = 0; } fn test3_2() { - let x: u128 = 0; //~ ERROR 128-bit type is unstable + let x: u128 = 0; } #[repr(u128)] diff --git a/src/test/ui/feature-gate-i128_type2.stderr b/src/test/ui/feature-gate-i128_type2.stderr index 23d4d6c98d9..fe4557899ac 100644 --- a/src/test/ui/feature-gate-i128_type2.stderr +++ b/src/test/ui/feature-gate-i128_type2.stderr @@ -1,35 +1,3 @@ -error[E0658]: 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:13:15 - | -LL | fn test1() -> i128 { //~ ERROR 128-bit type is unstable - | ^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error[E0658]: 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:17:17 - | -LL | fn test1_2() -> u128 { //~ ERROR 128-bit type is unstable - | ^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error[E0658]: 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:22:12 - | -LL | let x: i128 = 0; //~ ERROR 128-bit type is unstable - | ^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error[E0658]: 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:26:12 - | -LL | let x: u128 = 0; //~ ERROR 128-bit type is unstable - | ^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - error[E0658]: repr with 128-bit type is unstable (see issue #35118) --> $DIR/feature-gate-i128_type2.rs:30:1 | diff --git a/src/test/ui/lint-ctypes.rs b/src/test/ui/lint-ctypes.rs index 77cb1ef0f51..85957831653 100644 --- a/src/test/ui/lint-ctypes.rs +++ b/src/test/ui/lint-ctypes.rs @@ -9,7 +9,7 @@ // except according to those terms. #![deny(improper_ctypes)] -#![feature(libc, i128_type, repr_transparent)] +#![feature(libc, repr_transparent)] extern crate libc; diff --git a/src/test/ui/lint/type-overflow.rs b/src/test/ui/lint/type-overflow.rs index 495989587e5..30e6fb2883b 100644 --- a/src/test/ui/lint/type-overflow.rs +++ b/src/test/ui/lint/type-overflow.rs @@ -10,8 +10,6 @@ // must-compile-successfully -#![feature(i128_type)] - fn main() { let error = 255i8; //~WARNING literal out of range for i8 -- cgit 1.4.1-3-g733a5 From db7d9ea480e16c7135c997f56b44d3c0a657cc9d Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Fri, 16 Mar 2018 20:15:56 -0500 Subject: Stabilize i128 feature too --- src/doc/unstable-book/src/language-features/i128-type.md | 2 +- src/libcore/num/i128.rs | 4 ++-- src/libcore/num/mod.rs | 11 ++--------- src/librustc/lib.rs | 3 +-- src/librustc_const_math/lib.rs | 3 +-- src/librustc_data_structures/lib.rs | 3 +-- src/librustc_trans/lib.rs | 3 +-- src/libstd/lib.rs | 7 +++---- src/libsyntax/diagnostic_list.rs | 12 ++++++++---- src/test/ui/error-codes/E0658.stderr | 2 +- 10 files changed, 21 insertions(+), 29 deletions(-) (limited to 'src/libcore') diff --git a/src/doc/unstable-book/src/language-features/i128-type.md b/src/doc/unstable-book/src/language-features/i128-type.md index 6f46469f324..ff5fc0fdc15 100644 --- a/src/doc/unstable-book/src/language-features/i128-type.md +++ b/src/doc/unstable-book/src/language-features/i128-type.md @@ -9,7 +9,7 @@ The tracking issue for this feature is: [#35118] The `i128` feature adds support for `#[repr(u128)]` on `enum`s. ```rust -#![feature(i128)] +#![feature(repri128)] #[repr(u128)] enum Foo { diff --git a/src/libcore/num/i128.rs b/src/libcore/num/i128.rs index 04354e2e33f..989376d1ac2 100644 --- a/src/libcore/num/i128.rs +++ b/src/libcore/num/i128.rs @@ -12,6 +12,6 @@ //! //! *[See also the `i128` primitive type](../../std/primitive.i128.html).* -#![unstable(feature = "i128", issue="35118")] +#![stable(feature = "i128", since = "1.26.0")] -int_module! { i128, #[unstable(feature = "i128", issue="35118")] } +int_module! { i128, #[stable(feature = "i128", since="1.26.0")] } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 9ff42a6d4ea..66f7160827a 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1635,10 +1635,7 @@ impl i64 { #[lang = "i128"] impl i128 { int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, - 170141183460469231731687303715884105727, "#![feature(i128)] -# fn main() { -", " -# }" } + 170141183460469231731687303715884105727, "", "" } } #[cfg(target_pointer_width = "16")] @@ -3492,11 +3489,7 @@ impl u64 { #[lang = "u128"] impl u128 { - uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "#![feature(i128)] - -# fn main() { -", " -# }" } + uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "", "" } } #[cfg(target_pointer_width = "16")] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 061044cdf14..e835d6192e5 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -52,8 +52,7 @@ #![feature(entry_or_default)] #![feature(from_ref)] #![feature(fs_read_write)] -#![feature(i128)] -#![cfg_attr(stage0, feature(i128_type))] +#![cfg_attr(stage0, feature(i128_type, i128))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![cfg_attr(windows, feature(libc))] #![feature(match_default_bindings)] diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index a53055c7ce7..7177e2818fb 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -19,8 +19,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] -#![feature(i128)] -#![cfg_attr(stage0, feature(i128_type))] +#![cfg_attr(stage0, feature(i128_type, i128))] extern crate rustc_apfloat; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 01f91e37db8..378a06dd912 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -26,9 +26,8 @@ #![feature(unboxed_closures)] #![feature(fn_traits)] #![feature(unsize)] -#![cfg_attr(stage0, feature(i128_type))] -#![feature(i128)] #![cfg_attr(stage0, feature(conservative_impl_trait))] +#![cfg_attr(stage0, feature(i128_type, i128))] #![feature(specialization)] #![feature(optin_builtin_traits)] #![feature(underscore_lifetimes)] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index d89d19db63e..bd33707b1c6 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -24,8 +24,7 @@ #![feature(custom_attribute)] #![feature(fs_read_write)] #![allow(unused_attributes)] -#![cfg_attr(stage0, feature(i128_type))] -#![feature(i128)] +#![cfg_attr(stage0, feature(i128_type, i128))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(libc)] #![feature(quote)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3cc5d7b81c3..93996868f16 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -269,8 +269,7 @@ #![feature(generic_param_attrs)] #![feature(hashmap_internals)] #![feature(heap_api)] -#![feature(i128)] -#![cfg_attr(stage0, feature(i128_type))] +#![cfg_attr(stage0, feature(i128_type, i128))] #![feature(int_error_internals)] #![feature(integer_atomics)] #![feature(into_cow)] @@ -435,7 +434,7 @@ pub use core::i16; pub use core::i32; #[stable(feature = "rust1", since = "1.0.0")] pub use core::i64; -#[unstable(feature = "i128", issue = "35118")] +#[stable(feature = "i128", since = "1.26.0")] pub use core::i128; #[stable(feature = "rust1", since = "1.0.0")] pub use core::usize; @@ -465,7 +464,7 @@ pub use alloc::string; pub use alloc::vec; #[stable(feature = "rust1", since = "1.0.0")] pub use std_unicode::char; -#[unstable(feature = "i128", issue = "35118")] +#[stable(feature = "i128", since = "1.26.0")] pub use core::u128; pub mod f32; diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 1f87c1b94c5..3246dc47701 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -250,7 +250,10 @@ An unstable feature was used. Erroneous code example: ```compile_fail,E658 -let x = ::std::u128::MAX; // error: use of unstable library feature 'i128' +#[repr(u128)] // error: use of unstable library feature 'i128' +enum Foo { + Bar(u64), +} ``` If you're using a stable or a beta version of rustc, you won't be able to use @@ -261,10 +264,11 @@ If you're using a nightly version of rustc, just add the corresponding feature to be able to use it: ``` -#![feature(i128)] +#![feature(repri128)] -fn main() { - let x = ::std::u128::MAX; // ok! +#[repr(u128)] // ok! +enum Foo { + Bar(u64), } ``` "##, diff --git a/src/test/ui/error-codes/E0658.stderr b/src/test/ui/error-codes/E0658.stderr index 5be05600ee5..f4294e6b026 100644 --- a/src/test/ui/error-codes/E0658.stderr +++ b/src/test/ui/error-codes/E0658.stderr @@ -4,7 +4,7 @@ error[E0658]: use of unstable library feature 'i128' (see issue #35118) LL | let _ = ::std::u128::MAX; //~ ERROR E0658 | ^^^^^^^^^^^^^^^^ | - = help: add #![feature(i128)] to the crate attributes to enable + = help: add #![feature(repri128)] to the crate attributes to enable error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 07104692d5df1401fe0109fca800e4efe4e81a6c Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sat, 17 Mar 2018 11:46:31 -0500 Subject: Fix missed i128 feature gates --- .../unstable-book/src/language-features/repr128.md | 2 +- src/libcore/num/mod.rs | 24 +++++++-------- src/libstd/primitive_docs.rs | 4 +-- src/libsyntax/diagnostic_list.rs | 4 +-- src/test/run-pass/saturating-float-casts.rs | 2 +- src/test/run-pass/u128-as-f32.rs | 2 +- src/test/ui/feature-gate-i128_type2.rs | 34 ---------------------- src/test/ui/feature-gate-i128_type2.stderr | 13 --------- 8 files changed, 19 insertions(+), 66 deletions(-) delete mode 100644 src/test/ui/feature-gate-i128_type2.rs delete mode 100644 src/test/ui/feature-gate-i128_type2.stderr (limited to 'src/libcore') diff --git a/src/doc/unstable-book/src/language-features/repr128.md b/src/doc/unstable-book/src/language-features/repr128.md index 3c86d581fa7..0858988952c 100644 --- a/src/doc/unstable-book/src/language-features/repr128.md +++ b/src/doc/unstable-book/src/language-features/repr128.md @@ -1,4 +1,4 @@ -# `repri128` +# `repr128` The tracking issue for this feature is: [#35118] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 66f7160827a..55186b0a3ac 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4046,39 +4046,39 @@ macro_rules! impl_from { impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u8, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, u128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u8, u128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { u8, usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u16, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u16, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, u128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u16, u128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { u32, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u32, u128, #[unstable(feature = "i128", issue = "35118")] } -impl_from! { u64, u128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u32, u128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u64, u128, #[stable(feature = "i128", since = "1.26.0")] } // Signed -> Signed impl_from! { i8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { i8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { i8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i8, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { i8, i128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { i8, isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { i16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { i16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i16, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { i16, i128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { i32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i32, i128, #[unstable(feature = "i128", issue = "35118")] } -impl_from! { i64, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { i32, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { i64, i128, #[stable(feature = "i128", since = "1.26.0")] } // Unsigned -> Signed impl_from! { u8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u8, i128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { u16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u16, i128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { u32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u32, i128, #[unstable(feature = "i128", issue = "35118")] } -impl_from! { u64, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u32, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u64, i128, #[stable(feature = "i128", since = "1.26.0")] } // Note: integers can only be represented with full precision in a float if // they fit in the significand, which is 24 bits in f32 and 53 bits in f64. diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index e6e6be2e453..ce4bbfffc2e 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -751,7 +751,7 @@ mod prim_i64 { } /// The 128-bit signed integer type. /// /// *[See also the `std::i128` module](i128/index.html).* -#[unstable(feature = "i128", issue="35118")] +#[stable(feature = "i128", since="1.26.0")] mod prim_i128 { } #[doc(primitive = "u8")] @@ -791,7 +791,7 @@ mod prim_u64 { } /// The 128-bit unsigned integer type. /// /// *[See also the `std::u128` module](u128/index.html).* -#[unstable(feature = "i128", issue="35118")] +#[stable(feature = "i128", since="1.26.0")] mod prim_u128 { } #[doc(primitive = "isize")] diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 3246dc47701..bb7988e64bc 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -250,7 +250,7 @@ An unstable feature was used. Erroneous code example: ```compile_fail,E658 -#[repr(u128)] // error: use of unstable library feature 'i128' +#[repr(u128)] // error: use of unstable library feature 'repr128' enum Foo { Bar(u64), } @@ -264,7 +264,7 @@ If you're using a nightly version of rustc, just add the corresponding feature to be able to use it: ``` -#![feature(repri128)] +#![feature(repr128)] #[repr(u128)] // ok! enum Foo { diff --git a/src/test/run-pass/saturating-float-casts.rs b/src/test/run-pass/saturating-float-casts.rs index d1a0901bb3d..ad3b4b17259 100644 --- a/src/test/run-pass/saturating-float-casts.rs +++ b/src/test/run-pass/saturating-float-casts.rs @@ -11,7 +11,7 @@ // Tests saturating float->int casts. See u128-as-f32.rs for the opposite direction. // compile-flags: -Z saturating-float-casts -#![feature(test, i128, stmt_expr_attributes)] +#![feature(test, stmt_expr_attributes)] #![deny(overflowing_literals)] extern crate test; diff --git a/src/test/run-pass/u128-as-f32.rs b/src/test/run-pass/u128-as-f32.rs index 3531a961bef..2848fb2d51a 100644 --- a/src/test/run-pass/u128-as-f32.rs +++ b/src/test/run-pass/u128-as-f32.rs @@ -10,7 +10,7 @@ // ignore-emscripten u128 not supported -#![feature(test, i128)] +#![feature(test)] #![deny(overflowing_literals)] extern crate test; diff --git a/src/test/ui/feature-gate-i128_type2.rs b/src/test/ui/feature-gate-i128_type2.rs deleted file mode 100644 index cd65b9d9223..00000000000 --- a/src/test/ui/feature-gate-i128_type2.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// gate-test-i128_type - -fn test1() -> i128 { - 0 -} - -fn test1_2() -> u128 { - 0 -} - -fn test3() { - let x: i128 = 0; -} - -fn test3_2() { - let x: u128 = 0; -} - -#[repr(u128)] -enum A { //~ ERROR 128-bit type is unstable - A(u64) -} - -fn main() {} diff --git a/src/test/ui/feature-gate-i128_type2.stderr b/src/test/ui/feature-gate-i128_type2.stderr deleted file mode 100644 index fe4557899ac..00000000000 --- a/src/test/ui/feature-gate-i128_type2.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: repr with 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:30:1 - | -LL | / enum A { //~ ERROR 128-bit type is unstable -LL | | A(u64) -LL | | } - | |_^ - | - = help: add #![feature(repr128)] to the crate attributes to enable - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0658`. -- cgit 1.4.1-3-g733a5 From a7f21f1c0a57984eb9a04b39223ae0c5b1cf63fb Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sat, 17 Mar 2018 11:55:44 -0500 Subject: Fix a few more --- src/libcore/num/u128.rs | 4 ++-- src/libstd/net/ip.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/u128.rs b/src/libcore/num/u128.rs index 987ac3e0007..e8c783a1bb5 100644 --- a/src/libcore/num/u128.rs +++ b/src/libcore/num/u128.rs @@ -12,5 +12,5 @@ //! //! *[See also the `u128` primitive type](../../std/primitive.u128.html).* -#![unstable(feature = "i128", issue="35118")] -uint_module! { u128, #[unstable(feature = "i128", issue="35118")] } +#![stable(feature = "i128", since = "1.26.0")] +uint_module! { u128, #[stable(feature = "i128", since="1.26.0")] } diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 0d73a6f4fd7..36376c07791 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -1346,7 +1346,7 @@ impl FromInner for Ipv6Addr { } } -#[unstable(feature = "i128", issue = "35118")] +#[stable(feature = "i128", since = "1.26.0")] impl From for u128 { fn from(ip: Ipv6Addr) -> u128 { let ip = ip.segments(); @@ -1355,7 +1355,7 @@ impl From for u128 { ((ip[6] as u128) << 16) + (ip[7] as u128) } } -#[unstable(feature = "i128", issue = "35118")] +#[stable(feature = "i128", since = "1.26.0")] impl From for Ipv6Addr { fn from(ip: u128) -> Ipv6Addr { Ipv6Addr::new( -- cgit 1.4.1-3-g733a5 From 463865e6957f8b698349460cb231f9d641300df0 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sat, 17 Mar 2018 20:10:18 -0500 Subject: Fix a few more unstables that I missed --- src/libcore/hash/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index ab714645675..3e1f21cafe4 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -308,7 +308,7 @@ pub trait Hasher { } /// Writes a single `u128` into this hasher. #[inline] - #[unstable(feature = "i128", issue = "35118")] + #[stable(feature = "i128", since = "1.26.0")] fn write_u128(&mut self, i: u128) { self.write(&unsafe { mem::transmute::<_, [u8; 16]>(i) }) } @@ -348,7 +348,7 @@ pub trait Hasher { } /// Writes a single `i128` into this hasher. #[inline] - #[unstable(feature = "i128", issue = "35118")] + #[stable(feature = "i128", since = "1.26.0")] fn write_i128(&mut self, i: i128) { self.write_u128(i as u128) } -- cgit 1.4.1-3-g733a5 From 140bf949bf65bb0479dbe31bd3474d5546ef59e1 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sat, 24 Mar 2018 18:19:33 -0500 Subject: fix last two tidy --- src/libcore/num/mod.rs | 8 +------- src/libstd/num.rs | 7 +------ 2 files changed, 2 insertions(+), 13 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 55186b0a3ac..a5ba0bcdf7e 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -97,14 +97,8 @@ nonzero_integers! { NonZeroU16(u16); NonZeroI16(i16); NonZeroU32(u32); NonZeroI32(i32); NonZeroU64(u64); NonZeroI64(i64); - NonZeroUsize(usize); NonZeroIsize(isize); -} - -nonzero_integers! { - // Change this to `#[unstable(feature = "i128", issue = "35118")]` - // if other NonZero* integer types are stabilizied before 128-bit integers - #[unstable(feature = "nonzero", issue = "49137")] NonZeroU128(u128); NonZeroI128(i128); + NonZeroUsize(usize); NonZeroIsize(isize); } /// Provides intentionally-wrapped arithmetic on `T`. diff --git a/src/libstd/num.rs b/src/libstd/num.rs index 6f537fd5c50..547b8c7c925 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -24,14 +24,9 @@ pub use core::num::Wrapping; #[unstable(feature = "nonzero", issue = "49137")] pub use core::num::{ NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, - NonZeroU64, NonZeroI64, NonZeroUsize, NonZeroIsize, + NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize, }; -// Change this to `#[unstable(feature = "i128", issue = "35118")]` -// if other NonZero* integer types are stabilizied before 128-bit integers -#[unstable(feature = "nonzero", issue = "49137")] -pub use core::num::{NonZeroU128, NonZeroI128}; - #[cfg(test)] use fmt; #[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem}; -- cgit 1.4.1-3-g733a5 From 9255bbd035ee032f1ccd47fcf93c87f7bc2e4bad Mon Sep 17 00:00:00 2001 From: Fabian Zaiser Date: Mon, 26 Mar 2018 20:15:19 +0200 Subject: Implement RFC #2169 (Euclidean division). Tracking issue: #49048 --- src/libcore/num/mod.rs | 436 +++++++++++++++++++++++++++++++++++++++++++++++++ src/libstd/f32.rs | 51 ++++++ src/libstd/f64.rs | 50 ++++++ 3 files changed, 537 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 18e0aa453d8..b4a43b216e8 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -633,6 +633,32 @@ $EndFeature, " } } + doc_comment! { + concat!("Checked Euclidean division. Computes `self.div_euc(rhs)`, returning `None` if `rhs == 0` +or the division results in overflow. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((", stringify!($SelfT), +"::min_value() + 1).checked_div_euc(-1), Some(", stringify!($Max), ")); +assert_eq!(", stringify!($SelfT), "::min_value().checked_div_euc(-1), None); +assert_eq!((1", stringify!($SelfT), ").checked_div_euc(0), None);", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn checked_div_euc(self, rhs: Self) -> Option { + if rhs == 0 || (self == Self::min_value() && rhs == -1) { + None + } else { + Some(self.div_euc(rhs)) + } + } + } + doc_comment! { concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if `rhs == 0` or the division results in overflow. @@ -660,6 +686,33 @@ $EndFeature, " } } + doc_comment! { + concat!("Checked Euclidean modulo. Computes `self.mod_euc(rhs)`, returning `None` if +`rhs == 0` or the division results in overflow. + +# Examples + +Basic usage: + +``` +", $Feature, "use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(0), None); +assert_eq!(", stringify!($SelfT), "::MIN.checked_mod_euc(-1), None);", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn checked_mod_euc(self, rhs: Self) -> Option { + if rhs == 0 || (self == Self::min_value() && rhs == -1) { + None + } else { + Some(self.mod_euc(rhs)) + } + } + } + doc_comment! { concat!("Checked negation. Computes `-self`, returning `None` if `self == MIN`. @@ -993,6 +1046,34 @@ $EndFeature, " } } + doc_comment! { + concat!("Wrapping Euclidean division. Computes `self.div_euc(rhs)`, wrapping around at the +boundary of the type. + +The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where +`MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value +that is too large to represent in the type. In such a case, this function returns `MIN` itself. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_div_euc(10), 10); +assert_eq!((-128i8).wrapping_div_euc(-1), -128);", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn wrapping_div_euc(self, rhs: Self) -> Self { + self.overflowing_div_euc(rhs).0 + } + } + doc_comment! { concat!("Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the boundary of the type. @@ -1021,6 +1102,34 @@ $EndFeature, " } } + doc_comment! { + concat!("Wrapping Euclidean modulo. Computes `self.mod_euc(rhs)`, wrapping around at the +boundary of the type. + +Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y` +invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case, +this function returns `0`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_mod_euc(10), 0); +assert_eq!((-128i8).wrapping_mod_euc(-1), 0);", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn wrapping_mod_euc(self, rhs: Self) -> Self { + self.overflowing_mod_euc(rhs).0 + } + } + doc_comment! { concat!("Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary of the type. @@ -1286,6 +1395,39 @@ $EndFeature, " } } + doc_comment! { + concat!("Calculates the quotient of Euclidean division `self.div_euc(rhs)`. + +Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would +occur. If an overflow would occur then self is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, "use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euc(-1), (", stringify!($SelfT), +"::MIN, true));", +$EndFeature, " +```"), + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn overflowing_div_euc(self, rhs: Self) -> (Self, bool) { + if self == Self::min_value() && rhs == -1 { + (self, true) + } else { + (self.div_euc(rhs), false) + } + } + } + doc_comment! { concat!("Calculates the remainder when `self` is divided by `rhs`. @@ -1318,6 +1460,40 @@ $EndFeature, " } } + + doc_comment! { + concat!("Calculates the modulo of Euclidean divsion `self.mod_euc(rhs)`. + +Returns a tuple of the remainder after dividing along with a boolean indicating whether an +arithmetic overflow would occur. If an overflow would occur then 0 is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, "use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_mod_euc(-1), (0, true));", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn overflowing_mod_euc(self, rhs: Self) -> (Self, bool) { + if self == Self::min_value() && rhs == -1 { + (0, true) + } else { + (self.mod_euc(rhs), false) + } + } + } + + doc_comment! { concat!("Negates self, overflowing if this is equal to the minimum value. @@ -1512,6 +1688,80 @@ $EndFeature, " } } + doc_comment! { + concat!("Calculates the quotient of Euclidean division of `self` by `rhs`. + +This computes the integer n such that `self = n * rhs + self.mod_euc(rhs)`. +In other words, the result is `self / rhs` rounded to the integer n +such that `self >= n * rhs`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, "let a: ", stringify!($SelfT), " = 7; // or any other integer type +let b = 4; + +assert_eq!(a.div_euc(b), 1); // 7 >= 4 * 1 +assert_eq!(a.div_euc(-b), -1); // 7 >= -4 * -1 +assert_eq!((-a).div_euc(b), -2); // -7 >= 4 * -2 +assert_eq!((-a).div_euc(-b), 2); // -7 >= -4 * 2", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + #[rustc_inherit_overflow_checks] + pub fn div_euc(self, rhs: Self) -> Self { + let q = self / rhs; + if self % rhs < 0 { + return if rhs > 0 { q - 1 } else { q + 1 } + } + q + } + } + + + doc_comment! { + concat!("Calculates the modulo `self mod rhs` by Euclidean division. + +In particular, the result `n` satisfies `0 <= n < rhs.abs()`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, "let a: ", stringify!($SelfT), " = 7; // or any other integer type +let b = 4; + +assert_eq!(a.mod_euc(b), 3); +assert_eq!((-a).mod_euc(b), 1); +assert_eq!(a.mod_euc(-b), 3); +assert_eq!((-a).mod_euc(-b), 1);", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + #[rustc_inherit_overflow_checks] + pub fn mod_euc(self, rhs: Self) -> Self { + let r = self % rhs; + if r < 0 { + r + rhs.abs() + } else { + r + } + } + } + doc_comment! { concat!("Computes the absolute value of `self`. @@ -2103,6 +2353,30 @@ assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, " } } + doc_comment! { + concat!("Checked Euclidean division. Computes `self.div_euc(rhs)`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64)); +assert_eq!(1", stringify!($SelfT), ".checked_div_euc(0), None); +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn checked_div_euc(self, rhs: Self) -> Option { + if rhs == 0 { + None + } else { + Some(self.div_euc(rhs)) + } + } + } + + doc_comment! { concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if `rhs == 0`. @@ -2126,6 +2400,30 @@ assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, " } } + doc_comment! { + concat!("Checked Euclidean modulo. Computes `self.mod_euc(rhs)`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(0), None);", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn checked_mod_euc(self, rhs: Self) -> Option { + if rhs == 0 { + None + } else { + Some(self.mod_euc(rhs)) + } + } + } + doc_comment! { concat!("Checked negation. Computes `-self`, returning `None` unless `self == 0`. @@ -2405,6 +2703,27 @@ Basic usage: } } + doc_comment! { + concat!("Wrapping Euclidean division. Computes `self.div_euc(rhs)`. +Wrapped division on unsigned types is just normal division. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div_euc(10), 10);", $EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn wrapping_div_euc(self, rhs: Self) -> Self { + self.div_euc(rhs) + } + } + doc_comment! { concat!("Wrapping (modular) remainder. Computes `self % rhs`. Wrapped remainder calculation on unsigned types is @@ -2427,6 +2746,28 @@ Basic usage: } } + doc_comment! { + concat!("Wrapping Euclidean modulo. Computes `self.mod_euc(rhs)`. +Wrapped modulo calculation on unsigned types is +just the regular remainder calculation. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_mod_euc(10), 0);", $EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn wrapping_mod_euc(self, rhs: Self) -> Self { + self % rhs + } + } + /// Wrapping (modular) negation. Computes `-self`, /// wrapping around at the boundary of the type. /// @@ -2660,6 +3001,32 @@ Basic usage } } + doc_comment! { + concat!("Calculates the quotient of Euclidean division `self.div_euc(rhs)`. + +Returns a tuple of the divisor along with a boolean indicating +whether an arithmetic overflow would occur. Note that for unsigned +integers overflow never occurs, so the second value is always +`false`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false));", $EndFeature, " +```"), + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn overflowing_div_euc(self, rhs: Self) -> (Self, bool) { + (self / rhs, false) + } + } + doc_comment! { concat!("Calculates the remainder when `self` is divided by `rhs`. @@ -2686,6 +3053,32 @@ Basic usage } } + doc_comment! { + concat!("Calculates the modulo of Euclidean division of `self.mod_euc(rhs)`. + +Returns a tuple of the modulo after dividing along with a boolean +indicating whether an arithmetic overflow would occur. Note that for +unsigned integers overflow never occurs, so the second value is +always `false`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false));", $EndFeature, " +```"), + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn overflowing_mod_euc(self, rhs: Self) -> (Self, bool) { + (self % rhs, false) + } + } + doc_comment! { concat!("Negates self in an overflowing fashion. @@ -2843,6 +3236,49 @@ Basic usage: } } + doc_comment! { + concat!("Performs Euclidean division. + +For unsigned types, this is just the same as `self / rhs`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq(7", stringify!($SelfT), ".div_euc(4), 1); // or any other integer type", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + #[rustc_inherit_overflow_checks] + pub fn div_euc(self, rhs: Self) -> Self { + self / rhs + } + } + + + doc_comment! { + concat!("Calculates the Euclidean modulo `self mod rhs`. + +For unsigned types, this is just the same as `self % rhs`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq(7", stringify!($SelfT), ".mod_euc(4), 3); // or any other integer type", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + #[rustc_inherit_overflow_checks] + pub fn mod_euc(self, rhs: Self) -> Self { + self % rhs + } + } + doc_comment! { concat!("Returns `true` if and only if `self == 2^k` for some `k`. diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index ceb019bc95b..ed63f445084 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -329,6 +329,57 @@ impl f32 { unsafe { intrinsics::fmaf32(self, a, b) } } + /// Calculates Euclidean division, the matching method for `mod_euc`. + /// + /// This computes the integer n such that + /// `self = n * rhs + self.mod_euc(rhs)`. + /// In other words, the result is `self / rhs` rounded to the integer n + /// such that `self >= n * rhs`. + /// + /// ``` + /// #![feature(euclidean_division)] + /// let a: f32 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.div_euc(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euc(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euc(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euc(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// ``` + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn div_euc(self, rhs: f32) -> f32 { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 } + } + q + } + + /// Calculates the Euclidean modulo (self mod rhs), which is never negative. + /// + /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`. + /// + /// ``` + /// #![feature(euclidean_division)] + /// let a: f32 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.mod_euc(b), 3.0); + /// assert_eq!((-a).mod_euc(b), 1.0); + /// assert_eq!(a.mod_euc(-b), 3.0); + /// assert_eq!((-a).mod_euc(-b), 1.0); + /// ``` + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn mod_euc(self, rhs: f32) -> f32 { + let r = self % rhs; + if r < 0.0 { + r + rhs.abs() + } else { + r + } + } + + /// Takes the reciprocal (inverse) of a number, `1/x`. /// /// ``` diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 97adf108b73..320655c443c 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -315,6 +315,56 @@ impl f64 { unsafe { intrinsics::fmaf64(self, a, b) } } + /// Calculates Euclidean division, the matching method for `mod_euc`. + /// + /// This computes the integer n such that + /// `self = n * rhs + self.mod_euc(rhs)`. + /// In other words, the result is `self / rhs` rounded to the integer n + /// such that `self >= n * rhs`. + /// + /// ``` + /// #![feature(euclidean_division)] + /// let a: f64 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.div_euc(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euc(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euc(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euc(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// ``` + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn div_euc(self, rhs: f64) -> f64 { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 } + } + q + } + + /// Calculates the Euclidean modulo (self mod rhs), which is never negative. + /// + /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`. + /// + /// ``` + /// #![feature(euclidean_division)] + /// let a: f64 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.mod_euc(b), 3.0); + /// assert_eq!((-a).mod_euc(b), 1.0); + /// assert_eq!(a.mod_euc(-b), 3.0); + /// assert_eq!((-a).mod_euc(-b), 1.0); + /// ``` + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn mod_euc(self, rhs: f64) -> f64 { + let r = self % rhs; + if r < 0.0 { + r + rhs.abs() + } else { + r + } + } + /// Takes the reciprocal (inverse) of a number, `1/x`. /// /// ``` -- cgit 1.4.1-3-g733a5 From 2178ef8b220daec3228f6f4dae60787e506fa089 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Mar 2018 13:36:08 +0100 Subject: TryFrom for integers: use From instead for truely-infallible impls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is precendent in C for having a minimum pointer size, but I don’t feel confident enough about the future to mandate a maximum. --- src/libcore/num/mod.rs | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index a5ba0bcdf7e..fa535e0e628 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3804,14 +3804,11 @@ mod ptr_try_from_impls { try_from_both_bounded!(isize, i8); try_from_unbounded!(isize, i16, i32, i64, i128); - rev!(try_from_unbounded, usize, u16); rev!(try_from_upper_bounded, usize, u32, u64, u128); rev!(try_from_lower_bounded, usize, i8, i16); rev!(try_from_both_bounded, usize, i32, i64, i128); - rev!(try_from_unbounded, isize, u8); rev!(try_from_upper_bounded, isize, u16, u32, u64, u128); - rev!(try_from_unbounded, isize, i16); rev!(try_from_both_bounded, isize, i32, i64, i128); } @@ -3830,14 +3827,14 @@ mod ptr_try_from_impls { try_from_both_bounded!(isize, i8, i16); try_from_unbounded!(isize, i32, i64, i128); - rev!(try_from_unbounded, usize, u16, u32); + rev!(try_from_unbounded, usize, u32); rev!(try_from_upper_bounded, usize, u64, u128); rev!(try_from_lower_bounded, usize, i8, i16, i32); rev!(try_from_both_bounded, usize, i64, i128); - rev!(try_from_unbounded, isize, u8, u16); + rev!(try_from_unbounded, isize, u16); rev!(try_from_upper_bounded, isize, u32, u64, u128); - rev!(try_from_unbounded, isize, i16, i32); + rev!(try_from_unbounded, isize, i32); rev!(try_from_both_bounded, isize, i64, i128); } @@ -3856,14 +3853,14 @@ mod ptr_try_from_impls { try_from_both_bounded!(isize, i8, i16, i32); try_from_unbounded!(isize, i64, i128); - rev!(try_from_unbounded, usize, u16, u32, u64); + rev!(try_from_unbounded, usize, u32, u64); rev!(try_from_upper_bounded, usize, u128); rev!(try_from_lower_bounded, usize, i8, i16, i32, i64); rev!(try_from_both_bounded, usize, i128); - rev!(try_from_unbounded, isize, u8, u16, u32); + rev!(try_from_unbounded, isize, u16, u32); rev!(try_from_upper_bounded, isize, u64, u128); - rev!(try_from_unbounded, isize, i16, i32, i64); + rev!(try_from_unbounded, isize, i32, i64); rev!(try_from_both_bounded, isize, i128); } @@ -4074,6 +4071,20 @@ impl_from! { u32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] impl_from! { u32, i128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { u64, i128, #[stable(feature = "i128", since = "1.26.0")] } +// The C99 standard defines bounds on INTPTR_MIN, INTPTR_MAX, and UINTPTR_MAX +// which imply that pointer-sized integers must be at least 16 bits: +// https://port70.net/~nsz/c/c99/n1256.html#7.18.2.4 +impl_from! { u16, usize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } +impl_from! { u8, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } +impl_from! { i16, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } + +// RISC-V defines the possibility of a 128-bit address space (RV128). + +// CHERI proposes 256-bit “capabilities”. Unclear if this would be relevant to usize/isize. +// https://www.cl.cam.ac.uk/research/security/ctsrd/pdfs/20171017a-cheri-poster.pdf +// http://www.csl.sri.com/users/neumann/2012resolve-cheri.pdf + + // Note: integers can only be represented with full precision in a float if // they fit in the significand, which is 24 bits in f32 and 53 bits in f64. // Lossy float conversions are not implemented at this time. -- cgit 1.4.1-3-g733a5 From 9fd399feb149bb7b58f21c54fc8c9358fea487a2 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Mar 2018 13:42:43 +0100 Subject: Don’t use `type Error = !` for target-dependant TryFrom impls. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead, expose apparently-fallible conversions in cases where the implementation happens to be infallible for a given target. Having an associated type / return type in a public API change based on the target is a portability hazard. --- src/libcore/num/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index fa535e0e628..2da5718a358 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3681,7 +3681,7 @@ macro_rules! try_from_unbounded { ($source:ty, $($target:ty),*) => {$( #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { - type Error = !; + type Error = TryFromIntError; #[inline] fn try_from(value: $source) -> Result { -- cgit 1.4.1-3-g733a5 From e53a2a72743810e05f58c61c9d8a4c89b712ad2e Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Mar 2018 13:52:54 +0100 Subject: Stabilize the TryFrom and TryInto traits Tracking issue: https://github.com/rust-lang/rust/issues/33417 --- src/libcore/array.rs | 6 +++--- src/libcore/char.rs | 6 +++--- src/libcore/convert.rs | 12 ++++++++---- src/libcore/num/mod.rs | 14 +++++++------- src/libcore/tests/lib.rs | 1 - src/librustc_apfloat/lib.rs | 2 +- src/libstd/error.rs | 6 +++--- src/libstd/lib.rs | 1 - src/libstd_unicode/char.rs | 2 +- src/libstd_unicode/lib.rs | 1 - src/test/ui/e0119/conflict-with-std.rs | 2 -- src/test/ui/e0119/conflict-with-std.stderr | 6 +++--- 12 files changed, 29 insertions(+), 30 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 3d24f8902bd..87144c27c9e 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -59,7 +59,7 @@ unsafe impl> FixedSizeArray for A { } /// The error type returned when a conversion from a slice to an array fails. -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] #[derive(Debug, Copy, Clone)] pub struct TryFromSliceError(()); @@ -148,7 +148,7 @@ macro_rules! array_impls { } } - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl<'a, T> TryFrom<&'a [T]> for &'a [T; $N] { type Error = TryFromSliceError; @@ -162,7 +162,7 @@ macro_rules! array_impls { } } - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl<'a, T> TryFrom<&'a mut [T]> for &'a mut [T; $N] { type Error = TryFromSliceError; diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 1638f9710f5..bbeebf52a73 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -265,7 +265,7 @@ impl FromStr for char { } -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl TryFrom for char { type Error = CharTryFromError; @@ -280,11 +280,11 @@ impl TryFrom for char { } /// The error type returned when a conversion from u32 to char fails. -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct CharTryFromError(()); -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl fmt::Display for CharTryFromError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { "converted integer out of range for `char`".fmt(f) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 7324df95bc5..63721395784 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -322,22 +322,26 @@ pub trait From: Sized { /// /// [`TryFrom`]: trait.TryFrom.html /// [`Into`]: trait.Into.html -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] pub trait TryInto: Sized { /// The type returned in the event of a conversion error. + #[stable(feature = "try_from", since = "1.26.0")] type Error; /// Performs the conversion. + #[stable(feature = "try_from", since = "1.26.0")] fn try_into(self) -> Result; } /// Attempt to construct `Self` via a conversion. -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] pub trait TryFrom: Sized { /// The type returned in the event of a conversion error. + #[stable(feature = "try_from", since = "1.26.0")] type Error; /// Performs the conversion. + #[stable(feature = "try_from", since = "1.26.0")] fn try_from(value: T) -> Result; } @@ -405,7 +409,7 @@ impl From for T { // TryFrom implies TryInto -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl TryInto for T where U: TryFrom { type Error = U::Error; @@ -417,7 +421,7 @@ impl TryInto for T where U: TryFrom // Infallible conversions are semantically equivalent to fallible conversions // with an uninhabited error type. -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl TryFrom for T where T: From { type Error = !; diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 2da5718a358..8f7e8d0c8ab 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3647,7 +3647,7 @@ macro_rules! from_str_radix_int_impl { from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } /// The error type returned when a checked integral type conversion fails. -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] #[derive(Debug, Copy, Clone)] pub struct TryFromIntError(()); @@ -3662,14 +3662,14 @@ impl TryFromIntError { } } -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl fmt::Display for TryFromIntError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { self.__description().fmt(fmt) } } -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl From for TryFromIntError { fn from(never: !) -> TryFromIntError { never @@ -3679,7 +3679,7 @@ impl From for TryFromIntError { // no possible bounds violation macro_rules! try_from_unbounded { ($source:ty, $($target:ty),*) => {$( - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -3694,7 +3694,7 @@ macro_rules! try_from_unbounded { // only negative bounds macro_rules! try_from_lower_bounded { ($source:ty, $($target:ty),*) => {$( - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -3713,7 +3713,7 @@ macro_rules! try_from_lower_bounded { // unsigned to signed (only positive bound) macro_rules! try_from_upper_bounded { ($source:ty, $($target:ty),*) => {$( - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -3732,7 +3732,7 @@ macro_rules! try_from_upper_bounded { // all other cases macro_rules! try_from_both_bounded { ($source:ty, $($target:ty),*) => {$( - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl TryFrom<$source> for $target { type Error = TryFromIntError; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 0b70f692403..1a68f04532d 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -43,7 +43,6 @@ #![feature(step_trait)] #![feature(test)] #![feature(trusted_len)] -#![feature(try_from)] #![feature(try_trait)] #![feature(exact_chunks)] #![feature(atomic_nand)] diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 2ee7bea8476..6f08fcf7025 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -48,7 +48,7 @@ #![cfg_attr(stage0, feature(slice_patterns))] #![cfg_attr(stage0, feature(i128_type))] -#![feature(try_from)] +#![cfg_attr(stage0, feature(try_from))] // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 79bb6af168f..3d0c96585b5 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -275,14 +275,14 @@ impl Error for num::ParseIntError { } } -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl Error for num::TryFromIntError { fn description(&self) -> &str { self.__description() } } -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl Error for array::TryFromSliceError { fn description(&self) -> &str { self.__description() @@ -356,7 +356,7 @@ impl Error for cell::BorrowMutError { } } -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl Error for char::CharTryFromError { fn description(&self) -> &str { "converted integer out of range for `char`" diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 93996868f16..15a22443b6a 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -310,7 +310,6 @@ #![feature(test, rustc_private)] #![feature(thread_local)] #![feature(toowned_clone_into)] -#![feature(try_from)] #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(unicode)] diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index de8b46d5f1b..33e47ade8cb 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -42,7 +42,7 @@ pub use core::char::{EscapeDebug, EscapeDefault, EscapeUnicode}; pub use core::char::ParseCharError; // unstable re-exports -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] pub use core::char::CharTryFromError; #[unstable(feature = "decode_utf8", issue = "33906")] pub use core::char::{DecodeUtf8, decode_utf8}; diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index f155b62e3cc..c22ea1671fa 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -39,7 +39,6 @@ #![feature(lang_items)] #![feature(non_exhaustive)] #![feature(staged_api)] -#![feature(try_from)] #![feature(unboxed_closures)] mod bool_trie; diff --git a/src/test/ui/e0119/conflict-with-std.rs b/src/test/ui/e0119/conflict-with-std.rs index ed9033ad53d..a9f747d09ec 100644 --- a/src/test/ui/e0119/conflict-with-std.rs +++ b/src/test/ui/e0119/conflict-with-std.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(try_from)] - use std::marker::PhantomData; use std::convert::{TryFrom, AsRef}; diff --git a/src/test/ui/e0119/conflict-with-std.stderr b/src/test/ui/e0119/conflict-with-std.stderr index e8b2c84c0df..417ff1de3f8 100644 --- a/src/test/ui/e0119/conflict-with-std.stderr +++ b/src/test/ui/e0119/conflict-with-std.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `std::convert::AsRef` for type `std::boxed::Box`: - --> $DIR/conflict-with-std.rs:17:1 + --> $DIR/conflict-with-std.rs:15:1 | LL | impl AsRef for Box { //~ ERROR conflicting implementations | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | impl AsRef for Box { //~ ERROR conflicting implementations where T: ?Sized; error[E0119]: conflicting implementations of trait `std::convert::From` for type `S`: - --> $DIR/conflict-with-std.rs:24:1 + --> $DIR/conflict-with-std.rs:22:1 | LL | impl From for S { //~ ERROR conflicting implementations | ^^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | impl From for S { //~ ERROR conflicting implementations - impl std::convert::From for T; error[E0119]: conflicting implementations of trait `std::convert::TryFrom` for type `X`: - --> $DIR/conflict-with-std.rs:31:1 + --> $DIR/conflict-with-std.rs:29:1 | LL | impl TryFrom for X { //~ ERROR conflicting implementations | ^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 09008cc23ff6395c2c928f3690e07d7389d08ebc Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 26 Mar 2018 11:17:31 +0200 Subject: Add TryFrom and TryInto to the prelude --- src/libcore/prelude/v1.rs | 3 +++ src/libstd/prelude/v1.rs | 2 ++ 2 files changed, 5 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index d43496c387c..2c8e27abac9 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -39,6 +39,9 @@ pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use convert::{AsRef, AsMut, Into, From}; +#[stable(feature = "try_from", since = "1.26.0")] +#[doc(no_inline)] +pub use convert::{TryFrom, TryInto}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use default::Default; diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index feedd4e1abe..d5b7c68a3fa 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -35,6 +35,8 @@ #[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use convert::{AsRef, AsMut, Into, From}; +#[stable(feature = "try_from", since = "1.26.0")] +#[doc(no_inline)] pub use convert::{TryFrom, TryInto}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use default::Default; #[stable(feature = "rust1", since = "1.0.0")] -- cgit 1.4.1-3-g733a5 From 27164faaef69853e2c1adcc0ccd6e70780b6da0a Mon Sep 17 00:00:00 2001 From: Francis Gagné Date: Mon, 12 Feb 2018 01:17:32 -0500 Subject: Move some implementations of Clone and Copy to libcore Add implementations of `Clone` and `Copy` for some primitive types to libcore so that they show up in the documentation. The concerned types are the following: * All primitive signed and unsigned integer types (`usize`, `u8`, `u16`, `u32`, `u64`, `u128`, `isize`, `i8`, `i16`, `i32`, `i64`, `i128`); * All primitive floating point types (`f32`, `f64`) * `bool` * `char` * `!` * Raw pointers (`*const T` and `*mut T`) * Shared references (`&'a T`) These types already implemented `Clone` and `Copy`, but the implementation was provided by the compiler. The compiler no longer provides these implementations and instead tries to look them up as normal trait implementations. The goal of this change is to make the implementations appear in the generated documentation. For `Copy` specifically, the compiler would reject an attempt to write an `impl` for the primitive types listed above with error `E0206`; this error no longer occurs for these types, but it will still occur for the other types that used to raise that error. The trait implementations are guarded with `#[cfg(not(stage0))]` because they are invalid according to the stage0 compiler. When the stage0 compiler is updated to a revision that includes this change, the attribute will have to be removed, otherwise the stage0 build will fail because the types mentioned above no longer implement `Clone` or `Copy`. For type variants that are variadic, such as tuples and function pointers, and for array types, the `Clone` and `Copy` implementations are still provided by the compiler, because the language is not expressive enough yet to be able to write the appropriate implementations in Rust. The initial plan was to add `impl` blocks guarded by `#[cfg(dox)]` to make them apply only when generating documentation, without having to touch the compiler. However, rustdoc's usage of the compiler still rejected those `impl` blocks. This is a [breaking-change] for users of `#![no_core]`, because they will now have to supply their own implementations of `Clone` and `Copy` for the primitive types listed above. The easiest way to do that is to simply copy the implementations from `src/libcore/clone.rs` and `src/libcore/marker.rs`. Fixes #25893 --- src/libcore/clone.rs | 60 ++++++++++++++++++++++ src/libcore/marker.rs | 40 +++++++++++++++ src/librustc/traits/select.rs | 10 ++-- src/librustc/ty/util.rs | 7 +++ src/librustc_typeck/diagnostics.rs | 8 +-- .../atomic-lock-free/atomic_lock_free.rs | 2 + src/test/run-make-fulldeps/simd-ffi/simd.rs | 3 ++ src/test/ui/coherence-impls-copy.rs | 8 ++- src/test/ui/coherence-impls-copy.stderr | 60 ++++++++++++++++------ src/test/ui/error-codes/E0206.rs | 4 +- src/test/ui/error-codes/E0206.stderr | 4 +- 11 files changed, 176 insertions(+), 30 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index d25f498b99e..5c83dd79bd7 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -135,3 +135,63 @@ pub struct AssertParamIsClone { _field: ::marker::PhantomData reason = "deriving hack, should not be public", issue = "0")] pub struct AssertParamIsCopy { _field: ::marker::PhantomData } + +/// Implementations of `Clone` for primitive types. +/// +/// Implementations that cannot be described in Rust +/// are implemented in `SelectionContext::copy_clone_conditions()` in librustc. +#[cfg(not(stage0))] +mod impls { + + use super::Clone; + + macro_rules! impl_clone { + ($($t:ty)*) => { + $( + #[stable(feature = "rust1", since = "1.0.0")] + impl Clone for $t { + fn clone(&self) -> Self { + *self + } + } + )* + } + } + + impl_clone! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 + f32 f64 + bool char + } + + #[stable(feature = "never_type", since = "1.26.0")] + impl Clone for ! { + fn clone(&self) -> Self { + *self + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl Clone for *const T { + fn clone(&self) -> Self { + *self + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl Clone for *mut T { + fn clone(&self) -> Self { + *self + } + } + + // Shared references can be cloned, but mutable references *cannot*! + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, T: ?Sized> Clone for &'a T { + fn clone(&self) -> Self { + *self + } + } + +} diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 7d0174a178a..008cb15131d 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -593,3 +593,43 @@ unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} /// This trait is automatically implemented for almost every type. #[unstable(feature = "pin", issue = "49150")] pub unsafe auto trait Unpin {} + +/// Implementations of `Copy` for primitive types. +/// +/// Implementations that cannot be described in Rust +/// are implemented in `SelectionContext::copy_clone_conditions()` in librustc. +#[cfg(not(stage0))] +mod copy_impls { + + use super::Copy; + + macro_rules! impl_copy { + ($($t:ty)*) => { + $( + #[stable(feature = "rust1", since = "1.0.0")] + impl Copy for $t {} + )* + } + } + + impl_copy! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 + f32 f64 + bool char + } + + #[stable(feature = "never_type", since = "1.26.0")] + impl Copy for ! {} + + #[stable(feature = "rust1", since = "1.0.0")] + impl Copy for *const T {} + + #[stable(feature = "rust1", since = "1.0.0")] + impl Copy for *mut T {} + + // Shared references can be copied, but mutable references *cannot*! + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, T: ?Sized> Copy for &'a T {} + +} diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 11daa96134c..8a585d6ac14 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2061,11 +2061,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { match self_ty.sty { ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) | + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyError => { + Where(ty::Binder(Vec::new())) + } + ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | - ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | - ty::TyRawPtr(..) | ty::TyError | ty::TyNever | + ty::TyChar | ty::TyRawPtr(..) | ty::TyNever | ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => { - Where(ty::Binder(Vec::new())) + // Implementations provided in libcore + None } ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) | diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index afe977d10ba..22f851a908b 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -197,7 +197,14 @@ impl<'tcx> ty::ParamEnv<'tcx> { // FIXME: (@jroesch) float this code up tcx.infer_ctxt().enter(|infcx| { let (adt, substs) = match self_type.sty { + // These types used to have a builtin impl. + // Now libcore provides that impl. + ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | + ty::TyChar | ty::TyRawPtr(..) | ty::TyNever | + ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => return Ok(()), + ty::TyAdt(adt, substs) => (adt, substs), + _ => return Err(CopyImplementationError::NotAnAdt), }; diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 1f882676f61..691e0ffb6a5 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1918,16 +1918,16 @@ differs from the behavior for `&T`, which is always `Copy`). E0206: r##" You can only implement `Copy` for a struct or enum. Both of the following -examples will fail, because neither `i32` (primitive type) nor `&'static Bar` -(reference to `Bar`) is a struct or enum: +examples will fail, because neither `[u8; 256]` nor `&'static mut Bar` +(mutable reference to `Bar`) is a struct or enum: ```compile_fail,E0206 -type Foo = i32; +type Foo = [u8; 256]; impl Copy for Foo { } // error #[derive(Copy, Clone)] struct Bar; -impl Copy for &'static Bar { } // error +impl Copy for &'static mut Bar { } // error ``` "##, diff --git a/src/test/run-make-fulldeps/atomic-lock-free/atomic_lock_free.rs b/src/test/run-make-fulldeps/atomic-lock-free/atomic_lock_free.rs index b41e8e9226b..54f888b3796 100644 --- a/src/test/run-make-fulldeps/atomic-lock-free/atomic_lock_free.rs +++ b/src/test/run-make-fulldeps/atomic-lock-free/atomic_lock_free.rs @@ -23,6 +23,8 @@ trait Copy {} #[lang = "freeze"] trait Freeze {} +impl Copy for *mut T {} + #[cfg(target_has_atomic = "8")] pub unsafe fn atomic_u8(x: *mut u8) { atomic_xadd(x, 1); diff --git a/src/test/run-make-fulldeps/simd-ffi/simd.rs b/src/test/run-make-fulldeps/simd-ffi/simd.rs index 94b91c711cc..21411a35e3c 100644 --- a/src/test/run-make-fulldeps/simd-ffi/simd.rs +++ b/src/test/run-make-fulldeps/simd-ffi/simd.rs @@ -75,6 +75,9 @@ pub trait Sized { } #[lang = "copy"] pub trait Copy { } +impl Copy for f32 {} +impl Copy for i32 {} + pub mod marker { pub use Copy; } diff --git a/src/test/ui/coherence-impls-copy.rs b/src/test/ui/coherence-impls-copy.rs index 51f43d27c34..f48790d1f40 100644 --- a/src/test/ui/coherence-impls-copy.rs +++ b/src/test/ui/coherence-impls-copy.rs @@ -12,6 +12,10 @@ use std::marker::Copy; +impl Copy for i32 {} +//~^ ERROR conflicting implementations of trait `std::marker::Copy` for type `i32`: +//~| ERROR only traits defined in the current crate can be implemented for arbitrary types + enum TestE { A } @@ -35,14 +39,14 @@ impl Copy for (MyType, MyType) {} //~| ERROR only traits defined in the current crate can be implemented for arbitrary types impl Copy for &'static NotSync {} -//~^ ERROR the trait `Copy` may not be implemented for this type +//~^ ERROR conflicting implementations of trait `std::marker::Copy` for type `&NotSync`: impl Copy for [MyType] {} //~^ ERROR the trait `Copy` may not be implemented for this type //~| ERROR only traits defined in the current crate can be implemented for arbitrary types impl Copy for &'static [NotSync] {} -//~^ ERROR the trait `Copy` may not be implemented for this type +//~^ ERROR conflicting implementations of trait `std::marker::Copy` for type `&[NotSync]`: //~| ERROR only traits defined in the current crate can be implemented for arbitrary types fn main() { diff --git a/src/test/ui/coherence-impls-copy.stderr b/src/test/ui/coherence-impls-copy.stderr index 5f9b0c62df2..24e7e85b1a9 100644 --- a/src/test/ui/coherence-impls-copy.stderr +++ b/src/test/ui/coherence-impls-copy.stderr @@ -1,35 +1,61 @@ -error[E0206]: the trait `Copy` may not be implemented for this type - --> $DIR/coherence-impls-copy.rs:29:15 +error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `i32`: + --> $DIR/coherence-impls-copy.rs:15:1 | -LL | impl Copy for &'static mut MyType {} - | ^^^^^^^^^^^^^^^^^^^ type is not a structure or enumeration +LL | impl Copy for i32 {} + | ^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl std::marker::Copy for i32; + +error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&NotSync`: + --> $DIR/coherence-impls-copy.rs:41:1 + | +LL | impl Copy for &'static NotSync {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl<'a, T> std::marker::Copy for &'a T + where T: ?Sized; + +error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&[NotSync]`: + --> $DIR/coherence-impls-copy.rs:48:1 + | +LL | impl Copy for &'static [NotSync] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl<'a, T> std::marker::Copy for &'a T + where T: ?Sized; error[E0206]: the trait `Copy` may not be implemented for this type --> $DIR/coherence-impls-copy.rs:33:15 | -LL | impl Copy for (MyType, MyType) {} - | ^^^^^^^^^^^^^^^^ type is not a structure or enumeration +LL | impl Copy for &'static mut MyType {} + | ^^^^^^^^^^^^^^^^^^^ type is not a structure or enumeration error[E0206]: the trait `Copy` may not be implemented for this type --> $DIR/coherence-impls-copy.rs:37:15 | -LL | impl Copy for &'static NotSync {} +LL | impl Copy for (MyType, MyType) {} | ^^^^^^^^^^^^^^^^ type is not a structure or enumeration error[E0206]: the trait `Copy` may not be implemented for this type - --> $DIR/coherence-impls-copy.rs:40:15 + --> $DIR/coherence-impls-copy.rs:44:15 | LL | impl Copy for [MyType] {} | ^^^^^^^^ type is not a structure or enumeration -error[E0206]: the trait `Copy` may not be implemented for this type - --> $DIR/coherence-impls-copy.rs:44:15 +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/coherence-impls-copy.rs:15:1 | -LL | impl Copy for &'static [NotSync] {} - | ^^^^^^^^^^^^^^^^^^ type is not a structure or enumeration +LL | impl Copy for i32 {} + | ^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference any types defined in this crate + = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impls-copy.rs:33:1 + --> $DIR/coherence-impls-copy.rs:37:1 | LL | impl Copy for (MyType, MyType) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate @@ -38,7 +64,7 @@ LL | impl Copy for (MyType, MyType) {} = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impls-copy.rs:40:1 + --> $DIR/coherence-impls-copy.rs:44:1 | LL | impl Copy for [MyType] {} | ^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate @@ -47,7 +73,7 @@ LL | impl Copy for [MyType] {} = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impls-copy.rs:44:1 + --> $DIR/coherence-impls-copy.rs:48:1 | LL | impl Copy for &'static [NotSync] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate @@ -55,7 +81,7 @@ LL | impl Copy for &'static [NotSync] {} = note: the impl does not reference any types defined in this crate = note: define and implement a trait or new type instead -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors -Some errors occurred: E0117, E0206. +Some errors occurred: E0117, E0119, E0206. For more information about an error, try `rustc --explain E0117`. diff --git a/src/test/ui/error-codes/E0206.rs b/src/test/ui/error-codes/E0206.rs index da0370b301b..9b3d1b351dd 100644 --- a/src/test/ui/error-codes/E0206.rs +++ b/src/test/ui/error-codes/E0206.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -type Foo = i32; +type Foo = [u8; 256]; impl Copy for Foo { } //~^ ERROR the trait `Copy` may not be implemented for this type @@ -17,7 +17,7 @@ impl Copy for Foo { } #[derive(Copy, Clone)] struct Bar; -impl Copy for &'static Bar { } +impl Copy for &'static mut Bar { } //~^ ERROR the trait `Copy` may not be implemented for this type fn main() { diff --git a/src/test/ui/error-codes/E0206.stderr b/src/test/ui/error-codes/E0206.stderr index bbc0da2248f..f2c23b0767a 100644 --- a/src/test/ui/error-codes/E0206.stderr +++ b/src/test/ui/error-codes/E0206.stderr @@ -7,8 +7,8 @@ LL | impl Copy for Foo { } error[E0206]: the trait `Copy` may not be implemented for this type --> $DIR/E0206.rs:20:15 | -LL | impl Copy for &'static Bar { } - | ^^^^^^^^^^^^ type is not a structure or enumeration +LL | impl Copy for &'static mut Bar { } + | ^^^^^^^^^^^^^^^^ type is not a structure or enumeration error[E0117]: only traits defined in the current crate can be implemented for arbitrary types --> $DIR/E0206.rs:13:1 -- cgit 1.4.1-3-g733a5 From f48c043154aeed1af44e6be66b17122fafacda51 Mon Sep 17 00:00:00 2001 From: Francis Gagné Date: Mon, 12 Feb 2018 02:31:26 -0500 Subject: Document builtin implementations of Clone and Copy There are types that implement `Clone` and `Copy` but are not mentioned in the documentation, because the implementations are provided by the compiler. They are types of variants that cannot be fully covered by trait implementations in Rust code, because the language is not expressive enough. --- src/libcore/clone.rs | 22 +++++++++++++++++----- src/libcore/marker.rs | 21 ++++++++++++++++----- 2 files changed, 33 insertions(+), 10 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 5c83dd79bd7..b6a5948e645 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -63,11 +63,6 @@ /// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d /// implementation of [`clone`] calls [`clone`] on each field. /// -/// ## Closures -/// -/// Closure types automatically implement `Clone` if they capture no value from the environment -/// or if all such captured values implement `Clone` themselves. -/// /// ## How can I implement `Clone`? /// /// Types that are [`Copy`] should have a trivial implementation of `Clone`. More formally: @@ -92,6 +87,23 @@ /// fn clone(&self) -> Stats { *self } /// } /// ``` +/// +/// ## Additional implementors +/// +/// In addition to the [implementors listed below][impls], +/// the following types also implement `Clone`: +/// +/// * Function item types (i.e. the distinct types defined for each function) +/// * Function pointer types (e.g. `fn() -> i32`) +/// * Array types, for all sizes, if the item type also implements `Clone` (e.g. `[i32; 123456]`) +/// * Tuple types, if each component also implements `Clone` (e.g. `()`, `(i32, bool)`) +/// * Closure types, if they capture no value from the environment +/// or if all such captured values implement `Clone` themselves. +/// Note that variables captured by shared reference always implement `Clone` +/// (even if the referent doesn't), +/// while variables captured by mutable reference never implement `Clone`. +/// +/// [impls]: #implementors #[stable(feature = "rust1", since = "1.0.0")] #[lang = "clone"] pub trait Clone : Sized { diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 008cb15131d..885aabe0806 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -166,11 +166,6 @@ pub trait Unsize { /// are allowed to access `x` after the assignment. Under the hood, both a copy and a move /// can result in bits being copied in memory, although this is sometimes optimized away. /// -/// ## Closures -/// -/// Closure types automatically implement `Copy` if they capture no value from the environment -/// or if all such captured values implement `Copy` themselves. -/// /// ## How can I implement `Copy`? /// /// There are two ways to implement `Copy` on your type. The simplest is to use `derive`: @@ -265,6 +260,21 @@ pub trait Unsize { /// non-`Copy` in the future, it could be prudent to omit the `Copy` implementation now, to /// avoid a breaking API change. /// +/// ## Additional implementors +/// +/// In addition to the [implementors listed below][impls], +/// the following types also implement `Copy`: +/// +/// * Function item types (i.e. the distinct types defined for each function) +/// * Function pointer types (e.g. `fn() -> i32`) +/// * Array types, for all sizes, if the item type also implements `Copy` (e.g. `[i32; 123456]`) +/// * Tuple types, if each component also implements `Copy` (e.g. `()`, `(i32, bool)`) +/// * Closure types, if they capture no value from the environment +/// or if all such captured values implement `Copy` themselves. +/// Note that variables captured by shared reference always implement `Copy` +/// (even if the referent doesn't), +/// while variables captured by mutable reference never implement `Copy`. +/// /// [`Vec`]: ../../std/vec/struct.Vec.html /// [`String`]: ../../std/string/struct.String.html /// [`Drop`]: ../../std/ops/trait.Drop.html @@ -272,6 +282,7 @@ pub trait Unsize { /// [`Clone`]: ../clone/trait.Clone.html /// [`String`]: ../../std/string/struct.String.html /// [`i32`]: ../../std/primitive.i32.html +/// [impls]: #implementors #[stable(feature = "rust1", since = "1.0.0")] #[lang = "copy"] pub trait Copy : Clone { -- cgit 1.4.1-3-g733a5 From afa7f5bc8ac79503bb99a20a1dd19365318f504f Mon Sep 17 00:00:00 2001 From: Francis Gagné Date: Sat, 10 Mar 2018 17:43:44 -0500 Subject: Add #[inline] to Clone impls for primitive types --- src/libcore/clone.rs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index b6a5948e645..f8e8c69621a 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -162,6 +162,7 @@ mod impls { $( #[stable(feature = "rust1", since = "1.0.0")] impl Clone for $t { + #[inline] fn clone(&self) -> Self { *self } @@ -179,6 +180,7 @@ mod impls { #[stable(feature = "never_type", since = "1.26.0")] impl Clone for ! { + #[inline] fn clone(&self) -> Self { *self } @@ -186,6 +188,7 @@ mod impls { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for *const T { + #[inline] fn clone(&self) -> Self { *self } @@ -193,6 +196,7 @@ mod impls { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for *mut T { + #[inline] fn clone(&self) -> Self { *self } @@ -201,6 +205,7 @@ mod impls { // Shared references can be cloned, but mutable references *cannot*! #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized> Clone for &'a T { + #[inline] fn clone(&self) -> Self { *self } -- cgit 1.4.1-3-g733a5 From 837d6c70233715a0ae8e15c703d40e3046a2f36a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 26 Mar 2018 22:48:12 +0200 Subject: Remove TryFrom impls that might become conditionally-infallible with a portability lint https://github.com/rust-lang/rust/pull/49305#issuecomment-376293243 --- src/libcore/iter/range.rs | 74 ++++++++++++++++++++++++- src/libcore/num/mod.rs | 70 ++++-------------------- src/libcore/tests/num/mod.rs | 127 ------------------------------------------- src/libstd/io/cursor.rs | 20 ++++++- 4 files changed, 100 insertions(+), 191 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 8d1080bb876..72b48b56571 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -91,7 +91,7 @@ macro_rules! step_impl_unsigned { #[inline] #[allow(unreachable_patterns)] fn add_usize(&self, n: usize) -> Option { - match <$t>::try_from(n) { + match <$t>::private_try_from(n) { Ok(n_as_t) => self.checked_add(n_as_t), Err(_) => None, } @@ -123,7 +123,7 @@ macro_rules! step_impl_signed { #[inline] #[allow(unreachable_patterns)] fn add_usize(&self, n: usize) -> Option { - match <$unsigned>::try_from(n) { + match <$unsigned>::private_try_from(n) { Ok(n_as_unsigned) => { // Wrapping in unsigned space handles cases like // `-120_i8.add_usize(200) == Some(80_i8)`, @@ -461,3 +461,73 @@ impl DoubleEndedIterator for ops::RangeInclusive { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::RangeInclusive {} + +/// Compensate removal of some impls per +/// https://github.com/rust-lang/rust/pull/49305#issuecomment-376293243 +trait PrivateTryFromUsize: Sized { + fn private_try_from(n: usize) -> Result; +} + +impl PrivateTryFromUsize for T where T: TryFrom { + #[inline] + fn private_try_from(n: usize) -> Result { + T::try_from(n).map_err(|_| ()) + } +} + +// no possible bounds violation +macro_rules! try_from_unbounded { + ($($target:ty),*) => {$( + impl PrivateTryFromUsize for $target { + #[inline] + fn private_try_from(value: usize) -> Result { + Ok(value as $target) + } + } + )*} +} + +// unsigned to signed (only positive bound) +macro_rules! try_from_upper_bounded { + ($($target:ty),*) => {$( + impl PrivateTryFromUsize for $target { + #[inline] + fn private_try_from(u: usize) -> Result<$target, ()> { + if u > (<$target>::max_value() as usize) { + Err(()) + } else { + Ok(u as $target) + } + } + } + )*} +} + + +#[cfg(target_pointer_width = "16")] +mod ptr_try_from_impls { + use super::PrivateTryFromUsize; + + try_from_unbounded!(u16, u32, u64, u128); + try_from_unbounded!(i32, i64, i128); +} + +#[cfg(target_pointer_width = "32")] +mod ptr_try_from_impls { + use super::PrivateTryFromUsize; + + try_from_upper_bounded!(u16); + try_from_unbounded!(u32, u64, u128); + try_from_upper_bounded!(i32); + try_from_unbounded!(i64, i128); +} + +#[cfg(target_pointer_width = "64")] +mod ptr_try_from_impls { + use super::PrivateTryFromUsize; + + try_from_upper_bounded!(u16, u32); + try_from_unbounded!(u64, u128); + try_from_upper_bounded!(i32, i64); + try_from_unbounded!(i128); +} diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 8f7e8d0c8ab..ee041e1e4f1 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3676,21 +3676,6 @@ impl From for TryFromIntError { } } -// no possible bounds violation -macro_rules! try_from_unbounded { - ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.26.0")] - impl TryFrom<$source> for $target { - type Error = TryFromIntError; - - #[inline] - fn try_from(value: $source) -> Result { - Ok(value as $target) - } - } - )*} -} - // only negative bounds macro_rules! try_from_lower_bounded { ($source:ty, $($target:ty),*) => {$( @@ -3789,27 +3774,20 @@ try_from_both_bounded!(i128, u64, u32, u16, u8); try_from_upper_bounded!(usize, isize); try_from_lower_bounded!(isize, usize); +try_from_upper_bounded!(usize, u8); +try_from_upper_bounded!(usize, i8, i16); +try_from_both_bounded!(isize, u8); +try_from_both_bounded!(isize, i8); + #[cfg(target_pointer_width = "16")] mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - try_from_upper_bounded!(usize, u8); - try_from_unbounded!(usize, u16, u32, u64, u128); - try_from_upper_bounded!(usize, i8, i16); - try_from_unbounded!(usize, i32, i64, i128); - - try_from_both_bounded!(isize, u8); + // Fallible across platfoms, only implementation differs try_from_lower_bounded!(isize, u16, u32, u64, u128); - try_from_both_bounded!(isize, i8); - try_from_unbounded!(isize, i16, i32, i64, i128); - - rev!(try_from_upper_bounded, usize, u32, u64, u128); rev!(try_from_lower_bounded, usize, i8, i16); rev!(try_from_both_bounded, usize, i32, i64, i128); - - rev!(try_from_upper_bounded, isize, u16, u32, u64, u128); - rev!(try_from_both_bounded, isize, i32, i64, i128); } #[cfg(target_pointer_width = "32")] @@ -3817,25 +3795,11 @@ mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - try_from_upper_bounded!(usize, u8, u16); - try_from_unbounded!(usize, u32, u64, u128); - try_from_upper_bounded!(usize, i8, i16, i32); - try_from_unbounded!(usize, i64, i128); - - try_from_both_bounded!(isize, u8, u16); + // Fallible across platfoms, only implementation differs + try_from_both_bounded!(isize, u16); try_from_lower_bounded!(isize, u32, u64, u128); - try_from_both_bounded!(isize, i8, i16); - try_from_unbounded!(isize, i32, i64, i128); - - rev!(try_from_unbounded, usize, u32); - rev!(try_from_upper_bounded, usize, u64, u128); rev!(try_from_lower_bounded, usize, i8, i16, i32); rev!(try_from_both_bounded, usize, i64, i128); - - rev!(try_from_unbounded, isize, u16); - rev!(try_from_upper_bounded, isize, u32, u64, u128); - rev!(try_from_unbounded, isize, i32); - rev!(try_from_both_bounded, isize, i64, i128); } #[cfg(target_pointer_width = "64")] @@ -3843,25 +3807,11 @@ mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - try_from_upper_bounded!(usize, u8, u16, u32); - try_from_unbounded!(usize, u64, u128); - try_from_upper_bounded!(usize, i8, i16, i32, i64); - try_from_unbounded!(usize, i128); - - try_from_both_bounded!(isize, u8, u16, u32); + // Fallible across platfoms, only implementation differs + try_from_both_bounded!(isize, u16, u32); try_from_lower_bounded!(isize, u64, u128); - try_from_both_bounded!(isize, i8, i16, i32); - try_from_unbounded!(isize, i64, i128); - - rev!(try_from_unbounded, usize, u32, u64); - rev!(try_from_upper_bounded, usize, u128); rev!(try_from_lower_bounded, usize, i8, i16, i32, i64); rev!(try_from_both_bounded, usize, i128); - - rev!(try_from_unbounded, isize, u16, u32); - rev!(try_from_upper_bounded, isize, u64, u128); - rev!(try_from_unbounded, isize, i32, i64); - rev!(try_from_both_bounded, isize, i128); } #[doc(hidden)] diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index 587dcbe6d67..c7edb55b378 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -37,15 +37,6 @@ mod flt2dec; mod dec2flt; mod bignum; - -/// Adds the attribute to all items in the block. -macro_rules! cfg_block { - ($(#[$attr:meta]{$($it:item)*})*) => {$($( - #[$attr] - $it - )*)*} -} - /// Groups items that assume the pointer width is either 16/32/64, and has to be altered if /// support for larger/smaller pointer widths are added in the future. macro_rules! assume_usize_width { @@ -318,42 +309,6 @@ assume_usize_width! { test_impl_try_from_always_ok! { test_try_u16usize, u16, usize } test_impl_try_from_always_ok! { test_try_i16isize, i16, isize } - - test_impl_try_from_always_ok! { test_try_usizeu64, usize, u64 } - test_impl_try_from_always_ok! { test_try_usizeu128, usize, u128 } - test_impl_try_from_always_ok! { test_try_usizei128, usize, i128 } - - test_impl_try_from_always_ok! { test_try_isizei64, isize, i64 } - test_impl_try_from_always_ok! { test_try_isizei128, isize, i128 } - - cfg_block!( - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_always_ok! { test_try_usizeu16, usize, u16 } - test_impl_try_from_always_ok! { test_try_isizei16, isize, i16 } - test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } - test_impl_try_from_always_ok! { test_try_usizei32, usize, i32 } - test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } - test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } - } - - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } - test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } - test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } - test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } - test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } - test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } - } - - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } - test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } - test_impl_try_from_always_ok! { test_try_u32isize, u32, isize } - test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } - test_impl_try_from_always_ok! { test_try_u64usize, u64, usize } - test_impl_try_from_always_ok! { test_try_i64isize, i64, isize } - } - ); } /// Conversions where max of $source can be represented as $target, @@ -402,24 +357,6 @@ assume_usize_width! { test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu64, isize, u64 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu128, isize, u128 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeusize, isize, usize } - - cfg_block!( - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu16, isize, u16 } - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } - } - - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } - - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } - } - - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64usize, i64, usize } - } - ); } /// Conversions where max of $source can not be represented as $target, @@ -461,29 +398,9 @@ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i64, u128, i64 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i128, u128, i128 } assume_usize_width! { - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64isize, u64, isize } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128isize, u128, isize } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei8, usize, i8 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei16, usize, i16 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizeisize, usize, isize } - - cfg_block!( - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16isize, u16, isize } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } - } - - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } - } - - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei64, usize, i64 } - } - ); } /// Conversions where min/max of $source can not be represented as $target. @@ -543,34 +460,6 @@ test_impl_try_from_same_sign_err! { test_try_i128i64, i128, i64 } assume_usize_width! { test_impl_try_from_same_sign_err! { test_try_usizeu8, usize, u8 } - test_impl_try_from_same_sign_err! { test_try_u128usize, u128, usize } - test_impl_try_from_same_sign_err! { test_try_i128isize, i128, isize } - - cfg_block!( - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_same_sign_err! { test_try_u32usize, u32, usize } - test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } - - test_impl_try_from_same_sign_err! { test_try_i32isize, i32, isize } - test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } - } - - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } - test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } - - test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } - test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } - } - - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } - test_impl_try_from_same_sign_err! { test_try_usizeu32, usize, u32 } - - test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } - test_impl_try_from_same_sign_err! { test_try_isizei32, isize, i32 } - } - ); } /// Conversions where neither the min nor the max of $source can be represented by @@ -615,22 +504,6 @@ test_impl_try_from_signed_to_unsigned_err! { test_try_i128u64, i128, u64 } assume_usize_width! { test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu8, isize, u8 } test_impl_try_from_signed_to_unsigned_err! { test_try_i128usize, i128, usize } - - cfg_block! { - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_signed_to_unsigned_err! { test_try_i32usize, i32, usize } - test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } - } - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } - - test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } - } - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } - test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu32, isize, u32 } - } - } } macro_rules! test_float { diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 76bcb5fedc9..2673f3ccfa3 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -10,7 +10,6 @@ use io::prelude::*; -use core::convert::TryInto; use cmp; use io::{self, Initializer, SeekFrom, Error, ErrorKind}; @@ -260,9 +259,26 @@ fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result Result { + if n <= (::max_value() as u64) { + Ok(n as usize) + } else { + Err(()) + } +} + +#[cfg(any(target_pointer_width = "64"))] +fn try_into(n: u64) -> Result { + Ok(n as usize) +} + // Resizing write implementation fn vec_write(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> io::Result { - let pos: usize = (*pos_mut).try_into().map_err(|_| { + let pos: usize = try_into(*pos_mut).map_err(|_| { Error::new(ErrorKind::InvalidInput, "cursor position exceeds maximum possible vector length") })?; -- cgit 1.4.1-3-g733a5 From ece87c3f4e76fd996dbbbaf8202f2adecff06c1e Mon Sep 17 00:00:00 2001 From: Fabian Zaiser Date: Wed, 28 Mar 2018 01:41:40 +0200 Subject: Address nits and tidy errors. --- src/libcore/num/mod.rs | 28 +++++++++++++++------------- src/libstd/f32.rs | 4 ++-- src/libstd/f64.rs | 4 ++-- 3 files changed, 19 insertions(+), 17 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index b4a43b216e8..9e7e9357159 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -634,8 +634,8 @@ $EndFeature, " } doc_comment! { - concat!("Checked Euclidean division. Computes `self.div_euc(rhs)`, returning `None` if `rhs == 0` -or the division results in overflow. + concat!("Checked Euclidean division. Computes `self.div_euc(rhs)`, +returning `None` if `rhs == 0` or the division results in overflow. # Examples @@ -1047,8 +1047,8 @@ $EndFeature, " } doc_comment! { - concat!("Wrapping Euclidean division. Computes `self.div_euc(rhs)`, wrapping around at the -boundary of the type. + concat!("Wrapping Euclidean division. Computes `self.div_euc(rhs)`, +wrapping around at the boundary of the type. The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value @@ -1462,7 +1462,7 @@ $EndFeature, " doc_comment! { - concat!("Calculates the modulo of Euclidean divsion `self.mod_euc(rhs)`. + concat!("Calculates the remainder `self.mod_euc(rhs)` by Euclidean division. Returns a tuple of the remainder after dividing along with a boolean indicating whether an arithmetic overflow would occur. If an overflow would occur then 0 is returned. @@ -1691,8 +1691,8 @@ $EndFeature, " doc_comment! { concat!("Calculates the quotient of Euclidean division of `self` by `rhs`. -This computes the integer n such that `self = n * rhs + self.mod_euc(rhs)`. -In other words, the result is `self / rhs` rounded to the integer n +This computes the integer `n` such that `self = n * rhs + self.mod_euc(rhs)`. +In other words, the result is `self / rhs` rounded to the integer `n` such that `self >= n * rhs`. # Panics @@ -1727,7 +1727,7 @@ $EndFeature, " doc_comment! { - concat!("Calculates the modulo `self mod rhs` by Euclidean division. + concat!("Calculates the remainder `self mod rhs` by Euclidean division. In particular, the result `n` satisfies `0 <= n < rhs.abs()`. @@ -2720,7 +2720,7 @@ Basic usage: #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] pub fn wrapping_div_euc(self, rhs: Self) -> Self { - self.div_euc(rhs) + self / rhs } } @@ -3018,7 +3018,8 @@ This function will panic if `rhs` is 0. Basic usage ``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false));", $EndFeature, " +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false));", +$EndFeature, " ```"), #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] @@ -3054,7 +3055,7 @@ Basic usage } doc_comment! { - concat!("Calculates the modulo of Euclidean division of `self.mod_euc(rhs)`. + concat!("Calculates the remainder `self.mod_euc(rhs)` by Euclidean division. Returns a tuple of the modulo after dividing along with a boolean indicating whether an arithmetic overflow would occur. Note that for @@ -3070,7 +3071,8 @@ This function will panic if `rhs` is 0. Basic usage ``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false));", $EndFeature, " +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false));", +$EndFeature, " ```"), #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] @@ -3259,7 +3261,7 @@ $EndFeature, " doc_comment! { - concat!("Calculates the Euclidean modulo `self mod rhs`. + concat!("Calculates the remainder `self mod rhs` by Euclidean division. For unsigned types, this is just the same as `self % rhs`. diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index ed63f445084..ca39089a958 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -331,9 +331,9 @@ impl f32 { /// Calculates Euclidean division, the matching method for `mod_euc`. /// - /// This computes the integer n such that + /// This computes the integer `n` such that /// `self = n * rhs + self.mod_euc(rhs)`. - /// In other words, the result is `self / rhs` rounded to the integer n + /// In other words, the result is `self / rhs` rounded to the integer `n` /// such that `self >= n * rhs`. /// /// ``` diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 320655c443c..a9585670ad0 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -317,9 +317,9 @@ impl f64 { /// Calculates Euclidean division, the matching method for `mod_euc`. /// - /// This computes the integer n such that + /// This computes the integer `n` such that /// `self = n * rhs + self.mod_euc(rhs)`. - /// In other words, the result is `self / rhs` rounded to the integer n + /// In other words, the result is `self / rhs` rounded to the integer `n` /// such that `self >= n * rhs`. /// /// ``` -- cgit 1.4.1-3-g733a5 From 1f143bc46fe04aa564736b4741a8f179c46eccc5 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 28 Mar 2018 11:25:52 +0200 Subject: Explicitly mention `Option` in `?` error message. Save users the time/effort of having to lookup what types implement the `Try` trait. --- src/libcore/ops/try.rs | 2 +- src/test/ui/suggestions/try-on-option.stderr | 2 +- src/test/ui/suggestions/try-operator-on-main.stderr | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs index 81e5cb5c350..ef6a8fb6a61 100644 --- a/src/libcore/ops/try.rs +++ b/src/libcore/ops/try.rs @@ -20,7 +20,7 @@ any(from_method="from_error", from_method="from_ok"), from_desugaring="?"), message="the `?` operator can only be used in a \ - function that returns `Result` \ + function that returns `Result` or `Option` \ (or another type that implements `{Try}`)", label="cannot use the `?` operator in a function that returns `{Self}`"), on(all(from_method="into_result", from_desugaring="?"), diff --git a/src/test/ui/suggestions/try-on-option.stderr b/src/test/ui/suggestions/try-on-option.stderr index aee52808f1e..265ee593bb7 100644 --- a/src/test/ui/suggestions/try-on-option.stderr +++ b/src/test/ui/suggestions/try-on-option.stderr @@ -6,7 +6,7 @@ LL | x?; //~ the trait bound | = note: required by `std::convert::From::from` -error[E0277]: the `?` operator can only be used in a function that returns `Result` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> $DIR/try-on-option.rs:23:5 | LL | x?; //~ the `?` operator diff --git a/src/test/ui/suggestions/try-operator-on-main.stderr b/src/test/ui/suggestions/try-operator-on-main.stderr index 7536bbcd2db..121ae14f999 100644 --- a/src/test/ui/suggestions/try-operator-on-main.stderr +++ b/src/test/ui/suggestions/try-operator-on-main.stderr @@ -1,4 +1,4 @@ -error[E0277]: the `?` operator can only be used in a function that returns `Result` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> $DIR/try-operator-on-main.rs:19:5 | LL | std::fs::File::open("foo")?; //~ ERROR the `?` operator can only -- cgit 1.4.1-3-g733a5 From 1b5db85314a35416b617e8b7d0a3baa72922a2f3 Mon Sep 17 00:00:00 2001 From: Fabian Zaiser Date: Wed, 28 Mar 2018 16:22:37 +0200 Subject: Fix #![feature]s. --- src/libcore/num/mod.rs | 77 ++++++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 37 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 9e7e9357159..1346435a21a 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -642,11 +642,11 @@ returning `None` if `rhs == 0` or the division results in overflow. Basic usage: ``` -", $Feature, "assert_eq!((", stringify!($SelfT), +#![feature(euclidean_division)] +assert_eq!((", stringify!($SelfT), "::min_value() + 1).checked_div_euc(-1), Some(", stringify!($Max), ")); assert_eq!(", stringify!($SelfT), "::min_value().checked_div_euc(-1), None); -assert_eq!((1", stringify!($SelfT), ").checked_div_euc(0), None);", -$EndFeature, " +assert_eq!((1", stringify!($SelfT), ").checked_div_euc(0), None); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] @@ -695,12 +695,12 @@ $EndFeature, " Basic usage: ``` -", $Feature, "use std::", stringify!($SelfT), "; +#![feature(euclidean_division)] +use std::", stringify!($SelfT), "; assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(2), Some(1)); assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(0), None); -assert_eq!(", stringify!($SelfT), "::MIN.checked_mod_euc(-1), None);", -$EndFeature, " +assert_eq!(", stringify!($SelfT), "::MIN.checked_mod_euc(-1), None); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] @@ -1063,9 +1063,9 @@ This function will panic if `rhs` is 0. Basic usage: ``` +#![feature(euclidean_division)] assert_eq!(100", stringify!($SelfT), ".wrapping_div_euc(10), 10); -assert_eq!((-128i8).wrapping_div_euc(-1), -128);", -$EndFeature, " +assert_eq!((-128i8).wrapping_div_euc(-1), -128); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] @@ -1119,9 +1119,9 @@ This function will panic if `rhs` is 0. Basic usage: ``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_mod_euc(10), 0); -assert_eq!((-128i8).wrapping_mod_euc(-1), 0);", -$EndFeature, " +#![feature(euclidean_division)] +assert_eq!(100", stringify!($SelfT), ".wrapping_mod_euc(10), 0); +assert_eq!((-128i8).wrapping_mod_euc(-1), 0); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] @@ -1410,12 +1410,12 @@ This function will panic if `rhs` is 0. Basic usage: ``` -", $Feature, "use std::", stringify!($SelfT), "; +#![feature(euclidean_division)] +use std::", stringify!($SelfT), "; assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false)); assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euc(-1), (", stringify!($SelfT), -"::MIN, true));", -$EndFeature, " +"::MIN, true)); ```"), #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] @@ -1476,11 +1476,11 @@ This function will panic if `rhs` is 0. Basic usage: ``` -", $Feature, "use std::", stringify!($SelfT), "; +#![feature(euclidean_division)] +use std::", stringify!($SelfT), "; assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_mod_euc(-1), (0, true));", -$EndFeature, " +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_mod_euc(-1), (0, true)); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] @@ -1704,14 +1704,14 @@ This function will panic if `rhs` is 0. Basic usage: ``` -", $Feature, "let a: ", stringify!($SelfT), " = 7; // or any other integer type +#![feature(euclidean_division)] +let a: ", stringify!($SelfT), " = 7; // or any other integer type let b = 4; assert_eq!(a.div_euc(b), 1); // 7 >= 4 * 1 assert_eq!(a.div_euc(-b), -1); // 7 >= -4 * -1 assert_eq!((-a).div_euc(b), -2); // -7 >= 4 * -2 -assert_eq!((-a).div_euc(-b), 2); // -7 >= -4 * 2", -$EndFeature, " +assert_eq!((-a).div_euc(-b), 2); // -7 >= -4 * 2 ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] @@ -1740,14 +1740,14 @@ This function will panic if `rhs` is 0. Basic usage: ``` -", $Feature, "let a: ", stringify!($SelfT), " = 7; // or any other integer type +#![feature(euclidean_division)] +let a: ", stringify!($SelfT), " = 7; // or any other integer type let b = 4; assert_eq!(a.mod_euc(b), 3); assert_eq!((-a).mod_euc(b), 1); assert_eq!(a.mod_euc(-b), 3); -assert_eq!((-a).mod_euc(-b), 1);", -$EndFeature, " +assert_eq!((-a).mod_euc(-b), 1); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] @@ -2362,7 +2362,8 @@ if `rhs == 0`. Basic usage: ``` -", $Feature, "assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64)); +#![feature(euclidean_division)] +assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64)); assert_eq!(1", stringify!($SelfT), ".checked_div_euc(0), None); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] @@ -2409,9 +2410,9 @@ if `rhs == 0`. Basic usage: ``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(2), Some(1)); -assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(0), None);", -$EndFeature, " +#![feature(euclidean_division)] +assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(0), None); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] @@ -2715,7 +2716,8 @@ are accounted for in the wrapping operations. Basic usage: ``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div_euc(10), 10);", $EndFeature, " +#![feature(euclidean_division)] +assert_eq!(100", stringify!($SelfT), ".wrapping_div_euc(10), 10); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] @@ -2759,7 +2761,8 @@ are accounted for in the wrapping operations. Basic usage: ``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_mod_euc(10), 0);", $EndFeature, " +#![feature(euclidean_division)] +assert_eq!(100", stringify!($SelfT), ".wrapping_mod_euc(10), 0); ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] @@ -3018,8 +3021,8 @@ This function will panic if `rhs` is 0. Basic usage ``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false));", -$EndFeature, " +#![feature(euclidean_division)] +assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false)); ```"), #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] @@ -3071,8 +3074,8 @@ This function will panic if `rhs` is 0. Basic usage ``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false));", -$EndFeature, " +#![feature(euclidean_division)] +assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false)); ```"), #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] @@ -3248,8 +3251,8 @@ For unsigned types, this is just the same as `self / rhs`. Basic usage: ``` -", $Feature, "assert_eq(7", stringify!($SelfT), ".div_euc(4), 1); // or any other integer type", -$EndFeature, " +#![feature(euclidean_division)] +assert_eq(7", stringify!($SelfT), ".div_euc(4), 1); // or any other integer type ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] @@ -3270,8 +3273,8 @@ For unsigned types, this is just the same as `self % rhs`. Basic usage: ``` -", $Feature, "assert_eq(7", stringify!($SelfT), ".mod_euc(4), 3); // or any other integer type", -$EndFeature, " +#![feature(euclidean_division)] +assert_eq(7", stringify!($SelfT), ".mod_euc(4), 3); // or any other integer type ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] -- cgit 1.4.1-3-g733a5 From c0870e2f55b8b160c8ad7af684831902b4979cfb Mon Sep 17 00:00:00 2001 From: Fabian Zaiser Date: Thu, 29 Mar 2018 01:10:37 +0200 Subject: Fix doctest (typo). --- src/libcore/num/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 1346435a21a..89276fcee80 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3252,7 +3252,7 @@ Basic usage: ``` #![feature(euclidean_division)] -assert_eq(7", stringify!($SelfT), ".div_euc(4), 1); // or any other integer type +assert_eq!(7", stringify!($SelfT), ".div_euc(4), 1); // or any other integer type ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] @@ -3274,7 +3274,7 @@ Basic usage: ``` #![feature(euclidean_division)] -assert_eq(7", stringify!($SelfT), ".mod_euc(4), 3); // or any other integer type +assert_eq!(7", stringify!($SelfT), ".mod_euc(4), 3); // or any other integer type ```"), #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] -- cgit 1.4.1-3-g733a5 From 39fe29bf0ca4d105a6118b4a1ca5ce17a59b71b1 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 29 Mar 2018 09:43:26 +0200 Subject: src/libcore/ptr.rs: Fix documentation for size of `Option>` Seems more useful to say that it has the same size as `*mut T`. --- src/libcore/ptr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index aebd50d9c6b..5a54de06b5e 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2653,7 +2653,7 @@ impl<'a, T: ?Sized> From> for Unique { /// /// Unlike `*mut T`, the pointer must always be non-null, even if the pointer /// is never dereferenced. This is so that enums may use this forbidden value -/// as a discriminant -- `Option>` has the same size as `NonNull`. +/// as a discriminant -- `Option>` has the same size as `*mut T`. /// However the pointer may still dangle if it isn't dereferenced. /// /// Unlike `*mut T`, `NonNull` is covariant over `T`. If this is incorrect -- cgit 1.4.1-3-g733a5 From c3a63970dee2422e2fcc79d8b99303b4b046f444 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 19 Mar 2018 09:01:17 +0100 Subject: Move alloc::Bound to {core,std}::ops The stable reexport `std::collections::Bound` is now deprecated. Another deprecated reexport could be added in `alloc`, but that crate is unstable. --- src/liballoc/btree/map.rs | 4 +- src/liballoc/btree/set.rs | 2 +- src/liballoc/lib.rs | 51 ---------------------- src/liballoc/range.rs | 2 +- src/liballoc/string.rs | 2 +- src/liballoc/tests/btree/map.rs | 2 +- src/liballoc/vec.rs | 2 +- src/liballoc/vec_deque.rs | 2 +- src/libcore/ops/mod.rs | 2 +- src/libcore/ops/range.rs | 51 ++++++++++++++++++++++ src/librustc_data_structures/array_vec.rs | 2 +- src/libstd/collections/mod.rs | 3 +- .../sync-send-iterators-in-libcollections.rs | 2 +- 13 files changed, 64 insertions(+), 63 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index cada190032a..2ba56063e36 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -13,11 +13,11 @@ use core::fmt::Debug; use core::hash::{Hash, Hasher}; use core::iter::{FromIterator, Peekable, FusedIterator}; use core::marker::PhantomData; +use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::Index; use core::{fmt, intrinsics, mem, ptr}; use borrow::Borrow; -use Bound::{Excluded, Included, Unbounded}; use range::RangeArgument; use super::node::{self, Handle, NodeRef, marker}; @@ -804,7 +804,7 @@ impl BTreeMap { /// /// ``` /// use std::collections::BTreeMap; - /// use std::collections::Bound::Included; + /// use std::ops::Bound::Included; /// /// let mut map = BTreeMap::new(); /// map.insert(3, "a"); diff --git a/src/liballoc/btree/set.rs b/src/liballoc/btree/set.rs index 2e3157147a0..d488dd6cbbd 100644 --- a/src/liballoc/btree/set.rs +++ b/src/liballoc/btree/set.rs @@ -240,7 +240,7 @@ impl BTreeSet { /// /// ``` /// use std::collections::BTreeSet; - /// use std::collections::Bound::Included; + /// use std::ops::Bound::Included; /// /// let mut set = BTreeSet::new(); /// set.insert(3); diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 19d64d8fea9..eddbd50ea03 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -204,57 +204,6 @@ mod std { pub use core::ops; // RangeFull } -/// An endpoint of a range of keys. -/// -/// # Examples -/// -/// `Bound`s are range endpoints: -/// -/// ``` -/// #![feature(collections_range)] -/// -/// use std::collections::range::RangeArgument; -/// use std::collections::Bound::*; -/// -/// assert_eq!((..100).start(), Unbounded); -/// assert_eq!((1..12).start(), Included(&1)); -/// assert_eq!((1..12).end(), Excluded(&12)); -/// ``` -/// -/// Using a tuple of `Bound`s as an argument to [`BTreeMap::range`]. -/// Note that in most cases, it's better to use range syntax (`1..5`) instead. -/// -/// ``` -/// use std::collections::BTreeMap; -/// use std::collections::Bound::{Excluded, Included, Unbounded}; -/// -/// let mut map = BTreeMap::new(); -/// map.insert(3, "a"); -/// map.insert(5, "b"); -/// map.insert(8, "c"); -/// -/// for (key, value) in map.range((Excluded(3), Included(8))) { -/// println!("{}: {}", key, value); -/// } -/// -/// assert_eq!(Some((&3, &"a")), map.range((Unbounded, Included(5))).next()); -/// ``` -/// -/// [`BTreeMap::range`]: btree_map/struct.BTreeMap.html#method.range -#[stable(feature = "collections_bound", since = "1.17.0")] -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] -pub enum Bound { - /// An inclusive bound. - #[stable(feature = "collections_bound", since = "1.17.0")] - Included(#[stable(feature = "collections_bound", since = "1.17.0")] T), - /// An exclusive bound. - #[stable(feature = "collections_bound", since = "1.17.0")] - Excluded(#[stable(feature = "collections_bound", since = "1.17.0")] T), - /// An infinite endpoint. Indicates that there is no bound in this direction. - #[stable(feature = "collections_bound", since = "1.17.0")] - Unbounded, -} - /// An intermediate trait for specialization of `Extend`. #[doc(hidden)] trait SpecExtend { diff --git a/src/liballoc/range.rs b/src/liballoc/range.rs index b03abc85180..7cadbf3c90a 100644 --- a/src/liballoc/range.rs +++ b/src/liballoc/range.rs @@ -15,7 +15,7 @@ //! Range syntax. use core::ops::{RangeFull, Range, RangeTo, RangeFrom, RangeInclusive, RangeToInclusive}; -use Bound::{self, Excluded, Included, Unbounded}; +use core::ops::Bound::{self, Excluded, Included, Unbounded}; /// `RangeArgument` is implemented by Rust's built-in range types, produced /// by range syntax like `..`, `a..`, `..b` or `c..d`. diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 23c12bef3aa..754c78f7779 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -59,6 +59,7 @@ use core::fmt; use core::hash; use core::iter::{FromIterator, FusedIterator}; +use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Add, AddAssign, Index, IndexMut}; use core::ptr; use core::str::pattern::Pattern; @@ -67,7 +68,6 @@ use std_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; use borrow::{Cow, ToOwned}; use range::RangeArgument; -use Bound::{Excluded, Included, Unbounded}; use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; use vec::Vec; use boxed::Box; diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index 2393101040d..6ebdb86cc4a 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -9,8 +9,8 @@ // except according to those terms. use std::collections::BTreeMap; -use std::collections::Bound::{self, Excluded, Included, Unbounded}; use std::collections::btree_map::Entry::{Occupied, Vacant}; +use std::ops::Bound::{self, Excluded, Included, Unbounded}; use std::rc::Rc; use std::iter::FromIterator; diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index bcc999d7386..280570ecd65 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -75,6 +75,7 @@ use core::marker::PhantomData; use core::mem; #[cfg(not(test))] use core::num::Float; +use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{InPlace, Index, IndexMut, Place, Placer}; use core::ops; use core::ptr; @@ -87,7 +88,6 @@ use boxed::Box; use raw_vec::RawVec; use super::range::RangeArgument; use super::allocator::CollectionAllocErr; -use Bound::{Excluded, Included, Unbounded}; /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index be6e8d0f22f..9efd730790d 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -21,6 +21,7 @@ use core::cmp::Ordering; use core::fmt; use core::iter::{repeat, FromIterator, FusedIterator}; use core::mem; +use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{Index, IndexMut, Place, Placer, InPlace}; use core::ptr; use core::ptr::NonNull; @@ -33,7 +34,6 @@ use raw_vec::RawVec; use super::allocator::CollectionAllocErr; use super::range::RangeArgument; -use Bound::{Excluded, Included, Unbounded}; use super::vec::Vec; const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index 234970a81fa..b0e75135282 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -192,7 +192,7 @@ pub use self::index::{Index, IndexMut}; pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; #[stable(feature = "inclusive_range", since = "1.26.0")] -pub use self::range::{RangeInclusive, RangeToInclusive}; +pub use self::range::{RangeInclusive, RangeToInclusive, Bound}; #[unstable(feature = "try_trait", issue = "42327")] pub use self::try::Try; diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index be51f5239b0..dd44aedd09f 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -442,3 +442,54 @@ impl> RangeToInclusive { // RangeToInclusive cannot impl From> // because underflow would be possible with (..0).into() + +/// An endpoint of a range of keys. +/// +/// # Examples +/// +/// `Bound`s are range endpoints: +/// +/// ``` +/// #![feature(collections_range)] +/// +/// use std::collections::range::RangeArgument; +/// use std::ops::Bound::*; +/// +/// assert_eq!((..100).start(), Unbounded); +/// assert_eq!((1..12).start(), Included(&1)); +/// assert_eq!((1..12).end(), Excluded(&12)); +/// ``` +/// +/// Using a tuple of `Bound`s as an argument to [`BTreeMap::range`]. +/// Note that in most cases, it's better to use range syntax (`1..5`) instead. +/// +/// ``` +/// use std::collections::BTreeMap; +/// use std::ops::Bound::{Excluded, Included, Unbounded}; +/// +/// let mut map = BTreeMap::new(); +/// map.insert(3, "a"); +/// map.insert(5, "b"); +/// map.insert(8, "c"); +/// +/// for (key, value) in map.range((Excluded(3), Included(8))) { +/// println!("{}: {}", key, value); +/// } +/// +/// assert_eq!(Some((&3, &"a")), map.range((Unbounded, Included(5))).next()); +/// ``` +/// +/// [`BTreeMap::range`]: ../../std/collections/btree_map/struct.BTreeMap.html#method.range +#[stable(feature = "collections_bound", since = "1.17.0")] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] +pub enum Bound { + /// An inclusive bound. + #[stable(feature = "collections_bound", since = "1.17.0")] + Included(#[stable(feature = "collections_bound", since = "1.17.0")] T), + /// An exclusive bound. + #[stable(feature = "collections_bound", since = "1.17.0")] + Excluded(#[stable(feature = "collections_bound", since = "1.17.0")] T), + /// An infinite endpoint. Indicates that there is no bound in this direction. + #[stable(feature = "collections_bound", since = "1.17.0")] + Unbounded, +} diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 511c407d45a..b40f2f92237 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -19,8 +19,8 @@ use std::slice; use std::fmt; use std::mem; use std::collections::range::RangeArgument; -use std::collections::Bound::{Excluded, Included, Unbounded}; use std::mem::ManuallyDrop; +use std::ops::Bound::{Excluded, Included, Unbounded}; pub unsafe trait Array { type Element; diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index be88f4e268a..e6f15a6119e 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -420,7 +420,8 @@ #![stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::Bound; +#[rustc_deprecated(reason = "moved to `std::ops::Bound`", since = "1.26.0")] +pub use ops::Bound; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc::{BinaryHeap, BTreeMap, BTreeSet}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/run-pass/sync-send-iterators-in-libcollections.rs b/src/test/run-pass/sync-send-iterators-in-libcollections.rs index 903532e9bc8..e096fb3bbae 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcollections.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcollections.rs @@ -18,8 +18,8 @@ use std::collections::VecDeque; use std::collections::HashMap; use std::collections::HashSet; -use std::collections::Bound::Included; use std::mem; +use std::ops::Bound::Included; fn is_sync(_: T) where T: Sync {} fn is_send(_: T) where T: Send {} -- cgit 1.4.1-3-g733a5 From 16d3ba1b23195da2d53e058c58c2a41def914dec Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 19 Mar 2018 09:26:29 +0100 Subject: Move RangeArguments to {core::std}::ops and rename to RangeBounds These unstable items are deprecated: * The `std::collections::range::RangeArgument` reexport * The `std::collections::range` module. --- src/liballoc/btree/map.rs | 8 +- src/liballoc/btree/set.rs | 5 +- src/liballoc/lib.rs | 2 +- src/liballoc/range.rs | 152 ------------------------ src/liballoc/string.rs | 7 +- src/liballoc/vec.rs | 7 +- src/liballoc/vec_deque.rs | 5 +- src/libcore/ops/mod.rs | 2 +- src/libcore/ops/range.rs | 155 ++++++++++++++++++++++++- src/librustc_data_structures/accumulate_vec.rs | 5 +- src/librustc_data_structures/array_vec.rs | 4 +- src/librustc_data_structures/indexed_vec.rs | 7 +- src/libstd/collections/mod.rs | 8 +- 13 files changed, 183 insertions(+), 184 deletions(-) delete mode 100644 src/liballoc/range.rs (limited to 'src/libcore') diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index 2ba56063e36..c604df7049e 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -15,10 +15,10 @@ use core::iter::{FromIterator, Peekable, FusedIterator}; use core::marker::PhantomData; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::Index; +use core::ops::RangeBounds; use core::{fmt, intrinsics, mem, ptr}; use borrow::Borrow; -use range::RangeArgument; use super::node::{self, Handle, NodeRef, marker}; use super::search; @@ -817,7 +817,7 @@ impl BTreeMap { /// ``` #[stable(feature = "btree_range", since = "1.17.0")] pub fn range(&self, range: R) -> Range - where T: Ord, K: Borrow, R: RangeArgument + where T: Ord, K: Borrow, R: RangeBounds { let root1 = self.root.as_ref(); let root2 = self.root.as_ref(); @@ -857,7 +857,7 @@ impl BTreeMap { /// ``` #[stable(feature = "btree_range", since = "1.17.0")] pub fn range_mut(&mut self, range: R) -> RangeMut - where T: Ord, K: Borrow, R: RangeArgument + where T: Ord, K: Borrow, R: RangeBounds { let root1 = self.root.as_mut(); let root2 = unsafe { ptr::read(&root1) }; @@ -1812,7 +1812,7 @@ fn last_leaf_edge } } -fn range_search>( +fn range_search>( root1: NodeRef, root2: NodeRef, range: R diff --git a/src/liballoc/btree/set.rs b/src/liballoc/btree/set.rs index d488dd6cbbd..2aad476d315 100644 --- a/src/liballoc/btree/set.rs +++ b/src/liballoc/btree/set.rs @@ -16,12 +16,11 @@ use core::cmp::{min, max}; use core::fmt::Debug; use core::fmt; use core::iter::{Peekable, FromIterator, FusedIterator}; -use core::ops::{BitOr, BitAnd, BitXor, Sub}; +use core::ops::{BitOr, BitAnd, BitXor, Sub, RangeBounds}; use borrow::Borrow; use btree_map::{BTreeMap, Keys}; use super::Recover; -use range::RangeArgument; // FIXME(conventions): implement bounded iterators @@ -253,7 +252,7 @@ impl BTreeSet { /// ``` #[stable(feature = "btree_range", since = "1.17.0")] pub fn range(&self, range: R) -> Range - where K: Ord, T: Borrow, R: RangeArgument + where K: Ord, T: Borrow, R: RangeBounds { Range { iter: self.map.range(range) } } diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index eddbd50ea03..e98b58994bf 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -88,6 +88,7 @@ #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] +#![feature(collections_range)] #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(custom_attribute)] @@ -178,7 +179,6 @@ mod btree; pub mod borrow; pub mod fmt; pub mod linked_list; -pub mod range; pub mod slice; pub mod str; pub mod string; diff --git a/src/liballoc/range.rs b/src/liballoc/range.rs deleted file mode 100644 index 7cadbf3c90a..00000000000 --- a/src/liballoc/range.rs +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "collections_range", - reason = "waiting for dust to settle on inclusive ranges", - issue = "30877")] - -//! Range syntax. - -use core::ops::{RangeFull, Range, RangeTo, RangeFrom, RangeInclusive, RangeToInclusive}; -use core::ops::Bound::{self, Excluded, Included, Unbounded}; - -/// `RangeArgument` is implemented by Rust's built-in range types, produced -/// by range syntax like `..`, `a..`, `..b` or `c..d`. -pub trait RangeArgument { - /// Start index bound. - /// - /// Returns the start value as a `Bound`. - /// - /// # Examples - /// - /// ``` - /// #![feature(alloc)] - /// #![feature(collections_range)] - /// - /// extern crate alloc; - /// - /// # fn main() { - /// use alloc::range::RangeArgument; - /// use alloc::Bound::*; - /// - /// assert_eq!((..10).start(), Unbounded); - /// assert_eq!((3..10).start(), Included(&3)); - /// # } - /// ``` - fn start(&self) -> Bound<&T>; - - /// End index bound. - /// - /// Returns the end value as a `Bound`. - /// - /// # Examples - /// - /// ``` - /// #![feature(alloc)] - /// #![feature(collections_range)] - /// - /// extern crate alloc; - /// - /// # fn main() { - /// use alloc::range::RangeArgument; - /// use alloc::Bound::*; - /// - /// assert_eq!((3..).end(), Unbounded); - /// assert_eq!((3..10).end(), Excluded(&10)); - /// # } - /// ``` - fn end(&self) -> Bound<&T>; -} - -// FIXME add inclusive ranges to RangeArgument - -impl RangeArgument for RangeFull { - fn start(&self) -> Bound<&T> { - Unbounded - } - fn end(&self) -> Bound<&T> { - Unbounded - } -} - -impl RangeArgument for RangeFrom { - fn start(&self) -> Bound<&T> { - Included(&self.start) - } - fn end(&self) -> Bound<&T> { - Unbounded - } -} - -impl RangeArgument for RangeTo { - fn start(&self) -> Bound<&T> { - Unbounded - } - fn end(&self) -> Bound<&T> { - Excluded(&self.end) - } -} - -impl RangeArgument for Range { - fn start(&self) -> Bound<&T> { - Included(&self.start) - } - fn end(&self) -> Bound<&T> { - Excluded(&self.end) - } -} - -#[stable(feature = "inclusive_range", since = "1.26.0")] -impl RangeArgument for RangeInclusive { - fn start(&self) -> Bound<&T> { - Included(&self.start) - } - fn end(&self) -> Bound<&T> { - Included(&self.end) - } -} - -#[stable(feature = "inclusive_range", since = "1.26.0")] -impl RangeArgument for RangeToInclusive { - fn start(&self) -> Bound<&T> { - Unbounded - } - fn end(&self) -> Bound<&T> { - Included(&self.end) - } -} - -impl RangeArgument for (Bound, Bound) { - fn start(&self) -> Bound<&T> { - match *self { - (Included(ref start), _) => Included(start), - (Excluded(ref start), _) => Excluded(start), - (Unbounded, _) => Unbounded, - } - } - - fn end(&self) -> Bound<&T> { - match *self { - (_, Included(ref end)) => Included(end), - (_, Excluded(ref end)) => Excluded(end), - (_, Unbounded) => Unbounded, - } - } -} - -impl<'a, T: ?Sized + 'a> RangeArgument for (Bound<&'a T>, Bound<&'a T>) { - fn start(&self) -> Bound<&T> { - self.0 - } - - fn end(&self) -> Bound<&T> { - self.1 - } -} diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 754c78f7779..aa202e23628 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -60,14 +60,13 @@ use core::fmt; use core::hash; use core::iter::{FromIterator, FusedIterator}; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{self, Add, AddAssign, Index, IndexMut}; +use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds}; use core::ptr; use core::str::pattern::Pattern; use std_unicode::lossy; use std_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; use borrow::{Cow, ToOwned}; -use range::RangeArgument; use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; use vec::Vec; use boxed::Box; @@ -1484,7 +1483,7 @@ impl String { /// ``` #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self, range: R) -> Drain - where R: RangeArgument + where R: RangeBounds { // Memory safety // @@ -1548,7 +1547,7 @@ impl String { /// ``` #[unstable(feature = "splice", reason = "recently added", issue = "44643")] pub fn splice(&mut self, range: R, replace_with: &str) - where R: RangeArgument + where R: RangeBounds { // Memory safety // diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 280570ecd65..df08e46fe25 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -76,7 +76,7 @@ use core::mem; #[cfg(not(test))] use core::num::Float; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{InPlace, Index, IndexMut, Place, Placer}; +use core::ops::{InPlace, Index, IndexMut, Place, Placer, RangeBounds}; use core::ops; use core::ptr; use core::ptr::NonNull; @@ -86,7 +86,6 @@ use borrow::ToOwned; use borrow::Cow; use boxed::Box; use raw_vec::RawVec; -use super::range::RangeArgument; use super::allocator::CollectionAllocErr; /// A contiguous growable array type, written `Vec` but pronounced 'vector'. @@ -1176,7 +1175,7 @@ impl Vec { /// ``` #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self, range: R) -> Drain - where R: RangeArgument + where R: RangeBounds { // Memory safety // @@ -1950,7 +1949,7 @@ impl Vec { #[inline] #[stable(feature = "vec_splice", since = "1.21.0")] pub fn splice(&mut self, range: R, replace_with: I) -> Splice - where R: RangeArgument, I: IntoIterator + where R: RangeBounds, I: IntoIterator { Splice { drain: self.drain(range), diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index 9efd730790d..94d042a45aa 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -22,7 +22,7 @@ use core::fmt; use core::iter::{repeat, FromIterator, FusedIterator}; use core::mem; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{Index, IndexMut, Place, Placer, InPlace}; +use core::ops::{Index, IndexMut, Place, Placer, InPlace, RangeBounds}; use core::ptr; use core::ptr::NonNull; use core::slice; @@ -33,7 +33,6 @@ use core::cmp; use raw_vec::RawVec; use super::allocator::CollectionAllocErr; -use super::range::RangeArgument; use super::vec::Vec; const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 @@ -969,7 +968,7 @@ impl VecDeque { #[inline] #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self, range: R) -> Drain - where R: RangeArgument + where R: RangeBounds { // Memory safety // diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index b0e75135282..0b480b618fc 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -192,7 +192,7 @@ pub use self::index::{Index, IndexMut}; pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; #[stable(feature = "inclusive_range", since = "1.26.0")] -pub use self::range::{RangeInclusive, RangeToInclusive, Bound}; +pub use self::range::{RangeInclusive, RangeToInclusive, RangeBounds, Bound}; #[unstable(feature = "try_trait", issue = "42327")] pub use self::try::Try; diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index dd44aedd09f..b5aa81e36c4 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -452,8 +452,8 @@ impl> RangeToInclusive { /// ``` /// #![feature(collections_range)] /// -/// use std::collections::range::RangeArgument; /// use std::ops::Bound::*; +/// use std::ops::RangeBounds; /// /// assert_eq!((..100).start(), Unbounded); /// assert_eq!((1..12).start(), Included(&1)); @@ -493,3 +493,156 @@ pub enum Bound { #[stable(feature = "collections_bound", since = "1.17.0")] Unbounded, } + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +/// `RangeBounds` is implemented by Rust's built-in range types, produced +/// by range syntax like `..`, `a..`, `..b` or `c..d`. +pub trait RangeBounds { + /// Start index bound. + /// + /// Returns the start value as a `Bound`. + /// + /// # Examples + /// + /// ``` + /// #![feature(collections_range)] + /// + /// # fn main() { + /// use std::ops::Bound::*; + /// use std::ops::RangeBounds; + /// + /// assert_eq!((..10).start(), Unbounded); + /// assert_eq!((3..10).start(), Included(&3)); + /// # } + /// ``` + fn start(&self) -> Bound<&T>; + + /// End index bound. + /// + /// Returns the end value as a `Bound`. + /// + /// # Examples + /// + /// ``` + /// #![feature(collections_range)] + /// + /// # fn main() { + /// use std::ops::Bound::*; + /// use std::ops::RangeBounds; + /// + /// assert_eq!((3..).end(), Unbounded); + /// assert_eq!((3..10).end(), Excluded(&10)); + /// # } + /// ``` + fn end(&self) -> Bound<&T>; +} + +use self::Bound::{Excluded, Included, Unbounded}; + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for RangeFull { + fn start(&self) -> Bound<&T> { + Unbounded + } + fn end(&self) -> Bound<&T> { + Unbounded + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for RangeFrom { + fn start(&self) -> Bound<&T> { + Included(&self.start) + } + fn end(&self) -> Bound<&T> { + Unbounded + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for RangeTo { + fn start(&self) -> Bound<&T> { + Unbounded + } + fn end(&self) -> Bound<&T> { + Excluded(&self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for Range { + fn start(&self) -> Bound<&T> { + Included(&self.start) + } + fn end(&self) -> Bound<&T> { + Excluded(&self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for RangeInclusive { + fn start(&self) -> Bound<&T> { + Included(&self.start) + } + fn end(&self) -> Bound<&T> { + Included(&self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for RangeToInclusive { + fn start(&self) -> Bound<&T> { + Unbounded + } + fn end(&self) -> Bound<&T> { + Included(&self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for (Bound, Bound) { + fn start(&self) -> Bound<&T> { + match *self { + (Included(ref start), _) => Included(start), + (Excluded(ref start), _) => Excluded(start), + (Unbounded, _) => Unbounded, + } + } + + fn end(&self) -> Bound<&T> { + match *self { + (_, Included(ref end)) => Included(end), + (_, Excluded(ref end)) => Excluded(end), + (_, Unbounded) => Unbounded, + } + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<'a, T: ?Sized + 'a> RangeBounds for (Bound<&'a T>, Bound<&'a T>) { + fn start(&self) -> Bound<&T> { + self.0 + } + + fn end(&self) -> Bound<&T> { + self.1 + } +} diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs index 52306de74cb..f50b8cadf15 100644 --- a/src/librustc_data_structures/accumulate_vec.rs +++ b/src/librustc_data_structures/accumulate_vec.rs @@ -15,11 +15,10 @@ //! //! The N above is determined by Array's implementor, by way of an associated constant. -use std::ops::{Deref, DerefMut}; +use std::ops::{Deref, DerefMut, RangeBounds}; use std::iter::{self, IntoIterator, FromIterator}; use std::slice; use std::vec; -use std::collections::range::RangeArgument; use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; @@ -74,7 +73,7 @@ impl AccumulateVec { } pub fn drain(&mut self, range: R) -> Drain - where R: RangeArgument + where R: RangeBounds { match *self { AccumulateVec::Array(ref mut v) => { diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index b40f2f92237..db1cfb5c767 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -18,9 +18,9 @@ use std::hash::{Hash, Hasher}; use std::slice; use std::fmt; use std::mem; -use std::collections::range::RangeArgument; use std::mem::ManuallyDrop; use std::ops::Bound::{Excluded, Included, Unbounded}; +use std::ops::RangeBounds; pub unsafe trait Array { type Element; @@ -106,7 +106,7 @@ impl ArrayVec { } pub fn drain(&mut self, range: R) -> Drain - where R: RangeArgument + where R: RangeBounds { // Memory safety // diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index cbb3ff51715..1fb63afc72f 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -8,12 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::collections::range::RangeArgument; use std::fmt::Debug; use std::iter::{self, FromIterator}; use std::slice; use std::marker::PhantomData; -use std::ops::{Index, IndexMut, Range}; +use std::ops::{Index, IndexMut, Range, RangeBounds}; use std::fmt; use std::vec; use std::u32; @@ -448,13 +447,13 @@ impl IndexVec { } #[inline] - pub fn drain<'a, R: RangeArgument>( + pub fn drain<'a, R: RangeBounds>( &'a mut self, range: R) -> impl Iterator + 'a { self.raw.drain(range) } #[inline] - pub fn drain_enumerated<'a, R: RangeArgument>( + pub fn drain_enumerated<'a, R: RangeBounds>( &'a mut self, range: R) -> impl Iterator + 'a { self.raw.drain(range).enumerate().map(IntoIdx { _marker: PhantomData }) } diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index e6f15a6119e..47ea3bc26bf 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -436,8 +436,12 @@ pub use self::hash_map::HashMap; #[stable(feature = "rust1", since = "1.0.0")] pub use self::hash_set::HashSet; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::range; +#[unstable(feature = "collections_range", issue = "30877")] +#[rustc_deprecated(reason = "renamed and moved to `std::ops::RangeBounds`", since = "1.26.0")] +/// Range syntax +pub mod range { + pub use ops::RangeBounds as RangeArgument; +} #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] pub use alloc::allocator::CollectionAllocErr; -- cgit 1.4.1-3-g733a5 From 124453e6fe03242233ab5f8c8e2360a8b9fcf831 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 20 Mar 2018 19:46:11 +0100 Subject: impl RangeBounds for Range{,From,To,Inclusive,ToInclusive}<&T> --- src/libcore/ops/range.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index b5aa81e36c4..3f667407125 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -646,3 +646,63 @@ impl<'a, T: ?Sized + 'a> RangeBounds for (Bound<&'a T>, Bound<&'a T>) { self.1 } } + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<'a, T> RangeBounds for RangeFrom<&'a T> { + fn start(&self) -> Bound<&T> { + Included(self.start) + } + fn end(&self) -> Bound<&T> { + Unbounded + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<'a, T> RangeBounds for RangeTo<&'a T> { + fn start(&self) -> Bound<&T> { + Unbounded + } + fn end(&self) -> Bound<&T> { + Excluded(self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<'a, T> RangeBounds for Range<&'a T> { + fn start(&self) -> Bound<&T> { + Included(self.start) + } + fn end(&self) -> Bound<&T> { + Excluded(self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<'a, T> RangeBounds for RangeInclusive<&'a T> { + fn start(&self) -> Bound<&T> { + Included(self.start) + } + fn end(&self) -> Bound<&T> { + Included(self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<'a, T> RangeBounds for RangeToInclusive<&'a T> { + fn start(&self) -> Bound<&T> { + Unbounded + } + fn end(&self) -> Bound<&T> { + Included(self.end) + } +} -- cgit 1.4.1-3-g733a5 From 94d1970bba87f2d2893f6e934e4c3f02ed50604d Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 28 Mar 2018 22:37:37 +0200 Subject: Move the alloc::allocator module to core::heap This is the `Alloc` trait and its dependencies. --- src/liballoc/allocator.rs | 1082 --------------------------------------------- src/liballoc/heap.rs | 2 +- src/liballoc/lib.rs | 7 +- src/libcore/heap.rs | 1082 +++++++++++++++++++++++++++++++++++++++++++++ src/libcore/lib.rs | 4 + src/libstd/heap.rs | 3 +- 6 files changed, 1093 insertions(+), 1087 deletions(-) delete mode 100644 src/liballoc/allocator.rs create mode 100644 src/libcore/heap.rs (limited to 'src/libcore') diff --git a/src/liballoc/allocator.rs b/src/liballoc/allocator.rs deleted file mode 100644 index fdc4efc66b9..00000000000 --- a/src/liballoc/allocator.rs +++ /dev/null @@ -1,1082 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked \ - slightly, especially to possibly take into account the \ - types being stored to make room for a future \ - tracing garbage collector", - issue = "32838")] - -use core::cmp; -use core::fmt; -use core::mem; -use core::usize; -use core::ptr::{self, NonNull}; - -/// Represents the combination of a starting address and -/// a total capacity of the returned block. -#[derive(Debug)] -pub struct Excess(pub *mut u8, pub usize); - -fn size_align() -> (usize, usize) { - (mem::size_of::(), mem::align_of::()) -} - -/// Layout of a block of memory. -/// -/// An instance of `Layout` describes a particular layout of memory. -/// You build a `Layout` up as an input to give to an allocator. -/// -/// All layouts have an associated non-negative size and a -/// power-of-two alignment. -/// -/// (Note however that layouts are *not* required to have positive -/// size, even though many allocators require that all memory -/// requests have positive size. A caller to the `Alloc::alloc` -/// method must either ensure that conditions like this are met, or -/// use specific allocators with looser requirements.) -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Layout { - // size of the requested block of memory, measured in bytes. - size: usize, - - // alignment of the requested block of memory, measured in bytes. - // we ensure that this is always a power-of-two, because API's - // like `posix_memalign` require it and it is a reasonable - // constraint to impose on Layout constructors. - // - // (However, we do not analogously require `align >= sizeof(void*)`, - // even though that is *also* a requirement of `posix_memalign`.) - align: usize, -} - - -// FIXME: audit default implementations for overflow errors, -// (potentially switching to overflowing_add and -// overflowing_mul as necessary). - -impl Layout { - /// Constructs a `Layout` from a given `size` and `align`, - /// or returns `None` if any of the following conditions - /// are not met: - /// - /// * `align` must be a power of two, - /// - /// * `align` must not exceed 231 (i.e. `1 << 31`), - /// - /// * `size`, when rounded up to the nearest multiple of `align`, - /// must not overflow (i.e. the rounded value must be less than - /// `usize::MAX`). - #[inline] - pub fn from_size_align(size: usize, align: usize) -> Option { - if !align.is_power_of_two() { - return None; - } - - if align > (1 << 31) { - return None; - } - - // (power-of-two implies align != 0.) - - // Rounded up size is: - // size_rounded_up = (size + align - 1) & !(align - 1); - // - // We know from above that align != 0. If adding (align - 1) - // does not overflow, then rounding up will be fine. - // - // Conversely, &-masking with !(align - 1) will subtract off - // only low-order-bits. Thus if overflow occurs with the sum, - // the &-mask cannot subtract enough to undo that overflow. - // - // Above implies that checking for summation overflow is both - // necessary and sufficient. - if size > usize::MAX - (align - 1) { - return None; - } - - unsafe { - Some(Layout::from_size_align_unchecked(size, align)) - } - } - - /// Creates a layout, bypassing all checks. - /// - /// # Safety - /// - /// This function is unsafe as it does not verify that `align` is - /// a power-of-two that is also less than or equal to 231, nor - /// that `size` aligned to `align` fits within the address space - /// (i.e. the `Layout::from_size_align` preconditions). - #[inline] - pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout { - Layout { size: size, align: align } - } - - /// The minimum size in bytes for a memory block of this layout. - #[inline] - pub fn size(&self) -> usize { self.size } - - /// The minimum byte alignment for a memory block of this layout. - #[inline] - pub fn align(&self) -> usize { self.align } - - /// Constructs a `Layout` suitable for holding a value of type `T`. - pub fn new() -> Self { - let (size, align) = size_align::(); - Layout::from_size_align(size, align).unwrap() - } - - /// Produces layout describing a record that could be used to - /// allocate backing structure for `T` (which could be a trait - /// or other unsized type like a slice). - pub fn for_value(t: &T) -> Self { - let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); - Layout::from_size_align(size, align).unwrap() - } - - /// Creates a layout describing the record that can hold a value - /// of the same layout as `self`, but that also is aligned to - /// alignment `align` (measured in bytes). - /// - /// If `self` already meets the prescribed alignment, then returns - /// `self`. - /// - /// Note that this method does not add any padding to the overall - /// size, regardless of whether the returned layout has a different - /// alignment. In other words, if `K` has size 16, `K.align_to(32)` - /// will *still* have size 16. - /// - /// # Panics - /// - /// Panics if the combination of `self.size` and the given `align` - /// violates the conditions listed in `from_size_align`. - #[inline] - pub fn align_to(&self, align: usize) -> Self { - Layout::from_size_align(self.size, cmp::max(self.align, align)).unwrap() - } - - /// Returns the amount of padding we must insert after `self` - /// to ensure that the following address will satisfy `align` - /// (measured in bytes). - /// - /// E.g. if `self.size` is 9, then `self.padding_needed_for(4)` - /// returns 3, because that is the minimum number of bytes of - /// padding required to get a 4-aligned address (assuming that the - /// corresponding memory block starts at a 4-aligned address). - /// - /// The return value of this function has no meaning if `align` is - /// not a power-of-two. - /// - /// Note that the utility of the returned value requires `align` - /// to be less than or equal to the alignment of the starting - /// address for the whole allocated block of memory. One way to - /// satisfy this constraint is to ensure `align <= self.align`. - #[inline] - pub fn padding_needed_for(&self, align: usize) -> usize { - let len = self.size(); - - // Rounded up value is: - // len_rounded_up = (len + align - 1) & !(align - 1); - // and then we return the padding difference: `len_rounded_up - len`. - // - // We use modular arithmetic throughout: - // - // 1. align is guaranteed to be > 0, so align - 1 is always - // valid. - // - // 2. `len + align - 1` can overflow by at most `align - 1`, - // so the &-mask wth `!(align - 1)` will ensure that in the - // case of overflow, `len_rounded_up` will itself be 0. - // Thus the returned padding, when added to `len`, yields 0, - // which trivially satisfies the alignment `align`. - // - // (Of course, attempts to allocate blocks of memory whose - // size and padding overflow in the above manner should cause - // the allocator to yield an error anyway.) - - let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); - return len_rounded_up.wrapping_sub(len); - } - - /// Creates a layout describing the record for `n` instances of - /// `self`, with a suitable amount of padding between each to - /// ensure that each instance is given its requested size and - /// alignment. On success, returns `(k, offs)` where `k` is the - /// layout of the array and `offs` is the distance between the start - /// of each element in the array. - /// - /// On arithmetic overflow, returns `None`. - #[inline] - pub fn repeat(&self, n: usize) -> Option<(Self, usize)> { - let padded_size = self.size.checked_add(self.padding_needed_for(self.align))?; - let alloc_size = padded_size.checked_mul(n)?; - - // We can assume that `self.align` is a power-of-two that does - // not exceed 231. Furthermore, `alloc_size` has already been - // rounded up to a multiple of `self.align`; therefore, the - // call to `Layout::from_size_align` below should never panic. - Some((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) - } - - /// Creates a layout describing the record for `self` followed by - /// `next`, including any necessary padding to ensure that `next` - /// will be properly aligned. Note that the result layout will - /// satisfy the alignment properties of both `self` and `next`. - /// - /// Returns `Some((k, offset))`, where `k` is layout of the concatenated - /// record and `offset` is the relative location, in bytes, of the - /// start of the `next` embedded within the concatenated record - /// (assuming that the record itself starts at offset 0). - /// - /// On arithmetic overflow, returns `None`. - pub fn extend(&self, next: Self) -> Option<(Self, usize)> { - let new_align = cmp::max(self.align, next.align); - let realigned = Layout::from_size_align(self.size, new_align)?; - - let pad = realigned.padding_needed_for(next.align); - - let offset = self.size.checked_add(pad)?; - let new_size = offset.checked_add(next.size)?; - - let layout = Layout::from_size_align(new_size, new_align)?; - Some((layout, offset)) - } - - /// Creates a layout describing the record for `n` instances of - /// `self`, with no padding between each instance. - /// - /// Note that, unlike `repeat`, `repeat_packed` does not guarantee - /// that the repeated instances of `self` will be properly - /// aligned, even if a given instance of `self` is properly - /// aligned. In other words, if the layout returned by - /// `repeat_packed` is used to allocate an array, it is not - /// guaranteed that all elements in the array will be properly - /// aligned. - /// - /// On arithmetic overflow, returns `None`. - pub fn repeat_packed(&self, n: usize) -> Option { - let size = self.size().checked_mul(n)?; - Layout::from_size_align(size, self.align) - } - - /// Creates a layout describing the record for `self` followed by - /// `next` with no additional padding between the two. Since no - /// padding is inserted, the alignment of `next` is irrelevant, - /// and is not incorporated *at all* into the resulting layout. - /// - /// Returns `(k, offset)`, where `k` is layout of the concatenated - /// record and `offset` is the relative location, in bytes, of the - /// start of the `next` embedded within the concatenated record - /// (assuming that the record itself starts at offset 0). - /// - /// (The `offset` is always the same as `self.size()`; we use this - /// signature out of convenience in matching the signature of - /// `extend`.) - /// - /// On arithmetic overflow, returns `None`. - pub fn extend_packed(&self, next: Self) -> Option<(Self, usize)> { - let new_size = self.size().checked_add(next.size())?; - let layout = Layout::from_size_align(new_size, self.align)?; - Some((layout, self.size())) - } - - /// Creates a layout describing the record for a `[T; n]`. - /// - /// On arithmetic overflow, returns `None`. - pub fn array(n: usize) -> Option { - Layout::new::() - .repeat(n) - .map(|(k, offs)| { - debug_assert!(offs == mem::size_of::()); - k - }) - } -} - -/// The `AllocErr` error specifies whether an allocation failure is -/// specifically due to resource exhaustion or if it is due to -/// something wrong when combining the given input arguments with this -/// allocator. -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum AllocErr { - /// Error due to hitting some resource limit or otherwise running - /// out of memory. This condition strongly implies that *some* - /// series of deallocations would allow a subsequent reissuing of - /// the original allocation request to succeed. - Exhausted { request: Layout }, - - /// Error due to allocator being fundamentally incapable of - /// satisfying the original request. This condition implies that - /// such an allocation request will never succeed on the given - /// allocator, regardless of environment, memory pressure, or - /// other contextual conditions. - /// - /// For example, an allocator that does not support requests for - /// large memory blocks might return this error variant. - Unsupported { details: &'static str }, -} - -impl AllocErr { - #[inline] - pub fn invalid_input(details: &'static str) -> Self { - AllocErr::Unsupported { details: details } - } - #[inline] - pub fn is_memory_exhausted(&self) -> bool { - if let AllocErr::Exhausted { .. } = *self { true } else { false } - } - #[inline] - pub fn is_request_unsupported(&self) -> bool { - if let AllocErr::Unsupported { .. } = *self { true } else { false } - } - #[inline] - pub fn description(&self) -> &str { - match *self { - AllocErr::Exhausted { .. } => "allocator memory exhausted", - AllocErr::Unsupported { .. } => "unsupported allocator request", - } - } -} - -// (we need this for downstream impl of trait Error) -impl fmt::Display for AllocErr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.description()) - } -} - -/// The `CannotReallocInPlace` error is used when `grow_in_place` or -/// `shrink_in_place` were unable to reuse the given memory block for -/// a requested layout. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct CannotReallocInPlace; - -impl CannotReallocInPlace { - pub fn description(&self) -> &str { - "cannot reallocate allocator's memory in place" - } -} - -// (we need this for downstream impl of trait Error) -impl fmt::Display for CannotReallocInPlace { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.description()) - } -} - -/// Augments `AllocErr` with a CapacityOverflow variant. -#[derive(Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub enum CollectionAllocErr { - /// Error due to the computed capacity exceeding the collection's maximum - /// (usually `isize::MAX` bytes). - CapacityOverflow, - /// Error due to the allocator (see the `AllocErr` type's docs). - AllocErr(AllocErr), -} - -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -impl From for CollectionAllocErr { - fn from(err: AllocErr) -> Self { - CollectionAllocErr::AllocErr(err) - } -} - -/// An implementation of `Alloc` can allocate, reallocate, and -/// deallocate arbitrary blocks of data described via `Layout`. -/// -/// Some of the methods require that a memory block be *currently -/// allocated* via an allocator. This means that: -/// -/// * the starting address for that memory block was previously -/// returned by a previous call to an allocation method (`alloc`, -/// `alloc_zeroed`, `alloc_excess`, `alloc_one`, `alloc_array`) or -/// reallocation method (`realloc`, `realloc_excess`, or -/// `realloc_array`), and -/// -/// * the memory block has not been subsequently deallocated, where -/// blocks are deallocated either by being passed to a deallocation -/// method (`dealloc`, `dealloc_one`, `dealloc_array`) or by being -/// passed to a reallocation method (see above) that returns `Ok`. -/// -/// A note regarding zero-sized types and zero-sized layouts: many -/// methods in the `Alloc` trait state that allocation requests -/// must be non-zero size, or else undefined behavior can result. -/// -/// * However, some higher-level allocation methods (`alloc_one`, -/// `alloc_array`) are well-defined on zero-sized types and can -/// optionally support them: it is left up to the implementor -/// whether to return `Err`, or to return `Ok` with some pointer. -/// -/// * If an `Alloc` implementation chooses to return `Ok` in this -/// case (i.e. the pointer denotes a zero-sized inaccessible block) -/// then that returned pointer must be considered "currently -/// allocated". On such an allocator, *all* methods that take -/// currently-allocated pointers as inputs must accept these -/// zero-sized pointers, *without* causing undefined behavior. -/// -/// * In other words, if a zero-sized pointer can flow out of an -/// allocator, then that allocator must likewise accept that pointer -/// flowing back into its deallocation and reallocation methods. -/// -/// Some of the methods require that a layout *fit* a memory block. -/// What it means for a layout to "fit" a memory block means (or -/// equivalently, for a memory block to "fit" a layout) is that the -/// following two conditions must hold: -/// -/// 1. The block's starting address must be aligned to `layout.align()`. -/// -/// 2. The block's size must fall in the range `[use_min, use_max]`, where: -/// -/// * `use_min` is `self.usable_size(layout).0`, and -/// -/// * `use_max` is the capacity that was (or would have been) -/// returned when (if) the block was allocated via a call to -/// `alloc_excess` or `realloc_excess`. -/// -/// Note that: -/// -/// * the size of the layout most recently used to allocate the block -/// is guaranteed to be in the range `[use_min, use_max]`, and -/// -/// * a lower-bound on `use_max` can be safely approximated by a call to -/// `usable_size`. -/// -/// * if a layout `k` fits a memory block (denoted by `ptr`) -/// currently allocated via an allocator `a`, then it is legal to -/// use that layout to deallocate it, i.e. `a.dealloc(ptr, k);`. -/// -/// # Unsafety -/// -/// The `Alloc` trait is an `unsafe` trait for a number of reasons, and -/// implementors must ensure that they adhere to these contracts: -/// -/// * Pointers returned from allocation functions must point to valid memory and -/// retain their validity until at least the instance of `Alloc` is dropped -/// itself. -/// -/// * It's undefined behavior if global allocators unwind. This restriction may -/// be lifted in the future, but currently a panic from any of these -/// functions may lead to memory unsafety. Note that as of the time of this -/// writing allocators *not* intending to be global allocators can still panic -/// in their implementation without violating memory safety. -/// -/// * `Layout` queries and calculations in general must be correct. Callers of -/// this trait are allowed to rely on the contracts defined on each method, -/// and implementors must ensure such contracts remain true. -/// -/// Note that this list may get tweaked over time as clarifications are made in -/// the future. Additionally global allocators may gain unique requirements for -/// how to safely implement one in the future as well. -pub unsafe trait Alloc { - - // (Note: existing allocators have unspecified but well-defined - // behavior in response to a zero size allocation request ; - // e.g. in C, `malloc` of 0 will either return a null pointer or a - // unique pointer, but will not have arbitrary undefined - // behavior. Rust should consider revising the alloc::heap crate - // to reflect this reality.) - - /// Returns a pointer meeting the size and alignment guarantees of - /// `layout`. - /// - /// If this method returns an `Ok(addr)`, then the `addr` returned - /// will be non-null address pointing to a block of storage - /// suitable for holding an instance of `layout`. - /// - /// The returned block of storage may or may not have its contents - /// initialized. (Extension subtraits might restrict this - /// behavior, e.g. to ensure initialization to particular sets of - /// bit patterns.) - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure that `layout` has non-zero size. - /// - /// (Extension subtraits might provide more specific bounds on - /// behavior, e.g. guarantee a sentinel address or a null pointer - /// in response to a zero-size allocation request.) - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `layout` does not meet allocator's size or alignment - /// constraints. - /// - /// Implementations are encouraged to return `Err` on memory - /// exhaustion rather than panicking or aborting, but this is not - /// a strict requirement. (Specifically: it is *legal* to - /// implement this trait atop an underlying native allocation - /// library that aborts on memory exhaustion.) - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; - - /// Deallocate the memory referenced by `ptr`. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must denote a block of memory currently allocated via - /// this allocator, - /// - /// * `layout` must *fit* that block of memory, - /// - /// * In addition to fitting the block of memory `layout`, the - /// alignment of the `layout` must match the alignment used - /// to allocate that block of memory. - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); - - /// Allocator-specific method for signaling an out-of-memory - /// condition. - /// - /// `oom` aborts the thread or process, optionally performing - /// cleanup or logging diagnostic information before panicking or - /// aborting. - /// - /// `oom` is meant to be used by clients unable to cope with an - /// unsatisfied allocation request (signaled by an error such as - /// `AllocErr::Exhausted`), and wish to abandon computation rather - /// than attempt to recover locally. Such clients should pass the - /// signaling error value back into `oom`, where the allocator - /// may incorporate that error value into its diagnostic report - /// before aborting. - /// - /// Implementations of the `oom` method are discouraged from - /// infinitely regressing in nested calls to `oom`. In - /// practice this means implementors should eschew allocating, - /// especially from `self` (directly or indirectly). - /// - /// Implementations of the allocation and reallocation methods - /// (e.g. `alloc`, `alloc_one`, `realloc`) are discouraged from - /// panicking (or aborting) in the event of memory exhaustion; - /// instead they should return an appropriate error from the - /// invoked method, and let the client decide whether to invoke - /// this `oom` method in response. - fn oom(&mut self, _: AllocErr) -> ! { - unsafe { ::core::intrinsics::abort() } - } - - // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS == - // usable_size - - /// Returns bounds on the guaranteed usable size of a successful - /// allocation created with the specified `layout`. - /// - /// In particular, if one has a memory block allocated via a given - /// allocator `a` and layout `k` where `a.usable_size(k)` returns - /// `(l, u)`, then one can pass that block to `a.dealloc()` with a - /// layout in the size range [l, u]. - /// - /// (All implementors of `usable_size` must ensure that - /// `l <= k.size() <= u`) - /// - /// Both the lower- and upper-bounds (`l` and `u` respectively) - /// are provided, because an allocator based on size classes could - /// misbehave if one attempts to deallocate a block without - /// providing a correct value for its size (i.e., one within the - /// range `[l, u]`). - /// - /// Clients who wish to make use of excess capacity are encouraged - /// to use the `alloc_excess` and `realloc_excess` instead, as - /// this method is constrained to report conservative values that - /// serve as valid bounds for *all possible* allocation method - /// calls. - /// - /// However, for clients that do not wish to track the capacity - /// returned by `alloc_excess` locally, this method is likely to - /// produce useful results. - #[inline] - fn usable_size(&self, layout: &Layout) -> (usize, usize) { - (layout.size(), layout.size()) - } - - // == METHODS FOR MEMORY REUSE == - // realloc. alloc_excess, realloc_excess - - /// Returns a pointer suitable for holding data described by - /// `new_layout`, meeting its size and alignment guarantees. To - /// accomplish this, this may extend or shrink the allocation - /// referenced by `ptr` to fit `new_layout`. - /// - /// If this returns `Ok`, then ownership of the memory block - /// referenced by `ptr` has been transferred to this - /// allocator. The memory may or may not have been freed, and - /// should be considered unusable (unless of course it was - /// transferred back to the caller again via the return value of - /// this method). - /// - /// If this method returns `Err`, then ownership of the memory - /// block has not been transferred to this allocator, and the - /// contents of the memory block are unaltered. - /// - /// For best results, `new_layout` should not impose a different - /// alignment constraint than `layout`. (In other words, - /// `new_layout.align()` should equal `layout.align()`.) However, - /// behavior is well-defined (though underspecified) when this - /// constraint is violated; further discussion below. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must be currently allocated via this allocator, - /// - /// * `layout` must *fit* the `ptr` (see above). (The `new_layout` - /// argument need not fit it.) - /// - /// * `new_layout` must have size greater than zero. - /// - /// * the alignment of `new_layout` is non-zero. - /// - /// (Extension subtraits might provide more specific bounds on - /// behavior, e.g. guarantee a sentinel address or a null pointer - /// in response to a zero-size allocation request.) - /// - /// # Errors - /// - /// Returns `Err` only if `new_layout` does not match the - /// alignment of `layout`, or does not meet the allocator's size - /// and alignment constraints of the allocator, or if reallocation - /// otherwise fails. - /// - /// (Note the previous sentence did not say "if and only if" -- in - /// particular, an implementation of this method *can* return `Ok` - /// if `new_layout.align() != old_layout.align()`; or it can - /// return `Err` in that scenario, depending on whether this - /// allocator can dynamically adjust the alignment constraint for - /// the block.) - /// - /// Implementations are encouraged to return `Err` on memory - /// exhaustion rather than panicking or aborting, but this is not - /// a strict requirement. (Specifically: it is *legal* to - /// implement this trait atop an underlying native allocation - /// library that aborts on memory exhaustion.) - /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn realloc(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - let new_size = new_layout.size(); - let old_size = layout.size(); - let aligns_match = layout.align == new_layout.align; - - if new_size >= old_size && aligns_match { - if let Ok(()) = self.grow_in_place(ptr, layout.clone(), new_layout.clone()) { - return Ok(ptr); - } - } else if new_size < old_size && aligns_match { - if let Ok(()) = self.shrink_in_place(ptr, layout.clone(), new_layout.clone()) { - return Ok(ptr); - } - } - - // otherwise, fall back on alloc + copy + dealloc. - let result = self.alloc(new_layout); - if let Ok(new_ptr) = result { - ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size)); - self.dealloc(ptr, layout); - } - result - } - - /// Behaves like `alloc`, but also ensures that the contents - /// are set to zero before being returned. - /// - /// # Safety - /// - /// This function is unsafe for the same reasons that `alloc` is. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `layout` does not meet allocator's size or alignment - /// constraints, just as in `alloc`. - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let size = layout.size(); - let p = self.alloc(layout); - if let Ok(p) = p { - ptr::write_bytes(p, 0, size); - } - p - } - - /// Behaves like `alloc`, but also returns the whole size of - /// the returned block. For some `layout` inputs, like arrays, this - /// may include extra storage usable for additional data. - /// - /// # Safety - /// - /// This function is unsafe for the same reasons that `alloc` is. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `layout` does not meet allocator's size or alignment - /// constraints, just as in `alloc`. - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { - let usable_size = self.usable_size(&layout); - self.alloc(layout).map(|p| Excess(p, usable_size.1)) - } - - /// Behaves like `realloc`, but also returns the whole size of - /// the returned block. For some `layout` inputs, like arrays, this - /// may include extra storage usable for additional data. - /// - /// # Safety - /// - /// This function is unsafe for the same reasons that `realloc` is. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `layout` does not meet allocator's size or alignment - /// constraints, just as in `realloc`. - /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn realloc_excess(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result { - let usable_size = self.usable_size(&new_layout); - self.realloc(ptr, layout, new_layout) - .map(|p| Excess(p, usable_size.1)) - } - - /// Attempts to extend the allocation referenced by `ptr` to fit `new_layout`. - /// - /// If this returns `Ok`, then the allocator has asserted that the - /// memory block referenced by `ptr` now fits `new_layout`, and thus can - /// be used to carry data of that layout. (The allocator is allowed to - /// expend effort to accomplish this, such as extending the memory block to - /// include successor blocks, or virtual memory tricks.) - /// - /// Regardless of what this method returns, ownership of the - /// memory block referenced by `ptr` has not been transferred, and - /// the contents of the memory block are unaltered. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must be currently allocated via this allocator, - /// - /// * `layout` must *fit* the `ptr` (see above); note the - /// `new_layout` argument need not fit it, - /// - /// * `new_layout.size()` must not be less than `layout.size()`, - /// - /// * `new_layout.align()` must equal `layout.align()`. - /// - /// # Errors - /// - /// Returns `Err(CannotReallocInPlace)` when the allocator is - /// unable to assert that the memory block referenced by `ptr` - /// could fit `layout`. - /// - /// Note that one cannot pass `CannotReallocInPlace` to the `oom` - /// method; clients are expected either to be able to recover from - /// `grow_in_place` failures without aborting, or to fall back on - /// another reallocation method before resorting to an abort. - unsafe fn grow_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let _ = ptr; // this default implementation doesn't care about the actual address. - debug_assert!(new_layout.size >= layout.size); - debug_assert!(new_layout.align == layout.align); - let (_l, u) = self.usable_size(&layout); - // _l <= layout.size() [guaranteed by usable_size()] - // layout.size() <= new_layout.size() [required by this method] - if new_layout.size <= u { - return Ok(()); - } else { - return Err(CannotReallocInPlace); - } - } - - /// Attempts to shrink the allocation referenced by `ptr` to fit `new_layout`. - /// - /// If this returns `Ok`, then the allocator has asserted that the - /// memory block referenced by `ptr` now fits `new_layout`, and - /// thus can only be used to carry data of that smaller - /// layout. (The allocator is allowed to take advantage of this, - /// carving off portions of the block for reuse elsewhere.) The - /// truncated contents of the block within the smaller layout are - /// unaltered, and ownership of block has not been transferred. - /// - /// If this returns `Err`, then the memory block is considered to - /// still represent the original (larger) `layout`. None of the - /// block has been carved off for reuse elsewhere, ownership of - /// the memory block has not been transferred, and the contents of - /// the memory block are unaltered. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must be currently allocated via this allocator, - /// - /// * `layout` must *fit* the `ptr` (see above); note the - /// `new_layout` argument need not fit it, - /// - /// * `new_layout.size()` must not be greater than `layout.size()` - /// (and must be greater than zero), - /// - /// * `new_layout.align()` must equal `layout.align()`. - /// - /// # Errors - /// - /// Returns `Err(CannotReallocInPlace)` when the allocator is - /// unable to assert that the memory block referenced by `ptr` - /// could fit `layout`. - /// - /// Note that one cannot pass `CannotReallocInPlace` to the `oom` - /// method; clients are expected either to be able to recover from - /// `shrink_in_place` failures without aborting, or to fall back - /// on another reallocation method before resorting to an abort. - unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let _ = ptr; // this default implementation doesn't care about the actual address. - debug_assert!(new_layout.size <= layout.size); - debug_assert!(new_layout.align == layout.align); - let (l, _u) = self.usable_size(&layout); - // layout.size() <= _u [guaranteed by usable_size()] - // new_layout.size() <= layout.size() [required by this method] - if l <= new_layout.size { - return Ok(()); - } else { - return Err(CannotReallocInPlace); - } - } - - - // == COMMON USAGE PATTERNS == - // alloc_one, dealloc_one, alloc_array, realloc_array. dealloc_array - - /// Allocates a block suitable for holding an instance of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// The returned block is suitable for passing to the - /// `alloc`/`realloc` methods of this allocator. - /// - /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` - /// must be considered "currently allocated" and must be - /// acceptable input to methods such as `realloc` or `dealloc`, - /// *even if* `T` is a zero-sized type. In other words, if your - /// `Alloc` implementation overrides this method in a manner - /// that can return a zero-sized `ptr`, then all reallocation and - /// deallocation methods need to be similarly overridden to accept - /// such values as input. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `T` does not meet allocator's size or alignment constraints. - /// - /// For zero-sized `T`, may return either of `Ok` or `Err`, but - /// will *not* yield undefined behavior. - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - fn alloc_one(&mut self) -> Result, AllocErr> - where Self: Sized - { - let k = Layout::new::(); - if k.size() > 0 { - unsafe { self.alloc(k).map(|p| NonNull::new_unchecked(p as *mut T)) } - } else { - Err(AllocErr::invalid_input("zero-sized type invalid for alloc_one")) - } - } - - /// Deallocates a block suitable for holding an instance of `T`. - /// - /// The given block must have been produced by this allocator, - /// and must be suitable for storing a `T` (in terms of alignment - /// as well as minimum and maximum size); otherwise yields - /// undefined behavior. - /// - /// Captures a common usage pattern for allocators. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure both: - /// - /// * `ptr` must denote a block of memory currently allocated via this allocator - /// - /// * the layout of `T` must *fit* that block of memory. - unsafe fn dealloc_one(&mut self, ptr: NonNull) - where Self: Sized - { - let raw_ptr = ptr.as_ptr() as *mut u8; - let k = Layout::new::(); - if k.size() > 0 { - self.dealloc(raw_ptr, k); - } - } - - /// Allocates a block suitable for holding `n` instances of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// The returned block is suitable for passing to the - /// `alloc`/`realloc` methods of this allocator. - /// - /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` - /// must be considered "currently allocated" and must be - /// acceptable input to methods such as `realloc` or `dealloc`, - /// *even if* `T` is a zero-sized type. In other words, if your - /// `Alloc` implementation overrides this method in a manner - /// that can return a zero-sized `ptr`, then all reallocation and - /// deallocation methods need to be similarly overridden to accept - /// such values as input. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `[T; n]` does not meet allocator's size or alignment - /// constraints. - /// - /// For zero-sized `T` or `n == 0`, may return either of `Ok` or - /// `Err`, but will *not* yield undefined behavior. - /// - /// Always returns `Err` on arithmetic overflow. - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - fn alloc_array(&mut self, n: usize) -> Result, AllocErr> - where Self: Sized - { - match Layout::array::(n) { - Some(ref layout) if layout.size() > 0 => { - unsafe { - self.alloc(layout.clone()) - .map(|p| { - NonNull::new_unchecked(p as *mut T) - }) - } - } - _ => Err(AllocErr::invalid_input("invalid layout for alloc_array")), - } - } - - /// Reallocates a block previously suitable for holding `n_old` - /// instances of `T`, returning a block suitable for holding - /// `n_new` instances of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// The returned block is suitable for passing to the - /// `alloc`/`realloc` methods of this allocator. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must be currently allocated via this allocator, - /// - /// * the layout of `[T; n_old]` must *fit* that block of memory. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `[T; n_new]` does not meet allocator's size or alignment - /// constraints. - /// - /// For zero-sized `T` or `n_new == 0`, may return either of `Ok` or - /// `Err`, but will *not* yield undefined behavior. - /// - /// Always returns `Err` on arithmetic overflow. - /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn realloc_array(&mut self, - ptr: NonNull, - n_old: usize, - n_new: usize) -> Result, AllocErr> - where Self: Sized - { - match (Layout::array::(n_old), Layout::array::(n_new), ptr.as_ptr()) { - (Some(ref k_old), Some(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { - self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone()) - .map(|p| NonNull::new_unchecked(p as *mut T)) - } - _ => { - Err(AllocErr::invalid_input("invalid layout for realloc_array")) - } - } - } - - /// Deallocates a block suitable for holding `n` instances of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure both: - /// - /// * `ptr` must denote a block of memory currently allocated via this allocator - /// - /// * the layout of `[T; n]` must *fit* that block of memory. - /// - /// # Errors - /// - /// Returning `Err` indicates that either `[T; n]` or the given - /// memory block does not meet allocator's size or alignment - /// constraints. - /// - /// Always returns `Err` on arithmetic overflow. - unsafe fn dealloc_array(&mut self, ptr: NonNull, n: usize) -> Result<(), AllocErr> - where Self: Sized - { - let raw_ptr = ptr.as_ptr() as *mut u8; - match Layout::array::(n) { - Some(ref k) if k.size() > 0 => { - Ok(self.dealloc(raw_ptr, k.clone())) - } - _ => { - Err(AllocErr::invalid_input("invalid layout for dealloc_array")) - } - } - } -} diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index c13ad39e5e1..9296a113071 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -19,7 +19,7 @@ use core::intrinsics::{min_align_of_val, size_of_val}; use core::mem::{self, ManuallyDrop}; use core::usize; -pub use allocator::*; +pub use core::heap::*; #[doc(hidden)] pub mod __core { pub use core::*; diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 19d64d8fea9..5594caa65b9 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -81,6 +81,7 @@ #![cfg_attr(not(test), feature(exact_size_is_empty))] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(rand, test))] +#![feature(allocator_api)] #![feature(allow_internal_unstable)] #![feature(ascii_ctype)] #![feature(box_into_raw_non_null)] @@ -145,9 +146,9 @@ extern crate std_unicode; #[macro_use] mod macros; -// Allocator trait and helper struct definitions - -pub mod allocator; +#[rustc_deprecated(since = "1.27.0", reason = "use the heap module in core, alloc, or std instead")] +#[unstable(feature = "allocator_api", issue = "32838")] +pub use core::heap as allocator; // Heaps provided for low-level allocation strategies diff --git a/src/libcore/heap.rs b/src/libcore/heap.rs new file mode 100644 index 00000000000..dae60b1647f --- /dev/null +++ b/src/libcore/heap.rs @@ -0,0 +1,1082 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "allocator_api", + reason = "the precise API and guarantees it provides may be tweaked \ + slightly, especially to possibly take into account the \ + types being stored to make room for a future \ + tracing garbage collector", + issue = "32838")] + +use cmp; +use fmt; +use mem; +use usize; +use ptr::{self, NonNull}; + +/// Represents the combination of a starting address and +/// a total capacity of the returned block. +#[derive(Debug)] +pub struct Excess(pub *mut u8, pub usize); + +fn size_align() -> (usize, usize) { + (mem::size_of::(), mem::align_of::()) +} + +/// Layout of a block of memory. +/// +/// An instance of `Layout` describes a particular layout of memory. +/// You build a `Layout` up as an input to give to an allocator. +/// +/// All layouts have an associated non-negative size and a +/// power-of-two alignment. +/// +/// (Note however that layouts are *not* required to have positive +/// size, even though many allocators require that all memory +/// requests have positive size. A caller to the `Alloc::alloc` +/// method must either ensure that conditions like this are met, or +/// use specific allocators with looser requirements.) +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Layout { + // size of the requested block of memory, measured in bytes. + size: usize, + + // alignment of the requested block of memory, measured in bytes. + // we ensure that this is always a power-of-two, because API's + // like `posix_memalign` require it and it is a reasonable + // constraint to impose on Layout constructors. + // + // (However, we do not analogously require `align >= sizeof(void*)`, + // even though that is *also* a requirement of `posix_memalign`.) + align: usize, +} + + +// FIXME: audit default implementations for overflow errors, +// (potentially switching to overflowing_add and +// overflowing_mul as necessary). + +impl Layout { + /// Constructs a `Layout` from a given `size` and `align`, + /// or returns `None` if any of the following conditions + /// are not met: + /// + /// * `align` must be a power of two, + /// + /// * `align` must not exceed 231 (i.e. `1 << 31`), + /// + /// * `size`, when rounded up to the nearest multiple of `align`, + /// must not overflow (i.e. the rounded value must be less than + /// `usize::MAX`). + #[inline] + pub fn from_size_align(size: usize, align: usize) -> Option { + if !align.is_power_of_two() { + return None; + } + + if align > (1 << 31) { + return None; + } + + // (power-of-two implies align != 0.) + + // Rounded up size is: + // size_rounded_up = (size + align - 1) & !(align - 1); + // + // We know from above that align != 0. If adding (align - 1) + // does not overflow, then rounding up will be fine. + // + // Conversely, &-masking with !(align - 1) will subtract off + // only low-order-bits. Thus if overflow occurs with the sum, + // the &-mask cannot subtract enough to undo that overflow. + // + // Above implies that checking for summation overflow is both + // necessary and sufficient. + if size > usize::MAX - (align - 1) { + return None; + } + + unsafe { + Some(Layout::from_size_align_unchecked(size, align)) + } + } + + /// Creates a layout, bypassing all checks. + /// + /// # Safety + /// + /// This function is unsafe as it does not verify that `align` is + /// a power-of-two that is also less than or equal to 231, nor + /// that `size` aligned to `align` fits within the address space + /// (i.e. the `Layout::from_size_align` preconditions). + #[inline] + pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout { + Layout { size: size, align: align } + } + + /// The minimum size in bytes for a memory block of this layout. + #[inline] + pub fn size(&self) -> usize { self.size } + + /// The minimum byte alignment for a memory block of this layout. + #[inline] + pub fn align(&self) -> usize { self.align } + + /// Constructs a `Layout` suitable for holding a value of type `T`. + pub fn new() -> Self { + let (size, align) = size_align::(); + Layout::from_size_align(size, align).unwrap() + } + + /// Produces layout describing a record that could be used to + /// allocate backing structure for `T` (which could be a trait + /// or other unsized type like a slice). + pub fn for_value(t: &T) -> Self { + let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); + Layout::from_size_align(size, align).unwrap() + } + + /// Creates a layout describing the record that can hold a value + /// of the same layout as `self`, but that also is aligned to + /// alignment `align` (measured in bytes). + /// + /// If `self` already meets the prescribed alignment, then returns + /// `self`. + /// + /// Note that this method does not add any padding to the overall + /// size, regardless of whether the returned layout has a different + /// alignment. In other words, if `K` has size 16, `K.align_to(32)` + /// will *still* have size 16. + /// + /// # Panics + /// + /// Panics if the combination of `self.size` and the given `align` + /// violates the conditions listed in `from_size_align`. + #[inline] + pub fn align_to(&self, align: usize) -> Self { + Layout::from_size_align(self.size, cmp::max(self.align, align)).unwrap() + } + + /// Returns the amount of padding we must insert after `self` + /// to ensure that the following address will satisfy `align` + /// (measured in bytes). + /// + /// E.g. if `self.size` is 9, then `self.padding_needed_for(4)` + /// returns 3, because that is the minimum number of bytes of + /// padding required to get a 4-aligned address (assuming that the + /// corresponding memory block starts at a 4-aligned address). + /// + /// The return value of this function has no meaning if `align` is + /// not a power-of-two. + /// + /// Note that the utility of the returned value requires `align` + /// to be less than or equal to the alignment of the starting + /// address for the whole allocated block of memory. One way to + /// satisfy this constraint is to ensure `align <= self.align`. + #[inline] + pub fn padding_needed_for(&self, align: usize) -> usize { + let len = self.size(); + + // Rounded up value is: + // len_rounded_up = (len + align - 1) & !(align - 1); + // and then we return the padding difference: `len_rounded_up - len`. + // + // We use modular arithmetic throughout: + // + // 1. align is guaranteed to be > 0, so align - 1 is always + // valid. + // + // 2. `len + align - 1` can overflow by at most `align - 1`, + // so the &-mask wth `!(align - 1)` will ensure that in the + // case of overflow, `len_rounded_up` will itself be 0. + // Thus the returned padding, when added to `len`, yields 0, + // which trivially satisfies the alignment `align`. + // + // (Of course, attempts to allocate blocks of memory whose + // size and padding overflow in the above manner should cause + // the allocator to yield an error anyway.) + + let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); + return len_rounded_up.wrapping_sub(len); + } + + /// Creates a layout describing the record for `n` instances of + /// `self`, with a suitable amount of padding between each to + /// ensure that each instance is given its requested size and + /// alignment. On success, returns `(k, offs)` where `k` is the + /// layout of the array and `offs` is the distance between the start + /// of each element in the array. + /// + /// On arithmetic overflow, returns `None`. + #[inline] + pub fn repeat(&self, n: usize) -> Option<(Self, usize)> { + let padded_size = self.size.checked_add(self.padding_needed_for(self.align))?; + let alloc_size = padded_size.checked_mul(n)?; + + // We can assume that `self.align` is a power-of-two that does + // not exceed 231. Furthermore, `alloc_size` has already been + // rounded up to a multiple of `self.align`; therefore, the + // call to `Layout::from_size_align` below should never panic. + Some((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) + } + + /// Creates a layout describing the record for `self` followed by + /// `next`, including any necessary padding to ensure that `next` + /// will be properly aligned. Note that the result layout will + /// satisfy the alignment properties of both `self` and `next`. + /// + /// Returns `Some((k, offset))`, where `k` is layout of the concatenated + /// record and `offset` is the relative location, in bytes, of the + /// start of the `next` embedded within the concatenated record + /// (assuming that the record itself starts at offset 0). + /// + /// On arithmetic overflow, returns `None`. + pub fn extend(&self, next: Self) -> Option<(Self, usize)> { + let new_align = cmp::max(self.align, next.align); + let realigned = Layout::from_size_align(self.size, new_align)?; + + let pad = realigned.padding_needed_for(next.align); + + let offset = self.size.checked_add(pad)?; + let new_size = offset.checked_add(next.size)?; + + let layout = Layout::from_size_align(new_size, new_align)?; + Some((layout, offset)) + } + + /// Creates a layout describing the record for `n` instances of + /// `self`, with no padding between each instance. + /// + /// Note that, unlike `repeat`, `repeat_packed` does not guarantee + /// that the repeated instances of `self` will be properly + /// aligned, even if a given instance of `self` is properly + /// aligned. In other words, if the layout returned by + /// `repeat_packed` is used to allocate an array, it is not + /// guaranteed that all elements in the array will be properly + /// aligned. + /// + /// On arithmetic overflow, returns `None`. + pub fn repeat_packed(&self, n: usize) -> Option { + let size = self.size().checked_mul(n)?; + Layout::from_size_align(size, self.align) + } + + /// Creates a layout describing the record for `self` followed by + /// `next` with no additional padding between the two. Since no + /// padding is inserted, the alignment of `next` is irrelevant, + /// and is not incorporated *at all* into the resulting layout. + /// + /// Returns `(k, offset)`, where `k` is layout of the concatenated + /// record and `offset` is the relative location, in bytes, of the + /// start of the `next` embedded within the concatenated record + /// (assuming that the record itself starts at offset 0). + /// + /// (The `offset` is always the same as `self.size()`; we use this + /// signature out of convenience in matching the signature of + /// `extend`.) + /// + /// On arithmetic overflow, returns `None`. + pub fn extend_packed(&self, next: Self) -> Option<(Self, usize)> { + let new_size = self.size().checked_add(next.size())?; + let layout = Layout::from_size_align(new_size, self.align)?; + Some((layout, self.size())) + } + + /// Creates a layout describing the record for a `[T; n]`. + /// + /// On arithmetic overflow, returns `None`. + pub fn array(n: usize) -> Option { + Layout::new::() + .repeat(n) + .map(|(k, offs)| { + debug_assert!(offs == mem::size_of::()); + k + }) + } +} + +/// The `AllocErr` error specifies whether an allocation failure is +/// specifically due to resource exhaustion or if it is due to +/// something wrong when combining the given input arguments with this +/// allocator. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum AllocErr { + /// Error due to hitting some resource limit or otherwise running + /// out of memory. This condition strongly implies that *some* + /// series of deallocations would allow a subsequent reissuing of + /// the original allocation request to succeed. + Exhausted { request: Layout }, + + /// Error due to allocator being fundamentally incapable of + /// satisfying the original request. This condition implies that + /// such an allocation request will never succeed on the given + /// allocator, regardless of environment, memory pressure, or + /// other contextual conditions. + /// + /// For example, an allocator that does not support requests for + /// large memory blocks might return this error variant. + Unsupported { details: &'static str }, +} + +impl AllocErr { + #[inline] + pub fn invalid_input(details: &'static str) -> Self { + AllocErr::Unsupported { details: details } + } + #[inline] + pub fn is_memory_exhausted(&self) -> bool { + if let AllocErr::Exhausted { .. } = *self { true } else { false } + } + #[inline] + pub fn is_request_unsupported(&self) -> bool { + if let AllocErr::Unsupported { .. } = *self { true } else { false } + } + #[inline] + pub fn description(&self) -> &str { + match *self { + AllocErr::Exhausted { .. } => "allocator memory exhausted", + AllocErr::Unsupported { .. } => "unsupported allocator request", + } + } +} + +// (we need this for downstream impl of trait Error) +impl fmt::Display for AllocErr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +/// The `CannotReallocInPlace` error is used when `grow_in_place` or +/// `shrink_in_place` were unable to reuse the given memory block for +/// a requested layout. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct CannotReallocInPlace; + +impl CannotReallocInPlace { + pub fn description(&self) -> &str { + "cannot reallocate allocator's memory in place" + } +} + +// (we need this for downstream impl of trait Error) +impl fmt::Display for CannotReallocInPlace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +/// Augments `AllocErr` with a CapacityOverflow variant. +#[derive(Clone, PartialEq, Eq, Debug)] +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +pub enum CollectionAllocErr { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + /// Error due to the allocator (see the `AllocErr` type's docs). + AllocErr(AllocErr), +} + +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +impl From for CollectionAllocErr { + fn from(err: AllocErr) -> Self { + CollectionAllocErr::AllocErr(err) + } +} + +/// An implementation of `Alloc` can allocate, reallocate, and +/// deallocate arbitrary blocks of data described via `Layout`. +/// +/// Some of the methods require that a memory block be *currently +/// allocated* via an allocator. This means that: +/// +/// * the starting address for that memory block was previously +/// returned by a previous call to an allocation method (`alloc`, +/// `alloc_zeroed`, `alloc_excess`, `alloc_one`, `alloc_array`) or +/// reallocation method (`realloc`, `realloc_excess`, or +/// `realloc_array`), and +/// +/// * the memory block has not been subsequently deallocated, where +/// blocks are deallocated either by being passed to a deallocation +/// method (`dealloc`, `dealloc_one`, `dealloc_array`) or by being +/// passed to a reallocation method (see above) that returns `Ok`. +/// +/// A note regarding zero-sized types and zero-sized layouts: many +/// methods in the `Alloc` trait state that allocation requests +/// must be non-zero size, or else undefined behavior can result. +/// +/// * However, some higher-level allocation methods (`alloc_one`, +/// `alloc_array`) are well-defined on zero-sized types and can +/// optionally support them: it is left up to the implementor +/// whether to return `Err`, or to return `Ok` with some pointer. +/// +/// * If an `Alloc` implementation chooses to return `Ok` in this +/// case (i.e. the pointer denotes a zero-sized inaccessible block) +/// then that returned pointer must be considered "currently +/// allocated". On such an allocator, *all* methods that take +/// currently-allocated pointers as inputs must accept these +/// zero-sized pointers, *without* causing undefined behavior. +/// +/// * In other words, if a zero-sized pointer can flow out of an +/// allocator, then that allocator must likewise accept that pointer +/// flowing back into its deallocation and reallocation methods. +/// +/// Some of the methods require that a layout *fit* a memory block. +/// What it means for a layout to "fit" a memory block means (or +/// equivalently, for a memory block to "fit" a layout) is that the +/// following two conditions must hold: +/// +/// 1. The block's starting address must be aligned to `layout.align()`. +/// +/// 2. The block's size must fall in the range `[use_min, use_max]`, where: +/// +/// * `use_min` is `self.usable_size(layout).0`, and +/// +/// * `use_max` is the capacity that was (or would have been) +/// returned when (if) the block was allocated via a call to +/// `alloc_excess` or `realloc_excess`. +/// +/// Note that: +/// +/// * the size of the layout most recently used to allocate the block +/// is guaranteed to be in the range `[use_min, use_max]`, and +/// +/// * a lower-bound on `use_max` can be safely approximated by a call to +/// `usable_size`. +/// +/// * if a layout `k` fits a memory block (denoted by `ptr`) +/// currently allocated via an allocator `a`, then it is legal to +/// use that layout to deallocate it, i.e. `a.dealloc(ptr, k);`. +/// +/// # Unsafety +/// +/// The `Alloc` trait is an `unsafe` trait for a number of reasons, and +/// implementors must ensure that they adhere to these contracts: +/// +/// * Pointers returned from allocation functions must point to valid memory and +/// retain their validity until at least the instance of `Alloc` is dropped +/// itself. +/// +/// * It's undefined behavior if global allocators unwind. This restriction may +/// be lifted in the future, but currently a panic from any of these +/// functions may lead to memory unsafety. Note that as of the time of this +/// writing allocators *not* intending to be global allocators can still panic +/// in their implementation without violating memory safety. +/// +/// * `Layout` queries and calculations in general must be correct. Callers of +/// this trait are allowed to rely on the contracts defined on each method, +/// and implementors must ensure such contracts remain true. +/// +/// Note that this list may get tweaked over time as clarifications are made in +/// the future. Additionally global allocators may gain unique requirements for +/// how to safely implement one in the future as well. +pub unsafe trait Alloc { + + // (Note: existing allocators have unspecified but well-defined + // behavior in response to a zero size allocation request ; + // e.g. in C, `malloc` of 0 will either return a null pointer or a + // unique pointer, but will not have arbitrary undefined + // behavior. Rust should consider revising the alloc::heap crate + // to reflect this reality.) + + /// Returns a pointer meeting the size and alignment guarantees of + /// `layout`. + /// + /// If this method returns an `Ok(addr)`, then the `addr` returned + /// will be non-null address pointing to a block of storage + /// suitable for holding an instance of `layout`. + /// + /// The returned block of storage may or may not have its contents + /// initialized. (Extension subtraits might restrict this + /// behavior, e.g. to ensure initialization to particular sets of + /// bit patterns.) + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure that `layout` has non-zero size. + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints. + /// + /// Implementations are encouraged to return `Err` on memory + /// exhaustion rather than panicking or aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; + + /// Deallocate the memory referenced by `ptr`. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must denote a block of memory currently allocated via + /// this allocator, + /// + /// * `layout` must *fit* that block of memory, + /// + /// * In addition to fitting the block of memory `layout`, the + /// alignment of the `layout` must match the alignment used + /// to allocate that block of memory. + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); + + /// Allocator-specific method for signaling an out-of-memory + /// condition. + /// + /// `oom` aborts the thread or process, optionally performing + /// cleanup or logging diagnostic information before panicking or + /// aborting. + /// + /// `oom` is meant to be used by clients unable to cope with an + /// unsatisfied allocation request (signaled by an error such as + /// `AllocErr::Exhausted`), and wish to abandon computation rather + /// than attempt to recover locally. Such clients should pass the + /// signaling error value back into `oom`, where the allocator + /// may incorporate that error value into its diagnostic report + /// before aborting. + /// + /// Implementations of the `oom` method are discouraged from + /// infinitely regressing in nested calls to `oom`. In + /// practice this means implementors should eschew allocating, + /// especially from `self` (directly or indirectly). + /// + /// Implementations of the allocation and reallocation methods + /// (e.g. `alloc`, `alloc_one`, `realloc`) are discouraged from + /// panicking (or aborting) in the event of memory exhaustion; + /// instead they should return an appropriate error from the + /// invoked method, and let the client decide whether to invoke + /// this `oom` method in response. + fn oom(&mut self, _: AllocErr) -> ! { + unsafe { ::intrinsics::abort() } + } + + // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS == + // usable_size + + /// Returns bounds on the guaranteed usable size of a successful + /// allocation created with the specified `layout`. + /// + /// In particular, if one has a memory block allocated via a given + /// allocator `a` and layout `k` where `a.usable_size(k)` returns + /// `(l, u)`, then one can pass that block to `a.dealloc()` with a + /// layout in the size range [l, u]. + /// + /// (All implementors of `usable_size` must ensure that + /// `l <= k.size() <= u`) + /// + /// Both the lower- and upper-bounds (`l` and `u` respectively) + /// are provided, because an allocator based on size classes could + /// misbehave if one attempts to deallocate a block without + /// providing a correct value for its size (i.e., one within the + /// range `[l, u]`). + /// + /// Clients who wish to make use of excess capacity are encouraged + /// to use the `alloc_excess` and `realloc_excess` instead, as + /// this method is constrained to report conservative values that + /// serve as valid bounds for *all possible* allocation method + /// calls. + /// + /// However, for clients that do not wish to track the capacity + /// returned by `alloc_excess` locally, this method is likely to + /// produce useful results. + #[inline] + fn usable_size(&self, layout: &Layout) -> (usize, usize) { + (layout.size(), layout.size()) + } + + // == METHODS FOR MEMORY REUSE == + // realloc. alloc_excess, realloc_excess + + /// Returns a pointer suitable for holding data described by + /// `new_layout`, meeting its size and alignment guarantees. To + /// accomplish this, this may extend or shrink the allocation + /// referenced by `ptr` to fit `new_layout`. + /// + /// If this returns `Ok`, then ownership of the memory block + /// referenced by `ptr` has been transferred to this + /// allocator. The memory may or may not have been freed, and + /// should be considered unusable (unless of course it was + /// transferred back to the caller again via the return value of + /// this method). + /// + /// If this method returns `Err`, then ownership of the memory + /// block has not been transferred to this allocator, and the + /// contents of the memory block are unaltered. + /// + /// For best results, `new_layout` should not impose a different + /// alignment constraint than `layout`. (In other words, + /// `new_layout.align()` should equal `layout.align()`.) However, + /// behavior is well-defined (though underspecified) when this + /// constraint is violated; further discussion below. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above). (The `new_layout` + /// argument need not fit it.) + /// + /// * `new_layout` must have size greater than zero. + /// + /// * the alignment of `new_layout` is non-zero. + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// # Errors + /// + /// Returns `Err` only if `new_layout` does not match the + /// alignment of `layout`, or does not meet the allocator's size + /// and alignment constraints of the allocator, or if reallocation + /// otherwise fails. + /// + /// (Note the previous sentence did not say "if and only if" -- in + /// particular, an implementation of this method *can* return `Ok` + /// if `new_layout.align() != old_layout.align()`; or it can + /// return `Err` in that scenario, depending on whether this + /// allocator can dynamically adjust the alignment constraint for + /// the block.) + /// + /// Implementations are encouraged to return `Err` on memory + /// exhaustion rather than panicking or aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an + /// reallocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn realloc(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<*mut u8, AllocErr> { + let new_size = new_layout.size(); + let old_size = layout.size(); + let aligns_match = layout.align == new_layout.align; + + if new_size >= old_size && aligns_match { + if let Ok(()) = self.grow_in_place(ptr, layout.clone(), new_layout.clone()) { + return Ok(ptr); + } + } else if new_size < old_size && aligns_match { + if let Ok(()) = self.shrink_in_place(ptr, layout.clone(), new_layout.clone()) { + return Ok(ptr); + } + } + + // otherwise, fall back on alloc + copy + dealloc. + let result = self.alloc(new_layout); + if let Ok(new_ptr) = result { + ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size)); + self.dealloc(ptr, layout); + } + result + } + + /// Behaves like `alloc`, but also ensures that the contents + /// are set to zero before being returned. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `alloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `alloc`. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + let size = layout.size(); + let p = self.alloc(layout); + if let Ok(p) = p { + ptr::write_bytes(p, 0, size); + } + p + } + + /// Behaves like `alloc`, but also returns the whole size of + /// the returned block. For some `layout` inputs, like arrays, this + /// may include extra storage usable for additional data. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `alloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `alloc`. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { + let usable_size = self.usable_size(&layout); + self.alloc(layout).map(|p| Excess(p, usable_size.1)) + } + + /// Behaves like `realloc`, but also returns the whole size of + /// the returned block. For some `layout` inputs, like arrays, this + /// may include extra storage usable for additional data. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `realloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `realloc`. + /// + /// Clients wishing to abort computation in response to an + /// reallocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn realloc_excess(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result { + let usable_size = self.usable_size(&new_layout); + self.realloc(ptr, layout, new_layout) + .map(|p| Excess(p, usable_size.1)) + } + + /// Attempts to extend the allocation referenced by `ptr` to fit `new_layout`. + /// + /// If this returns `Ok`, then the allocator has asserted that the + /// memory block referenced by `ptr` now fits `new_layout`, and thus can + /// be used to carry data of that layout. (The allocator is allowed to + /// expend effort to accomplish this, such as extending the memory block to + /// include successor blocks, or virtual memory tricks.) + /// + /// Regardless of what this method returns, ownership of the + /// memory block referenced by `ptr` has not been transferred, and + /// the contents of the memory block are unaltered. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above); note the + /// `new_layout` argument need not fit it, + /// + /// * `new_layout.size()` must not be less than `layout.size()`, + /// + /// * `new_layout.align()` must equal `layout.align()`. + /// + /// # Errors + /// + /// Returns `Err(CannotReallocInPlace)` when the allocator is + /// unable to assert that the memory block referenced by `ptr` + /// could fit `layout`. + /// + /// Note that one cannot pass `CannotReallocInPlace` to the `oom` + /// method; clients are expected either to be able to recover from + /// `grow_in_place` failures without aborting, or to fall back on + /// another reallocation method before resorting to an abort. + unsafe fn grow_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + let _ = ptr; // this default implementation doesn't care about the actual address. + debug_assert!(new_layout.size >= layout.size); + debug_assert!(new_layout.align == layout.align); + let (_l, u) = self.usable_size(&layout); + // _l <= layout.size() [guaranteed by usable_size()] + // layout.size() <= new_layout.size() [required by this method] + if new_layout.size <= u { + return Ok(()); + } else { + return Err(CannotReallocInPlace); + } + } + + /// Attempts to shrink the allocation referenced by `ptr` to fit `new_layout`. + /// + /// If this returns `Ok`, then the allocator has asserted that the + /// memory block referenced by `ptr` now fits `new_layout`, and + /// thus can only be used to carry data of that smaller + /// layout. (The allocator is allowed to take advantage of this, + /// carving off portions of the block for reuse elsewhere.) The + /// truncated contents of the block within the smaller layout are + /// unaltered, and ownership of block has not been transferred. + /// + /// If this returns `Err`, then the memory block is considered to + /// still represent the original (larger) `layout`. None of the + /// block has been carved off for reuse elsewhere, ownership of + /// the memory block has not been transferred, and the contents of + /// the memory block are unaltered. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above); note the + /// `new_layout` argument need not fit it, + /// + /// * `new_layout.size()` must not be greater than `layout.size()` + /// (and must be greater than zero), + /// + /// * `new_layout.align()` must equal `layout.align()`. + /// + /// # Errors + /// + /// Returns `Err(CannotReallocInPlace)` when the allocator is + /// unable to assert that the memory block referenced by `ptr` + /// could fit `layout`. + /// + /// Note that one cannot pass `CannotReallocInPlace` to the `oom` + /// method; clients are expected either to be able to recover from + /// `shrink_in_place` failures without aborting, or to fall back + /// on another reallocation method before resorting to an abort. + unsafe fn shrink_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + let _ = ptr; // this default implementation doesn't care about the actual address. + debug_assert!(new_layout.size <= layout.size); + debug_assert!(new_layout.align == layout.align); + let (l, _u) = self.usable_size(&layout); + // layout.size() <= _u [guaranteed by usable_size()] + // new_layout.size() <= layout.size() [required by this method] + if l <= new_layout.size { + return Ok(()); + } else { + return Err(CannotReallocInPlace); + } + } + + + // == COMMON USAGE PATTERNS == + // alloc_one, dealloc_one, alloc_array, realloc_array. dealloc_array + + /// Allocates a block suitable for holding an instance of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` + /// must be considered "currently allocated" and must be + /// acceptable input to methods such as `realloc` or `dealloc`, + /// *even if* `T` is a zero-sized type. In other words, if your + /// `Alloc` implementation overrides this method in a manner + /// that can return a zero-sized `ptr`, then all reallocation and + /// deallocation methods need to be similarly overridden to accept + /// such values as input. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `T` does not meet allocator's size or alignment constraints. + /// + /// For zero-sized `T`, may return either of `Ok` or `Err`, but + /// will *not* yield undefined behavior. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + fn alloc_one(&mut self) -> Result, AllocErr> + where Self: Sized + { + let k = Layout::new::(); + if k.size() > 0 { + unsafe { self.alloc(k).map(|p| NonNull::new_unchecked(p as *mut T)) } + } else { + Err(AllocErr::invalid_input("zero-sized type invalid for alloc_one")) + } + } + + /// Deallocates a block suitable for holding an instance of `T`. + /// + /// The given block must have been produced by this allocator, + /// and must be suitable for storing a `T` (in terms of alignment + /// as well as minimum and maximum size); otherwise yields + /// undefined behavior. + /// + /// Captures a common usage pattern for allocators. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure both: + /// + /// * `ptr` must denote a block of memory currently allocated via this allocator + /// + /// * the layout of `T` must *fit* that block of memory. + unsafe fn dealloc_one(&mut self, ptr: NonNull) + where Self: Sized + { + let raw_ptr = ptr.as_ptr() as *mut u8; + let k = Layout::new::(); + if k.size() > 0 { + self.dealloc(raw_ptr, k); + } + } + + /// Allocates a block suitable for holding `n` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` + /// must be considered "currently allocated" and must be + /// acceptable input to methods such as `realloc` or `dealloc`, + /// *even if* `T` is a zero-sized type. In other words, if your + /// `Alloc` implementation overrides this method in a manner + /// that can return a zero-sized `ptr`, then all reallocation and + /// deallocation methods need to be similarly overridden to accept + /// such values as input. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `[T; n]` does not meet allocator's size or alignment + /// constraints. + /// + /// For zero-sized `T` or `n == 0`, may return either of `Ok` or + /// `Err`, but will *not* yield undefined behavior. + /// + /// Always returns `Err` on arithmetic overflow. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + fn alloc_array(&mut self, n: usize) -> Result, AllocErr> + where Self: Sized + { + match Layout::array::(n) { + Some(ref layout) if layout.size() > 0 => { + unsafe { + self.alloc(layout.clone()) + .map(|p| { + NonNull::new_unchecked(p as *mut T) + }) + } + } + _ => Err(AllocErr::invalid_input("invalid layout for alloc_array")), + } + } + + /// Reallocates a block previously suitable for holding `n_old` + /// instances of `T`, returning a block suitable for holding + /// `n_new` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * the layout of `[T; n_old]` must *fit* that block of memory. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `[T; n_new]` does not meet allocator's size or alignment + /// constraints. + /// + /// For zero-sized `T` or `n_new == 0`, may return either of `Ok` or + /// `Err`, but will *not* yield undefined behavior. + /// + /// Always returns `Err` on arithmetic overflow. + /// + /// Clients wishing to abort computation in response to an + /// reallocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn realloc_array(&mut self, + ptr: NonNull, + n_old: usize, + n_new: usize) -> Result, AllocErr> + where Self: Sized + { + match (Layout::array::(n_old), Layout::array::(n_new), ptr.as_ptr()) { + (Some(ref k_old), Some(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { + self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone()) + .map(|p| NonNull::new_unchecked(p as *mut T)) + } + _ => { + Err(AllocErr::invalid_input("invalid layout for realloc_array")) + } + } + } + + /// Deallocates a block suitable for holding `n` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure both: + /// + /// * `ptr` must denote a block of memory currently allocated via this allocator + /// + /// * the layout of `[T; n]` must *fit* that block of memory. + /// + /// # Errors + /// + /// Returning `Err` indicates that either `[T; n]` or the given + /// memory block does not meet allocator's size or alignment + /// constraints. + /// + /// Always returns `Err` on arithmetic overflow. + unsafe fn dealloc_array(&mut self, ptr: NonNull, n: usize) -> Result<(), AllocErr> + where Self: Sized + { + let raw_ptr = ptr.as_ptr() as *mut u8; + match Layout::array::(n) { + Some(ref k) if k.size() > 0 => { + Ok(self.dealloc(raw_ptr, k.clone())) + } + _ => { + Err(AllocErr::invalid_input("invalid layout for dealloc_array")) + } + } + } +} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 11fecde3951..c77402ed442 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -185,6 +185,10 @@ pub mod hash; pub mod fmt; pub mod time; +/* Heap memory allocator trait */ +#[allow(missing_docs)] +pub mod heap; + // note: does not need to be public mod char_private; mod iter_private; diff --git a/src/libstd/heap.rs b/src/libstd/heap.rs index 4d5e4df6f95..4a391372c3a 100644 --- a/src/libstd/heap.rs +++ b/src/libstd/heap.rs @@ -12,8 +12,9 @@ #![unstable(issue = "32838", feature = "allocator_api")] -pub use alloc::heap::{Heap, Alloc, Layout, Excess, CannotReallocInPlace, AllocErr}; +pub use alloc::heap::Heap; pub use alloc_system::System; +pub use core::heap::*; #[cfg(not(test))] #[doc(hidden)] -- cgit 1.4.1-3-g733a5 From 0f5e4191632de4bbc1ef4ef2be26b517861cbff0 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Fri, 2 Mar 2018 06:52:27 +0100 Subject: Add a generic CAS loop to std::sync::Atomic* This adds a new method to all numeric `Atomic*` types with a safe compare-and-set loop, so users will no longer need to write their own, except in *very* strange circumstances. This solves #48384 with `x.fetch_max(_)`/`x.fetch_min(_)`. It also relates to #48655 (which I misuse as tracking issue for now). *note* This *might* need a crater run because the functions could clash with third party extension traits. --- src/libcore/sync/atomic.rs | 185 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index fe5ed5d4942..3d5f63f41b4 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -949,6 +949,7 @@ macro_rules! atomic_int { $stable_nand:meta, $s_int_type:expr, $int_ref:expr, $extra_feature:expr, + $min_fn:ident, $max_fn:ident, $int_type:ident $atomic_type:ident $atomic_init:ident) => { /// An integer type which can be safely shared between threads. /// @@ -1418,6 +1419,128 @@ assert_eq!(foo.load(Ordering::SeqCst), 0b011110); unsafe { atomic_xor(self.v.get(), val, order) } } } + + doc_comment! { + concat!("Fetches the value, and applies a function to it that returns an optional +new value. Returns a `Result` (`Ok(_)` if the function returned `Some(_)`, else `Err(_)`) of the +previous value. + +Note: This may call the function multiple times if the value has been changed from other threads in +the meantime, as long as the function returns `Some(_)`, but the function will have been applied +but once to the stored value. + +# Examples + +```rust +#![feature(no_more_cas)] +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let x = ", stringify!($atomic_type), "::new(7); +assert_eq!(x.fetch_update(|_| None, Ordering::SeqCst, Ordering::SeqCst), Err(7)); +assert_eq!(x.fetch_update(|x| Some(x + 1), Ordering::SeqCst, Ordering::SeqCst), Ok(7)); +assert_eq!(x.fetch_update(|x| Some(x + 1), Ordering::SeqCst, Ordering::SeqCst), Ok(8)); +assert_eq!(x.load(Ordering::SeqCst), 9); +```"), + #[inline] + #[unstable(feature = "no_more_cas", + reason = "no more CAS loops in user code", + issue = "48655")] + pub fn fetch_update(&self, + mut f: F, + fetch_order: Ordering, + set_order: Ordering) -> Result<$int_type, $int_type> + where F: FnMut($int_type) -> Option<$int_type> { + let mut prev = self.load(fetch_order); + while let Some(next) = f(prev) { + match self.compare_exchange_weak(prev, next, set_order, fetch_order) { + x @ Ok(_) => return x, + Err(next_prev) => prev = next_prev + } + } + Err(prev) + } + } + + doc_comment! { + concat!("Maximum with the current value. + +Finds the maximum of the current value and the argument `val`, and +sets the new value to the result. + +Returns the previous value. + +# Examples + +``` +#![feature(atomic_min_max)] +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(23); +assert_eq!(foo.fetch_max(42, Ordering::SeqCst), 23); +assert_eq!(foo.load(Ordering::SeqCst), 42); +``` + +If you want to obtain the maximum value in one step, you can use the following: + +``` +#![feature(atomic_min_max)] +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(23); +let bar = 42; +let max_foo = foo.fetch_max(bar, Ordering::SeqCst).max(bar); +assert!(max_foo == 42); +```"), + #[inline] + #[unstable(feature = "atomic_min_max", + reason = "easier and faster min/max than writing manual CAS loop", + issue = "48655")] + pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { $max_fn(self.v.get(), val, order) } + } + } + + doc_comment! { + concat!("Minimum with the current value. + +Finds the minimum of the current value and the argument `val`, and +sets the new value to the result. + +Returns the previous value. + +# Examples + +``` +#![feature(atomic_min_max)] +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(23); +assert_eq!(foo.fetch_min(42, Ordering::Relaxed), 23); +assert_eq!(foo.load(Ordering::Relaxed), 23); +assert_eq!(foo.fetch_min(22, Ordering::Relaxed), 23); +assert_eq!(foo.load(Ordering::Relaxed), 22); +``` + +If you want to obtain the minimum value in one step, you can use the following: + +``` +#![feature(atomic_min_max)] +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let foo = ", stringify!($atomic_type), "::new(23); +let bar = 12; +let min_foo = foo.fetch_min(bar, Ordering::SeqCst).min(bar); +assert_eq!(min_foo, 12); +```"), + #[inline] + #[unstable(feature = "atomic_min_max", + reason = "easier and faster min/max than writing manual CAS loop", + issue = "48655")] + pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type { + unsafe { $min_fn(self.v.get(), val, order) } + } + } + } } } @@ -1432,6 +1555,7 @@ atomic_int! { unstable(feature = "atomic_nand", issue = "13226"), "i8", "../../../std/primitive.i8.html", "#![feature(integer_atomics)]\n\n", + atomic_min, atomic_max, i8 AtomicI8 ATOMIC_I8_INIT } #[cfg(target_has_atomic = "8")] @@ -1444,6 +1568,7 @@ atomic_int! { unstable(feature = "atomic_nand", issue = "13226"), "u8", "../../../std/primitive.u8.html", "#![feature(integer_atomics)]\n\n", + atomic_umin, atomic_umax, u8 AtomicU8 ATOMIC_U8_INIT } #[cfg(target_has_atomic = "16")] @@ -1456,6 +1581,7 @@ atomic_int! { unstable(feature = "atomic_nand", issue = "13226"), "i16", "../../../std/primitive.i16.html", "#![feature(integer_atomics)]\n\n", + atomic_min, atomic_max, i16 AtomicI16 ATOMIC_I16_INIT } #[cfg(target_has_atomic = "16")] @@ -1468,6 +1594,7 @@ atomic_int! { unstable(feature = "atomic_nand", issue = "13226"), "u16", "../../../std/primitive.u16.html", "#![feature(integer_atomics)]\n\n", + atomic_umin, atomic_umax, u16 AtomicU16 ATOMIC_U16_INIT } #[cfg(target_has_atomic = "32")] @@ -1480,6 +1607,7 @@ atomic_int! { unstable(feature = "atomic_nand", issue = "13226"), "i32", "../../../std/primitive.i32.html", "#![feature(integer_atomics)]\n\n", + atomic_min, atomic_max, i32 AtomicI32 ATOMIC_I32_INIT } #[cfg(target_has_atomic = "32")] @@ -1492,6 +1620,7 @@ atomic_int! { unstable(feature = "atomic_nand", issue = "13226"), "u32", "../../../std/primitive.u32.html", "#![feature(integer_atomics)]\n\n", + atomic_umin, atomic_umax, u32 AtomicU32 ATOMIC_U32_INIT } #[cfg(target_has_atomic = "64")] @@ -1504,6 +1633,7 @@ atomic_int! { unstable(feature = "atomic_nand", issue = "13226"), "i64", "../../../std/primitive.i64.html", "#![feature(integer_atomics)]\n\n", + atomic_min, atomic_max, i64 AtomicI64 ATOMIC_I64_INIT } #[cfg(target_has_atomic = "64")] @@ -1516,6 +1646,7 @@ atomic_int! { unstable(feature = "atomic_nand", issue = "13226"), "u64", "../../../std/primitive.u64.html", "#![feature(integer_atomics)]\n\n", + atomic_umin, atomic_umax, u64 AtomicU64 ATOMIC_U64_INIT } #[cfg(target_has_atomic = "ptr")] @@ -1528,6 +1659,7 @@ atomic_int!{ unstable(feature = "atomic_nand", issue = "13226"), "isize", "../../../std/primitive.isize.html", "", + atomic_min, atomic_max, isize AtomicIsize ATOMIC_ISIZE_INIT } #[cfg(target_has_atomic = "ptr")] @@ -1540,6 +1672,7 @@ atomic_int!{ unstable(feature = "atomic_nand", issue = "13226"), "usize", "../../../std/primitive.usize.html", "", + atomic_umin, atomic_umax, usize AtomicUsize ATOMIC_USIZE_INIT } @@ -1717,6 +1850,58 @@ unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { } } +/// returns the max value (signed comparison) +#[inline] +unsafe fn atomic_max(dst: *mut T, val: T, order: Ordering) -> T { + match order { + Acquire => intrinsics::atomic_max_acq(dst, val), + Release => intrinsics::atomic_max_rel(dst, val), + AcqRel => intrinsics::atomic_max_acqrel(dst, val), + Relaxed => intrinsics::atomic_max_relaxed(dst, val), + SeqCst => intrinsics::atomic_max(dst, val), + __Nonexhaustive => panic!("invalid memory ordering"), + } +} + +/// returns the min value (signed comparison) +#[inline] +unsafe fn atomic_min(dst: *mut T, val: T, order: Ordering) -> T { + match order { + Acquire => intrinsics::atomic_min_acq(dst, val), + Release => intrinsics::atomic_min_rel(dst, val), + AcqRel => intrinsics::atomic_min_acqrel(dst, val), + Relaxed => intrinsics::atomic_min_relaxed(dst, val), + SeqCst => intrinsics::atomic_min(dst, val), + __Nonexhaustive => panic!("invalid memory ordering"), + } +} + +/// returns the max value (signed comparison) +#[inline] +unsafe fn atomic_umax(dst: *mut T, val: T, order: Ordering) -> T { + match order { + Acquire => intrinsics::atomic_umax_acq(dst, val), + Release => intrinsics::atomic_umax_rel(dst, val), + AcqRel => intrinsics::atomic_umax_acqrel(dst, val), + Relaxed => intrinsics::atomic_umax_relaxed(dst, val), + SeqCst => intrinsics::atomic_umax(dst, val), + __Nonexhaustive => panic!("invalid memory ordering"), + } +} + +/// returns the min value (signed comparison) +#[inline] +unsafe fn atomic_umin(dst: *mut T, val: T, order: Ordering) -> T { + match order { + Acquire => intrinsics::atomic_umin_acq(dst, val), + Release => intrinsics::atomic_umin_rel(dst, val), + AcqRel => intrinsics::atomic_umin_acqrel(dst, val), + Relaxed => intrinsics::atomic_umin_relaxed(dst, val), + SeqCst => intrinsics::atomic_umin(dst, val), + __Nonexhaustive => panic!("invalid memory ordering"), + } +} + /// An atomic fence. /// /// Depending on the specified order, a fence prevents the compiler and CPU from -- cgit 1.4.1-3-g733a5 From ba4f310e3fc961af7b9e6db52c53b51244473ae7 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 30 Mar 2018 15:54:05 +0200 Subject: Revert "Add TryFrom and TryInto to the prelude" This reverts commit 09008cc23ff6395c2c928f3690e07d7389d08ebc. --- src/libcore/prelude/v1.rs | 3 --- src/libstd/prelude/v1.rs | 2 -- 2 files changed, 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index 2c8e27abac9..d43496c387c 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -39,9 +39,6 @@ pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use convert::{AsRef, AsMut, Into, From}; -#[stable(feature = "try_from", since = "1.26.0")] -#[doc(no_inline)] -pub use convert::{TryFrom, TryInto}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use default::Default; diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index d5b7c68a3fa..feedd4e1abe 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -35,8 +35,6 @@ #[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use convert::{AsRef, AsMut, Into, From}; -#[stable(feature = "try_from", since = "1.26.0")] -#[doc(no_inline)] pub use convert::{TryFrom, TryInto}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use default::Default; #[stable(feature = "rust1", since = "1.0.0")] -- cgit 1.4.1-3-g733a5 From cea018f290f05b32ca6b5bcb2f8599d20b5de75c Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 24 Mar 2018 11:15:10 +0100 Subject: Deprecate signed std::num::NonZeroI* with a call for use cases --- src/libcore/lib.rs | 1 + src/libcore/num/mod.rs | 30 +++++++++++++++++++++++------- src/libstd/num.rs | 1 + 3 files changed, 25 insertions(+), 7 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 11fecde3951..9c791597175 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -86,6 +86,7 @@ #![feature(lang_items)] #![feature(link_llvm_intrinsics)] #![feature(exhaustive_patterns)] +#![feature(macro_at_most_once_rep)] #![feature(no_core)] #![feature(on_unimplemented)] #![feature(optin_builtin_traits)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index ee041e1e4f1..dcda404721c 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -23,6 +23,7 @@ macro_rules! impl_nonzero_fmt { ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { $( #[$stability] + #[allow(deprecated)] impl fmt::$Trait for $Ty { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -34,7 +35,7 @@ macro_rules! impl_nonzero_fmt { } macro_rules! nonzero_integers { - ( #[$stability: meta] $( $Ty: ident($Int: ty); )+ ) => { + ( #[$stability: meta] #[$deprecation: meta] $( $Ty: ident($Int: ty); )+ ) => { $( /// An integer that is known not to equal zero. /// @@ -46,6 +47,7 @@ macro_rules! nonzero_integers { /// assert_eq!(size_of::>(), size_of::()); /// ``` #[$stability] + #[$deprecation] #[allow(deprecated)] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct $Ty(NonZero<$Int>); @@ -93,12 +95,26 @@ macro_rules! nonzero_integers { nonzero_integers! { #[unstable(feature = "nonzero", issue = "49137")] - NonZeroU8(u8); NonZeroI8(i8); - NonZeroU16(u16); NonZeroI16(i16); - NonZeroU32(u32); NonZeroI32(i32); - NonZeroU64(u64); NonZeroI64(i64); - NonZeroU128(u128); NonZeroI128(i128); - NonZeroUsize(usize); NonZeroIsize(isize); + #[allow(deprecated)] // Redundant, works around "error: inconsistent lockstep iteration" + NonZeroU8(u8); + NonZeroU16(u16); + NonZeroU32(u32); + NonZeroU64(u64); + NonZeroU128(u128); + NonZeroUsize(usize); +} + +nonzero_integers! { + #[unstable(feature = "nonzero", issue = "49137")] + #[rustc_deprecated(since = "1.26.0", reason = "\ + signed non-zero integers are considered for removal due to lack of known use cases. \ + If you’re using them, please comment on https://github.com/rust-lang/rust/issues/49137")] + NonZeroI8(i8); + NonZeroI16(i16); + NonZeroI32(i32); + NonZeroI64(i64); + NonZeroI128(i128); + NonZeroIsize(isize); } /// Provides intentionally-wrapped arithmetic on `T`. diff --git a/src/libstd/num.rs b/src/libstd/num.rs index 547b8c7c925..4b975dd912a 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -22,6 +22,7 @@ pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError} pub use core::num::Wrapping; #[unstable(feature = "nonzero", issue = "49137")] +#[allow(deprecated)] pub use core::num::{ NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize, -- cgit 1.4.1-3-g733a5 From 5057e3c9e10f329d39a0e45607cf6a9ab467f7bf Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Sat, 31 Mar 2018 01:13:02 -0400 Subject: Commit code for option size hint --- src/libcore/option.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 1ca69f3f503..61ef6798b2e 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -1191,7 +1191,12 @@ impl> FromIterator> for Option { #[inline] fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() + if self.found_none { + (0, Some(0)) + } else { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } } } -- cgit 1.4.1-3-g733a5 From fb7deda27419eae61da3cbf5a5b1b4f51ae16d04 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 30 Mar 2018 23:06:05 -0700 Subject: Add #[must_use] to a few standard library methods Chosen to start a precedent of using it on ones that are potentially-expensive and where using it for side effects is particularly discouraged. Discuss :) --- src/liballoc/borrow.rs | 1 + src/libcore/clone.rs | 1 + src/libcore/iter/iterator.rs | 1 + src/librustc_mir/build/mod.rs | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index acae0daa86b..c6741ddb822 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -59,6 +59,7 @@ pub trait ToOwned { /// let vv: Vec = v.to_owned(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "cloning is often expensive and is not expected to have side effects"] fn to_owned(&self) -> Self::Owned; /// Uses borrowed data to replace owned data, usually by cloning. diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index d25f498b99e..c175ae15d28 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -105,6 +105,7 @@ pub trait Clone : Sized { /// assert_eq!("Hello", hello.clone()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "cloning is often expensive and is not expected to have side effects"] fn clone(&self) -> Self; /// Performs copy-assignment from `source`. diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 31f77f92435..42fd9051292 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1368,6 +1368,7 @@ pub trait Iterator { /// [`Result`]: ../../std/result/enum.Result.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"] fn collect>(self) -> B where Self: Sized { FromIterator::from_iter(self) } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 8494c043f90..6f5fcc9e421 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -317,7 +317,7 @@ newtype_index!(ScopeId); /// macro (and methods below) makes working with `BlockAnd` much more /// convenient. -#[must_use] // if you don't use one of these results, you're leaving a dangling edge +#[must_use = "if you don't use one of these results, you're leaving a dangling edge"] struct BlockAnd(BasicBlock, T); trait BlockAndExtension { -- cgit 1.4.1-3-g733a5 From b394165538bc52063f79a1820135cfefa19370e7 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 31 Mar 2018 22:35:37 -0700 Subject: Deprecate offset_to; switch core&alloc to using offset_from instead Bonus: might make code than uses `.len()` on slice iterators faster --- src/liballoc/lib.rs | 2 +- src/liballoc/vec.rs | 7 ++++--- src/libcore/ptr.rs | 12 ++++++++---- src/libcore/slice/mod.rs | 11 ++++++----- 4 files changed, 19 insertions(+), 13 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index e98b58994bf..009441e1680 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -103,13 +103,13 @@ #![feature(lang_items)] #![feature(needs_allocator)] #![feature(nonzero)] -#![feature(offset_to)] #![feature(optin_builtin_traits)] #![feature(pattern)] #![feature(pin)] #![feature(placement_in_syntax)] #![feature(placement_new_protocol)] #![feature(ptr_internals)] +#![feature(ptr_offset_from)] #![feature(rustc_attrs)] #![feature(slice_get_slice)] #![feature(slice_rsplit)] diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 2eedb964f88..d8ec956df8a 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2338,9 +2338,10 @@ impl Iterator for IntoIter { #[inline] fn size_hint(&self) -> (usize, Option) { - let exact = match self.ptr.offset_to(self.end) { - Some(x) => x as usize, - None => (self.end as usize).wrapping_sub(self.ptr as usize), + let exact = if mem::size_of::() == 0 { + (self.end as usize).wrapping_sub(self.ptr as usize) + } else { + unsafe { self.end.offset_from(self.ptr) as usize } }; (exact, Some(exact)) } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 5a54de06b5e..c1e150e9fb9 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -677,6 +677,7 @@ impl *const T { /// /// ``` /// #![feature(offset_to)] + /// #![allow(deprecated)] /// /// fn main() { /// let a = [0; 5]; @@ -689,14 +690,15 @@ impl *const T { /// } /// ``` #[unstable(feature = "offset_to", issue = "41079")] + #[rustc_deprecated(since = "1.27.0", reason = "Replaced by `wrapping_offset_from`, with the \ + opposite argument order. If you're writing unsafe code, consider `offset_from`.")] #[inline] pub fn offset_to(self, other: *const T) -> Option where T: Sized { let size = mem::size_of::(); if size == 0 { None } else { - let diff = (other as isize).wrapping_sub(self as isize); - Some(diff / size as isize) + Some(other.wrapping_offset_from(self)) } } @@ -1442,6 +1444,7 @@ impl *mut T { /// /// ``` /// #![feature(offset_to)] + /// #![allow(deprecated)] /// /// fn main() { /// let mut a = [0; 5]; @@ -1454,14 +1457,15 @@ impl *mut T { /// } /// ``` #[unstable(feature = "offset_to", issue = "41079")] + #[rustc_deprecated(since = "1.27.0", reason = "Replaced by `wrapping_offset_from`, with the \ + opposite argument order. If you're writing unsafe code, consider `offset_from`.")] #[inline] pub fn offset_to(self, other: *const T) -> Option where T: Sized { let size = mem::size_of::(); if size == 0 { None } else { - let diff = (other as isize).wrapping_sub(self as isize); - Some(diff / size as isize) + Some(other.wrapping_offset_from(self)) } } diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 0f1b7cb8fcc..0a22028da81 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1185,7 +1185,7 @@ macro_rules! iterator { #[inline] fn size_hint(&self) -> (usize, Option) { - let exact = ptrdistance(self.ptr, self.end); + let exact = unsafe { ptrdistance(self.ptr, self.end) }; (exact, Some(exact)) } @@ -1593,10 +1593,11 @@ unsafe impl<'a, T> TrustedLen for IterMut<'a, T> {} // Return the number of elements of `T` from `start` to `end`. // Return the arithmetic difference if `T` is zero size. #[inline(always)] -fn ptrdistance(start: *const T, end: *const T) -> usize { - match start.offset_to(end) { - Some(x) => x as usize, - None => (end as usize).wrapping_sub(start as usize), +unsafe fn ptrdistance(start: *const T, end: *const T) -> usize { + if mem::size_of::() == 0 { + (end as usize).wrapping_sub(start as usize) + } else { + end.offset_from(start) as usize } } -- cgit 1.4.1-3-g733a5 From da9e18b3dbf2edee36bdcc274b771493a4d4afc1 Mon Sep 17 00:00:00 2001 From: Anders Pitman Date: Sun, 1 Apr 2018 16:19:42 -0700 Subject: Update drop.rs --- src/libcore/ops/drop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/drop.rs b/src/libcore/ops/drop.rs index 70ab7b2f3b7..474f7e34c34 100644 --- a/src/libcore/ops/drop.rs +++ b/src/libcore/ops/drop.rs @@ -95,7 +95,7 @@ pub trait Drop { /// Executes the destructor for this type. /// - /// This method is called implilcitly when the value goes out of scope, + /// This method is called implicitly when the value goes out of scope, /// and cannot be called explicitly (this is compiler error [E0040]). /// However, the [`std::mem::drop`] function in the prelude can be /// used to call the argument's `Drop` implementation. -- cgit 1.4.1-3-g733a5 From 98175a8793942a60bce944050ba4fcb1cd067055 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Mon, 2 Apr 2018 11:06:19 +0900 Subject: Reject huge alignments on macos with system allocator only ef8804ba277b055fdc3e6d148e680e3c1b597ad8 addressed #30170 by rejecting huge alignments at the allocator API level, transforming a specific platform bug/limitation into an enforced API limitation on all platforms. This change essentially reverts that commit, and instead makes alloc() itself return AllocErr::Unsupported when receiving huge alignments. This was discussed in https://github.com/rust-lang/rust/issues/32838#issuecomment-368348408 and following. --- src/liballoc_system/lib.rs | 8 ++++++++ src/libcore/heap.rs | 21 +++++++-------------- 2 files changed, 15 insertions(+), 14 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 1d5e7b73be5..1175aafb4a3 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -134,6 +134,14 @@ mod platform { let ptr = if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { libc::malloc(layout.size()) as *mut u8 } else { + #[cfg(target_os = "macos")] + { + if layout.align() > (1 << 31) { + return Err(AllocErr::Unsupported { + details: "requested alignment too large" + }) + } + } aligned_malloc(&layout) }; if !ptr.is_null() { diff --git a/src/libcore/heap.rs b/src/libcore/heap.rs index dae60b1647f..fe19c923a58 100644 --- a/src/libcore/heap.rs +++ b/src/libcore/heap.rs @@ -65,13 +65,11 @@ pub struct Layout { impl Layout { /// Constructs a `Layout` from a given `size` and `align`, - /// or returns `None` if any of the following conditions + /// or returns `None` if either of the following conditions /// are not met: /// /// * `align` must be a power of two, /// - /// * `align` must not exceed 231 (i.e. `1 << 31`), - /// /// * `size`, when rounded up to the nearest multiple of `align`, /// must not overflow (i.e. the rounded value must be less than /// `usize::MAX`). @@ -81,10 +79,6 @@ impl Layout { return None; } - if align > (1 << 31) { - return None; - } - // (power-of-two implies align != 0.) // Rounded up size is: @@ -113,9 +107,8 @@ impl Layout { /// # Safety /// /// This function is unsafe as it does not verify that `align` is - /// a power-of-two that is also less than or equal to 231, nor - /// that `size` aligned to `align` fits within the address space - /// (i.e. the `Layout::from_size_align` preconditions). + /// a power-of-two nor `size` aligned to `align` fits within the + /// address space (i.e. the `Layout::from_size_align` preconditions). #[inline] pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout { Layout { size: size, align: align } @@ -220,10 +213,10 @@ impl Layout { let padded_size = self.size.checked_add(self.padding_needed_for(self.align))?; let alloc_size = padded_size.checked_mul(n)?; - // We can assume that `self.align` is a power-of-two that does - // not exceed 231. Furthermore, `alloc_size` has already been - // rounded up to a multiple of `self.align`; therefore, the - // call to `Layout::from_size_align` below should never panic. + // We can assume that `self.align` is a power-of-two. + // Furthermore, `alloc_size` has already been rounded up + // to a multiple of `self.align`; therefore, the call to + // `Layout::from_size_align` below should never panic. Some((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) } -- cgit 1.4.1-3-g733a5 From 5152a6f2852f5200665a591bbf59e7e827a68af4 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Sun, 1 Apr 2018 22:11:51 -0600 Subject: Stabilize `Option::filter`. Fixes #45860 --- src/libcore/option.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 61ef6798b2e..002fe68ad9b 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -639,7 +639,7 @@ impl Option { /// assert_eq!(Some(4).filter(is_even), Some(4)); /// ``` #[inline] - #[unstable(feature = "option_filter", issue = "45860")] + #[stable(feature = "option_filter", since = "1.27.0")] pub fn filter bool>(self, predicate: P) -> Self { if let Some(x) = self { if predicate(&x) { -- cgit 1.4.1-3-g733a5 From 591dd5d992ef5c9eb6a37cf9870c5f094d6363e4 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 16 Mar 2018 19:38:25 +0300 Subject: Add Iterator::find_map --- src/libcore/iter/iterator.rs | 32 ++++++++++++++++++++++++++++++++ src/libcore/tests/iter.rs | 27 +++++++++++++++++++++++++++ src/libcore/tests/lib.rs | 1 + 3 files changed, 60 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 31f77f92435..f039d1730eb 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1745,6 +1745,38 @@ pub trait Iterator { }).break_value() } + /// Applies function to the elements of iterator and returns + /// the first non-none result. + /// + /// `iter.find_map(f)` is equivalent to `iter.filter_map(f).next()`. + /// + /// + /// # Examples + /// + /// ``` + /// #![feature(iterator_find_map)] + /// let a = ["lol", "NaN", "2", "5"]; + /// + /// let mut first_number = a.iter().find_map(|s| s.parse().ok()); + /// + /// assert_eq!(first_number, Some(2)); + /// ``` + #[inline] + #[unstable(feature = "iterator_find_map", + reason = "unstable new API", + issue = "49602")] + fn find_map(&mut self, mut f: F) -> Option where + Self: Sized, + F: FnMut(Self::Item) -> Option, + { + self.try_for_each(move |x| { + match f(x) { + Some(x) => LoopState::Break(x), + None => LoopState::Continue(()), + } + }).break_value() + } + /// Searches for an element in an iterator, returning its index. /// /// `position()` takes a closure that returns `true` or `false`. It applies diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index a962efadd64..2abac0cf1d5 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1146,6 +1146,33 @@ fn test_find() { assert!(v.iter().find(|&&x| x % 12 == 0).is_none()); } +#[test] +fn test_find_map() { + let xs: &[isize] = &[]; + assert_eq!(xs.iter().find_map(half_if_even), None); + let xs: &[isize] = &[3, 5]; + assert_eq!(xs.iter().find_map(half_if_even), None); + let xs: &[isize] = &[4, 5]; + assert_eq!(xs.iter().find_map(half_if_even), Some(2)); + let xs: &[isize] = &[3, 6]; + assert_eq!(xs.iter().find_map(half_if_even), Some(3)); + + let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7]; + let mut iter = xs.iter(); + assert_eq!(iter.find_map(half_if_even), Some(1)); + assert_eq!(iter.find_map(half_if_even), Some(2)); + assert_eq!(iter.find_map(half_if_even), Some(3)); + assert_eq!(iter.next(), Some(&7)); + + fn half_if_even(x: &isize) -> Option { + if x % 2 == 0 { + Some(x / 2) + } else { + None + } + } +} + #[test] fn test_position() { let v = &[1, 3, 9, 27, 103, 14, 11]; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 0b70f692403..9dfe12a979e 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -49,6 +49,7 @@ #![feature(atomic_nand)] #![feature(reverse_bits)] #![feature(inclusive_range_fields)] +#![feature(iterator_find_map)] extern crate core; extern crate test; -- cgit 1.4.1-3-g733a5 From 1c8d10bce503bdd66921005dbd0b86a31745e5a7 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 2 Apr 2018 16:33:09 -0700 Subject: Stabilize iter_rfold in 1.27.0 --- src/liballoc/lib.rs | 1 - src/libcore/iter/traits.rs | 4 +--- src/libcore/tests/lib.rs | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index e6a311041f5..cbdb135c78c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -100,7 +100,6 @@ #![feature(fundamental)] #![feature(generic_param_attrs)] #![cfg_attr(stage0, feature(i128_type))] -#![feature(iter_rfold)] #![feature(lang_items)] #![feature(needs_allocator)] #![feature(nonzero)] diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index c3aebc4fb23..f84dc98912f 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -491,7 +491,6 @@ pub trait DoubleEndedIterator: Iterator { /// Basic usage: /// /// ``` - /// #![feature(iter_rfold)] /// let a = [1, 2, 3]; /// /// // the sum of all of the elements of a @@ -505,7 +504,6 @@ pub trait DoubleEndedIterator: Iterator { /// and continuing with each element from the back until the front: /// /// ``` - /// #![feature(iter_rfold)] /// let numbers = [1, 2, 3, 4, 5]; /// /// let zero = "0".to_string(); @@ -517,7 +515,7 @@ pub trait DoubleEndedIterator: Iterator { /// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))"); /// ``` #[inline] - #[unstable(feature = "iter_rfold", issue = "44705")] + #[stable(feature = "iter_rfold", since = "1.27.0")] fn rfold(mut self, accum: B, mut f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 1a68f04532d..e04968a6359 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -29,7 +29,6 @@ #![feature(iterator_flatten)] #![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(iter_rfind)] -#![feature(iter_rfold)] #![feature(iterator_repeat_with)] #![feature(nonzero)] #![feature(pattern)] -- cgit 1.4.1-3-g733a5 From d8c4c83dadb3a8d539bf0f4ad8260bc87420ca37 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 2 Apr 2018 16:37:06 -0700 Subject: Stabilize iter_rfind in 1.27.0 --- src/libcore/iter/traits.rs | 8 ++------ src/libcore/tests/lib.rs | 1 - 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index f84dc98912f..ee278651c8d 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -522,7 +522,7 @@ pub trait DoubleEndedIterator: Iterator { self.try_rfold(accum, move |acc, x| AlwaysOk(f(acc, x))).0 } - /// Searches for an element of an iterator from the right that satisfies a predicate. + /// Searches for an element of an iterator from the back that satisfies a predicate. /// /// `rfind()` takes a closure that returns `true` or `false`. It applies /// this closure to each element of the iterator, starting at the end, and if any @@ -545,8 +545,6 @@ pub trait DoubleEndedIterator: Iterator { /// Basic usage: /// /// ``` - /// #![feature(iter_rfind)] - /// /// let a = [1, 2, 3]; /// /// assert_eq!(a.iter().rfind(|&&x| x == 2), Some(&2)); @@ -557,8 +555,6 @@ pub trait DoubleEndedIterator: Iterator { /// Stopping at the first `true`: /// /// ``` - /// #![feature(iter_rfind)] - /// /// let a = [1, 2, 3]; /// /// let mut iter = a.iter(); @@ -569,7 +565,7 @@ pub trait DoubleEndedIterator: Iterator { /// assert_eq!(iter.next_back(), Some(&1)); /// ``` #[inline] - #[unstable(feature = "iter_rfind", issue = "39480")] + #[stable(feature = "iter_rfind", since = "1.27.0")] fn rfind

(&self, pred: P) -> Split where P: FnMut(&Self::Item) -> bool; - #[unstable(feature = "slice_rsplit", issue = "41020")] + #[stable(feature = "slice_rsplit", since = "1.27.0")] fn rsplit

(&self, pred: P) -> RSplit where P: FnMut(&Self::Item) -> bool; @@ -169,7 +169,7 @@ pub trait SliceExt { fn split_mut

(&mut self, pred: P) -> SplitMut where P: FnMut(&Self::Item) -> bool; - #[unstable(feature = "slice_rsplit", issue = "41020")] + #[stable(feature = "slice_rsplit", since = "1.27.0")] fn rsplit_mut

(&mut self, pred: P) -> RSplitMut where P: FnMut(&Self::Item) -> bool; @@ -1840,13 +1840,13 @@ impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool { /// /// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit /// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] #[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`? pub struct RSplit<'a, T:'a, P> where P: FnMut(&T) -> bool { inner: Split<'a, T, P> } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplit<'a, T, P> where P: FnMut(&T) -> bool { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("RSplit") @@ -1856,7 +1856,7 @@ impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplit<'a, T, P> where P: FnMut(& } } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T, P> Iterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool { type Item = &'a [T]; @@ -1871,7 +1871,7 @@ impl<'a, T, P> Iterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool { } } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool { #[inline] fn next_back(&mut self) -> Option<&'a [T]> { @@ -1879,7 +1879,7 @@ impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bo } } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool { #[inline] fn finish(&mut self) -> Option<&'a [T]> { @@ -1887,7 +1887,7 @@ impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool { } } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T, P> FusedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {} /// An iterator over the subslices of the vector which are separated @@ -1897,12 +1897,12 @@ impl<'a, T, P> FusedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {} /// /// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut /// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] pub struct RSplitMut<'a, T:'a, P> where P: FnMut(&T) -> bool { inner: SplitMut<'a, T, P> } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("RSplitMut") @@ -1912,7 +1912,7 @@ impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplitMut<'a, T, P> where P: FnMu } } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { #[inline] fn finish(&mut self) -> Option<&'a mut [T]> { @@ -1920,7 +1920,7 @@ impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { } } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T, P> Iterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { type Item = &'a mut [T]; @@ -1935,7 +1935,7 @@ impl<'a, T, P> Iterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { } } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool, { @@ -1945,7 +1945,7 @@ impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where } } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T, P> FusedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {} /// An private iterator over subslices separated by elements that -- cgit 1.4.1-3-g733a5 From 41c211d2043df20b2ff5c9a13f8c7d711f74c13a Mon Sep 17 00:00:00 2001 From: tinaun Date: Tue, 17 Apr 2018 00:36:13 -0400 Subject: stabilize `swap_nonoverlapping` feature --- src/libcore/ptr.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 4a7d7c410eb..f953b29fdc8 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -166,8 +166,6 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { /// Basic usage: /// /// ``` -/// #![feature(swap_nonoverlapping)] -/// /// use std::ptr; /// /// let mut x = [1, 2, 3, 4]; @@ -181,7 +179,7 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { /// assert_eq!(y, [1, 2, 9]); /// ``` #[inline] -#[unstable(feature = "swap_nonoverlapping", issue = "42818")] +#[stable(feature = "swap_nonoverlapping", since = "1.27.0")] pub unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { let x = x as *mut u8; let y = y as *mut u8; -- cgit 1.4.1-3-g733a5 From 78a8c257032b18b5ca63f41b18d2fe7d57d1cffa Mon Sep 17 00:00:00 2001 From: tinaun Date: Tue, 17 Apr 2018 00:40:07 -0400 Subject: stabilize `swap_with_slice` feature --- src/liballoc/lib.rs | 2 +- src/liballoc/slice.rs | 8 +------- src/libcore/slice/mod.rs | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 87ad2751c5b..f2a61bda4aa 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -123,7 +123,7 @@ #![feature(inclusive_range_fields)] #![cfg_attr(stage0, feature(generic_param_attrs))] -#![cfg_attr(not(test), feature(fn_traits, swap_with_slice, i128))] +#![cfg_attr(not(test), feature(fn_traits, i128))] #![cfg_attr(test, feature(test))] // Allow testing this library diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index eb8a293013d..33e652856e8 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -1702,8 +1702,6 @@ impl [T] { /// Swapping two elements across slices: /// /// ``` - /// #![feature(swap_with_slice)] - /// /// let mut slice1 = [0, 0]; /// let mut slice2 = [1, 2, 3, 4]; /// @@ -1719,8 +1717,6 @@ impl [T] { /// a compile failure: /// /// ```compile_fail - /// #![feature(swap_with_slice)] - /// /// let mut slice = [1, 2, 3, 4, 5]; /// slice[..2].swap_with_slice(&mut slice[3..]); // compile fail! /// ``` @@ -1729,8 +1725,6 @@ impl [T] { /// mutable sub-slices from a slice: /// /// ``` - /// #![feature(swap_with_slice)] - /// /// let mut slice = [1, 2, 3, 4, 5]; /// /// { @@ -1742,7 +1736,7 @@ impl [T] { /// ``` /// /// [`split_at_mut`]: #method.split_at_mut - #[unstable(feature = "swap_with_slice", issue = "44030")] + #[stable(feature = "swap_with_slice", since = "1.27.0")] pub fn swap_with_slice(&mut self, other: &mut [T]) { core_slice::SliceExt::swap_with_slice(self, other) } diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 68f081c2e87..afb149f2997 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -223,7 +223,7 @@ pub trait SliceExt { #[stable(feature = "copy_from_slice", since = "1.9.0")] fn copy_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Copy; - #[unstable(feature = "swap_with_slice", issue = "44030")] + #[stable(feature = "swap_with_slice", since = "1.27.0")] fn swap_with_slice(&mut self, src: &mut [Self::Item]); #[stable(feature = "sort_unstable", since = "1.20.0")] -- cgit 1.4.1-3-g733a5 From 335195d6280cbf6d30d4a56df77142423afee264 Mon Sep 17 00:00:00 2001 From: tinaun Date: Tue, 17 Apr 2018 00:43:48 -0400 Subject: stabilize `duration_from_micros` feature --- src/libcore/time.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/time.rs b/src/libcore/time.rs index b8d0719b9b9..e71a8f5da63 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -137,7 +137,6 @@ impl Duration { /// # Examples /// /// ``` - /// #![feature(duration_from_micros)] /// use std::time::Duration; /// /// let duration = Duration::from_micros(1_000_002); @@ -145,7 +144,7 @@ impl Duration { /// assert_eq!(1, duration.as_secs()); /// assert_eq!(2000, duration.subsec_nanos()); /// ``` - #[unstable(feature = "duration_from_micros", issue = "44400")] + #[stable(feature = "duration_from_micros", since = "1.27.0")] #[inline] pub const fn from_micros(micros: u64) -> Duration { Duration { -- cgit 1.4.1-3-g733a5 From 4a8f4b7e4958f5a57ca2ebb936a2f6770191eebd Mon Sep 17 00:00:00 2001 From: tinaun Date: Tue, 17 Apr 2018 00:56:20 -0400 Subject: stabilize `duration_extras` feature --- src/libcore/time.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/time.rs b/src/libcore/time.rs index e71a8f5da63..e22fe450bb1 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -158,7 +158,6 @@ impl Duration { /// # Examples /// /// ``` - /// #![feature(duration_extras)] /// use std::time::Duration; /// /// let duration = Duration::from_nanos(1_000_000_123); @@ -166,7 +165,7 @@ impl Duration { /// assert_eq!(1, duration.as_secs()); /// assert_eq!(123, duration.subsec_nanos()); /// ``` - #[unstable(feature = "duration_extras", issue = "46507")] + #[stable(feature = "duration_extras", since = "1.27.0")] #[inline] pub const fn from_nanos(nanos: u64) -> Duration { Duration { @@ -216,14 +215,13 @@ impl Duration { /// # Examples /// /// ``` - /// #![feature(duration_extras)] /// use std::time::Duration; /// /// let duration = Duration::from_millis(5432); /// assert_eq!(duration.as_secs(), 5); /// assert_eq!(duration.subsec_millis(), 432); /// ``` - #[unstable(feature = "duration_extras", issue = "46507")] + #[stable(feature = "duration_extras", since = "1.27.0")] #[inline] pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI } @@ -236,14 +234,13 @@ impl Duration { /// # Examples /// /// ``` - /// #![feature(duration_extras, duration_from_micros)] /// use std::time::Duration; /// /// let duration = Duration::from_micros(1_234_567); /// assert_eq!(duration.as_secs(), 1); /// assert_eq!(duration.subsec_micros(), 234_567); /// ``` - #[unstable(feature = "duration_extras", issue = "46507")] + #[stable(feature = "duration_extras", since = "1.27.0")] #[inline] pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO } -- cgit 1.4.1-3-g733a5 From b84baf23788e96a1d79de543eb264ff7d2334c63 Mon Sep 17 00:00:00 2001 From: tinaun Date: Tue, 17 Apr 2018 00:59:16 -0400 Subject: stabilize `nonnull_cast` feature --- src/liballoc/lib.rs | 1 - src/libcore/ptr.rs | 2 +- src/libstd/lib.rs | 1 - src/test/run-pass/realloc-16687.rs | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index f2a61bda4aa..163aef61b43 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -99,7 +99,6 @@ #![feature(lang_items)] #![feature(libc)] #![feature(needs_allocator)] -#![feature(nonnull_cast)] #![feature(nonzero)] #![feature(optin_builtin_traits)] #![feature(pattern)] diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index f953b29fdc8..74bb264cc67 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2742,7 +2742,7 @@ impl NonNull { } /// Cast to a pointer of another type - #[unstable(feature = "nonnull_cast", issue = "47653")] + #[stable(feature = "nonnull_cast", since = "1.27.0")] pub fn cast(self) -> NonNull { unsafe { NonNull::new_unchecked(self.as_ptr() as *mut U) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index dd96c57538c..63e4a17d32e 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -275,7 +275,6 @@ #![feature(macro_reexport)] #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] -#![feature(nonnull_cast)] #![feature(exhaustive_patterns)] #![feature(nonzero)] #![feature(num_bits_bytes)] diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index 38cc23c16a9..afa3494c389 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -13,7 +13,7 @@ // Ideally this would be revised to use no_std, but for now it serves // well enough to reproduce (and illustrate) the bug from #16687. -#![feature(heap_api, allocator_api, nonnull_cast)] +#![feature(heap_api, allocator_api)] use std::alloc::{Global, Alloc, Layout}; use std::ptr::{self, NonNull}; -- cgit 1.4.1-3-g733a5 From b74d6922ff15d9f3bf39d317ccd7141518f4f5ec Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Mon, 16 Apr 2018 16:34:09 -0400 Subject: smaller PR just to fix #50002 --- src/liballoc/tests/str.rs | 16 ++++++++++++++++ src/libcore/str/mod.rs | 9 ++------- 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index a3f4c385fe2..e3f198f7362 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -401,6 +401,22 @@ fn test_str_get_maxinclusive() { } } +#[test] +fn test_str_slicemut_rangetoinclusive_ok() { + let mut s = "abcαβγ".to_owned(); + let s: &mut str = &mut s; + &mut s[..=3]; // before alpha + &mut s[..=5]; // after alpha +} + +#[test] +#[should_panic] +fn test_str_slicemut_rangetoinclusive_notok() { + let mut s = "abcαβγ".to_owned(); + let s: &mut str = &mut s; + &mut s[..=4]; // middle of alpha, which is 2 bytes long +} + #[test] fn test_is_char_boundary() { let s = "ศไทย中华Việt Nam β-release 🐱123"; diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index f1fe23092de..5b52119d031 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2100,18 +2100,13 @@ mod traits { fn index(self, slice: &str) -> &Self::Output { assert!(self.end != usize::max_value(), "attempted to index str up to maximum usize"); - let end = self.end + 1; - self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end)) + (..self.end+1).index(slice) } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { assert!(self.end != usize::max_value(), "attempted to index str up to maximum usize"); - if slice.is_char_boundary(self.end) { - unsafe { self.get_unchecked_mut(slice) } - } else { - super::slice_error_fail(slice, 0, self.end + 1) - } + (..self.end+1).index_mut(slice) } } -- cgit 1.4.1-3-g733a5 From 1caaafdce7871bc2816c9f42a14fd9262eda4037 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 20 Apr 2018 13:56:07 +0200 Subject: Implement Copy for std::alloc::Layout Fixes https://github.com/rust-lang/rust/issues/48458 --- src/libcore/alloc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index f08baa3dd71..54440eaa40f 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -63,7 +63,7 @@ fn size_align() -> (usize, usize) { /// requests have positive size. A caller to the `Alloc::alloc` /// method must either ensure that conditions like this are met, or /// use specific allocators with looser requirements.) -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Layout { // size of the requested block of memory, measured in bytes. size: usize, -- cgit 1.4.1-3-g733a5 From fadabd6fbbfe1a401bbdd4ba0919b21ba4f7c5d2 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 20 Apr 2018 17:07:58 +0200 Subject: Revert stabilization of `feature(never_type)`. This commit is just covering the feature gate itself and the tests that made direct use of `!` and thus need to opt back into the feature. A follow on commit brings back the other change that motivates the revert: Namely, going back to the old rules for falling back to `()`. --- src/libcore/clone.rs | 2 +- src/libcore/cmp.rs | 8 ++-- src/libcore/fmt/mod.rs | 4 +- src/libcore/lib.rs | 1 + src/libcore/marker.rs | 2 +- src/librustc/lib.rs | 1 + src/librustc_mir/build/matches/simplify.rs | 1 + src/libstd/error.rs | 2 +- src/libstd/lib.rs | 1 + src/libsyntax/feature_gate.rs | 7 ++++ .../compile-fail/call-fn-never-arg-wrong-type.rs | 2 + src/test/compile-fail/coerce-to-bang-cast.rs | 2 + src/test/compile-fail/coerce-to-bang.rs | 2 + .../compile-fail/inhabitedness-infinite-loop.rs | 1 + src/test/compile-fail/loop-break-value.rs | 2 + src/test/compile-fail/match-privately-empty.rs | 1 + src/test/compile-fail/never-assign-dead-code.rs | 1 + src/test/compile-fail/never-assign-wrong-type.rs | 1 + src/test/compile-fail/uninhabited-irrefutable.rs | 1 + src/test/compile-fail/uninhabited-patterns.rs | 1 + src/test/compile-fail/unreachable-loop-patterns.rs | 1 + src/test/compile-fail/unreachable-try-pattern.rs | 1 + .../run-pass/diverging-fallback-control-flow.rs | 2 + src/test/run-pass/empty-types-in-patterns.rs | 1 + src/test/run-pass/impl-for-never.rs | 2 + src/test/run-pass/issue-44402.rs | 1 + src/test/run-pass/loop-break-value.rs | 2 + src/test/run-pass/mir_calls_to_shims.rs | 1 + src/test/run-pass/never-result.rs | 2 + src/test/run-pass/type-sizes.rs | 1 + src/test/ui/feature-gate-exhaustive-patterns.rs | 2 +- src/test/ui/feature-gate-never_type.rs | 27 ++++++++++++++ src/test/ui/feature-gate-never_type.stderr | 43 ++++++++++++++++++++++ src/test/ui/print_type_sizes/uninhabited.rs | 1 + src/test/ui/reachable/expr_add.rs | 2 +- src/test/ui/reachable/expr_assign.rs | 2 +- src/test/ui/reachable/expr_call.rs | 2 +- src/test/ui/reachable/expr_cast.rs | 2 +- src/test/ui/reachable/expr_method.rs | 2 +- src/test/ui/reachable/expr_type.rs | 2 +- src/test/ui/reachable/expr_unary.rs | 2 +- 41 files changed, 127 insertions(+), 17 deletions(-) create mode 100644 src/test/ui/feature-gate-never_type.rs create mode 100644 src/test/ui/feature-gate-never_type.stderr (limited to 'src/libcore') diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 58a8439162c..f79f7351698 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -179,7 +179,7 @@ mod impls { bool char } - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl Clone for ! { #[inline] fn clone(&self) -> Self { diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 3ae9b05b865..c91aa06609d 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -881,24 +881,24 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl PartialEq for ! { fn eq(&self, _: &!) -> bool { *self } } - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl Eq for ! {} - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl PartialOrd for ! { fn partial_cmp(&self, _: &!) -> Option { *self } } - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl Ord for ! { fn cmp(&self, _: &!) -> Ordering { *self diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 277bef2bf66..a8430f14410 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1780,14 +1780,14 @@ macro_rules! fmt_refs { fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp } -#[stable(feature = "never_type", since = "1.26.0")] +#[unstable(feature = "never_type", issue = "35121")] impl Debug for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self } } -#[stable(feature = "never_type", since = "1.26.0")] +#[unstable(feature = "never_type", issue = "35121")] impl Display for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index ea7a46f44ae..ac1a8091eb3 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -82,6 +82,7 @@ #![feature(iterator_repeat_with)] #![feature(lang_items)] #![feature(link_llvm_intrinsics)] +#![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(macro_at_most_once_rep)] #![feature(no_core)] diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 885aabe0806..feb689dbc1f 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -630,7 +630,7 @@ mod copy_impls { bool char } - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl Copy for ! {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index a2cefe488c6..bb495049483 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -52,6 +52,7 @@ #![cfg_attr(windows, feature(libc))] #![feature(macro_lifetime_matcher)] #![feature(macro_vis_matcher)] +#![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(non_exhaustive)] #![feature(nonzero)] diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index 4e95ee6444d..147b8cc2175 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -113,6 +113,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| { i == variant_index || { + self.hir.tcx().features().never_type && self.hir.tcx().features().exhaustive_patterns && self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs) } diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 3c209928d43..6c149b2e0f1 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -233,7 +233,7 @@ impl<'a> From> for Box { } } -#[stable(feature = "never_type", since = "1.26.0")] +#[unstable(feature = "never_type", issue = "35121")] impl Error for ! { fn description(&self) -> &str { *self } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 7d896695311..8980cd8c6a4 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -275,6 +275,7 @@ #![feature(macro_reexport)] #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] +#![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(nonzero)] #![feature(num_bits_bytes)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 7b7cfe5eea0..a515b591f69 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -272,6 +272,9 @@ declare_features! ( // Allows cfg(target_has_atomic = "..."). (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), + // The `!` type. Does not imply exhaustive_patterns (below) any more. + (active, never_type, "1.13.0", Some(35121), None), + // Allows exhaustive pattern matching on types that contain uninhabited types. (active, exhaustive_patterns, "1.13.0", None, None), @@ -1635,6 +1638,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::BareFn(ref bare_fn_ty) => { self.check_abi(bare_fn_ty.abi, ty.span); } + ast::TyKind::Never => { + gate_feature_post!(&self, never_type, ty.span, + "The `!` type is experimental"); + } ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => { gate_feature_post!(&self, dyn_trait, ty.span, "`dyn Trait` syntax is unstable"); diff --git a/src/test/compile-fail/call-fn-never-arg-wrong-type.rs b/src/test/compile-fail/call-fn-never-arg-wrong-type.rs index c2f157cd35c..583befed1e8 100644 --- a/src/test/compile-fail/call-fn-never-arg-wrong-type.rs +++ b/src/test/compile-fail/call-fn-never-arg-wrong-type.rs @@ -10,6 +10,8 @@ // Test that we can't pass other types for ! +#![feature(never_type)] + fn foo(x: !) -> ! { x } diff --git a/src/test/compile-fail/coerce-to-bang-cast.rs b/src/test/compile-fail/coerce-to-bang-cast.rs index 5efb4dadc64..14a06b306d8 100644 --- a/src/test/compile-fail/coerce-to-bang-cast.rs +++ b/src/test/compile-fail/coerce-to-bang-cast.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] + fn foo(x: usize, y: !, z: usize) { } fn cast_a() { diff --git a/src/test/compile-fail/coerce-to-bang.rs b/src/test/compile-fail/coerce-to-bang.rs index 15049232a4d..62ff09f4616 100644 --- a/src/test/compile-fail/coerce-to-bang.rs +++ b/src/test/compile-fail/coerce-to-bang.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] + fn foo(x: usize, y: !, z: usize) { } fn call_foo_a() { diff --git a/src/test/compile-fail/inhabitedness-infinite-loop.rs b/src/test/compile-fail/inhabitedness-infinite-loop.rs index b9741e0add6..d11aacec196 100644 --- a/src/test/compile-fail/inhabitedness-infinite-loop.rs +++ b/src/test/compile-fail/inhabitedness-infinite-loop.rs @@ -10,6 +10,7 @@ // error-pattern:reached recursion limit +#![feature(never_type)] #![feature(exhaustive_patterns)] struct Foo<'a, T: 'a> { diff --git a/src/test/compile-fail/loop-break-value.rs b/src/test/compile-fail/loop-break-value.rs index 5ef46bb27fd..938f7fba2a0 100644 --- a/src/test/compile-fail/loop-break-value.rs +++ b/src/test/compile-fail/loop-break-value.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] + fn main() { let val: ! = loop { break break; }; //~^ ERROR mismatched types diff --git a/src/test/compile-fail/match-privately-empty.rs b/src/test/compile-fail/match-privately-empty.rs index e18c7d77ce3..8777ef2ffe3 100644 --- a/src/test/compile-fail/match-privately-empty.rs +++ b/src/test/compile-fail/match-privately-empty.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns)] mod private { diff --git a/src/test/compile-fail/never-assign-dead-code.rs b/src/test/compile-fail/never-assign-dead-code.rs index 4e987d1ddce..0fb75b535c6 100644 --- a/src/test/compile-fail/never-assign-dead-code.rs +++ b/src/test/compile-fail/never-assign-dead-code.rs @@ -10,6 +10,7 @@ // Test that an assignment of type ! makes the rest of the block dead code. +#![feature(never_type)] #![feature(rustc_attrs)] #![warn(unused)] diff --git a/src/test/compile-fail/never-assign-wrong-type.rs b/src/test/compile-fail/never-assign-wrong-type.rs index 8c2de7d68d3..c0dd2cab749 100644 --- a/src/test/compile-fail/never-assign-wrong-type.rs +++ b/src/test/compile-fail/never-assign-wrong-type.rs @@ -10,6 +10,7 @@ // Test that we can't use another type in place of ! +#![feature(never_type)] #![deny(warnings)] fn main() { diff --git a/src/test/compile-fail/uninhabited-irrefutable.rs b/src/test/compile-fail/uninhabited-irrefutable.rs index 72b0afa6bd3..05a97b855e7 100644 --- a/src/test/compile-fail/uninhabited-irrefutable.rs +++ b/src/test/compile-fail/uninhabited-irrefutable.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns)] mod foo { diff --git a/src/test/compile-fail/uninhabited-patterns.rs b/src/test/compile-fail/uninhabited-patterns.rs index e130df5c845..2cf4b78bdff 100644 --- a/src/test/compile-fail/uninhabited-patterns.rs +++ b/src/test/compile-fail/uninhabited-patterns.rs @@ -10,6 +10,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(slice_patterns)] #![deny(unreachable_patterns)] diff --git a/src/test/compile-fail/unreachable-loop-patterns.rs b/src/test/compile-fail/unreachable-loop-patterns.rs index dca79bdfb87..cfd829e416e 100644 --- a/src/test/compile-fail/unreachable-loop-patterns.rs +++ b/src/test/compile-fail/unreachable-loop-patterns.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns)] #![deny(unreachable_patterns)] diff --git a/src/test/compile-fail/unreachable-try-pattern.rs b/src/test/compile-fail/unreachable-try-pattern.rs index 0caf7d51234..df340095bb4 100644 --- a/src/test/compile-fail/unreachable-try-pattern.rs +++ b/src/test/compile-fail/unreachable-try-pattern.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns, rustc_attrs)] #![warn(unreachable_code)] #![warn(unreachable_patterns)] diff --git a/src/test/run-pass/diverging-fallback-control-flow.rs b/src/test/run-pass/diverging-fallback-control-flow.rs index a96f98b9efd..723a98bcdfa 100644 --- a/src/test/run-pass/diverging-fallback-control-flow.rs +++ b/src/test/run-pass/diverging-fallback-control-flow.rs @@ -14,6 +14,8 @@ // These represent current behavior, but are pretty dubious. I would // like to revisit these and potentially change them. --nmatsakis +#![feature(never_type)] + trait BadDefault { fn default() -> Self; } diff --git a/src/test/run-pass/empty-types-in-patterns.rs b/src/test/run-pass/empty-types-in-patterns.rs index 87db4401929..86cf9b5ec47 100644 --- a/src/test/run-pass/empty-types-in-patterns.rs +++ b/src/test/run-pass/empty-types-in-patterns.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(slice_patterns)] #![allow(unreachable_patterns)] diff --git a/src/test/run-pass/impl-for-never.rs b/src/test/run-pass/impl-for-never.rs index cf54e1c3bd5..794f5969bff 100644 --- a/src/test/run-pass/impl-for-never.rs +++ b/src/test/run-pass/impl-for-never.rs @@ -10,6 +10,8 @@ // Test that we can call static methods on ! both directly and when it appears in a generic +#![feature(never_type)] + trait StringifyType { fn stringify_type() -> &'static str; } diff --git a/src/test/run-pass/issue-44402.rs b/src/test/run-pass/issue-44402.rs index a5a0a5a5794..5cbd3446d9b 100644 --- a/src/test/run-pass/issue-44402.rs +++ b/src/test/run-pass/issue-44402.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns)] // Regression test for inhabitedness check. The old diff --git a/src/test/run-pass/loop-break-value.rs b/src/test/run-pass/loop-break-value.rs index ffdd99ebf6e..39053769b24 100644 --- a/src/test/run-pass/loop-break-value.rs +++ b/src/test/run-pass/loop-break-value.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] + #[allow(unused)] fn never_returns() { loop { diff --git a/src/test/run-pass/mir_calls_to_shims.rs b/src/test/run-pass/mir_calls_to_shims.rs index dda7a46f325..9641ed28293 100644 --- a/src/test/run-pass/mir_calls_to_shims.rs +++ b/src/test/run-pass/mir_calls_to_shims.rs @@ -11,6 +11,7 @@ // ignore-wasm32-bare compiled with panic=abort by default #![feature(fn_traits)] +#![feature(never_type)] use std::panic; diff --git a/src/test/run-pass/never-result.rs b/src/test/run-pass/never-result.rs index 8aa2a13ed8c..5c0af392f44 100644 --- a/src/test/run-pass/never-result.rs +++ b/src/test/run-pass/never-result.rs @@ -10,6 +10,8 @@ // Test that we can extract a ! through pattern matching then use it as several different types. +#![feature(never_type)] + fn main() { let x: Result = Ok(123); match x { diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs index 0bb18d8729a..7bd9a1703ee 100644 --- a/src/test/run-pass/type-sizes.rs +++ b/src/test/run-pass/type-sizes.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] use std::mem::size_of; diff --git a/src/test/ui/feature-gate-exhaustive-patterns.rs b/src/test/ui/feature-gate-exhaustive-patterns.rs index 477dd1b38eb..c83d9b56bc3 100644 --- a/src/test/ui/feature-gate-exhaustive-patterns.rs +++ b/src/test/ui/feature-gate-exhaustive-patterns.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] fn foo() -> Result { Ok(123) } diff --git a/src/test/ui/feature-gate-never_type.rs b/src/test/ui/feature-gate-never_type.rs new file mode 100644 index 00000000000..ebbe17a821f --- /dev/null +++ b/src/test/ui/feature-gate-never_type.rs @@ -0,0 +1,27 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that ! errors when used in illegal positions with feature(never_type) disabled + +trait Foo { + type Wub; +} + +type Ma = (u32, !, i32); //~ ERROR type is experimental +type Meeshka = Vec; //~ ERROR type is experimental +type Mow = &fn(!) -> !; //~ ERROR type is experimental +type Skwoz = &mut !; //~ ERROR type is experimental + +impl Foo for Meeshka { + type Wub = !; //~ ERROR type is experimental +} + +fn main() { +} diff --git a/src/test/ui/feature-gate-never_type.stderr b/src/test/ui/feature-gate-never_type.stderr new file mode 100644 index 00000000000..187be6d8291 --- /dev/null +++ b/src/test/ui/feature-gate-never_type.stderr @@ -0,0 +1,43 @@ +error[E0658]: The `!` type is experimental (see issue #35121) + --> $DIR/feature-gate-never_type.rs:17:17 + | +LL | type Ma = (u32, !, i32); //~ ERROR type is experimental + | ^ + | + = help: add #![feature(never_type)] to the crate attributes to enable + +error[E0658]: The `!` type is experimental (see issue #35121) + --> $DIR/feature-gate-never_type.rs:18:20 + | +LL | type Meeshka = Vec; //~ ERROR type is experimental + | ^ + | + = help: add #![feature(never_type)] to the crate attributes to enable + +error[E0658]: The `!` type is experimental (see issue #35121) + --> $DIR/feature-gate-never_type.rs:19:16 + | +LL | type Mow = &fn(!) -> !; //~ ERROR type is experimental + | ^ + | + = help: add #![feature(never_type)] to the crate attributes to enable + +error[E0658]: The `!` type is experimental (see issue #35121) + --> $DIR/feature-gate-never_type.rs:20:19 + | +LL | type Skwoz = &mut !; //~ ERROR type is experimental + | ^ + | + = help: add #![feature(never_type)] to the crate attributes to enable + +error[E0658]: The `!` type is experimental (see issue #35121) + --> $DIR/feature-gate-never_type.rs:23:16 + | +LL | type Wub = !; //~ ERROR type is experimental + | ^ + | + = help: add #![feature(never_type)] to the crate attributes to enable + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs index 1908ef244cf..9ae86136a90 100644 --- a/src/test/ui/print_type_sizes/uninhabited.rs +++ b/src/test/ui/print_type_sizes/uninhabited.rs @@ -11,6 +11,7 @@ // compile-flags: -Z print-type-sizes // compile-pass +#![feature(never_type)] #![feature(start)] #[start] diff --git a/src/test/ui/reachable/expr_add.rs b/src/test/ui/reachable/expr_add.rs index 3e39b75d8c0..26760cfea44 100644 --- a/src/test/ui/reachable/expr_add.rs +++ b/src/test/ui/reachable/expr_add.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] #![allow(unused_variables)] #![deny(unreachable_code)] diff --git a/src/test/ui/reachable/expr_assign.rs b/src/test/ui/reachable/expr_assign.rs index 73083af34d9..308f2483be5 100644 --- a/src/test/ui/reachable/expr_assign.rs +++ b/src/test/ui/reachable/expr_assign.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] diff --git a/src/test/ui/reachable/expr_call.rs b/src/test/ui/reachable/expr_call.rs index 2772dd429d1..9696bdadf87 100644 --- a/src/test/ui/reachable/expr_call.rs +++ b/src/test/ui/reachable/expr_call.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] diff --git a/src/test/ui/reachable/expr_cast.rs b/src/test/ui/reachable/expr_cast.rs index 88846b63841..fc0041daf7c 100644 --- a/src/test/ui/reachable/expr_cast.rs +++ b/src/test/ui/reachable/expr_cast.rs @@ -12,7 +12,7 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(type_ascription)] +#![feature(never_type, type_ascription)] fn a() { // the cast is unreachable: diff --git a/src/test/ui/reachable/expr_method.rs b/src/test/ui/reachable/expr_method.rs index 7dabb307097..c91646cfa1e 100644 --- a/src/test/ui/reachable/expr_method.rs +++ b/src/test/ui/reachable/expr_method.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] diff --git a/src/test/ui/reachable/expr_type.rs b/src/test/ui/reachable/expr_type.rs index 2381ea2ac7a..ce12412ba74 100644 --- a/src/test/ui/reachable/expr_type.rs +++ b/src/test/ui/reachable/expr_type.rs @@ -12,7 +12,7 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(type_ascription)] +#![feature(never_type, type_ascription)] fn a() { // the cast is unreachable: diff --git a/src/test/ui/reachable/expr_unary.rs b/src/test/ui/reachable/expr_unary.rs index 4096865f4c6..5b7ea57b166 100644 --- a/src/test/ui/reachable/expr_unary.rs +++ b/src/test/ui/reachable/expr_unary.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] -- cgit 1.4.1-3-g733a5 From d141fdc3bfce5ab675a0c74b2fd6cf89ac4ef3f8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 20 Apr 2018 17:41:31 +0200 Subject: Revert "Stabilize the TryFrom and TryInto traits" This reverts commit e53a2a72743810e05f58c61c9d8a4c89b712ad2e. --- src/libcore/array.rs | 6 +++--- src/libcore/char/convert.rs | 6 +++--- src/libcore/char/mod.rs | 2 +- src/libcore/convert.rs | 12 ++++-------- src/libcore/num/mod.rs | 12 ++++++------ src/libcore/tests/lib.rs | 1 + src/librustc_apfloat/lib.rs | 1 + src/libstd/error.rs | 6 +++--- src/libstd/lib.rs | 1 + src/test/ui/e0119/conflict-with-std.rs | 2 ++ src/test/ui/e0119/conflict-with-std.stderr | 6 +++--- 11 files changed, 28 insertions(+), 27 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 87144c27c9e..3d24f8902bd 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -59,7 +59,7 @@ unsafe impl> FixedSizeArray for A { } /// The error type returned when a conversion from a slice to an array fails. -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] #[derive(Debug, Copy, Clone)] pub struct TryFromSliceError(()); @@ -148,7 +148,7 @@ macro_rules! array_impls { } } - #[stable(feature = "try_from", since = "1.26.0")] + #[unstable(feature = "try_from", issue = "33417")] impl<'a, T> TryFrom<&'a [T]> for &'a [T; $N] { type Error = TryFromSliceError; @@ -162,7 +162,7 @@ macro_rules! array_impls { } } - #[stable(feature = "try_from", since = "1.26.0")] + #[unstable(feature = "try_from", issue = "33417")] impl<'a, T> TryFrom<&'a mut [T]> for &'a mut [T; $N] { type Error = TryFromSliceError; diff --git a/src/libcore/char/convert.rs b/src/libcore/char/convert.rs index 150562a4a9b..803a924eb3a 100644 --- a/src/libcore/char/convert.rs +++ b/src/libcore/char/convert.rs @@ -204,7 +204,7 @@ impl FromStr for char { } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl TryFrom for char { type Error = CharTryFromError; @@ -219,11 +219,11 @@ impl TryFrom for char { } /// The error type returned when a conversion from u32 to char fails. -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct CharTryFromError(()); -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl fmt::Display for CharTryFromError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { "converted integer out of range for `char`".fmt(f) diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index 9edc0c88756..210eceebc51 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -40,7 +40,7 @@ pub use self::convert::{from_u32, from_digit}; pub use self::convert::from_u32_unchecked; #[stable(feature = "char_from_str", since = "1.20.0")] pub use self::convert::ParseCharError; -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] pub use self::convert::CharTryFromError; #[stable(feature = "decode_utf16", since = "1.9.0")] pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error}; diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 63721395784..7324df95bc5 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -322,26 +322,22 @@ pub trait From: Sized { /// /// [`TryFrom`]: trait.TryFrom.html /// [`Into`]: trait.Into.html -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] pub trait TryInto: Sized { /// The type returned in the event of a conversion error. - #[stable(feature = "try_from", since = "1.26.0")] type Error; /// Performs the conversion. - #[stable(feature = "try_from", since = "1.26.0")] fn try_into(self) -> Result; } /// Attempt to construct `Self` via a conversion. -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] pub trait TryFrom: Sized { /// The type returned in the event of a conversion error. - #[stable(feature = "try_from", since = "1.26.0")] type Error; /// Performs the conversion. - #[stable(feature = "try_from", since = "1.26.0")] fn try_from(value: T) -> Result; } @@ -409,7 +405,7 @@ impl From for T { // TryFrom implies TryInto -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl TryInto for T where U: TryFrom { type Error = U::Error; @@ -421,7 +417,7 @@ impl TryInto for T where U: TryFrom // Infallible conversions are semantically equivalent to fallible conversions // with an uninhabited error type. -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl TryFrom for T where T: From { type Error = !; diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index f2e8caaad14..801e2328a4b 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4192,7 +4192,7 @@ macro_rules! from_str_radix_int_impl { from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } /// The error type returned when a checked integral type conversion fails. -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] #[derive(Debug, Copy, Clone)] pub struct TryFromIntError(()); @@ -4207,14 +4207,14 @@ impl TryFromIntError { } } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl fmt::Display for TryFromIntError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { self.__description().fmt(fmt) } } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl From for TryFromIntError { fn from(never: !) -> TryFromIntError { never @@ -4224,7 +4224,7 @@ impl From for TryFromIntError { // only negative bounds macro_rules! try_from_lower_bounded { ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.26.0")] + #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -4243,7 +4243,7 @@ macro_rules! try_from_lower_bounded { // unsigned to signed (only positive bound) macro_rules! try_from_upper_bounded { ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.26.0")] + #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -4262,7 +4262,7 @@ macro_rules! try_from_upper_bounded { // all other cases macro_rules! try_from_both_bounded { ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.26.0")] + #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { type Error = TryFromIntError; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index bb875c7219a..3b080689cb3 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -36,6 +36,7 @@ #![feature(str_internals)] #![feature(test)] #![feature(trusted_len)] +#![feature(try_from)] #![feature(try_trait)] #![feature(exact_chunks)] #![cfg_attr(stage0, feature(atomic_nand))] diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 0f051ea5981..08438805a70 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -45,6 +45,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![forbid(unsafe_code)] +#![feature(try_from)] // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] extern crate rustc_cratesio_shim; diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 6c149b2e0f1..749b8ccc13d 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -284,14 +284,14 @@ impl Error for num::ParseIntError { } } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl Error for num::TryFromIntError { fn description(&self) -> &str { self.__description() } } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl Error for array::TryFromSliceError { fn description(&self) -> &str { self.__description() @@ -365,7 +365,7 @@ impl Error for cell::BorrowMutError { } } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl Error for char::CharTryFromError { fn description(&self) -> &str { "converted integer out of range for `char`" diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 8980cd8c6a4..e53e009678c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -307,6 +307,7 @@ #![feature(test, rustc_private)] #![feature(thread_local)] #![feature(toowned_clone_into)] +#![feature(try_from)] #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(untagged_unions)] diff --git a/src/test/ui/e0119/conflict-with-std.rs b/src/test/ui/e0119/conflict-with-std.rs index a9f747d09ec..ed9033ad53d 100644 --- a/src/test/ui/e0119/conflict-with-std.rs +++ b/src/test/ui/e0119/conflict-with-std.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(try_from)] + use std::marker::PhantomData; use std::convert::{TryFrom, AsRef}; diff --git a/src/test/ui/e0119/conflict-with-std.stderr b/src/test/ui/e0119/conflict-with-std.stderr index 417ff1de3f8..e8b2c84c0df 100644 --- a/src/test/ui/e0119/conflict-with-std.stderr +++ b/src/test/ui/e0119/conflict-with-std.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `std::convert::AsRef` for type `std::boxed::Box`: - --> $DIR/conflict-with-std.rs:15:1 + --> $DIR/conflict-with-std.rs:17:1 | LL | impl AsRef for Box { //~ ERROR conflicting implementations | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | impl AsRef for Box { //~ ERROR conflicting implementations where T: ?Sized; error[E0119]: conflicting implementations of trait `std::convert::From` for type `S`: - --> $DIR/conflict-with-std.rs:22:1 + --> $DIR/conflict-with-std.rs:24:1 | LL | impl From for S { //~ ERROR conflicting implementations | ^^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | impl From for S { //~ ERROR conflicting implementations - impl std::convert::From for T; error[E0119]: conflicting implementations of trait `std::convert::TryFrom` for type `X`: - --> $DIR/conflict-with-std.rs:29:1 + --> $DIR/conflict-with-std.rs:31:1 | LL | impl TryFrom for X { //~ ERROR conflicting implementations | ^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From de8ed6a1d6ae3b2f2c7f1035ef3b71abda7a6a84 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 7 Apr 2018 11:45:22 +0200 Subject: Move non-allocating [u8] inherent methods to libcore Fixes #45803 --- src/liballoc/slice.rs | 58 ++-------------------- src/libcore/lib.rs | 1 + src/libcore/slice/mod.rs | 65 +++++++++++++++++++++++++ src/librustc/middle/lang_items.rs | 1 + src/librustc_typeck/check/method/probe.rs | 3 ++ src/librustc_typeck/coherence/inherent_impls.rs | 28 ++++++++++- src/librustdoc/clean/inline.rs | 1 + 7 files changed, 101 insertions(+), 56 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 33e652856e8..70945a791f6 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -1782,16 +1782,10 @@ impl [T] { } } -#[lang = "slice_u8"] +#[cfg_attr(stage0, lang = "slice_u8")] +#[cfg_attr(not(stage0), lang = "slice_u8_alloc")] #[cfg(not(test))] impl [u8] { - /// Checks if all bytes in this slice are within the ASCII range. - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn is_ascii(&self) -> bool { - self.iter().all(|b| b.is_ascii()) - } - /// Returns a vector containing a copy of this slice where each byte /// is mapped to its ASCII upper case equivalent. /// @@ -1826,52 +1820,8 @@ impl [u8] { me } - /// Checks that two slices are an ASCII case-insensitive match. - /// - /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, - /// but without allocating and copying temporaries. - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { - self.len() == other.len() && - self.iter().zip(other).all(|(a, b)| { - a.eq_ignore_ascii_case(b) - }) - } - - /// Converts this slice to its ASCII upper case equivalent in-place. - /// - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new uppercased value without modifying the existing one, use - /// [`to_ascii_uppercase`]. - /// - /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn make_ascii_uppercase(&mut self) { - for byte in self { - byte.make_ascii_uppercase(); - } - } - - /// Converts this slice to its ASCII lower case equivalent in-place. - /// - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new lowercased value without modifying the existing one, use - /// [`to_ascii_lowercase`]. - /// - /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn make_ascii_lowercase(&mut self) { - for byte in self { - byte.make_ascii_lowercase(); - } - } + #[cfg(stage0)] + slice_u8_core_methods!(); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index ea7a46f44ae..88bd0444233 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -92,6 +92,7 @@ #![feature(rustc_attrs)] #![feature(rustc_const_unstable)] #![feature(simd_ffi)] +#![feature(core_slice_ext)] #![feature(specialization)] #![feature(staged_api)] #![feature(stmt_expr_attributes)] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index afb149f2997..4cda1c8778a 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -755,6 +755,71 @@ impl SliceExt for [T] { } } +#[cfg_attr(stage0, macro_export)] +#[unstable(feature = "core_slice_ext", issue = "32110")] +macro_rules! slice_u8_core_methods { () => { + /// Checks if all bytes in this slice are within the ASCII range. + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn is_ascii(&self) -> bool { + self.iter().all(|b| b.is_ascii()) + } + + /// Checks that two slices are an ASCII case-insensitive match. + /// + /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, + /// but without allocating and copying temporaries. + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { + self.len() == other.len() && + self.iter().zip(other).all(|(a, b)| { + a.eq_ignore_ascii_case(b) + }) + } + + /// Converts this slice to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`to_ascii_uppercase`]. + /// + /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn make_ascii_uppercase(&mut self) { + for byte in self { + byte.make_ascii_uppercase(); + } + } + + /// Converts this slice to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`to_ascii_lowercase`]. + /// + /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn make_ascii_lowercase(&mut self) { + for byte in self { + byte.make_ascii_lowercase(); + } + } +}} + +#[lang = "slice_u8"] +#[cfg(not(test))] +#[cfg(not(stage0))] +impl [u8] { + slice_u8_core_methods!(); +} + #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] impl ops::Index for [T] diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 3b37031cf46..f8cff8b186c 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -214,6 +214,7 @@ language_item_table! { StrImplItem, "str", str_impl; SliceImplItem, "slice", slice_impl; SliceU8ImplItem, "slice_u8", slice_u8_impl; + SliceU8AllocImplItem, "slice_u8_alloc", slice_u8_alloc_impl; ConstPtrImplItem, "const_ptr", const_ptr_impl; MutPtrImplItem, "mut_ptr", mut_ptr_impl; I8ImplItem, "i8", i8_impl; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index de570956622..7ba60f62791 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -478,6 +478,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let lang_def_id = lang_items.slice_u8_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); + + let lang_def_id = lang_items.slice_u8_alloc_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); } ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => { let lang_def_id = lang_items.const_ptr_impl(); diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index d43ab0d3713..d7657bae8c5 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -114,6 +114,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyChar => { self.check_primitive_impl(def_id, lang_items.char_impl(), + None, "char", "char", item.span); @@ -121,6 +122,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyStr => { self.check_primitive_impl(def_id, lang_items.str_impl(), + None, "str", "str", item.span); @@ -128,6 +130,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TySlice(slice_item) if slice_item == self.tcx.types.u8 => { self.check_primitive_impl(def_id, lang_items.slice_u8_impl(), + lang_items.slice_u8_alloc_impl(), "slice_u8", "[u8]", item.span); @@ -135,6 +138,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TySlice(_) => { self.check_primitive_impl(def_id, lang_items.slice_impl(), + None, "slice", "[T]", item.span); @@ -142,6 +146,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => { self.check_primitive_impl(def_id, lang_items.const_ptr_impl(), + None, "const_ptr", "*const T", item.span); @@ -149,6 +154,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => { self.check_primitive_impl(def_id, lang_items.mut_ptr_impl(), + None, "mut_ptr", "*mut T", item.span); @@ -156,6 +162,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyInt(ast::IntTy::I8) => { self.check_primitive_impl(def_id, lang_items.i8_impl(), + None, "i8", "i8", item.span); @@ -163,6 +170,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyInt(ast::IntTy::I16) => { self.check_primitive_impl(def_id, lang_items.i16_impl(), + None, "i16", "i16", item.span); @@ -170,6 +178,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyInt(ast::IntTy::I32) => { self.check_primitive_impl(def_id, lang_items.i32_impl(), + None, "i32", "i32", item.span); @@ -177,6 +186,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyInt(ast::IntTy::I64) => { self.check_primitive_impl(def_id, lang_items.i64_impl(), + None, "i64", "i64", item.span); @@ -184,6 +194,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyInt(ast::IntTy::I128) => { self.check_primitive_impl(def_id, lang_items.i128_impl(), + None, "i128", "i128", item.span); @@ -191,6 +202,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyInt(ast::IntTy::Isize) => { self.check_primitive_impl(def_id, lang_items.isize_impl(), + None, "isize", "isize", item.span); @@ -198,6 +210,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyUint(ast::UintTy::U8) => { self.check_primitive_impl(def_id, lang_items.u8_impl(), + None, "u8", "u8", item.span); @@ -205,6 +218,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyUint(ast::UintTy::U16) => { self.check_primitive_impl(def_id, lang_items.u16_impl(), + None, "u16", "u16", item.span); @@ -212,6 +226,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyUint(ast::UintTy::U32) => { self.check_primitive_impl(def_id, lang_items.u32_impl(), + None, "u32", "u32", item.span); @@ -219,6 +234,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyUint(ast::UintTy::U64) => { self.check_primitive_impl(def_id, lang_items.u64_impl(), + None, "u64", "u64", item.span); @@ -226,6 +242,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyUint(ast::UintTy::U128) => { self.check_primitive_impl(def_id, lang_items.u128_impl(), + None, "u128", "u128", item.span); @@ -233,6 +250,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyUint(ast::UintTy::Usize) => { self.check_primitive_impl(def_id, lang_items.usize_impl(), + None, "usize", "usize", item.span); @@ -240,6 +258,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyFloat(ast::FloatTy::F32) => { self.check_primitive_impl(def_id, lang_items.f32_impl(), + None, "f32", "f32", item.span); @@ -247,6 +266,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyFloat(ast::FloatTy::F64) => { self.check_primitive_impl(def_id, lang_items.f64_impl(), + None, "f64", "f64", item.span); @@ -305,11 +325,15 @@ impl<'a, 'tcx> InherentCollect<'a, 'tcx> { fn check_primitive_impl(&self, impl_def_id: DefId, lang_def_id: Option, + lang_def_id2: Option, lang: &str, ty: &str, span: Span) { - match lang_def_id { - Some(lang_def_id) if lang_def_id == impl_def_id => { + match (lang_def_id, lang_def_id2) { + (Some(lang_def_id), _) if lang_def_id == impl_def_id => { + // OK + } + (_, Some(lang_def_id)) if lang_def_id == impl_def_id => { // OK } _ => { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 32f23e923d9..4acd12e5862 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -290,6 +290,7 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec Date: Sat, 7 Apr 2018 19:38:35 +0200 Subject: Replace SliceExt with inherent [T] methods in libcore --- src/liballoc/lib.rs | 1 + src/liballoc/slice.rs | 1396 +--------------------- src/libcore/lib.rs | 2 +- src/libcore/prelude/v1.rs | 1 + src/libcore/slice/mod.rs | 1404 +++++++++++++++++++++++ src/librustc/middle/lang_items.rs | 1 + src/librustc_typeck/check/method/probe.rs | 3 + src/librustc_typeck/coherence/inherent_impls.rs | 2 +- src/librustdoc/clean/inline.rs | 1 + 9 files changed, 1418 insertions(+), 1393 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 163aef61b43..52011303543 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -90,6 +90,7 @@ #![feature(collections_range)] #![feature(const_fn)] #![feature(core_intrinsics)] +#![cfg_attr(stage0, feature(core_slice_ext))] #![feature(custom_attribute)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 70945a791f6..4594263c01f 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -101,7 +101,7 @@ use core::cmp::Ordering::{self, Less}; use core::mem::size_of; use core::mem; use core::ptr; -use core::slice as core_slice; +#[cfg(stage0)] use core::slice::SliceExt; use core::{u8, u16, u32}; use borrow::{Borrow, BorrowMut, ToOwned}; @@ -171,1059 +171,12 @@ mod hack { } } -#[lang = "slice"] +#[cfg_attr(stage0, lang = "slice")] +#[cfg_attr(not(stage0), lang = "slice_alloc")] #[cfg(not(test))] impl [T] { - /// Returns the number of elements in the slice. - /// - /// # Examples - /// - /// ``` - /// let a = [1, 2, 3]; - /// assert_eq!(a.len(), 3); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn len(&self) -> usize { - core_slice::SliceExt::len(self) - } - - /// Returns `true` if the slice has a length of 0. - /// - /// # Examples - /// - /// ``` - /// let a = [1, 2, 3]; - /// assert!(!a.is_empty()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_empty(&self) -> bool { - core_slice::SliceExt::is_empty(self) - } - - /// Returns the first element of the slice, or `None` if it is empty. - /// - /// # Examples - /// - /// ``` - /// let v = [10, 40, 30]; - /// assert_eq!(Some(&10), v.first()); - /// - /// let w: &[i32] = &[]; - /// assert_eq!(None, w.first()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn first(&self) -> Option<&T> { - core_slice::SliceExt::first(self) - } - - /// Returns a mutable pointer to the first element of the slice, or `None` if it is empty. - /// - /// # Examples - /// - /// ``` - /// let x = &mut [0, 1, 2]; - /// - /// if let Some(first) = x.first_mut() { - /// *first = 5; - /// } - /// assert_eq!(x, &[5, 1, 2]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn first_mut(&mut self) -> Option<&mut T> { - core_slice::SliceExt::first_mut(self) - } - - /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. - /// - /// # Examples - /// - /// ``` - /// let x = &[0, 1, 2]; - /// - /// if let Some((first, elements)) = x.split_first() { - /// assert_eq!(first, &0); - /// assert_eq!(elements, &[1, 2]); - /// } - /// ``` - #[stable(feature = "slice_splits", since = "1.5.0")] - #[inline] - pub fn split_first(&self) -> Option<(&T, &[T])> { - core_slice::SliceExt::split_first(self) - } - - /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. - /// - /// # Examples - /// - /// ``` - /// let x = &mut [0, 1, 2]; - /// - /// if let Some((first, elements)) = x.split_first_mut() { - /// *first = 3; - /// elements[0] = 4; - /// elements[1] = 5; - /// } - /// assert_eq!(x, &[3, 4, 5]); - /// ``` - #[stable(feature = "slice_splits", since = "1.5.0")] - #[inline] - pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { - core_slice::SliceExt::split_first_mut(self) - } - - /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. - /// - /// # Examples - /// - /// ``` - /// let x = &[0, 1, 2]; - /// - /// if let Some((last, elements)) = x.split_last() { - /// assert_eq!(last, &2); - /// assert_eq!(elements, &[0, 1]); - /// } - /// ``` - #[stable(feature = "slice_splits", since = "1.5.0")] - #[inline] - pub fn split_last(&self) -> Option<(&T, &[T])> { - core_slice::SliceExt::split_last(self) - - } - - /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. - /// - /// # Examples - /// - /// ``` - /// let x = &mut [0, 1, 2]; - /// - /// if let Some((last, elements)) = x.split_last_mut() { - /// *last = 3; - /// elements[0] = 4; - /// elements[1] = 5; - /// } - /// assert_eq!(x, &[4, 5, 3]); - /// ``` - #[stable(feature = "slice_splits", since = "1.5.0")] - #[inline] - pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { - core_slice::SliceExt::split_last_mut(self) - } - - /// Returns the last element of the slice, or `None` if it is empty. - /// - /// # Examples - /// - /// ``` - /// let v = [10, 40, 30]; - /// assert_eq!(Some(&30), v.last()); - /// - /// let w: &[i32] = &[]; - /// assert_eq!(None, w.last()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn last(&self) -> Option<&T> { - core_slice::SliceExt::last(self) - } - - /// Returns a mutable pointer to the last item in the slice. - /// - /// # Examples - /// - /// ``` - /// let x = &mut [0, 1, 2]; - /// - /// if let Some(last) = x.last_mut() { - /// *last = 10; - /// } - /// assert_eq!(x, &[0, 1, 10]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn last_mut(&mut self) -> Option<&mut T> { - core_slice::SliceExt::last_mut(self) - } - - /// Returns a reference to an element or subslice depending on the type of - /// index. - /// - /// - If given a position, returns a reference to the element at that - /// position or `None` if out of bounds. - /// - If given a range, returns the subslice corresponding to that range, - /// or `None` if out of bounds. - /// - /// # Examples - /// - /// ``` - /// let v = [10, 40, 30]; - /// assert_eq!(Some(&40), v.get(1)); - /// assert_eq!(Some(&[10, 40][..]), v.get(0..2)); - /// assert_eq!(None, v.get(3)); - /// assert_eq!(None, v.get(0..4)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex - { - core_slice::SliceExt::get(self, index) - } - - /// Returns a mutable reference to an element or subslice depending on the - /// type of index (see [`get`]) or `None` if the index is out of bounds. - /// - /// [`get`]: #method.get - /// - /// # Examples - /// - /// ``` - /// let x = &mut [0, 1, 2]; - /// - /// if let Some(elem) = x.get_mut(1) { - /// *elem = 42; - /// } - /// assert_eq!(x, &[0, 42, 2]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex - { - core_slice::SliceExt::get_mut(self, index) - } - - /// Returns a reference to an element or subslice, without doing bounds - /// checking. - /// - /// This is generally not recommended, use with caution! For a safe - /// alternative see [`get`]. - /// - /// [`get`]: #method.get - /// - /// # Examples - /// - /// ``` - /// let x = &[1, 2, 4]; - /// - /// unsafe { - /// assert_eq!(x.get_unchecked(1), &2); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex - { - core_slice::SliceExt::get_unchecked(self, index) - } - - /// Returns a mutable reference to an element or subslice, without doing - /// bounds checking. - /// - /// This is generally not recommended, use with caution! For a safe - /// alternative see [`get_mut`]. - /// - /// [`get_mut`]: #method.get_mut - /// - /// # Examples - /// - /// ``` - /// let x = &mut [1, 2, 4]; - /// - /// unsafe { - /// let elem = x.get_unchecked_mut(1); - /// *elem = 13; - /// } - /// assert_eq!(x, &[1, 13, 4]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex - { - core_slice::SliceExt::get_unchecked_mut(self, index) - } - - /// Returns a raw pointer to the slice's buffer. - /// - /// The caller must ensure that the slice outlives the pointer this - /// function returns, or else it will end up pointing to garbage. - /// - /// Modifying the container referenced by this slice may cause its buffer - /// to be reallocated, which would also make any pointers to it invalid. - /// - /// # Examples - /// - /// ``` - /// let x = &[1, 2, 4]; - /// let x_ptr = x.as_ptr(); - /// - /// unsafe { - /// for i in 0..x.len() { - /// assert_eq!(x.get_unchecked(i), &*x_ptr.offset(i as isize)); - /// } - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn as_ptr(&self) -> *const T { - core_slice::SliceExt::as_ptr(self) - } - - /// Returns an unsafe mutable pointer to the slice's buffer. - /// - /// The caller must ensure that the slice outlives the pointer this - /// function returns, or else it will end up pointing to garbage. - /// - /// Modifying the container referenced by this slice may cause its buffer - /// to be reallocated, which would also make any pointers to it invalid. - /// - /// # Examples - /// - /// ``` - /// let x = &mut [1, 2, 4]; - /// let x_ptr = x.as_mut_ptr(); - /// - /// unsafe { - /// for i in 0..x.len() { - /// *x_ptr.offset(i as isize) += 2; - /// } - /// } - /// assert_eq!(x, &[3, 4, 6]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn as_mut_ptr(&mut self) -> *mut T { - core_slice::SliceExt::as_mut_ptr(self) - } - - /// Swaps two elements in the slice. - /// - /// # Arguments - /// - /// * a - The index of the first element - /// * b - The index of the second element - /// - /// # Panics - /// - /// Panics if `a` or `b` are out of bounds. - /// - /// # Examples - /// - /// ``` - /// let mut v = ["a", "b", "c", "d"]; - /// v.swap(1, 3); - /// assert!(v == ["a", "d", "c", "b"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn swap(&mut self, a: usize, b: usize) { - core_slice::SliceExt::swap(self, a, b) - } - - /// Reverses the order of elements in the slice, in place. - /// - /// # Examples - /// - /// ``` - /// let mut v = [1, 2, 3]; - /// v.reverse(); - /// assert!(v == [3, 2, 1]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn reverse(&mut self) { - core_slice::SliceExt::reverse(self) - } - - /// Returns an iterator over the slice. - /// - /// # Examples - /// - /// ``` - /// let x = &[1, 2, 4]; - /// let mut iterator = x.iter(); - /// - /// assert_eq!(iterator.next(), Some(&1)); - /// assert_eq!(iterator.next(), Some(&2)); - /// assert_eq!(iterator.next(), Some(&4)); - /// assert_eq!(iterator.next(), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn iter(&self) -> Iter { - core_slice::SliceExt::iter(self) - } - - /// Returns an iterator that allows modifying each value. - /// - /// # Examples - /// - /// ``` - /// let x = &mut [1, 2, 4]; - /// for elem in x.iter_mut() { - /// *elem += 2; - /// } - /// assert_eq!(x, &[3, 4, 6]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn iter_mut(&mut self) -> IterMut { - core_slice::SliceExt::iter_mut(self) - } - - /// Returns an iterator over all contiguous windows of length - /// `size`. The windows overlap. If the slice is shorter than - /// `size`, the iterator returns no values. - /// - /// # Panics - /// - /// Panics if `size` is 0. - /// - /// # Examples - /// - /// ``` - /// let slice = ['r', 'u', 's', 't']; - /// let mut iter = slice.windows(2); - /// assert_eq!(iter.next().unwrap(), &['r', 'u']); - /// assert_eq!(iter.next().unwrap(), &['u', 's']); - /// assert_eq!(iter.next().unwrap(), &['s', 't']); - /// assert!(iter.next().is_none()); - /// ``` - /// - /// If the slice is shorter than `size`: - /// - /// ``` - /// let slice = ['f', 'o', 'o']; - /// let mut iter = slice.windows(4); - /// assert!(iter.next().is_none()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn windows(&self, size: usize) -> Windows { - core_slice::SliceExt::windows(self, size) - } - - /// Returns an iterator over `chunk_size` elements of the slice at a - /// time. The chunks are slices and do not overlap. If `chunk_size` does - /// not divide the length of the slice, then the last chunk will - /// not have length `chunk_size`. - /// - /// See [`exact_chunks`] for a variant of this iterator that returns chunks - /// of always exactly `chunk_size` elements. - /// - /// # Panics - /// - /// Panics if `chunk_size` is 0. - /// - /// # Examples - /// - /// ``` - /// let slice = ['l', 'o', 'r', 'e', 'm']; - /// let mut iter = slice.chunks(2); - /// assert_eq!(iter.next().unwrap(), &['l', 'o']); - /// assert_eq!(iter.next().unwrap(), &['r', 'e']); - /// assert_eq!(iter.next().unwrap(), &['m']); - /// assert!(iter.next().is_none()); - /// ``` - /// - /// [`exact_chunks`]: #method.exact_chunks - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn chunks(&self, chunk_size: usize) -> Chunks { - core_slice::SliceExt::chunks(self, chunk_size) - } - - /// Returns an iterator over `chunk_size` elements of the slice at a - /// time. The chunks are slices and do not overlap. If `chunk_size` does - /// not divide the length of the slice, then the last up to `chunk_size-1` - /// elements will be omitted. - /// - /// Due to each chunk having exactly `chunk_size` elements, the compiler - /// can often optimize the resulting code better than in the case of - /// [`chunks`]. - /// - /// # Panics - /// - /// Panics if `chunk_size` is 0. - /// - /// # Examples - /// - /// ``` - /// #![feature(exact_chunks)] - /// - /// let slice = ['l', 'o', 'r', 'e', 'm']; - /// let mut iter = slice.exact_chunks(2); - /// assert_eq!(iter.next().unwrap(), &['l', 'o']); - /// assert_eq!(iter.next().unwrap(), &['r', 'e']); - /// assert!(iter.next().is_none()); - /// ``` - /// - /// [`chunks`]: #method.chunks - #[unstable(feature = "exact_chunks", issue = "47115")] - #[inline] - pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks { - core_slice::SliceExt::exact_chunks(self, chunk_size) - } - - /// Returns an iterator over `chunk_size` elements of the slice at a time. - /// The chunks are mutable slices, and do not overlap. If `chunk_size` does - /// not divide the length of the slice, then the last chunk will not - /// have length `chunk_size`. - /// - /// See [`exact_chunks_mut`] for a variant of this iterator that returns chunks - /// of always exactly `chunk_size` elements. - /// - /// # Panics - /// - /// Panics if `chunk_size` is 0. - /// - /// # Examples - /// - /// ``` - /// let v = &mut [0, 0, 0, 0, 0]; - /// let mut count = 1; - /// - /// for chunk in v.chunks_mut(2) { - /// for elem in chunk.iter_mut() { - /// *elem += count; - /// } - /// count += 1; - /// } - /// assert_eq!(v, &[1, 1, 2, 2, 3]); - /// ``` - /// - /// [`exact_chunks_mut`]: #method.exact_chunks_mut - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut { - core_slice::SliceExt::chunks_mut(self, chunk_size) - } - - /// Returns an iterator over `chunk_size` elements of the slice at a time. - /// The chunks are mutable slices, and do not overlap. If `chunk_size` does - /// not divide the length of the slice, then the last up to `chunk_size-1` - /// elements will be omitted. - /// - /// - /// Due to each chunk having exactly `chunk_size` elements, the compiler - /// can often optimize the resulting code better than in the case of - /// [`chunks_mut`]. - /// - /// # Panics - /// - /// Panics if `chunk_size` is 0. - /// - /// # Examples - /// - /// ``` - /// #![feature(exact_chunks)] - /// - /// let v = &mut [0, 0, 0, 0, 0]; - /// let mut count = 1; - /// - /// for chunk in v.exact_chunks_mut(2) { - /// for elem in chunk.iter_mut() { - /// *elem += count; - /// } - /// count += 1; - /// } - /// assert_eq!(v, &[1, 1, 2, 2, 0]); - /// ``` - /// - /// [`chunks_mut`]: #method.chunks_mut - #[unstable(feature = "exact_chunks", issue = "47115")] - #[inline] - pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut { - core_slice::SliceExt::exact_chunks_mut(self, chunk_size) - } - - /// Divides one slice into two at an index. - /// - /// The first will contain all indices from `[0, mid)` (excluding - /// the index `mid` itself) and the second will contain all - /// indices from `[mid, len)` (excluding the index `len` itself). - /// - /// # Panics - /// - /// Panics if `mid > len`. - /// - /// # Examples - /// - /// ``` - /// let v = [1, 2, 3, 4, 5, 6]; - /// - /// { - /// let (left, right) = v.split_at(0); - /// assert!(left == []); - /// assert!(right == [1, 2, 3, 4, 5, 6]); - /// } - /// - /// { - /// let (left, right) = v.split_at(2); - /// assert!(left == [1, 2]); - /// assert!(right == [3, 4, 5, 6]); - /// } - /// - /// { - /// let (left, right) = v.split_at(6); - /// assert!(left == [1, 2, 3, 4, 5, 6]); - /// assert!(right == []); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn split_at(&self, mid: usize) -> (&[T], &[T]) { - core_slice::SliceExt::split_at(self, mid) - } - - /// Divides one mutable slice into two at an index. - /// - /// The first will contain all indices from `[0, mid)` (excluding - /// the index `mid` itself) and the second will contain all - /// indices from `[mid, len)` (excluding the index `len` itself). - /// - /// # Panics - /// - /// Panics if `mid > len`. - /// - /// # Examples - /// - /// ``` - /// let mut v = [1, 0, 3, 0, 5, 6]; - /// // scoped to restrict the lifetime of the borrows - /// { - /// let (left, right) = v.split_at_mut(2); - /// assert!(left == [1, 0]); - /// assert!(right == [3, 0, 5, 6]); - /// left[1] = 2; - /// right[1] = 4; - /// } - /// assert!(v == [1, 2, 3, 4, 5, 6]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { - core_slice::SliceExt::split_at_mut(self, mid) - } - - /// Returns an iterator over subslices separated by elements that match - /// `pred`. The matched element is not contained in the subslices. - /// - /// # Examples - /// - /// ``` - /// let slice = [10, 40, 33, 20]; - /// let mut iter = slice.split(|num| num % 3 == 0); - /// - /// assert_eq!(iter.next().unwrap(), &[10, 40]); - /// assert_eq!(iter.next().unwrap(), &[20]); - /// assert!(iter.next().is_none()); - /// ``` - /// - /// If the first element is matched, an empty slice will be the first item - /// returned by the iterator. Similarly, if the last element in the slice - /// is matched, an empty slice will be the last item returned by the - /// iterator: - /// - /// ``` - /// let slice = [10, 40, 33]; - /// let mut iter = slice.split(|num| num % 3 == 0); - /// - /// assert_eq!(iter.next().unwrap(), &[10, 40]); - /// assert_eq!(iter.next().unwrap(), &[]); - /// assert!(iter.next().is_none()); - /// ``` - /// - /// If two matched elements are directly adjacent, an empty slice will be - /// present between them: - /// - /// ``` - /// let slice = [10, 6, 33, 20]; - /// let mut iter = slice.split(|num| num % 3 == 0); - /// - /// assert_eq!(iter.next().unwrap(), &[10]); - /// assert_eq!(iter.next().unwrap(), &[]); - /// assert_eq!(iter.next().unwrap(), &[20]); - /// assert!(iter.next().is_none()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn split(&self, pred: F) -> Split - where F: FnMut(&T) -> bool - { - core_slice::SliceExt::split(self, pred) - } - - /// Returns an iterator over mutable subslices separated by elements that - /// match `pred`. The matched element is not contained in the subslices. - /// - /// # Examples - /// - /// ``` - /// let mut v = [10, 40, 30, 20, 60, 50]; - /// - /// for group in v.split_mut(|num| *num % 3 == 0) { - /// group[0] = 1; - /// } - /// assert_eq!(v, [1, 40, 30, 1, 60, 1]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn split_mut(&mut self, pred: F) -> SplitMut - where F: FnMut(&T) -> bool - { - core_slice::SliceExt::split_mut(self, pred) - } - - /// Returns an iterator over subslices separated by elements that match - /// `pred`, starting at the end of the slice and working backwards. - /// The matched element is not contained in the subslices. - /// - /// # Examples - /// - /// ``` - /// - /// let slice = [11, 22, 33, 0, 44, 55]; - /// let mut iter = slice.rsplit(|num| *num == 0); - /// - /// assert_eq!(iter.next().unwrap(), &[44, 55]); - /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]); - /// assert_eq!(iter.next(), None); - /// ``` - /// - /// As with `split()`, if the first or last element is matched, an empty - /// slice will be the first (or last) item returned by the iterator. - /// - /// ``` - /// let v = &[0, 1, 1, 2, 3, 5, 8]; - /// let mut it = v.rsplit(|n| *n % 2 == 0); - /// assert_eq!(it.next().unwrap(), &[]); - /// assert_eq!(it.next().unwrap(), &[3, 5]); - /// assert_eq!(it.next().unwrap(), &[1, 1]); - /// assert_eq!(it.next().unwrap(), &[]); - /// assert_eq!(it.next(), None); - /// ``` - #[stable(feature = "slice_rsplit", since = "1.27.0")] - #[inline] - pub fn rsplit(&self, pred: F) -> RSplit - where F: FnMut(&T) -> bool - { - core_slice::SliceExt::rsplit(self, pred) - } - - /// Returns an iterator over mutable subslices separated by elements that - /// match `pred`, starting at the end of the slice and working - /// backwards. The matched element is not contained in the subslices. - /// - /// # Examples - /// - /// ``` - /// let mut v = [100, 400, 300, 200, 600, 500]; - /// - /// let mut count = 0; - /// for group in v.rsplit_mut(|num| *num % 3 == 0) { - /// count += 1; - /// group[0] = count; - /// } - /// assert_eq!(v, [3, 400, 300, 2, 600, 1]); - /// ``` - /// - #[stable(feature = "slice_rsplit", since = "1.27.0")] - #[inline] - pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut - where F: FnMut(&T) -> bool - { - core_slice::SliceExt::rsplit_mut(self, pred) - } - - /// Returns an iterator over subslices separated by elements that match - /// `pred`, limited to returning at most `n` items. The matched element is - /// not contained in the subslices. - /// - /// The last element returned, if any, will contain the remainder of the - /// slice. - /// - /// # Examples - /// - /// Print the slice split once by numbers divisible by 3 (i.e. `[10, 40]`, - /// `[20, 60, 50]`): - /// - /// ``` - /// let v = [10, 40, 30, 20, 60, 50]; - /// - /// for group in v.splitn(2, |num| *num % 3 == 0) { - /// println!("{:?}", group); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn splitn(&self, n: usize, pred: F) -> SplitN - where F: FnMut(&T) -> bool - { - core_slice::SliceExt::splitn(self, n, pred) - } - - /// Returns an iterator over subslices separated by elements that match - /// `pred`, limited to returning at most `n` items. The matched element is - /// not contained in the subslices. - /// - /// The last element returned, if any, will contain the remainder of the - /// slice. - /// - /// # Examples - /// - /// ``` - /// let mut v = [10, 40, 30, 20, 60, 50]; - /// - /// for group in v.splitn_mut(2, |num| *num % 3 == 0) { - /// group[0] = 1; - /// } - /// assert_eq!(v, [1, 40, 30, 1, 60, 50]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn splitn_mut(&mut self, n: usize, pred: F) -> SplitNMut - where F: FnMut(&T) -> bool - { - core_slice::SliceExt::splitn_mut(self, n, pred) - } - - /// Returns an iterator over subslices separated by elements that match - /// `pred` limited to returning at most `n` items. This starts at the end of - /// the slice and works backwards. The matched element is not contained in - /// the subslices. - /// - /// The last element returned, if any, will contain the remainder of the - /// slice. - /// - /// # Examples - /// - /// Print the slice split once, starting from the end, by numbers divisible - /// by 3 (i.e. `[50]`, `[10, 40, 30, 20]`): - /// - /// ``` - /// let v = [10, 40, 30, 20, 60, 50]; - /// - /// for group in v.rsplitn(2, |num| *num % 3 == 0) { - /// println!("{:?}", group); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn rsplitn(&self, n: usize, pred: F) -> RSplitN - where F: FnMut(&T) -> bool - { - core_slice::SliceExt::rsplitn(self, n, pred) - } - - /// Returns an iterator over subslices separated by elements that match - /// `pred` limited to returning at most `n` items. This starts at the end of - /// the slice and works backwards. The matched element is not contained in - /// the subslices. - /// - /// The last element returned, if any, will contain the remainder of the - /// slice. - /// - /// # Examples - /// - /// ``` - /// let mut s = [10, 40, 30, 20, 60, 50]; - /// - /// for group in s.rsplitn_mut(2, |num| *num % 3 == 0) { - /// group[0] = 1; - /// } - /// assert_eq!(s, [1, 40, 30, 20, 60, 1]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn rsplitn_mut(&mut self, n: usize, pred: F) -> RSplitNMut - where F: FnMut(&T) -> bool - { - core_slice::SliceExt::rsplitn_mut(self, n, pred) - } - - /// Returns `true` if the slice contains an element with the given value. - /// - /// # Examples - /// - /// ``` - /// let v = [10, 40, 30]; - /// assert!(v.contains(&30)); - /// assert!(!v.contains(&50)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn contains(&self, x: &T) -> bool - where T: PartialEq - { - core_slice::SliceExt::contains(self, x) - } - - /// Returns `true` if `needle` is a prefix of the slice. - /// - /// # Examples - /// - /// ``` - /// let v = [10, 40, 30]; - /// assert!(v.starts_with(&[10])); - /// assert!(v.starts_with(&[10, 40])); - /// assert!(!v.starts_with(&[50])); - /// assert!(!v.starts_with(&[10, 50])); - /// ``` - /// - /// Always returns `true` if `needle` is an empty slice: - /// - /// ``` - /// let v = &[10, 40, 30]; - /// assert!(v.starts_with(&[])); - /// let v: &[u8] = &[]; - /// assert!(v.starts_with(&[])); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn starts_with(&self, needle: &[T]) -> bool - where T: PartialEq - { - core_slice::SliceExt::starts_with(self, needle) - } - - /// Returns `true` if `needle` is a suffix of the slice. - /// - /// # Examples - /// - /// ``` - /// let v = [10, 40, 30]; - /// assert!(v.ends_with(&[30])); - /// assert!(v.ends_with(&[40, 30])); - /// assert!(!v.ends_with(&[50])); - /// assert!(!v.ends_with(&[50, 30])); - /// ``` - /// - /// Always returns `true` if `needle` is an empty slice: - /// - /// ``` - /// let v = &[10, 40, 30]; - /// assert!(v.ends_with(&[])); - /// let v: &[u8] = &[]; - /// assert!(v.ends_with(&[])); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn ends_with(&self, needle: &[T]) -> bool - where T: PartialEq - { - core_slice::SliceExt::ends_with(self, needle) - } - - /// Binary searches this sorted slice for a given element. - /// - /// If the value is found then `Ok` is returned, containing the - /// index of the matching element; if the value is not found then - /// `Err` is returned, containing the index where a matching - /// element could be inserted while maintaining sorted order. - /// - /// # Examples - /// - /// Looks up a series of four elements. The first is found, with a - /// uniquely determined position; the second and third are not - /// found; the fourth could match any position in `[1, 4]`. - /// - /// ``` - /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; - /// - /// assert_eq!(s.binary_search(&13), Ok(9)); - /// assert_eq!(s.binary_search(&4), Err(7)); - /// assert_eq!(s.binary_search(&100), Err(13)); - /// let r = s.binary_search(&1); - /// assert!(match r { Ok(1...4) => true, _ => false, }); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn binary_search(&self, x: &T) -> Result - where T: Ord - { - core_slice::SliceExt::binary_search(self, x) - } - - /// Binary searches this sorted slice with a comparator function. - /// - /// The comparator function should implement an order consistent - /// with the sort order of the underlying slice, returning an - /// order code that indicates whether its argument is `Less`, - /// `Equal` or `Greater` the desired target. - /// - /// If a matching value is found then returns `Ok`, containing - /// the index for the matched element; if no match is found then - /// `Err` is returned, containing the index where a matching - /// element could be inserted while maintaining sorted order. - /// - /// # Examples - /// - /// Looks up a series of four elements. The first is found, with a - /// uniquely determined position; the second and third are not - /// found; the fourth could match any position in `[1, 4]`. - /// - /// ``` - /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; - /// - /// let seek = 13; - /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9)); - /// let seek = 4; - /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7)); - /// let seek = 100; - /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13)); - /// let seek = 1; - /// let r = s.binary_search_by(|probe| probe.cmp(&seek)); - /// assert!(match r { Ok(1...4) => true, _ => false, }); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result - where F: FnMut(&'a T) -> Ordering - { - core_slice::SliceExt::binary_search_by(self, f) - } - - /// Binary searches this sorted slice with a key extraction function. - /// - /// Assumes that the slice is sorted by the key, for instance with - /// [`sort_by_key`] using the same key extraction function. - /// - /// If a matching value is found then returns `Ok`, containing the - /// index for the matched element; if no match is found then `Err` - /// is returned, containing the index where a matching element could - /// be inserted while maintaining sorted order. - /// - /// [`sort_by_key`]: #method.sort_by_key - /// - /// # Examples - /// - /// Looks up a series of four elements in a slice of pairs sorted by - /// their second elements. The first is found, with a uniquely - /// determined position; the second and third are not found; the - /// fourth could match any position in `[1, 4]`. - /// - /// ``` - /// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1), - /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), - /// (1, 21), (2, 34), (4, 55)]; - /// - /// assert_eq!(s.binary_search_by_key(&13, |&(a,b)| b), Ok(9)); - /// assert_eq!(s.binary_search_by_key(&4, |&(a,b)| b), Err(7)); - /// assert_eq!(s.binary_search_by_key(&100, |&(a,b)| b), Err(13)); - /// let r = s.binary_search_by_key(&1, |&(a,b)| b); - /// assert!(match r { Ok(1...4) => true, _ => false, }); - /// ``` - #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] - #[inline] - pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result - where F: FnMut(&'a T) -> B, - B: Ord - { - core_slice::SliceExt::binary_search_by_key(self, b, f) - } + #[cfg(stage0)] + slice_core_methods!(); /// Sorts the slice. /// @@ -1402,345 +355,6 @@ impl [T] { sort_by_key!(usize, self, f) } - /// Sorts the slice, but may not preserve the order of equal elements. - /// - /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), - /// and `O(n log n)` worst-case. - /// - /// # Current implementation - /// - /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, - /// which combines the fast average case of randomized quicksort with the fast worst case of - /// heapsort, while achieving linear time on slices with certain patterns. It uses some - /// randomization to avoid degenerate cases, but with a fixed seed to always provide - /// deterministic behavior. - /// - /// It is typically faster than stable sorting, except in a few special cases, e.g. when the - /// slice consists of several concatenated sorted sequences. - /// - /// # Examples - /// - /// ``` - /// let mut v = [-5, 4, 1, -3, 2]; - /// - /// v.sort_unstable(); - /// assert!(v == [-5, -3, 1, 2, 4]); - /// ``` - /// - /// [pdqsort]: https://github.com/orlp/pdqsort - #[stable(feature = "sort_unstable", since = "1.20.0")] - #[inline] - pub fn sort_unstable(&mut self) - where T: Ord - { - core_slice::SliceExt::sort_unstable(self); - } - - /// Sorts the slice with a comparator function, but may not preserve the order of equal - /// elements. - /// - /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), - /// and `O(n log n)` worst-case. - /// - /// # Current implementation - /// - /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, - /// which combines the fast average case of randomized quicksort with the fast worst case of - /// heapsort, while achieving linear time on slices with certain patterns. It uses some - /// randomization to avoid degenerate cases, but with a fixed seed to always provide - /// deterministic behavior. - /// - /// It is typically faster than stable sorting, except in a few special cases, e.g. when the - /// slice consists of several concatenated sorted sequences. - /// - /// # Examples - /// - /// ``` - /// let mut v = [5, 4, 1, 3, 2]; - /// v.sort_unstable_by(|a, b| a.cmp(b)); - /// assert!(v == [1, 2, 3, 4, 5]); - /// - /// // reverse sorting - /// v.sort_unstable_by(|a, b| b.cmp(a)); - /// assert!(v == [5, 4, 3, 2, 1]); - /// ``` - /// - /// [pdqsort]: https://github.com/orlp/pdqsort - #[stable(feature = "sort_unstable", since = "1.20.0")] - #[inline] - pub fn sort_unstable_by(&mut self, compare: F) - where F: FnMut(&T, &T) -> Ordering - { - core_slice::SliceExt::sort_unstable_by(self, compare); - } - - /// Sorts the slice with a key extraction function, but may not preserve the order of equal - /// elements. - /// - /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), - /// and `O(m n log(m n))` worst-case, where the key function is `O(m)`. - /// - /// # Current implementation - /// - /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, - /// which combines the fast average case of randomized quicksort with the fast worst case of - /// heapsort, while achieving linear time on slices with certain patterns. It uses some - /// randomization to avoid degenerate cases, but with a fixed seed to always provide - /// deterministic behavior. - /// - /// # Examples - /// - /// ``` - /// let mut v = [-5i32, 4, 1, -3, 2]; - /// - /// v.sort_unstable_by_key(|k| k.abs()); - /// assert!(v == [1, 2, -3, 4, -5]); - /// ``` - /// - /// [pdqsort]: https://github.com/orlp/pdqsort - #[stable(feature = "sort_unstable", since = "1.20.0")] - #[inline] - pub fn sort_unstable_by_key(&mut self, f: F) - where F: FnMut(&T) -> K, K: Ord - { - core_slice::SliceExt::sort_unstable_by_key(self, f); - } - - /// Rotates the slice in-place such that the first `mid` elements of the - /// slice move to the end while the last `self.len() - mid` elements move to - /// the front. After calling `rotate_left`, the element previously at index - /// `mid` will become the first element in the slice. - /// - /// # Panics - /// - /// This function will panic if `mid` is greater than the length of the - /// slice. Note that `mid == self.len()` does _not_ panic and is a no-op - /// rotation. - /// - /// # Complexity - /// - /// Takes linear (in `self.len()`) time. - /// - /// # Examples - /// - /// ``` - /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; - /// a.rotate_left(2); - /// assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']); - /// ``` - /// - /// Rotating a subslice: - /// - /// ``` - /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; - /// a[1..5].rotate_left(1); - /// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']); - /// ``` - #[stable(feature = "slice_rotate", since = "1.26.0")] - pub fn rotate_left(&mut self, mid: usize) { - core_slice::SliceExt::rotate_left(self, mid); - } - - /// Rotates the slice in-place such that the first `self.len() - k` - /// elements of the slice move to the end while the last `k` elements move - /// to the front. After calling `rotate_right`, the element previously at - /// index `self.len() - k` will become the first element in the slice. - /// - /// # Panics - /// - /// This function will panic if `k` is greater than the length of the - /// slice. Note that `k == self.len()` does _not_ panic and is a no-op - /// rotation. - /// - /// # Complexity - /// - /// Takes linear (in `self.len()`) time. - /// - /// # Examples - /// - /// ``` - /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; - /// a.rotate_right(2); - /// assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']); - /// ``` - /// - /// Rotate a subslice: - /// - /// ``` - /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; - /// a[1..5].rotate_right(1); - /// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']); - /// ``` - #[stable(feature = "slice_rotate", since = "1.26.0")] - pub fn rotate_right(&mut self, k: usize) { - core_slice::SliceExt::rotate_right(self, k); - } - - /// Copies the elements from `src` into `self`. - /// - /// The length of `src` must be the same as `self`. - /// - /// If `src` implements `Copy`, it can be more performant to use - /// [`copy_from_slice`]. - /// - /// # Panics - /// - /// This function will panic if the two slices have different lengths. - /// - /// # Examples - /// - /// Cloning two elements from a slice into another: - /// - /// ``` - /// let src = [1, 2, 3, 4]; - /// let mut dst = [0, 0]; - /// - /// dst.clone_from_slice(&src[2..]); - /// - /// assert_eq!(src, [1, 2, 3, 4]); - /// assert_eq!(dst, [3, 4]); - /// ``` - /// - /// Rust enforces that there can only be one mutable reference with no - /// immutable references to a particular piece of data in a particular - /// scope. Because of this, attempting to use `clone_from_slice` on a - /// single slice will result in a compile failure: - /// - /// ```compile_fail - /// let mut slice = [1, 2, 3, 4, 5]; - /// - /// slice[..2].clone_from_slice(&slice[3..]); // compile fail! - /// ``` - /// - /// To work around this, we can use [`split_at_mut`] to create two distinct - /// sub-slices from a slice: - /// - /// ``` - /// let mut slice = [1, 2, 3, 4, 5]; - /// - /// { - /// let (left, right) = slice.split_at_mut(2); - /// left.clone_from_slice(&right[1..]); - /// } - /// - /// assert_eq!(slice, [4, 5, 3, 4, 5]); - /// ``` - /// - /// [`copy_from_slice`]: #method.copy_from_slice - /// [`split_at_mut`]: #method.split_at_mut - #[stable(feature = "clone_from_slice", since = "1.7.0")] - pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone { - core_slice::SliceExt::clone_from_slice(self, src) - } - - /// Copies all elements from `src` into `self`, using a memcpy. - /// - /// The length of `src` must be the same as `self`. - /// - /// If `src` does not implement `Copy`, use [`clone_from_slice`]. - /// - /// # Panics - /// - /// This function will panic if the two slices have different lengths. - /// - /// # Examples - /// - /// Copying two elements from a slice into another: - /// - /// ``` - /// let src = [1, 2, 3, 4]; - /// let mut dst = [0, 0]; - /// - /// dst.copy_from_slice(&src[2..]); - /// - /// assert_eq!(src, [1, 2, 3, 4]); - /// assert_eq!(dst, [3, 4]); - /// ``` - /// - /// Rust enforces that there can only be one mutable reference with no - /// immutable references to a particular piece of data in a particular - /// scope. Because of this, attempting to use `copy_from_slice` on a - /// single slice will result in a compile failure: - /// - /// ```compile_fail - /// let mut slice = [1, 2, 3, 4, 5]; - /// - /// slice[..2].copy_from_slice(&slice[3..]); // compile fail! - /// ``` - /// - /// To work around this, we can use [`split_at_mut`] to create two distinct - /// sub-slices from a slice: - /// - /// ``` - /// let mut slice = [1, 2, 3, 4, 5]; - /// - /// { - /// let (left, right) = slice.split_at_mut(2); - /// left.copy_from_slice(&right[1..]); - /// } - /// - /// assert_eq!(slice, [4, 5, 3, 4, 5]); - /// ``` - /// - /// [`clone_from_slice`]: #method.clone_from_slice - /// [`split_at_mut`]: #method.split_at_mut - #[stable(feature = "copy_from_slice", since = "1.9.0")] - pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy { - core_slice::SliceExt::copy_from_slice(self, src) - } - - /// Swaps all elements in `self` with those in `other`. - /// - /// The length of `other` must be the same as `self`. - /// - /// # Panics - /// - /// This function will panic if the two slices have different lengths. - /// - /// # Example - /// - /// Swapping two elements across slices: - /// - /// ``` - /// let mut slice1 = [0, 0]; - /// let mut slice2 = [1, 2, 3, 4]; - /// - /// slice1.swap_with_slice(&mut slice2[2..]); - /// - /// assert_eq!(slice1, [3, 4]); - /// assert_eq!(slice2, [1, 2, 0, 0]); - /// ``` - /// - /// Rust enforces that there can only be one mutable reference to a - /// particular piece of data in a particular scope. Because of this, - /// attempting to use `swap_with_slice` on a single slice will result in - /// a compile failure: - /// - /// ```compile_fail - /// let mut slice = [1, 2, 3, 4, 5]; - /// slice[..2].swap_with_slice(&mut slice[3..]); // compile fail! - /// ``` - /// - /// To work around this, we can use [`split_at_mut`] to create two distinct - /// mutable sub-slices from a slice: - /// - /// ``` - /// let mut slice = [1, 2, 3, 4, 5]; - /// - /// { - /// let (left, right) = slice.split_at_mut(2); - /// left.swap_with_slice(&mut right[1..]); - /// } - /// - /// assert_eq!(slice, [4, 5, 3, 1, 2]); - /// ``` - /// - /// [`split_at_mut`]: #method.split_at_mut - #[stable(feature = "swap_with_slice", since = "1.27.0")] - pub fn swap_with_slice(&mut self, other: &mut [T]) { - core_slice::SliceExt::swap_with_slice(self, other) - } - /// Copies `self` into a new `Vec`. /// /// # Examples diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 88bd0444233..f4fafe304c0 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -229,7 +229,7 @@ macro_rules! test_v512 { ($item:item) => {}; } #[allow(unused_macros)] macro_rules! vector_impl { ($([$f:ident, $($args:tt)*]),*) => { $($f!($($args)*);)* } } #[path = "../stdsimd/coresimd/mod.rs"] -#[allow(missing_docs, missing_debug_implementations, dead_code)] +#[allow(missing_docs, missing_debug_implementations, dead_code, unused_imports)] #[unstable(feature = "stdsimd", issue = "48556")] #[cfg(not(stage0))] // allow changes to how stdsimd works in stage0 mod coresimd; diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index cc3ad71117a..32c1531bdc0 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -58,6 +58,7 @@ pub use result::Result::{self, Ok, Err}; // Re-exported extension traits for primitive types #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] +#[cfg(stage0)] pub use slice::SliceExt; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 4cda1c8778a..0a260c663c2 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -755,6 +755,1410 @@ impl SliceExt for [T] { } } +// FIXME: remove (inline) this macro and the SliceExt trait +// when updating to a bootstrap compiler that has the new lang items. +#[cfg_attr(stage0, macro_export)] +#[unstable(feature = "core_slice_ext", issue = "32110")] +macro_rules! slice_core_methods { () => { + /// Returns the number of elements in the slice. + /// + /// # Examples + /// + /// ``` + /// let a = [1, 2, 3]; + /// assert_eq!(a.len(), 3); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn len(&self) -> usize { + SliceExt::len(self) + } + + /// Returns `true` if the slice has a length of 0. + /// + /// # Examples + /// + /// ``` + /// let a = [1, 2, 3]; + /// assert!(!a.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_empty(&self) -> bool { + SliceExt::is_empty(self) + } + + /// Returns the first element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&10), v.first()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(None, w.first()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn first(&self) -> Option<&T> { + SliceExt::first(self) + } + + /// Returns a mutable pointer to the first element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(first) = x.first_mut() { + /// *first = 5; + /// } + /// assert_eq!(x, &[5, 1, 2]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn first_mut(&mut self) -> Option<&mut T> { + SliceExt::first_mut(self) + } + + /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first() { + /// assert_eq!(first, &0); + /// assert_eq!(elements, &[1, 2]); + /// } + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[inline] + pub fn split_first(&self) -> Option<(&T, &[T])> { + SliceExt::split_first(self) + } + + /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first_mut() { + /// *first = 3; + /// elements[0] = 4; + /// elements[1] = 5; + /// } + /// assert_eq!(x, &[3, 4, 5]); + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[inline] + pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { + SliceExt::split_first_mut(self) + } + + /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((last, elements)) = x.split_last() { + /// assert_eq!(last, &2); + /// assert_eq!(elements, &[0, 1]); + /// } + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[inline] + pub fn split_last(&self) -> Option<(&T, &[T])> { + SliceExt::split_last(self) + + } + + /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((last, elements)) = x.split_last_mut() { + /// *last = 3; + /// elements[0] = 4; + /// elements[1] = 5; + /// } + /// assert_eq!(x, &[4, 5, 3]); + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[inline] + pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { + SliceExt::split_last_mut(self) + } + + /// Returns the last element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&30), v.last()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(None, w.last()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn last(&self) -> Option<&T> { + SliceExt::last(self) + } + + /// Returns a mutable pointer to the last item in the slice. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(last) = x.last_mut() { + /// *last = 10; + /// } + /// assert_eq!(x, &[0, 1, 10]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn last_mut(&mut self) -> Option<&mut T> { + SliceExt::last_mut(self) + } + + /// Returns a reference to an element or subslice depending on the type of + /// index. + /// + /// - If given a position, returns a reference to the element at that + /// position or `None` if out of bounds. + /// - If given a range, returns the subslice corresponding to that range, + /// or `None` if out of bounds. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&40), v.get(1)); + /// assert_eq!(Some(&[10, 40][..]), v.get(0..2)); + /// assert_eq!(None, v.get(3)); + /// assert_eq!(None, v.get(0..4)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn get(&self, index: I) -> Option<&I::Output> + where I: SliceIndex + { + SliceExt::get(self, index) + } + + /// Returns a mutable reference to an element or subslice depending on the + /// type of index (see [`get`]) or `None` if the index is out of bounds. + /// + /// [`get`]: #method.get + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(elem) = x.get_mut(1) { + /// *elem = 42; + /// } + /// assert_eq!(x, &[0, 42, 2]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + where I: SliceIndex + { + SliceExt::get_mut(self, index) + } + + /// Returns a reference to an element or subslice, without doing bounds + /// checking. + /// + /// This is generally not recommended, use with caution! For a safe + /// alternative see [`get`]. + /// + /// [`get`]: #method.get + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// + /// unsafe { + /// assert_eq!(x.get_unchecked(1), &2); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub unsafe fn get_unchecked(&self, index: I) -> &I::Output + where I: SliceIndex + { + SliceExt::get_unchecked(self, index) + } + + /// Returns a mutable reference to an element or subslice, without doing + /// bounds checking. + /// + /// This is generally not recommended, use with caution! For a safe + /// alternative see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// + /// unsafe { + /// let elem = x.get_unchecked_mut(1); + /// *elem = 13; + /// } + /// assert_eq!(x, &[1, 13, 4]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output + where I: SliceIndex + { + SliceExt::get_unchecked_mut(self, index) + } + + /// Returns a raw pointer to the slice's buffer. + /// + /// The caller must ensure that the slice outlives the pointer this + /// function returns, or else it will end up pointing to garbage. + /// + /// Modifying the container referenced by this slice may cause its buffer + /// to be reallocated, which would also make any pointers to it invalid. + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// let x_ptr = x.as_ptr(); + /// + /// unsafe { + /// for i in 0..x.len() { + /// assert_eq!(x.get_unchecked(i), &*x_ptr.offset(i as isize)); + /// } + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn as_ptr(&self) -> *const T { + SliceExt::as_ptr(self) + } + + /// Returns an unsafe mutable pointer to the slice's buffer. + /// + /// The caller must ensure that the slice outlives the pointer this + /// function returns, or else it will end up pointing to garbage. + /// + /// Modifying the container referenced by this slice may cause its buffer + /// to be reallocated, which would also make any pointers to it invalid. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// let x_ptr = x.as_mut_ptr(); + /// + /// unsafe { + /// for i in 0..x.len() { + /// *x_ptr.offset(i as isize) += 2; + /// } + /// } + /// assert_eq!(x, &[3, 4, 6]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut T { + SliceExt::as_mut_ptr(self) + } + + /// Swaps two elements in the slice. + /// + /// # Arguments + /// + /// * a - The index of the first element + /// * b - The index of the second element + /// + /// # Panics + /// + /// Panics if `a` or `b` are out of bounds. + /// + /// # Examples + /// + /// ``` + /// let mut v = ["a", "b", "c", "d"]; + /// v.swap(1, 3); + /// assert!(v == ["a", "d", "c", "b"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn swap(&mut self, a: usize, b: usize) { + SliceExt::swap(self, a, b) + } + + /// Reverses the order of elements in the slice, in place. + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 2, 3]; + /// v.reverse(); + /// assert!(v == [3, 2, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn reverse(&mut self) { + SliceExt::reverse(self) + } + + /// Returns an iterator over the slice. + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// let mut iterator = x.iter(); + /// + /// assert_eq!(iterator.next(), Some(&1)); + /// assert_eq!(iterator.next(), Some(&2)); + /// assert_eq!(iterator.next(), Some(&4)); + /// assert_eq!(iterator.next(), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn iter(&self) -> Iter { + SliceExt::iter(self) + } + + /// Returns an iterator that allows modifying each value. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// for elem in x.iter_mut() { + /// *elem += 2; + /// } + /// assert_eq!(x, &[3, 4, 6]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn iter_mut(&mut self) -> IterMut { + SliceExt::iter_mut(self) + } + + /// Returns an iterator over all contiguous windows of length + /// `size`. The windows overlap. If the slice is shorter than + /// `size`, the iterator returns no values. + /// + /// # Panics + /// + /// Panics if `size` is 0. + /// + /// # Examples + /// + /// ``` + /// let slice = ['r', 'u', 's', 't']; + /// let mut iter = slice.windows(2); + /// assert_eq!(iter.next().unwrap(), &['r', 'u']); + /// assert_eq!(iter.next().unwrap(), &['u', 's']); + /// assert_eq!(iter.next().unwrap(), &['s', 't']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the slice is shorter than `size`: + /// + /// ``` + /// let slice = ['f', 'o', 'o']; + /// let mut iter = slice.windows(4); + /// assert!(iter.next().is_none()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn windows(&self, size: usize) -> Windows { + SliceExt::windows(self, size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a + /// time. The chunks are slices and do not overlap. If `chunk_size` does + /// not divide the length of the slice, then the last chunk will + /// not have length `chunk_size`. + /// + /// See [`exact_chunks`] for a variant of this iterator that returns chunks + /// of always exactly `chunk_size` elements. + /// + /// # Panics + /// + /// Panics if `chunk_size` is 0. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.chunks(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert_eq!(iter.next().unwrap(), &['m']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`exact_chunks`]: #method.exact_chunks + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn chunks(&self, chunk_size: usize) -> Chunks { + SliceExt::chunks(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a + /// time. The chunks are slices and do not overlap. If `chunk_size` does + /// not divide the length of the slice, then the last up to `chunk_size-1` + /// elements will be omitted. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler + /// can often optimize the resulting code better than in the case of + /// [`chunks`]. + /// + /// # Panics + /// + /// Panics if `chunk_size` is 0. + /// + /// # Examples + /// + /// ``` + /// #![feature(exact_chunks)] + /// + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.exact_chunks(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`chunks`]: #method.chunks + #[unstable(feature = "exact_chunks", issue = "47115")] + #[inline] + pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks { + SliceExt::exact_chunks(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time. + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does + /// not divide the length of the slice, then the last chunk will not + /// have length `chunk_size`. + /// + /// See [`exact_chunks_mut`] for a variant of this iterator that returns chunks + /// of always exactly `chunk_size` elements. + /// + /// # Panics + /// + /// Panics if `chunk_size` is 0. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.chunks_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 3]); + /// ``` + /// + /// [`exact_chunks_mut`]: #method.exact_chunks_mut + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut { + SliceExt::chunks_mut(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time. + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does + /// not divide the length of the slice, then the last up to `chunk_size-1` + /// elements will be omitted. + /// + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler + /// can often optimize the resulting code better than in the case of + /// [`chunks_mut`]. + /// + /// # Panics + /// + /// Panics if `chunk_size` is 0. + /// + /// # Examples + /// + /// ``` + /// #![feature(exact_chunks)] + /// + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.exact_chunks_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 0]); + /// ``` + /// + /// [`chunks_mut`]: #method.chunks_mut + #[unstable(feature = "exact_chunks", issue = "47115")] + #[inline] + pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut { + SliceExt::exact_chunks_mut(self, chunk_size) + } + + /// Divides one slice into two at an index. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// # Panics + /// + /// Panics if `mid > len`. + /// + /// # Examples + /// + /// ``` + /// let v = [1, 2, 3, 4, 5, 6]; + /// + /// { + /// let (left, right) = v.split_at(0); + /// assert!(left == []); + /// assert!(right == [1, 2, 3, 4, 5, 6]); + /// } + /// + /// { + /// let (left, right) = v.split_at(2); + /// assert!(left == [1, 2]); + /// assert!(right == [3, 4, 5, 6]); + /// } + /// + /// { + /// let (left, right) = v.split_at(6); + /// assert!(left == [1, 2, 3, 4, 5, 6]); + /// assert!(right == []); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split_at(&self, mid: usize) -> (&[T], &[T]) { + SliceExt::split_at(self, mid) + } + + /// Divides one mutable slice into two at an index. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// # Panics + /// + /// Panics if `mid > len`. + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// // scoped to restrict the lifetime of the borrows + /// { + /// let (left, right) = v.split_at_mut(2); + /// assert!(left == [1, 0]); + /// assert!(right == [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; + /// } + /// assert!(v == [1, 2, 3, 4, 5, 6]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { + SliceExt::split_at_mut(self, mid) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the first element is matched, an empty slice will be the first item + /// returned by the iterator. Similarly, if the last element in the slice + /// is matched, an empty slice will be the last item returned by the + /// iterator: + /// + /// ``` + /// let slice = [10, 40, 33]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If two matched elements are directly adjacent, an empty slice will be + /// present between them: + /// + /// ``` + /// let slice = [10, 6, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10]); + /// assert_eq!(iter.next().unwrap(), &[]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split(&self, pred: F) -> Split + where F: FnMut(&T) -> bool + { + SliceExt::split(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.split_mut(|num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 30, 1, 60, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split_mut(&mut self, pred: F) -> SplitMut + where F: FnMut(&T) -> bool + { + SliceExt::split_mut(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, starting at the end of the slice and working backwards. + /// The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let slice = [11, 22, 33, 0, 44, 55]; + /// let mut iter = slice.rsplit(|num| *num == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[44, 55]); + /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// As with `split()`, if the first or last element is matched, an empty + /// slice will be the first (or last) item returned by the iterator. + /// + /// ``` + /// let v = &[0, 1, 1, 2, 3, 5, 8]; + /// let mut it = v.rsplit(|n| *n % 2 == 0); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next().unwrap(), &[3, 5]); + /// assert_eq!(it.next().unwrap(), &[1, 1]); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next(), None); + /// ``` + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] + pub fn rsplit(&self, pred: F) -> RSplit + where F: FnMut(&T) -> bool + { + SliceExt::rsplit(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, starting at the end of the slice and working + /// backwards. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let mut v = [100, 400, 300, 200, 600, 500]; + /// + /// let mut count = 0; + /// for group in v.rsplit_mut(|num| *num % 3 == 0) { + /// count += 1; + /// group[0] = count; + /// } + /// assert_eq!(v, [3, 400, 300, 2, 600, 1]); + /// ``` + /// + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] + pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut + where F: FnMut(&T) -> bool + { + SliceExt::rsplit_mut(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, limited to returning at most `n` items. The matched element is + /// not contained in the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// Print the slice split once by numbers divisible by 3 (i.e. `[10, 40]`, + /// `[20, 60, 50]`): + /// + /// ``` + /// let v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.splitn(2, |num| *num % 3 == 0) { + /// println!("{:?}", group); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn splitn(&self, n: usize, pred: F) -> SplitN + where F: FnMut(&T) -> bool + { + SliceExt::splitn(self, n, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, limited to returning at most `n` items. The matched element is + /// not contained in the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.splitn_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 30, 1, 60, 50]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn splitn_mut(&mut self, n: usize, pred: F) -> SplitNMut + where F: FnMut(&T) -> bool + { + SliceExt::splitn_mut(self, n, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred` limited to returning at most `n` items. This starts at the end of + /// the slice and works backwards. The matched element is not contained in + /// the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// Print the slice split once, starting from the end, by numbers divisible + /// by 3 (i.e. `[50]`, `[10, 40, 30, 20]`): + /// + /// ``` + /// let v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.rsplitn(2, |num| *num % 3 == 0) { + /// println!("{:?}", group); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplitn(&self, n: usize, pred: F) -> RSplitN + where F: FnMut(&T) -> bool + { + SliceExt::rsplitn(self, n, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred` limited to returning at most `n` items. This starts at the end of + /// the slice and works backwards. The matched element is not contained in + /// the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// ``` + /// let mut s = [10, 40, 30, 20, 60, 50]; + /// + /// for group in s.rsplitn_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(s, [1, 40, 30, 20, 60, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplitn_mut(&mut self, n: usize, pred: F) -> RSplitNMut + where F: FnMut(&T) -> bool + { + SliceExt::rsplitn_mut(self, n, pred) + } + + /// Returns `true` if the slice contains an element with the given value. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.contains(&30)); + /// assert!(!v.contains(&50)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn contains(&self, x: &T) -> bool + where T: PartialEq + { + SliceExt::contains(self, x) + } + + /// Returns `true` if `needle` is a prefix of the slice. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.starts_with(&[10])); + /// assert!(v.starts_with(&[10, 40])); + /// assert!(!v.starts_with(&[50])); + /// assert!(!v.starts_with(&[10, 50])); + /// ``` + /// + /// Always returns `true` if `needle` is an empty slice: + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert!(v.starts_with(&[])); + /// let v: &[u8] = &[]; + /// assert!(v.starts_with(&[])); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn starts_with(&self, needle: &[T]) -> bool + where T: PartialEq + { + SliceExt::starts_with(self, needle) + } + + /// Returns `true` if `needle` is a suffix of the slice. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.ends_with(&[30])); + /// assert!(v.ends_with(&[40, 30])); + /// assert!(!v.ends_with(&[50])); + /// assert!(!v.ends_with(&[50, 30])); + /// ``` + /// + /// Always returns `true` if `needle` is an empty slice: + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert!(v.ends_with(&[])); + /// let v: &[u8] = &[]; + /// assert!(v.ends_with(&[])); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn ends_with(&self, needle: &[T]) -> bool + where T: PartialEq + { + SliceExt::ends_with(self, needle) + } + + /// Binary searches this sorted slice for a given element. + /// + /// If the value is found then `Ok` is returned, containing the + /// index of the matching element; if the value is not found then + /// `Err` is returned, containing the index where a matching + /// element could be inserted while maintaining sorted order. + /// + /// # Examples + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// + /// assert_eq!(s.binary_search(&13), Ok(9)); + /// assert_eq!(s.binary_search(&4), Err(7)); + /// assert_eq!(s.binary_search(&100), Err(13)); + /// let r = s.binary_search(&1); + /// assert!(match r { Ok(1...4) => true, _ => false, }); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn binary_search(&self, x: &T) -> Result + where T: Ord + { + SliceExt::binary_search(self, x) + } + + /// Binary searches this sorted slice with a comparator function. + /// + /// The comparator function should implement an order consistent + /// with the sort order of the underlying slice, returning an + /// order code that indicates whether its argument is `Less`, + /// `Equal` or `Greater` the desired target. + /// + /// If a matching value is found then returns `Ok`, containing + /// the index for the matched element; if no match is found then + /// `Err` is returned, containing the index where a matching + /// element could be inserted while maintaining sorted order. + /// + /// # Examples + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// + /// let seek = 13; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9)); + /// let seek = 4; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7)); + /// let seek = 100; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13)); + /// let seek = 1; + /// let r = s.binary_search_by(|probe| probe.cmp(&seek)); + /// assert!(match r { Ok(1...4) => true, _ => false, }); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result + where F: FnMut(&'a T) -> Ordering + { + SliceExt::binary_search_by(self, f) + } + + /// Binary searches this sorted slice with a key extraction function. + /// + /// Assumes that the slice is sorted by the key, for instance with + /// [`sort_by_key`] using the same key extraction function. + /// + /// If a matching value is found then returns `Ok`, containing the + /// index for the matched element; if no match is found then `Err` + /// is returned, containing the index where a matching element could + /// be inserted while maintaining sorted order. + /// + /// [`sort_by_key`]: #method.sort_by_key + /// + /// # Examples + /// + /// Looks up a series of four elements in a slice of pairs sorted by + /// their second elements. The first is found, with a uniquely + /// determined position; the second and third are not found; the + /// fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1), + /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), + /// (1, 21), (2, 34), (4, 55)]; + /// + /// assert_eq!(s.binary_search_by_key(&13, |&(a,b)| b), Ok(9)); + /// assert_eq!(s.binary_search_by_key(&4, |&(a,b)| b), Err(7)); + /// assert_eq!(s.binary_search_by_key(&100, |&(a,b)| b), Err(13)); + /// let r = s.binary_search_by_key(&1, |&(a,b)| b); + /// assert!(match r { Ok(1...4) => true, _ => false, }); + /// ``` + #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] + #[inline] + pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result + where F: FnMut(&'a T) -> B, + B: Ord + { + SliceExt::binary_search_by_key(self, b, f) + } + + /// Sorts the slice, but may not preserve the order of equal elements. + /// + /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), + /// and `O(n log n)` worst-case. + /// + /// # Current implementation + /// + /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, + /// which combines the fast average case of randomized quicksort with the fast worst case of + /// heapsort, while achieving linear time on slices with certain patterns. It uses some + /// randomization to avoid degenerate cases, but with a fixed seed to always provide + /// deterministic behavior. + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g. when the + /// slice consists of several concatenated sorted sequences. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5, 4, 1, -3, 2]; + /// + /// v.sort_unstable(); + /// assert!(v == [-5, -3, 1, 2, 4]); + /// ``` + /// + /// [pdqsort]: https://github.com/orlp/pdqsort + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable(&mut self) + where T: Ord + { + SliceExt::sort_unstable(self); + } + + /// Sorts the slice with a comparator function, but may not preserve the order of equal + /// elements. + /// + /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), + /// and `O(n log n)` worst-case. + /// + /// # Current implementation + /// + /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, + /// which combines the fast average case of randomized quicksort with the fast worst case of + /// heapsort, while achieving linear time on slices with certain patterns. It uses some + /// randomization to avoid degenerate cases, but with a fixed seed to always provide + /// deterministic behavior. + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g. when the + /// slice consists of several concatenated sorted sequences. + /// + /// # Examples + /// + /// ``` + /// let mut v = [5, 4, 1, 3, 2]; + /// v.sort_unstable_by(|a, b| a.cmp(b)); + /// assert!(v == [1, 2, 3, 4, 5]); + /// + /// // reverse sorting + /// v.sort_unstable_by(|a, b| b.cmp(a)); + /// assert!(v == [5, 4, 3, 2, 1]); + /// ``` + /// + /// [pdqsort]: https://github.com/orlp/pdqsort + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable_by(&mut self, compare: F) + where F: FnMut(&T, &T) -> Ordering + { + SliceExt::sort_unstable_by(self, compare); + } + + /// Sorts the slice with a key extraction function, but may not preserve the order of equal + /// elements. + /// + /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), + /// and `O(m n log(m n))` worst-case, where the key function is `O(m)`. + /// + /// # Current implementation + /// + /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, + /// which combines the fast average case of randomized quicksort with the fast worst case of + /// heapsort, while achieving linear time on slices with certain patterns. It uses some + /// randomization to avoid degenerate cases, but with a fixed seed to always provide + /// deterministic behavior. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5i32, 4, 1, -3, 2]; + /// + /// v.sort_unstable_by_key(|k| k.abs()); + /// assert!(v == [1, 2, -3, 4, -5]); + /// ``` + /// + /// [pdqsort]: https://github.com/orlp/pdqsort + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable_by_key(&mut self, f: F) + where F: FnMut(&T) -> K, K: Ord + { + SliceExt::sort_unstable_by_key(self, f); + } + + /// Rotates the slice in-place such that the first `mid` elements of the + /// slice move to the end while the last `self.len() - mid` elements move to + /// the front. After calling `rotate_left`, the element previously at index + /// `mid` will become the first element in the slice. + /// + /// # Panics + /// + /// This function will panic if `mid` is greater than the length of the + /// slice. Note that `mid == self.len()` does _not_ panic and is a no-op + /// rotation. + /// + /// # Complexity + /// + /// Takes linear (in `self.len()`) time. + /// + /// # Examples + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a.rotate_left(2); + /// assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']); + /// ``` + /// + /// Rotating a subslice: + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a[1..5].rotate_left(1); + /// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']); + /// ``` + #[stable(feature = "slice_rotate", since = "1.26.0")] + pub fn rotate_left(&mut self, mid: usize) { + SliceExt::rotate_left(self, mid); + } + + /// Rotates the slice in-place such that the first `self.len() - k` + /// elements of the slice move to the end while the last `k` elements move + /// to the front. After calling `rotate_right`, the element previously at + /// index `self.len() - k` will become the first element in the slice. + /// + /// # Panics + /// + /// This function will panic if `k` is greater than the length of the + /// slice. Note that `k == self.len()` does _not_ panic and is a no-op + /// rotation. + /// + /// # Complexity + /// + /// Takes linear (in `self.len()`) time. + /// + /// # Examples + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a.rotate_right(2); + /// assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']); + /// ``` + /// + /// Rotate a subslice: + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a[1..5].rotate_right(1); + /// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']); + /// ``` + #[stable(feature = "slice_rotate", since = "1.26.0")] + pub fn rotate_right(&mut self, k: usize) { + SliceExt::rotate_right(self, k); + } + + /// Copies the elements from `src` into `self`. + /// + /// The length of `src` must be the same as `self`. + /// + /// If `src` implements `Copy`, it can be more performant to use + /// [`copy_from_slice`]. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Examples + /// + /// Cloning two elements from a slice into another: + /// + /// ``` + /// let src = [1, 2, 3, 4]; + /// let mut dst = [0, 0]; + /// + /// dst.clone_from_slice(&src[2..]); + /// + /// assert_eq!(src, [1, 2, 3, 4]); + /// assert_eq!(dst, [3, 4]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference with no + /// immutable references to a particular piece of data in a particular + /// scope. Because of this, attempting to use `clone_from_slice` on a + /// single slice will result in a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// slice[..2].clone_from_slice(&slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.clone_from_slice(&right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 4, 5]); + /// ``` + /// + /// [`copy_from_slice`]: #method.copy_from_slice + /// [`split_at_mut`]: #method.split_at_mut + #[stable(feature = "clone_from_slice", since = "1.7.0")] + pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone { + SliceExt::clone_from_slice(self, src) + } + + /// Copies all elements from `src` into `self`, using a memcpy. + /// + /// The length of `src` must be the same as `self`. + /// + /// If `src` does not implement `Copy`, use [`clone_from_slice`]. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Examples + /// + /// Copying two elements from a slice into another: + /// + /// ``` + /// let src = [1, 2, 3, 4]; + /// let mut dst = [0, 0]; + /// + /// dst.copy_from_slice(&src[2..]); + /// + /// assert_eq!(src, [1, 2, 3, 4]); + /// assert_eq!(dst, [3, 4]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference with no + /// immutable references to a particular piece of data in a particular + /// scope. Because of this, attempting to use `copy_from_slice` on a + /// single slice will result in a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// slice[..2].copy_from_slice(&slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.copy_from_slice(&right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 4, 5]); + /// ``` + /// + /// [`clone_from_slice`]: #method.clone_from_slice + /// [`split_at_mut`]: #method.split_at_mut + #[stable(feature = "copy_from_slice", since = "1.9.0")] + pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy { + SliceExt::copy_from_slice(self, src) + } + + /// Swaps all elements in `self` with those in `other`. + /// + /// The length of `other` must be the same as `self`. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Example + /// + /// Swapping two elements across slices: + /// + /// ``` + /// let mut slice1 = [0, 0]; + /// let mut slice2 = [1, 2, 3, 4]; + /// + /// slice1.swap_with_slice(&mut slice2[2..]); + /// + /// assert_eq!(slice1, [3, 4]); + /// assert_eq!(slice2, [1, 2, 0, 0]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference to a + /// particular piece of data in a particular scope. Because of this, + /// attempting to use `swap_with_slice` on a single slice will result in + /// a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// slice[..2].swap_with_slice(&mut slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// mutable sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.swap_with_slice(&mut right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 1, 2]); + /// ``` + /// + /// [`split_at_mut`]: #method.split_at_mut + #[stable(feature = "swap_with_slice", since = "1.27.0")] + pub fn swap_with_slice(&mut self, other: &mut [T]) { + SliceExt::swap_with_slice(self, other) + } +}} + +#[lang = "slice"] +#[cfg(not(test))] +#[cfg(not(stage0))] +impl [T] { + slice_core_methods!(); +} + +// FIXME: remove (inline) this macro +// when updating to a bootstrap compiler that has the new lang items. #[cfg_attr(stage0, macro_export)] #[unstable(feature = "core_slice_ext", issue = "32110")] macro_rules! slice_u8_core_methods { () => { diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index f8cff8b186c..237a22925b4 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -214,6 +214,7 @@ language_item_table! { StrImplItem, "str", str_impl; SliceImplItem, "slice", slice_impl; SliceU8ImplItem, "slice_u8", slice_u8_impl; + SliceAllocImplItem, "slice_alloc", slice_alloc_impl; SliceU8AllocImplItem, "slice_u8_alloc", slice_u8_alloc_impl; ConstPtrImplItem, "const_ptr", const_ptr_impl; MutPtrImplItem, "mut_ptr", mut_ptr_impl; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 7ba60f62791..ea4c2c08817 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -479,6 +479,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let lang_def_id = lang_items.slice_u8_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); + let lang_def_id = lang_items.slice_alloc_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + let lang_def_id = lang_items.slice_u8_alloc_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index d7657bae8c5..91f9e3e6fba 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -138,7 +138,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TySlice(_) => { self.check_primitive_impl(def_id, lang_items.slice_impl(), - None, + lang_items.slice_alloc_impl(), "slice", "[T]", item.span); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 4acd12e5862..38af4350815 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -290,6 +290,7 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec Date: Sat, 7 Apr 2018 21:56:02 +0200 Subject: Replace StrExt with inherent str methods in libcore --- src/liballoc/lib.rs | 1 + src/liballoc/str.rs | 1835 +------------------- src/libcore/lib.rs | 1 + src/libcore/prelude/v1.rs | 1 + src/libcore/str/mod.rs | 1762 ++++++++++++++++++- src/librustc/middle/lang_items.rs | 1 + src/librustc_typeck/check/method/probe.rs | 3 + src/librustc_typeck/coherence/inherent_impls.rs | 2 +- src/librustdoc/clean/inline.rs | 1 + .../compile-fail/single-primitive-inherent-impl.rs | 2 +- src/test/rustdoc/issue-23511.rs | 2 +- 11 files changed, 1818 insertions(+), 1793 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 52011303543..702d7b70cd3 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -91,6 +91,7 @@ #![feature(const_fn)] #![feature(core_intrinsics)] #![cfg_attr(stage0, feature(core_slice_ext))] +#![cfg_attr(stage0, feature(core_str_ext))] #![feature(custom_attribute)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 686a0408a7c..82ba2f45711 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -40,6 +40,7 @@ use core::fmt; use core::str as core_str; +#[cfg(stage0)] use core::str::StrExt; use core::str::pattern::Pattern; use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; @@ -76,7 +77,8 @@ pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError pub use core::str::SplitWhitespace; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::pattern; - +#[stable(feature = "encode_utf16", since = "1.8.0")] +pub use core::str::EncodeUtf16; #[unstable(feature = "slice_concat_ext", reason = "trait should not have to exist", @@ -90,1729 +92,78 @@ impl> SliceConcatExt for [S] { } // `len` calculation may overflow but push_str will check boundaries - let len = self.iter().map(|s| s.borrow().len()).sum(); - let mut result = String::with_capacity(len); - - for s in self { - result.push_str(s.borrow()) - } - - result - } - - fn join(&self, sep: &str) -> String { - if self.is_empty() { - return String::new(); - } - - // concat is faster - if sep.is_empty() { - return self.concat(); - } - - // this is wrong without the guarantee that `self` is non-empty - // `len` calculation may overflow but push_str but will check boundaries - let len = sep.len() * (self.len() - 1) + - self.iter().map(|s| s.borrow().len()).sum::(); - let mut result = String::with_capacity(len); - let mut first = true; - - for s in self { - if first { - first = false; - } else { - result.push_str(sep); - } - result.push_str(s.borrow()); - } - result - } - - fn connect(&self, sep: &str) -> String { - self.join(sep) - } -} - -/// An iterator of [`u16`] over the string encoded as UTF-16. -/// -/// [`u16`]: ../../std/primitive.u16.html -/// -/// This struct is created by the [`encode_utf16`] method on [`str`]. -/// See its documentation for more. -/// -/// [`encode_utf16`]: ../../std/primitive.str.html#method.encode_utf16 -/// [`str`]: ../../std/primitive.str.html -#[derive(Clone)] -#[stable(feature = "encode_utf16", since = "1.8.0")] -pub struct EncodeUtf16<'a> { - chars: Chars<'a>, - extra: u16, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a> fmt::Debug for EncodeUtf16<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("EncodeUtf16 { .. }") - } -} - -#[stable(feature = "encode_utf16", since = "1.8.0")] -impl<'a> Iterator for EncodeUtf16<'a> { - type Item = u16; - - #[inline] - fn next(&mut self) -> Option { - if self.extra != 0 { - let tmp = self.extra; - self.extra = 0; - return Some(tmp); - } - - let mut buf = [0; 2]; - self.chars.next().map(|ch| { - let n = ch.encode_utf16(&mut buf).len(); - if n == 2 { - self.extra = buf[1]; - } - buf[0] - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (low, high) = self.chars.size_hint(); - // every char gets either one u16 or two u16, - // so this iterator is between 1 or 2 times as - // long as the underlying iterator. - (low, high.and_then(|n| n.checked_mul(2))) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a> FusedIterator for EncodeUtf16<'a> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Borrow for String { - #[inline] - fn borrow(&self) -> &str { - &self[..] - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToOwned for str { - type Owned = String; - fn to_owned(&self) -> String { - unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) } - } - - fn clone_into(&self, target: &mut String) { - let mut b = mem::replace(target, String::new()).into_bytes(); - self.as_bytes().clone_into(&mut b); - *target = unsafe { String::from_utf8_unchecked(b) } - } -} - -/// Methods for string slices. -#[lang = "str"] -#[cfg(not(test))] -impl str { - /// Returns the length of `self`. - /// - /// This length is in bytes, not [`char`]s or graphemes. In other words, - /// it may not be what a human considers the length of the string. - /// - /// [`char`]: primitive.char.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let len = "foo".len(); - /// assert_eq!(3, len); - /// - /// let len = "ƒoo".len(); // fancy f! - /// assert_eq!(4, len); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn len(&self) -> usize { - core_str::StrExt::len(self) - } - - /// Returns `true` if `self` has a length of zero bytes. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = ""; - /// assert!(s.is_empty()); - /// - /// let s = "not empty"; - /// assert!(!s.is_empty()); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { - core_str::StrExt::is_empty(self) - } - - /// Checks that `index`-th byte lies at the start and/or end of a - /// UTF-8 code point sequence. - /// - /// The start and end of the string (when `index == self.len()`) are - /// considered to be - /// boundaries. - /// - /// Returns `false` if `index` is greater than `self.len()`. - /// - /// # Examples - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// assert!(s.is_char_boundary(0)); - /// // start of `老` - /// assert!(s.is_char_boundary(6)); - /// assert!(s.is_char_boundary(s.len())); - /// - /// // second byte of `ö` - /// assert!(!s.is_char_boundary(2)); - /// - /// // third byte of `老` - /// assert!(!s.is_char_boundary(8)); - /// ``` - #[stable(feature = "is_char_boundary", since = "1.9.0")] - #[inline] - pub fn is_char_boundary(&self, index: usize) -> bool { - core_str::StrExt::is_char_boundary(self, index) - } - - /// Converts a string slice to a byte slice. To convert the byte slice back - /// into a string slice, use the [`str::from_utf8`] function. - /// - /// [`str::from_utf8`]: ./str/fn.from_utf8.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let bytes = "bors".as_bytes(); - /// assert_eq!(b"bors", bytes); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline(always)] - pub fn as_bytes(&self) -> &[u8] { - core_str::StrExt::as_bytes(self) - } - - /// Converts a mutable string slice to a mutable byte slice. To convert the - /// mutable byte slice back into a mutable string slice, use the - /// [`str::from_utf8_mut`] function. - /// - /// [`str::from_utf8_mut`]: ./str/fn.from_utf8_mut.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut s = String::from("Hello"); - /// let bytes = unsafe { s.as_bytes_mut() }; - /// - /// assert_eq!(b"Hello", bytes); - /// ``` - /// - /// Mutability: - /// - /// ``` - /// let mut s = String::from("🗻∈🌏"); - /// - /// unsafe { - /// let bytes = s.as_bytes_mut(); - /// - /// bytes[0] = 0xF0; - /// bytes[1] = 0x9F; - /// bytes[2] = 0x8D; - /// bytes[3] = 0x94; - /// } - /// - /// assert_eq!("🍔∈🌏", s); - /// ``` - #[stable(feature = "str_mut_extras", since = "1.20.0")] - #[inline(always)] - pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { - core_str::StrExt::as_bytes_mut(self) - } - - /// Converts a string slice to a raw pointer. - /// - /// As string slices are a slice of bytes, the raw pointer points to a - /// [`u8`]. This pointer will be pointing to the first byte of the string - /// slice. - /// - /// [`u8`]: primitive.u8.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = "Hello"; - /// let ptr = s.as_ptr(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn as_ptr(&self) -> *const u8 { - core_str::StrExt::as_ptr(self) - } - - /// Returns a subslice of `str`. - /// - /// This is the non-panicking alternative to indexing the `str`. Returns - /// [`None`] whenever equivalent indexing operation would panic. - /// - /// [`None`]: option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ``` - /// let v = String::from("🗻∈🌏"); - /// - /// assert_eq!(Some("🗻"), v.get(0..4)); - /// - /// // indices not on UTF-8 sequence boundaries - /// assert!(v.get(1..).is_none()); - /// assert!(v.get(..8).is_none()); - /// - /// // out of bounds - /// assert!(v.get(..42).is_none()); - /// ``` - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - #[inline] - pub fn get>(&self, i: I) -> Option<&I::Output> { - core_str::StrExt::get(self, i) - } - - /// Returns a mutable subslice of `str`. - /// - /// This is the non-panicking alternative to indexing the `str`. Returns - /// [`None`] whenever equivalent indexing operation would panic. - /// - /// [`None`]: option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ``` - /// let mut v = String::from("hello"); - /// // correct length - /// assert!(v.get_mut(0..5).is_some()); - /// // out of bounds - /// assert!(v.get_mut(..42).is_none()); - /// assert_eq!(Some("he"), v.get_mut(0..2).map(|v| &*v)); - /// - /// assert_eq!("hello", v); - /// { - /// let s = v.get_mut(0..2); - /// let s = s.map(|s| { - /// s.make_ascii_uppercase(); - /// &*s - /// }); - /// assert_eq!(Some("HE"), s); - /// } - /// assert_eq!("HEllo", v); - /// ``` - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - #[inline] - pub fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { - core_str::StrExt::get_mut(self, i) - } - - /// Returns a unchecked subslice of `str`. - /// - /// This is the unchecked alternative to indexing the `str`. - /// - /// # Safety - /// - /// Callers of this function are responsible that these preconditions are - /// satisfied: - /// - /// * The starting index must come before the ending index; - /// * Indexes must be within bounds of the original slice; - /// * Indexes must lie on UTF-8 sequence boundaries. - /// - /// Failing that, the returned string slice may reference invalid memory or - /// violate the invariants communicated by the `str` type. - /// - /// # Examples - /// - /// ``` - /// let v = "🗻∈🌏"; - /// unsafe { - /// assert_eq!("🗻", v.get_unchecked(0..4)); - /// assert_eq!("∈", v.get_unchecked(4..7)); - /// assert_eq!("🌏", v.get_unchecked(7..11)); - /// } - /// ``` - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - #[inline] - pub unsafe fn get_unchecked>(&self, i: I) -> &I::Output { - core_str::StrExt::get_unchecked(self, i) - } - - /// Returns a mutable, unchecked subslice of `str`. - /// - /// This is the unchecked alternative to indexing the `str`. - /// - /// # Safety - /// - /// Callers of this function are responsible that these preconditions are - /// satisfied: - /// - /// * The starting index must come before the ending index; - /// * Indexes must be within bounds of the original slice; - /// * Indexes must lie on UTF-8 sequence boundaries. - /// - /// Failing that, the returned string slice may reference invalid memory or - /// violate the invariants communicated by the `str` type. - /// - /// # Examples - /// - /// ``` - /// let mut v = String::from("🗻∈🌏"); - /// unsafe { - /// assert_eq!("🗻", v.get_unchecked_mut(0..4)); - /// assert_eq!("∈", v.get_unchecked_mut(4..7)); - /// assert_eq!("🌏", v.get_unchecked_mut(7..11)); - /// } - /// ``` - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - #[inline] - pub unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { - core_str::StrExt::get_unchecked_mut(self, i) - } - - /// Creates a string slice from another string slice, bypassing safety - /// checks. - /// - /// This is generally not recommended, use with caution! For a safe - /// alternative see [`str`] and [`Index`]. - /// - /// [`str`]: primitive.str.html - /// [`Index`]: ops/trait.Index.html - /// - /// This new slice goes from `begin` to `end`, including `begin` but - /// excluding `end`. - /// - /// To get a mutable string slice instead, see the - /// [`slice_mut_unchecked`] method. - /// - /// [`slice_mut_unchecked`]: #method.slice_mut_unchecked - /// - /// # Safety - /// - /// Callers of this function are responsible that three preconditions are - /// satisfied: - /// - /// * `begin` must come before `end`. - /// * `begin` and `end` must be byte positions within the string slice. - /// * `begin` and `end` must lie on UTF-8 sequence boundaries. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// - /// unsafe { - /// assert_eq!("Löwe 老虎 Léopard", s.slice_unchecked(0, 21)); - /// } - /// - /// let s = "Hello, world!"; - /// - /// unsafe { - /// assert_eq!("world", s.slice_unchecked(7, 12)); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { - core_str::StrExt::slice_unchecked(self, begin, end) - } - - /// Creates a string slice from another string slice, bypassing safety - /// checks. - /// This is generally not recommended, use with caution! For a safe - /// alternative see [`str`] and [`IndexMut`]. - /// - /// [`str`]: primitive.str.html - /// [`IndexMut`]: ops/trait.IndexMut.html - /// - /// This new slice goes from `begin` to `end`, including `begin` but - /// excluding `end`. - /// - /// To get an immutable string slice instead, see the - /// [`slice_unchecked`] method. - /// - /// [`slice_unchecked`]: #method.slice_unchecked - /// - /// # Safety - /// - /// Callers of this function are responsible that three preconditions are - /// satisfied: - /// - /// * `begin` must come before `end`. - /// * `begin` and `end` must be byte positions within the string slice. - /// * `begin` and `end` must lie on UTF-8 sequence boundaries. - #[stable(feature = "str_slice_mut", since = "1.5.0")] - #[inline] - pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { - core_str::StrExt::slice_mut_unchecked(self, begin, end) - } - - /// Divide one string slice into two at an index. - /// - /// The argument, `mid`, should be a byte offset from the start of the - /// string. It must also be on the boundary of a UTF-8 code point. - /// - /// The two slices returned go from the start of the string slice to `mid`, - /// and from `mid` to the end of the string slice. - /// - /// To get mutable string slices instead, see the [`split_at_mut`] - /// method. - /// - /// [`split_at_mut`]: #method.split_at_mut - /// - /// # Panics - /// - /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is - /// beyond the last code point of the string slice. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = "Per Martin-Löf"; - /// - /// let (first, last) = s.split_at(3); - /// - /// assert_eq!("Per", first); - /// assert_eq!(" Martin-Löf", last); - /// ``` - #[inline] - #[stable(feature = "str_split_at", since = "1.4.0")] - pub fn split_at(&self, mid: usize) -> (&str, &str) { - core_str::StrExt::split_at(self, mid) - } - - /// Divide one mutable string slice into two at an index. - /// - /// The argument, `mid`, should be a byte offset from the start of the - /// string. It must also be on the boundary of a UTF-8 code point. - /// - /// The two slices returned go from the start of the string slice to `mid`, - /// and from `mid` to the end of the string slice. - /// - /// To get immutable string slices instead, see the [`split_at`] method. - /// - /// [`split_at`]: #method.split_at - /// - /// # Panics - /// - /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is - /// beyond the last code point of the string slice. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut s = "Per Martin-Löf".to_string(); - /// { - /// let (first, last) = s.split_at_mut(3); - /// first.make_ascii_uppercase(); - /// assert_eq!("PER", first); - /// assert_eq!(" Martin-Löf", last); - /// } - /// assert_eq!("PER Martin-Löf", s); - /// ``` - #[inline] - #[stable(feature = "str_split_at", since = "1.4.0")] - pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { - core_str::StrExt::split_at_mut(self, mid) - } - - /// Returns an iterator over the [`char`]s of a string slice. - /// - /// As a string slice consists of valid UTF-8, we can iterate through a - /// string slice by [`char`]. This method returns such an iterator. - /// - /// It's important to remember that [`char`] represents a Unicode Scalar - /// Value, and may not match your idea of what a 'character' is. Iteration - /// over grapheme clusters may be what you actually want. - /// - /// [`char`]: primitive.char.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let word = "goodbye"; - /// - /// let count = word.chars().count(); - /// assert_eq!(7, count); - /// - /// let mut chars = word.chars(); - /// - /// assert_eq!(Some('g'), chars.next()); - /// assert_eq!(Some('o'), chars.next()); - /// assert_eq!(Some('o'), chars.next()); - /// assert_eq!(Some('d'), chars.next()); - /// assert_eq!(Some('b'), chars.next()); - /// assert_eq!(Some('y'), chars.next()); - /// assert_eq!(Some('e'), chars.next()); - /// - /// assert_eq!(None, chars.next()); - /// ``` - /// - /// Remember, [`char`]s may not match your human intuition about characters: - /// - /// ``` - /// let y = "y̆"; - /// - /// let mut chars = y.chars(); - /// - /// assert_eq!(Some('y'), chars.next()); // not 'y̆' - /// assert_eq!(Some('\u{0306}'), chars.next()); - /// - /// assert_eq!(None, chars.next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn chars(&self) -> Chars { - core_str::StrExt::chars(self) - } - /// Returns an iterator over the [`char`]s of a string slice, and their - /// positions. - /// - /// As a string slice consists of valid UTF-8, we can iterate through a - /// string slice by [`char`]. This method returns an iterator of both - /// these [`char`]s, as well as their byte positions. - /// - /// The iterator yields tuples. The position is first, the [`char`] is - /// second. - /// - /// [`char`]: primitive.char.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let word = "goodbye"; - /// - /// let count = word.char_indices().count(); - /// assert_eq!(7, count); - /// - /// let mut char_indices = word.char_indices(); - /// - /// assert_eq!(Some((0, 'g')), char_indices.next()); - /// assert_eq!(Some((1, 'o')), char_indices.next()); - /// assert_eq!(Some((2, 'o')), char_indices.next()); - /// assert_eq!(Some((3, 'd')), char_indices.next()); - /// assert_eq!(Some((4, 'b')), char_indices.next()); - /// assert_eq!(Some((5, 'y')), char_indices.next()); - /// assert_eq!(Some((6, 'e')), char_indices.next()); - /// - /// assert_eq!(None, char_indices.next()); - /// ``` - /// - /// Remember, [`char`]s may not match your human intuition about characters: - /// - /// ``` - /// let yes = "y̆es"; - /// - /// let mut char_indices = yes.char_indices(); - /// - /// assert_eq!(Some((0, 'y')), char_indices.next()); // not (0, 'y̆') - /// assert_eq!(Some((1, '\u{0306}')), char_indices.next()); - /// - /// // note the 3 here - the last character took up two bytes - /// assert_eq!(Some((3, 'e')), char_indices.next()); - /// assert_eq!(Some((4, 's')), char_indices.next()); - /// - /// assert_eq!(None, char_indices.next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn char_indices(&self) -> CharIndices { - core_str::StrExt::char_indices(self) - } - - /// An iterator over the bytes of a string slice. - /// - /// As a string slice consists of a sequence of bytes, we can iterate - /// through a string slice by byte. This method returns such an iterator. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut bytes = "bors".bytes(); - /// - /// assert_eq!(Some(b'b'), bytes.next()); - /// assert_eq!(Some(b'o'), bytes.next()); - /// assert_eq!(Some(b'r'), bytes.next()); - /// assert_eq!(Some(b's'), bytes.next()); - /// - /// assert_eq!(None, bytes.next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn bytes(&self) -> Bytes { - core_str::StrExt::bytes(self) - } - - /// Split a string slice by whitespace. - /// - /// The iterator returned will return string slices that are sub-slices of - /// the original string slice, separated by any amount of whitespace. - /// - /// 'Whitespace' is defined according to the terms of the Unicode Derived - /// Core Property `White_Space`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut iter = "A few words".split_whitespace(); - /// - /// assert_eq!(Some("A"), iter.next()); - /// assert_eq!(Some("few"), iter.next()); - /// assert_eq!(Some("words"), iter.next()); - /// - /// assert_eq!(None, iter.next()); - /// ``` - /// - /// All kinds of whitespace are considered: - /// - /// ``` - /// let mut iter = " Mary had\ta\u{2009}little \n\t lamb".split_whitespace(); - /// assert_eq!(Some("Mary"), iter.next()); - /// assert_eq!(Some("had"), iter.next()); - /// assert_eq!(Some("a"), iter.next()); - /// assert_eq!(Some("little"), iter.next()); - /// assert_eq!(Some("lamb"), iter.next()); - /// - /// assert_eq!(None, iter.next()); - /// ``` - #[stable(feature = "split_whitespace", since = "1.1.0")] - #[inline] - pub fn split_whitespace(&self) -> SplitWhitespace { - StrExt::split_whitespace(self) - } - - /// An iterator over the lines of a string, as string slices. - /// - /// Lines are ended with either a newline (`\n`) or a carriage return with - /// a line feed (`\r\n`). - /// - /// The final line ending is optional. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let text = "foo\r\nbar\n\nbaz\n"; - /// let mut lines = text.lines(); - /// - /// assert_eq!(Some("foo"), lines.next()); - /// assert_eq!(Some("bar"), lines.next()); - /// assert_eq!(Some(""), lines.next()); - /// assert_eq!(Some("baz"), lines.next()); - /// - /// assert_eq!(None, lines.next()); - /// ``` - /// - /// The final line ending isn't required: - /// - /// ``` - /// let text = "foo\nbar\n\r\nbaz"; - /// let mut lines = text.lines(); - /// - /// assert_eq!(Some("foo"), lines.next()); - /// assert_eq!(Some("bar"), lines.next()); - /// assert_eq!(Some(""), lines.next()); - /// assert_eq!(Some("baz"), lines.next()); - /// - /// assert_eq!(None, lines.next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn lines(&self) -> Lines { - core_str::StrExt::lines(self) - } - - /// An iterator over the lines of a string. - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.4.0", reason = "use lines() instead now")] - #[inline] - #[allow(deprecated)] - pub fn lines_any(&self) -> LinesAny { - core_str::StrExt::lines_any(self) - } - - /// Returns an iterator of `u16` over the string encoded as UTF-16. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let text = "Zażółć gęślą jaźń"; - /// - /// let utf8_len = text.len(); - /// let utf16_len = text.encode_utf16().count(); - /// - /// assert!(utf16_len <= utf8_len); - /// ``` - #[stable(feature = "encode_utf16", since = "1.8.0")] - pub fn encode_utf16(&self) -> EncodeUtf16 { - EncodeUtf16 { chars: self[..].chars(), extra: 0 } - } - - /// Returns `true` if the given pattern matches a sub-slice of - /// this string slice. - /// - /// Returns `false` if it does not. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let bananas = "bananas"; - /// - /// assert!(bananas.contains("nana")); - /// assert!(!bananas.contains("apples")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - core_str::StrExt::contains(self, pat) - } - - /// Returns `true` if the given pattern matches a prefix of this - /// string slice. - /// - /// Returns `false` if it does not. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let bananas = "bananas"; - /// - /// assert!(bananas.starts_with("bana")); - /// assert!(!bananas.starts_with("nana")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - core_str::StrExt::starts_with(self, pat) - } - - /// Returns `true` if the given pattern matches a suffix of this - /// string slice. - /// - /// Returns `false` if it does not. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let bananas = "bananas"; - /// - /// assert!(bananas.ends_with("anas")); - /// assert!(!bananas.ends_with("nana")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::ends_with(self, pat) - } - - /// Returns the byte index of the first character of this string slice that - /// matches the pattern. - /// - /// Returns [`None`] if the pattern doesn't match. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines if - /// a character matches. - /// - /// [`char`]: primitive.char.html - /// [`None`]: option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// - /// assert_eq!(s.find('L'), Some(0)); - /// assert_eq!(s.find('é'), Some(14)); - /// assert_eq!(s.find("Léopard"), Some(13)); - /// ``` - /// - /// More complex patterns using point-free style and closures: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// - /// assert_eq!(s.find(char::is_whitespace), Some(5)); - /// assert_eq!(s.find(char::is_lowercase), Some(1)); - /// assert_eq!(s.find(|c: char| c.is_whitespace() || c.is_lowercase()), Some(1)); - /// assert_eq!(s.find(|c: char| (c < 'o') && (c > 'a')), Some(4)); - /// ``` - /// - /// Not finding the pattern: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// let x: &[_] = &['1', '2']; - /// - /// assert_eq!(s.find(x), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { - core_str::StrExt::find(self, pat) - } - - /// Returns the byte index of the last character of this string slice that - /// matches the pattern. - /// - /// Returns [`None`] if the pattern doesn't match. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines if - /// a character matches. - /// - /// [`char`]: primitive.char.html - /// [`None`]: option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// - /// assert_eq!(s.rfind('L'), Some(13)); - /// assert_eq!(s.rfind('é'), Some(14)); - /// ``` - /// - /// More complex patterns with closures: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// - /// assert_eq!(s.rfind(char::is_whitespace), Some(12)); - /// assert_eq!(s.rfind(char::is_lowercase), Some(20)); - /// ``` - /// - /// Not finding the pattern: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// let x: &[_] = &['1', '2']; - /// - /// assert_eq!(s.rfind(x), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rfind(self, pat) - } - - /// An iterator over substrings of this string slice, separated by - /// characters matched by a pattern. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines the - /// split. - /// - /// # Iterator behavior - /// - /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern - /// allows a reverse search and forward/reverse search yields the same - /// elements. This is true for, eg, [`char`] but not for `&str`. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// - /// If the pattern allows a reverse search but its results might differ - /// from a forward search, the [`rsplit`] method can be used. - /// - /// [`char`]: primitive.char.html - /// [`rsplit`]: #method.rsplit - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect(); - /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]); - /// - /// let v: Vec<&str> = "".split('X').collect(); - /// assert_eq!(v, [""]); - /// - /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect(); - /// assert_eq!(v, ["lion", "", "tiger", "leopard"]); - /// - /// let v: Vec<&str> = "lion::tiger::leopard".split("::").collect(); - /// assert_eq!(v, ["lion", "tiger", "leopard"]); - /// - /// let v: Vec<&str> = "abc1def2ghi".split(char::is_numeric).collect(); - /// assert_eq!(v, ["abc", "def", "ghi"]); - /// - /// let v: Vec<&str> = "lionXtigerXleopard".split(char::is_uppercase).collect(); - /// assert_eq!(v, ["lion", "tiger", "leopard"]); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// let v: Vec<&str> = "abc1defXghi".split(|c| c == '1' || c == 'X').collect(); - /// assert_eq!(v, ["abc", "def", "ghi"]); - /// ``` - /// - /// If a string contains multiple contiguous separators, you will end up - /// with empty strings in the output: - /// - /// ``` - /// let x = "||||a||b|c".to_string(); - /// let d: Vec<_> = x.split('|').collect(); - /// - /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]); - /// ``` - /// - /// Contiguous separators are separated by the empty string. - /// - /// ``` - /// let x = "(///)".to_string(); - /// let d: Vec<_> = x.split('/').collect(); - /// - /// assert_eq!(d, &["(", "", "", ")"]); - /// ``` - /// - /// Separators at the start or end of a string are neighbored - /// by empty strings. - /// - /// ``` - /// let d: Vec<_> = "010".split("0").collect(); - /// assert_eq!(d, &["", "1", ""]); - /// ``` - /// - /// When the empty string is used as a separator, it separates - /// every character in the string, along with the beginning - /// and end of the string. - /// - /// ``` - /// let f: Vec<_> = "rust".split("").collect(); - /// assert_eq!(f, &["", "r", "u", "s", "t", ""]); - /// ``` - /// - /// Contiguous separators can lead to possibly surprising behavior - /// when whitespace is used as the separator. This code is correct: - /// - /// ``` - /// let x = " a b c".to_string(); - /// let d: Vec<_> = x.split(' ').collect(); - /// - /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]); - /// ``` - /// - /// It does _not_ give you: - /// - /// ```,ignore - /// assert_eq!(d, &["a", "b", "c"]); - /// ``` - /// - /// Use [`split_whitespace`] for this behavior. - /// - /// [`split_whitespace`]: #method.split_whitespace - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { - core_str::StrExt::split(self, pat) - } - - /// An iterator over substrings of the given string slice, separated by - /// characters matched by a pattern and yielded in reverse order. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines the - /// split. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator requires that the pattern supports a reverse - /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse - /// search yields the same elements. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// - /// For iterating from the front, the [`split`] method can be used. - /// - /// [`split`]: #method.split - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect(); - /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]); - /// - /// let v: Vec<&str> = "".rsplit('X').collect(); - /// assert_eq!(v, [""]); - /// - /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect(); - /// assert_eq!(v, ["leopard", "tiger", "", "lion"]); - /// - /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect(); - /// assert_eq!(v, ["leopard", "tiger", "lion"]); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// let v: Vec<&str> = "abc1defXghi".rsplit(|c| c == '1' || c == 'X').collect(); - /// assert_eq!(v, ["ghi", "def", "abc"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rsplit(self, pat) - } - - /// An iterator over substrings of the given string slice, separated by - /// characters matched by a pattern. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines the - /// split. - /// - /// Equivalent to [`split`], except that the trailing substring - /// is skipped if empty. - /// - /// [`split`]: #method.split - /// - /// This method can be used for string data that is _terminated_, - /// rather than _separated_ by a pattern. - /// - /// # Iterator behavior - /// - /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern - /// allows a reverse search and forward/reverse search yields the same - /// elements. This is true for, eg, [`char`] but not for `&str`. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// [`char`]: primitive.char.html - /// - /// If the pattern allows a reverse search but its results might differ - /// from a forward search, the [`rsplit_terminator`] method can be used. - /// - /// [`rsplit_terminator`]: #method.rsplit_terminator - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let v: Vec<&str> = "A.B.".split_terminator('.').collect(); - /// assert_eq!(v, ["A", "B"]); - /// - /// let v: Vec<&str> = "A..B..".split_terminator(".").collect(); - /// assert_eq!(v, ["A", "", "B", ""]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { - core_str::StrExt::split_terminator(self, pat) - } - - /// An iterator over substrings of `self`, separated by characters - /// matched by a pattern and yielded in reverse order. - /// - /// The pattern can be a simple `&str`, [`char`], or a closure that - /// determines the split. - /// Additional libraries might provide more complex patterns like - /// regular expressions. - /// - /// [`char`]: primitive.char.html - /// - /// Equivalent to [`split`], except that the trailing substring is - /// skipped if empty. - /// - /// [`split`]: #method.split - /// - /// This method can be used for string data that is _terminated_, - /// rather than _separated_ by a pattern. - /// - /// # Iterator behavior - /// - /// The returned iterator requires that the pattern supports a - /// reverse search, and it will be double ended if a forward/reverse - /// search yields the same elements. - /// - /// For iterating from the front, the [`split_terminator`] method can be - /// used. - /// - /// [`split_terminator`]: #method.split_terminator - /// - /// # Examples - /// - /// ``` - /// let v: Vec<&str> = "A.B.".rsplit_terminator('.').collect(); - /// assert_eq!(v, ["B", "A"]); - /// - /// let v: Vec<&str> = "A..B..".rsplit_terminator(".").collect(); - /// assert_eq!(v, ["", "B", "", "A"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rsplit_terminator(self, pat) - } - - /// An iterator over substrings of the given string slice, separated by a - /// pattern, restricted to returning at most `n` items. - /// - /// If `n` substrings are returned, the last substring (the `n`th substring) - /// will contain the remainder of the string. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines the - /// split. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator will not be double ended, because it is - /// not efficient to support. - /// - /// If the pattern allows a reverse search, the [`rsplitn`] method can be - /// used. - /// - /// [`rsplitn`]: #method.rsplitn - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let v: Vec<&str> = "Mary had a little lambda".splitn(3, ' ').collect(); - /// assert_eq!(v, ["Mary", "had", "a little lambda"]); - /// - /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(3, "X").collect(); - /// assert_eq!(v, ["lion", "", "tigerXleopard"]); - /// - /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect(); - /// assert_eq!(v, ["abcXdef"]); - /// - /// let v: Vec<&str> = "".splitn(1, 'X').collect(); - /// assert_eq!(v, [""]); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// let v: Vec<&str> = "abc1defXghi".splitn(2, |c| c == '1' || c == 'X').collect(); - /// assert_eq!(v, ["abc", "defXghi"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> { - core_str::StrExt::splitn(self, n, pat) - } - - /// An iterator over substrings of this string slice, separated by a - /// pattern, starting from the end of the string, restricted to returning - /// at most `n` items. - /// - /// If `n` substrings are returned, the last substring (the `n`th substring) - /// will contain the remainder of the string. - /// - /// The pattern can be a `&str`, [`char`], or a closure that - /// determines the split. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator will not be double ended, because it is not - /// efficient to support. - /// - /// For splitting from the front, the [`splitn`] method can be used. - /// - /// [`splitn`]: #method.splitn - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect(); - /// assert_eq!(v, ["lamb", "little", "Mary had a"]); - /// - /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(3, 'X').collect(); - /// assert_eq!(v, ["leopard", "tiger", "lionX"]); - /// - /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect(); - /// assert_eq!(v, ["leopard", "lion::tiger"]); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// let v: Vec<&str> = "abc1defXghi".rsplitn(2, |c| c == '1' || c == 'X').collect(); - /// assert_eq!(v, ["ghi", "abc1def"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rsplitn(self, n, pat) - } - - /// An iterator over the disjoint matches of a pattern within the given string - /// slice. - /// - /// The pattern can be a `&str`, [`char`], or a closure that - /// determines if a character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern - /// allows a reverse search and forward/reverse search yields the same - /// elements. This is true for, eg, [`char`] but not for `&str`. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// [`char`]: primitive.char.html - /// - /// If the pattern allows a reverse search but its results might differ - /// from a forward search, the [`rmatches`] method can be used. - /// - /// [`rmatches`]: #method.rmatches - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect(); - /// assert_eq!(v, ["abc", "abc", "abc"]); - /// - /// let v: Vec<&str> = "1abc2abc3".matches(char::is_numeric).collect(); - /// assert_eq!(v, ["1", "2", "3"]); - /// ``` - #[stable(feature = "str_matches", since = "1.2.0")] - #[inline] - pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { - core_str::StrExt::matches(self, pat) - } + let len = self.iter().map(|s| s.borrow().len()).sum(); + let mut result = String::with_capacity(len); - /// An iterator over the disjoint matches of a pattern within this string slice, - /// yielded in reverse order. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines if - /// a character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator requires that the pattern supports a reverse - /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse - /// search yields the same elements. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// - /// For iterating from the front, the [`matches`] method can be used. - /// - /// [`matches`]: #method.matches - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let v: Vec<&str> = "abcXXXabcYYYabc".rmatches("abc").collect(); - /// assert_eq!(v, ["abc", "abc", "abc"]); - /// - /// let v: Vec<&str> = "1abc2abc3".rmatches(char::is_numeric).collect(); - /// assert_eq!(v, ["3", "2", "1"]); - /// ``` - #[stable(feature = "str_matches", since = "1.2.0")] - #[inline] - pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rmatches(self, pat) - } + for s in self { + result.push_str(s.borrow()) + } - /// An iterator over the disjoint matches of a pattern within this string - /// slice as well as the index that the match starts at. - /// - /// For matches of `pat` within `self` that overlap, only the indices - /// corresponding to the first match are returned. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines - /// if a character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern - /// allows a reverse search and forward/reverse search yields the same - /// elements. This is true for, eg, [`char`] but not for `&str`. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// - /// If the pattern allows a reverse search but its results might differ - /// from a forward search, the [`rmatch_indices`] method can be used. - /// - /// [`rmatch_indices`]: #method.rmatch_indices - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect(); - /// assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]); - /// - /// let v: Vec<_> = "1abcabc2".match_indices("abc").collect(); - /// assert_eq!(v, [(1, "abc"), (4, "abc")]); - /// - /// let v: Vec<_> = "ababa".match_indices("aba").collect(); - /// assert_eq!(v, [(0, "aba")]); // only the first `aba` - /// ``` - #[stable(feature = "str_match_indices", since = "1.5.0")] - #[inline] - pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { - core_str::StrExt::match_indices(self, pat) + result } - /// An iterator over the disjoint matches of a pattern within `self`, - /// yielded in reverse order along with the index of the match. - /// - /// For matches of `pat` within `self` that overlap, only the indices - /// corresponding to the last match are returned. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines if a - /// character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator requires that the pattern supports a reverse - /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse - /// search yields the same elements. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// - /// For iterating from the front, the [`match_indices`] method can be used. - /// - /// [`match_indices`]: #method.match_indices - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_indices("abc").collect(); - /// assert_eq!(v, [(12, "abc"), (6, "abc"), (0, "abc")]); - /// - /// let v: Vec<_> = "1abcabc2".rmatch_indices("abc").collect(); - /// assert_eq!(v, [(4, "abc"), (1, "abc")]); - /// - /// let v: Vec<_> = "ababa".rmatch_indices("aba").collect(); - /// assert_eq!(v, [(2, "aba")]); // only the last `aba` - /// ``` - #[stable(feature = "str_match_indices", since = "1.5.0")] - #[inline] - pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rmatch_indices(self, pat) - } + fn join(&self, sep: &str) -> String { + if self.is_empty() { + return String::new(); + } - /// Returns a string slice with leading and trailing whitespace removed. - /// - /// 'Whitespace' is defined according to the terms of the Unicode Derived - /// Core Property `White_Space`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = " Hello\tworld\t"; - /// - /// assert_eq!("Hello\tworld", s.trim()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim(&self) -> &str { - StrExt::trim(self) - } + // concat is faster + if sep.is_empty() { + return self.concat(); + } - /// Returns a string slice with leading whitespace removed. - /// - /// 'Whitespace' is defined according to the terms of the Unicode Derived - /// Core Property `White_Space`. - /// - /// # Text directionality - /// - /// A string is a sequence of bytes. 'Left' in this context means the first - /// position of that byte string; for a language like Arabic or Hebrew - /// which are 'right to left' rather than 'left to right', this will be - /// the _right_ side, not the left. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = " Hello\tworld\t"; - /// - /// assert_eq!("Hello\tworld\t", s.trim_left()); - /// ``` - /// - /// Directionality: - /// - /// ``` - /// let s = " English"; - /// assert!(Some('E') == s.trim_left().chars().next()); - /// - /// let s = " עברית"; - /// assert!(Some('ע') == s.trim_left().chars().next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_left(&self) -> &str { - StrExt::trim_left(self) - } + // this is wrong without the guarantee that `self` is non-empty + // `len` calculation may overflow but push_str but will check boundaries + let len = sep.len() * (self.len() - 1) + + self.iter().map(|s| s.borrow().len()).sum::(); + let mut result = String::with_capacity(len); + let mut first = true; - /// Returns a string slice with trailing whitespace removed. - /// - /// 'Whitespace' is defined according to the terms of the Unicode Derived - /// Core Property `White_Space`. - /// - /// # Text directionality - /// - /// A string is a sequence of bytes. 'Right' in this context means the last - /// position of that byte string; for a language like Arabic or Hebrew - /// which are 'right to left' rather than 'left to right', this will be - /// the _left_ side, not the right. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = " Hello\tworld\t"; - /// - /// assert_eq!(" Hello\tworld", s.trim_right()); - /// ``` - /// - /// Directionality: - /// - /// ``` - /// let s = "English "; - /// assert!(Some('h') == s.trim_right().chars().rev().next()); - /// - /// let s = "עברית "; - /// assert!(Some('ת') == s.trim_right().chars().rev().next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_right(&self) -> &str { - StrExt::trim_right(self) + for s in self { + if first { + first = false; + } else { + result.push_str(sep); + } + result.push_str(s.borrow()); + } + result } - /// Returns a string slice with all prefixes and suffixes that match a - /// pattern repeatedly removed. - /// - /// The pattern can be a [`char`] or a closure that determines if a - /// character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar"); - /// assert_eq!("123foo1bar123".trim_matches(char::is_numeric), "foo1bar"); - /// - /// let x: &[_] = &['1', '2']; - /// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar"); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// assert_eq!("1foo1barXX".trim_matches(|c| c == '1' || c == 'X'), "foo1bar"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: DoubleEndedSearcher<'a> - { - core_str::StrExt::trim_matches(self, pat) + fn connect(&self, sep: &str) -> String { + self.join(sep) } +} - /// Returns a string slice with all prefixes that match a pattern - /// repeatedly removed. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines if - /// a character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Text directionality - /// - /// A string is a sequence of bytes. 'Left' in this context means the first - /// position of that byte string; for a language like Arabic or Hebrew - /// which are 'right to left' rather than 'left to right', this will be - /// the _right_ side, not the left. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11"); - /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123"); - /// - /// let x: &[_] = &['1', '2']; - /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { - core_str::StrExt::trim_left_matches(self, pat) +#[stable(feature = "rust1", since = "1.0.0")] +impl Borrow for String { + #[inline] + fn borrow(&self) -> &str { + &self[..] } +} - /// Returns a string slice with all suffixes that match a pattern - /// repeatedly removed. - /// - /// The pattern can be a `&str`, [`char`], or a closure that - /// determines if a character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Text directionality - /// - /// A string is a sequence of bytes. 'Right' in this context means the last - /// position of that byte string; for a language like Arabic or Hebrew - /// which are 'right to left' rather than 'left to right', this will be - /// the _left_ side, not the right. - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar"); - /// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar"); - /// - /// let x: &[_] = &['1', '2']; - /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar"); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::trim_right_matches(self, pat) +#[stable(feature = "rust1", since = "1.0.0")] +impl ToOwned for str { + type Owned = String; + fn to_owned(&self) -> String { + unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) } } - /// Parses this string slice into another type. - /// - /// Because `parse` is so general, it can cause problems with type - /// inference. As such, `parse` is one of the few times you'll see - /// the syntax affectionately known as the 'turbofish': `::<>`. This - /// helps the inference algorithm understand specifically which type - /// you're trying to parse into. - /// - /// `parse` can parse any type that implements the [`FromStr`] trait. - /// - /// [`FromStr`]: str/trait.FromStr.html - /// - /// # Errors - /// - /// Will return [`Err`] if it's not possible to parse this string slice into - /// the desired type. - /// - /// [`Err`]: str/trait.FromStr.html#associatedtype.Err - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// let four: u32 = "4".parse().unwrap(); - /// - /// assert_eq!(4, four); - /// ``` - /// - /// Using the 'turbofish' instead of annotating `four`: - /// - /// ``` - /// let four = "4".parse::(); - /// - /// assert_eq!(Ok(4), four); - /// ``` - /// - /// Failing to parse: - /// - /// ``` - /// let nope = "j".parse::(); - /// - /// assert!(nope.is_err()); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn parse(&self) -> Result { - core_str::StrExt::parse(self) + fn clone_into(&self, target: &mut String) { + let mut b = mem::replace(target, String::new()).into_bytes(); + self.as_bytes().clone_into(&mut b); + *target = unsafe { String::from_utf8_unchecked(b) } } +} + +/// Methods for string slices. +#[cfg_attr(stage0, lang = "str")] +#[cfg_attr(not(stage0), lang = "str_alloc")] +#[cfg(not(test))] +impl str { + #[cfg(stage0)] + str_core_methods!(); /// Converts a `Box` into a `Box<[u8]>` without copying or allocating. /// @@ -2140,26 +491,6 @@ impl str { unsafe { String::from_utf8_unchecked(buf) } } - /// Checks if all characters in this string are within the ASCII range. - /// - /// # Examples - /// - /// ``` - /// let ascii = "hello!\n"; - /// let non_ascii = "Grüße, Jürgen ❤"; - /// - /// assert!(ascii.is_ascii()); - /// assert!(!non_ascii.is_ascii()); - /// ``` - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn is_ascii(&self) -> bool { - // We can treat each byte as character here: all multibyte characters - // start with a byte that is not in the ascii range, so we will stop - // there already. - self.bytes().all(|b| b.is_ascii()) - } - /// Returns a copy of this string where each character is mapped to its /// ASCII upper case equivalent. /// @@ -2219,54 +550,6 @@ impl str { // make_ascii_lowercase() preserves the UTF-8 invariant. unsafe { String::from_utf8_unchecked(bytes) } } - - /// Checks that two strings are an ASCII case-insensitive match. - /// - /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, - /// but without allocating and copying temporaries. - /// - /// # Examples - /// - /// ``` - /// assert!("Ferris".eq_ignore_ascii_case("FERRIS")); - /// assert!("Ferrös".eq_ignore_ascii_case("FERRöS")); - /// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS")); - /// ``` - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn eq_ignore_ascii_case(&self, other: &str) -> bool { - self.as_bytes().eq_ignore_ascii_case(other.as_bytes()) - } - - /// Converts this string to its ASCII upper case equivalent in-place. - /// - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new uppercased value without modifying the existing one, use - /// [`to_ascii_uppercase`]. - /// - /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - pub fn make_ascii_uppercase(&mut self) { - let me = unsafe { self.as_bytes_mut() }; - me.make_ascii_uppercase() - } - - /// Converts this string to its ASCII lower case equivalent in-place. - /// - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new lowercased value without modifying the existing one, use - /// [`to_ascii_lowercase`]. - /// - /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - pub fn make_ascii_lowercase(&mut self) { - let me = unsafe { self.as_bytes_mut() }; - me.make_ascii_lowercase() - } } /// Converts a boxed slice of bytes to a boxed string slice without checking diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index f4fafe304c0..5a107951b0b 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -93,6 +93,7 @@ #![feature(rustc_const_unstable)] #![feature(simd_ffi)] #![feature(core_slice_ext)] +#![feature(core_str_ext)] #![feature(specialization)] #![feature(staged_api)] #![feature(stmt_expr_attributes)] diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index 32c1531bdc0..8212648f2d8 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -62,4 +62,5 @@ pub use result::Result::{self, Ok, Err}; pub use slice::SliceExt; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] +#[cfg(stage0)] pub use str::StrExt; diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index f1fe23092de..d33eaace79d 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2218,10 +2218,6 @@ pub trait StrExt { fn parse(&self) -> Result; #[stable(feature = "split_whitespace", since = "1.1.0")] fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>; - #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")] - fn is_whitespace(&self) -> bool; - #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")] - fn is_alphanumeric(&self) -> bool; #[stable(feature = "rust1", since = "1.0.0")] fn trim(&self) -> &str; #[stable(feature = "rust1", since = "1.0.0")] @@ -2555,31 +2551,1700 @@ impl StrExt for str { } #[inline] - fn is_whitespace(&self) -> bool { - self.chars().all(|c| c.is_whitespace()) + fn trim(&self) -> &str { + self.trim_matches(|c: char| c.is_whitespace()) + } + + #[inline] + fn trim_left(&self) -> &str { + self.trim_left_matches(|c: char| c.is_whitespace()) + } + + #[inline] + fn trim_right(&self) -> &str { + self.trim_right_matches(|c: char| c.is_whitespace()) + } +} + +// FIXME: remove (inline) this macro and the SliceExt trait +// when updating to a bootstrap compiler that has the new lang items. +#[cfg_attr(stage0, macro_export)] +#[unstable(feature = "core_str_ext", issue = "32110")] +macro_rules! str_core_methods { () => { + /// Returns the length of `self`. + /// + /// This length is in bytes, not [`char`]s or graphemes. In other words, + /// it may not be what a human considers the length of the string. + /// + /// [`char`]: primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let len = "foo".len(); + /// assert_eq!(3, len); + /// + /// let len = "ƒoo".len(); // fancy f! + /// assert_eq!(4, len); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn len(&self) -> usize { + StrExt::len(self) + } + + /// Returns `true` if `self` has a length of zero bytes. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = ""; + /// assert!(s.is_empty()); + /// + /// let s = "not empty"; + /// assert!(!s.is_empty()); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_empty(&self) -> bool { + StrExt::is_empty(self) + } + + /// Checks that `index`-th byte lies at the start and/or end of a + /// UTF-8 code point sequence. + /// + /// The start and end of the string (when `index == self.len()`) are + /// considered to be + /// boundaries. + /// + /// Returns `false` if `index` is greater than `self.len()`. + /// + /// # Examples + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// assert!(s.is_char_boundary(0)); + /// // start of `老` + /// assert!(s.is_char_boundary(6)); + /// assert!(s.is_char_boundary(s.len())); + /// + /// // second byte of `ö` + /// assert!(!s.is_char_boundary(2)); + /// + /// // third byte of `老` + /// assert!(!s.is_char_boundary(8)); + /// ``` + #[stable(feature = "is_char_boundary", since = "1.9.0")] + #[inline] + pub fn is_char_boundary(&self, index: usize) -> bool { + StrExt::is_char_boundary(self, index) + } + + /// Converts a string slice to a byte slice. To convert the byte slice back + /// into a string slice, use the [`str::from_utf8`] function. + /// + /// [`str::from_utf8`]: ./str/fn.from_utf8.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let bytes = "bors".as_bytes(); + /// assert_eq!(b"bors", bytes); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline(always)] + pub fn as_bytes(&self) -> &[u8] { + StrExt::as_bytes(self) + } + + /// Converts a mutable string slice to a mutable byte slice. To convert the + /// mutable byte slice back into a mutable string slice, use the + /// [`str::from_utf8_mut`] function. + /// + /// [`str::from_utf8_mut`]: ./str/fn.from_utf8_mut.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut s = String::from("Hello"); + /// let bytes = unsafe { s.as_bytes_mut() }; + /// + /// assert_eq!(b"Hello", bytes); + /// ``` + /// + /// Mutability: + /// + /// ``` + /// let mut s = String::from("🗻∈🌏"); + /// + /// unsafe { + /// let bytes = s.as_bytes_mut(); + /// + /// bytes[0] = 0xF0; + /// bytes[1] = 0x9F; + /// bytes[2] = 0x8D; + /// bytes[3] = 0x94; + /// } + /// + /// assert_eq!("🍔∈🌏", s); + /// ``` + #[stable(feature = "str_mut_extras", since = "1.20.0")] + #[inline(always)] + pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { + StrExt::as_bytes_mut(self) + } + + /// Converts a string slice to a raw pointer. + /// + /// As string slices are a slice of bytes, the raw pointer points to a + /// [`u8`]. This pointer will be pointing to the first byte of the string + /// slice. + /// + /// [`u8`]: primitive.u8.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = "Hello"; + /// let ptr = s.as_ptr(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn as_ptr(&self) -> *const u8 { + StrExt::as_ptr(self) + } + + /// Returns a subslice of `str`. + /// + /// This is the non-panicking alternative to indexing the `str`. Returns + /// [`None`] whenever equivalent indexing operation would panic. + /// + /// [`None`]: option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// let v = String::from("🗻∈🌏"); + /// + /// assert_eq!(Some("🗻"), v.get(0..4)); + /// + /// // indices not on UTF-8 sequence boundaries + /// assert!(v.get(1..).is_none()); + /// assert!(v.get(..8).is_none()); + /// + /// // out of bounds + /// assert!(v.get(..42).is_none()); + /// ``` + #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[inline] + pub fn get>(&self, i: I) -> Option<&I::Output> { + StrExt::get(self, i) + } + + /// Returns a mutable subslice of `str`. + /// + /// This is the non-panicking alternative to indexing the `str`. Returns + /// [`None`] whenever equivalent indexing operation would panic. + /// + /// [`None`]: option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// let mut v = String::from("hello"); + /// // correct length + /// assert!(v.get_mut(0..5).is_some()); + /// // out of bounds + /// assert!(v.get_mut(..42).is_none()); + /// assert_eq!(Some("he"), v.get_mut(0..2).map(|v| &*v)); + /// + /// assert_eq!("hello", v); + /// { + /// let s = v.get_mut(0..2); + /// let s = s.map(|s| { + /// s.make_ascii_uppercase(); + /// &*s + /// }); + /// assert_eq!(Some("HE"), s); + /// } + /// assert_eq!("HEllo", v); + /// ``` + #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[inline] + pub fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { + StrExt::get_mut(self, i) + } + + /// Returns a unchecked subslice of `str`. + /// + /// This is the unchecked alternative to indexing the `str`. + /// + /// # Safety + /// + /// Callers of this function are responsible that these preconditions are + /// satisfied: + /// + /// * The starting index must come before the ending index; + /// * Indexes must be within bounds of the original slice; + /// * Indexes must lie on UTF-8 sequence boundaries. + /// + /// Failing that, the returned string slice may reference invalid memory or + /// violate the invariants communicated by the `str` type. + /// + /// # Examples + /// + /// ``` + /// let v = "🗻∈🌏"; + /// unsafe { + /// assert_eq!("🗻", v.get_unchecked(0..4)); + /// assert_eq!("∈", v.get_unchecked(4..7)); + /// assert_eq!("🌏", v.get_unchecked(7..11)); + /// } + /// ``` + #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[inline] + pub unsafe fn get_unchecked>(&self, i: I) -> &I::Output { + StrExt::get_unchecked(self, i) + } + + /// Returns a mutable, unchecked subslice of `str`. + /// + /// This is the unchecked alternative to indexing the `str`. + /// + /// # Safety + /// + /// Callers of this function are responsible that these preconditions are + /// satisfied: + /// + /// * The starting index must come before the ending index; + /// * Indexes must be within bounds of the original slice; + /// * Indexes must lie on UTF-8 sequence boundaries. + /// + /// Failing that, the returned string slice may reference invalid memory or + /// violate the invariants communicated by the `str` type. + /// + /// # Examples + /// + /// ``` + /// let mut v = String::from("🗻∈🌏"); + /// unsafe { + /// assert_eq!("🗻", v.get_unchecked_mut(0..4)); + /// assert_eq!("∈", v.get_unchecked_mut(4..7)); + /// assert_eq!("🌏", v.get_unchecked_mut(7..11)); + /// } + /// ``` + #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[inline] + pub unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { + StrExt::get_unchecked_mut(self, i) + } + + /// Creates a string slice from another string slice, bypassing safety + /// checks. + /// + /// This is generally not recommended, use with caution! For a safe + /// alternative see [`str`] and [`Index`]. + /// + /// [`str`]: primitive.str.html + /// [`Index`]: ops/trait.Index.html + /// + /// This new slice goes from `begin` to `end`, including `begin` but + /// excluding `end`. + /// + /// To get a mutable string slice instead, see the + /// [`slice_mut_unchecked`] method. + /// + /// [`slice_mut_unchecked`]: #method.slice_mut_unchecked + /// + /// # Safety + /// + /// Callers of this function are responsible that three preconditions are + /// satisfied: + /// + /// * `begin` must come before `end`. + /// * `begin` and `end` must be byte positions within the string slice. + /// * `begin` and `end` must lie on UTF-8 sequence boundaries. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// + /// unsafe { + /// assert_eq!("Löwe 老虎 Léopard", s.slice_unchecked(0, 21)); + /// } + /// + /// let s = "Hello, world!"; + /// + /// unsafe { + /// assert_eq!("world", s.slice_unchecked(7, 12)); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { + StrExt::slice_unchecked(self, begin, end) + } + + /// Creates a string slice from another string slice, bypassing safety + /// checks. + /// This is generally not recommended, use with caution! For a safe + /// alternative see [`str`] and [`IndexMut`]. + /// + /// [`str`]: primitive.str.html + /// [`IndexMut`]: ops/trait.IndexMut.html + /// + /// This new slice goes from `begin` to `end`, including `begin` but + /// excluding `end`. + /// + /// To get an immutable string slice instead, see the + /// [`slice_unchecked`] method. + /// + /// [`slice_unchecked`]: #method.slice_unchecked + /// + /// # Safety + /// + /// Callers of this function are responsible that three preconditions are + /// satisfied: + /// + /// * `begin` must come before `end`. + /// * `begin` and `end` must be byte positions within the string slice. + /// * `begin` and `end` must lie on UTF-8 sequence boundaries. + #[stable(feature = "str_slice_mut", since = "1.5.0")] + #[inline] + pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { + StrExt::slice_mut_unchecked(self, begin, end) + } + + /// Divide one string slice into two at an index. + /// + /// The argument, `mid`, should be a byte offset from the start of the + /// string. It must also be on the boundary of a UTF-8 code point. + /// + /// The two slices returned go from the start of the string slice to `mid`, + /// and from `mid` to the end of the string slice. + /// + /// To get mutable string slices instead, see the [`split_at_mut`] + /// method. + /// + /// [`split_at_mut`]: #method.split_at_mut + /// + /// # Panics + /// + /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is + /// beyond the last code point of the string slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = "Per Martin-Löf"; + /// + /// let (first, last) = s.split_at(3); + /// + /// assert_eq!("Per", first); + /// assert_eq!(" Martin-Löf", last); + /// ``` + #[inline] + #[stable(feature = "str_split_at", since = "1.4.0")] + pub fn split_at(&self, mid: usize) -> (&str, &str) { + StrExt::split_at(self, mid) + } + + /// Divide one mutable string slice into two at an index. + /// + /// The argument, `mid`, should be a byte offset from the start of the + /// string. It must also be on the boundary of a UTF-8 code point. + /// + /// The two slices returned go from the start of the string slice to `mid`, + /// and from `mid` to the end of the string slice. + /// + /// To get immutable string slices instead, see the [`split_at`] method. + /// + /// [`split_at`]: #method.split_at + /// + /// # Panics + /// + /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is + /// beyond the last code point of the string slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut s = "Per Martin-Löf".to_string(); + /// { + /// let (first, last) = s.split_at_mut(3); + /// first.make_ascii_uppercase(); + /// assert_eq!("PER", first); + /// assert_eq!(" Martin-Löf", last); + /// } + /// assert_eq!("PER Martin-Löf", s); + /// ``` + #[inline] + #[stable(feature = "str_split_at", since = "1.4.0")] + pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { + StrExt::split_at_mut(self, mid) + } + + /// Returns an iterator over the [`char`]s of a string slice. + /// + /// As a string slice consists of valid UTF-8, we can iterate through a + /// string slice by [`char`]. This method returns such an iterator. + /// + /// It's important to remember that [`char`] represents a Unicode Scalar + /// Value, and may not match your idea of what a 'character' is. Iteration + /// over grapheme clusters may be what you actually want. + /// + /// [`char`]: primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let word = "goodbye"; + /// + /// let count = word.chars().count(); + /// assert_eq!(7, count); + /// + /// let mut chars = word.chars(); + /// + /// assert_eq!(Some('g'), chars.next()); + /// assert_eq!(Some('o'), chars.next()); + /// assert_eq!(Some('o'), chars.next()); + /// assert_eq!(Some('d'), chars.next()); + /// assert_eq!(Some('b'), chars.next()); + /// assert_eq!(Some('y'), chars.next()); + /// assert_eq!(Some('e'), chars.next()); + /// + /// assert_eq!(None, chars.next()); + /// ``` + /// + /// Remember, [`char`]s may not match your human intuition about characters: + /// + /// ``` + /// let y = "y̆"; + /// + /// let mut chars = y.chars(); + /// + /// assert_eq!(Some('y'), chars.next()); // not 'y̆' + /// assert_eq!(Some('\u{0306}'), chars.next()); + /// + /// assert_eq!(None, chars.next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn chars(&self) -> Chars { + StrExt::chars(self) + } + /// Returns an iterator over the [`char`]s of a string slice, and their + /// positions. + /// + /// As a string slice consists of valid UTF-8, we can iterate through a + /// string slice by [`char`]. This method returns an iterator of both + /// these [`char`]s, as well as their byte positions. + /// + /// The iterator yields tuples. The position is first, the [`char`] is + /// second. + /// + /// [`char`]: primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let word = "goodbye"; + /// + /// let count = word.char_indices().count(); + /// assert_eq!(7, count); + /// + /// let mut char_indices = word.char_indices(); + /// + /// assert_eq!(Some((0, 'g')), char_indices.next()); + /// assert_eq!(Some((1, 'o')), char_indices.next()); + /// assert_eq!(Some((2, 'o')), char_indices.next()); + /// assert_eq!(Some((3, 'd')), char_indices.next()); + /// assert_eq!(Some((4, 'b')), char_indices.next()); + /// assert_eq!(Some((5, 'y')), char_indices.next()); + /// assert_eq!(Some((6, 'e')), char_indices.next()); + /// + /// assert_eq!(None, char_indices.next()); + /// ``` + /// + /// Remember, [`char`]s may not match your human intuition about characters: + /// + /// ``` + /// let yes = "y̆es"; + /// + /// let mut char_indices = yes.char_indices(); + /// + /// assert_eq!(Some((0, 'y')), char_indices.next()); // not (0, 'y̆') + /// assert_eq!(Some((1, '\u{0306}')), char_indices.next()); + /// + /// // note the 3 here - the last character took up two bytes + /// assert_eq!(Some((3, 'e')), char_indices.next()); + /// assert_eq!(Some((4, 's')), char_indices.next()); + /// + /// assert_eq!(None, char_indices.next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn char_indices(&self) -> CharIndices { + StrExt::char_indices(self) + } + + /// An iterator over the bytes of a string slice. + /// + /// As a string slice consists of a sequence of bytes, we can iterate + /// through a string slice by byte. This method returns such an iterator. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut bytes = "bors".bytes(); + /// + /// assert_eq!(Some(b'b'), bytes.next()); + /// assert_eq!(Some(b'o'), bytes.next()); + /// assert_eq!(Some(b'r'), bytes.next()); + /// assert_eq!(Some(b's'), bytes.next()); + /// + /// assert_eq!(None, bytes.next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn bytes(&self) -> Bytes { + StrExt::bytes(self) + } + + /// Split a string slice by whitespace. + /// + /// The iterator returned will return string slices that are sub-slices of + /// the original string slice, separated by any amount of whitespace. + /// + /// 'Whitespace' is defined according to the terms of the Unicode Derived + /// Core Property `White_Space`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut iter = "A few words".split_whitespace(); + /// + /// assert_eq!(Some("A"), iter.next()); + /// assert_eq!(Some("few"), iter.next()); + /// assert_eq!(Some("words"), iter.next()); + /// + /// assert_eq!(None, iter.next()); + /// ``` + /// + /// All kinds of whitespace are considered: + /// + /// ``` + /// let mut iter = " Mary had\ta\u{2009}little \n\t lamb".split_whitespace(); + /// assert_eq!(Some("Mary"), iter.next()); + /// assert_eq!(Some("had"), iter.next()); + /// assert_eq!(Some("a"), iter.next()); + /// assert_eq!(Some("little"), iter.next()); + /// assert_eq!(Some("lamb"), iter.next()); + /// + /// assert_eq!(None, iter.next()); + /// ``` + #[stable(feature = "split_whitespace", since = "1.1.0")] + #[inline] + pub fn split_whitespace(&self) -> SplitWhitespace { + StrExt::split_whitespace(self) + } + + /// An iterator over the lines of a string, as string slices. + /// + /// Lines are ended with either a newline (`\n`) or a carriage return with + /// a line feed (`\r\n`). + /// + /// The final line ending is optional. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let text = "foo\r\nbar\n\nbaz\n"; + /// let mut lines = text.lines(); + /// + /// assert_eq!(Some("foo"), lines.next()); + /// assert_eq!(Some("bar"), lines.next()); + /// assert_eq!(Some(""), lines.next()); + /// assert_eq!(Some("baz"), lines.next()); + /// + /// assert_eq!(None, lines.next()); + /// ``` + /// + /// The final line ending isn't required: + /// + /// ``` + /// let text = "foo\nbar\n\r\nbaz"; + /// let mut lines = text.lines(); + /// + /// assert_eq!(Some("foo"), lines.next()); + /// assert_eq!(Some("bar"), lines.next()); + /// assert_eq!(Some(""), lines.next()); + /// assert_eq!(Some("baz"), lines.next()); + /// + /// assert_eq!(None, lines.next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn lines(&self) -> Lines { + StrExt::lines(self) + } + + /// An iterator over the lines of a string. + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated(since = "1.4.0", reason = "use lines() instead now")] + #[inline] + #[allow(deprecated)] + pub fn lines_any(&self) -> LinesAny { + StrExt::lines_any(self) + } + + /// Returns an iterator of `u16` over the string encoded as UTF-16. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let text = "Zażółć gęślą jaźń"; + /// + /// let utf8_len = text.len(); + /// let utf16_len = text.encode_utf16().count(); + /// + /// assert!(utf16_len <= utf8_len); + /// ``` + #[stable(feature = "encode_utf16", since = "1.8.0")] + pub fn encode_utf16(&self) -> EncodeUtf16 { + EncodeUtf16::new(self) + } + + /// Returns `true` if the given pattern matches a sub-slice of + /// this string slice. + /// + /// Returns `false` if it does not. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let bananas = "bananas"; + /// + /// assert!(bananas.contains("nana")); + /// assert!(!bananas.contains("apples")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { + StrExt::contains(self, pat) + } + + /// Returns `true` if the given pattern matches a prefix of this + /// string slice. + /// + /// Returns `false` if it does not. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let bananas = "bananas"; + /// + /// assert!(bananas.starts_with("bana")); + /// assert!(!bananas.starts_with("nana")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { + StrExt::starts_with(self, pat) + } + + /// Returns `true` if the given pattern matches a suffix of this + /// string slice. + /// + /// Returns `false` if it does not. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let bananas = "bananas"; + /// + /// assert!(bananas.ends_with("anas")); + /// assert!(!bananas.ends_with("nana")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool + where P::Searcher: ReverseSearcher<'a> + { + StrExt::ends_with(self, pat) + } + + /// Returns the byte index of the first character of this string slice that + /// matches the pattern. + /// + /// Returns [`None`] if the pattern doesn't match. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines if + /// a character matches. + /// + /// [`char`]: primitive.char.html + /// [`None`]: option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// + /// assert_eq!(s.find('L'), Some(0)); + /// assert_eq!(s.find('é'), Some(14)); + /// assert_eq!(s.find("Léopard"), Some(13)); + /// ``` + /// + /// More complex patterns using point-free style and closures: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// + /// assert_eq!(s.find(char::is_whitespace), Some(5)); + /// assert_eq!(s.find(char::is_lowercase), Some(1)); + /// assert_eq!(s.find(|c: char| c.is_whitespace() || c.is_lowercase()), Some(1)); + /// assert_eq!(s.find(|c: char| (c < 'o') && (c > 'a')), Some(4)); + /// ``` + /// + /// Not finding the pattern: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// let x: &[_] = &['1', '2']; + /// + /// assert_eq!(s.find(x), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { + StrExt::find(self, pat) + } + + /// Returns the byte index of the last character of this string slice that + /// matches the pattern. + /// + /// Returns [`None`] if the pattern doesn't match. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines if + /// a character matches. + /// + /// [`char`]: primitive.char.html + /// [`None`]: option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// + /// assert_eq!(s.rfind('L'), Some(13)); + /// assert_eq!(s.rfind('é'), Some(14)); + /// ``` + /// + /// More complex patterns with closures: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// + /// assert_eq!(s.rfind(char::is_whitespace), Some(12)); + /// assert_eq!(s.rfind(char::is_lowercase), Some(20)); + /// ``` + /// + /// Not finding the pattern: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// let x: &[_] = &['1', '2']; + /// + /// assert_eq!(s.rfind(x), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option + where P::Searcher: ReverseSearcher<'a> + { + StrExt::rfind(self, pat) + } + + /// An iterator over substrings of this string slice, separated by + /// characters matched by a pattern. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines the + /// split. + /// + /// # Iterator behavior + /// + /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern + /// allows a reverse search and forward/reverse search yields the same + /// elements. This is true for, eg, [`char`] but not for `&str`. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, the [`rsplit`] method can be used. + /// + /// [`char`]: primitive.char.html + /// [`rsplit`]: #method.rsplit + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect(); + /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]); + /// + /// let v: Vec<&str> = "".split('X').collect(); + /// assert_eq!(v, [""]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect(); + /// assert_eq!(v, ["lion", "", "tiger", "leopard"]); + /// + /// let v: Vec<&str> = "lion::tiger::leopard".split("::").collect(); + /// assert_eq!(v, ["lion", "tiger", "leopard"]); + /// + /// let v: Vec<&str> = "abc1def2ghi".split(char::is_numeric).collect(); + /// assert_eq!(v, ["abc", "def", "ghi"]); + /// + /// let v: Vec<&str> = "lionXtigerXleopard".split(char::is_uppercase).collect(); + /// assert_eq!(v, ["lion", "tiger", "leopard"]); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// let v: Vec<&str> = "abc1defXghi".split(|c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["abc", "def", "ghi"]); + /// ``` + /// + /// If a string contains multiple contiguous separators, you will end up + /// with empty strings in the output: + /// + /// ``` + /// let x = "||||a||b|c".to_string(); + /// let d: Vec<_> = x.split('|').collect(); + /// + /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]); + /// ``` + /// + /// Contiguous separators are separated by the empty string. + /// + /// ``` + /// let x = "(///)".to_string(); + /// let d: Vec<_> = x.split('/').collect(); + /// + /// assert_eq!(d, &["(", "", "", ")"]); + /// ``` + /// + /// Separators at the start or end of a string are neighbored + /// by empty strings. + /// + /// ``` + /// let d: Vec<_> = "010".split("0").collect(); + /// assert_eq!(d, &["", "1", ""]); + /// ``` + /// + /// When the empty string is used as a separator, it separates + /// every character in the string, along with the beginning + /// and end of the string. + /// + /// ``` + /// let f: Vec<_> = "rust".split("").collect(); + /// assert_eq!(f, &["", "r", "u", "s", "t", ""]); + /// ``` + /// + /// Contiguous separators can lead to possibly surprising behavior + /// when whitespace is used as the separator. This code is correct: + /// + /// ``` + /// let x = " a b c".to_string(); + /// let d: Vec<_> = x.split(' ').collect(); + /// + /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]); + /// ``` + /// + /// It does _not_ give you: + /// + /// ```,ignore + /// assert_eq!(d, &["a", "b", "c"]); + /// ``` + /// + /// Use [`split_whitespace`] for this behavior. + /// + /// [`split_whitespace`]: #method.split_whitespace + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { + StrExt::split(self, pat) + } + + /// An iterator over substrings of the given string slice, separated by + /// characters matched by a pattern and yielded in reverse order. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines the + /// split. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a reverse + /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse + /// search yields the same elements. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// + /// For iterating from the front, the [`split`] method can be used. + /// + /// [`split`]: #method.split + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect(); + /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]); + /// + /// let v: Vec<&str> = "".rsplit('X').collect(); + /// assert_eq!(v, [""]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect(); + /// assert_eq!(v, ["leopard", "tiger", "", "lion"]); + /// + /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect(); + /// assert_eq!(v, ["leopard", "tiger", "lion"]); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// let v: Vec<&str> = "abc1defXghi".rsplit(|c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["ghi", "def", "abc"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + StrExt::rsplit(self, pat) + } + + /// An iterator over substrings of the given string slice, separated by + /// characters matched by a pattern. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines the + /// split. + /// + /// Equivalent to [`split`], except that the trailing substring + /// is skipped if empty. + /// + /// [`split`]: #method.split + /// + /// This method can be used for string data that is _terminated_, + /// rather than _separated_ by a pattern. + /// + /// # Iterator behavior + /// + /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern + /// allows a reverse search and forward/reverse search yields the same + /// elements. This is true for, eg, [`char`] but not for `&str`. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// [`char`]: primitive.char.html + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, the [`rsplit_terminator`] method can be used. + /// + /// [`rsplit_terminator`]: #method.rsplit_terminator + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let v: Vec<&str> = "A.B.".split_terminator('.').collect(); + /// assert_eq!(v, ["A", "B"]); + /// + /// let v: Vec<&str> = "A..B..".split_terminator(".").collect(); + /// assert_eq!(v, ["A", "", "B", ""]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { + StrExt::split_terminator(self, pat) + } + + /// An iterator over substrings of `self`, separated by characters + /// matched by a pattern and yielded in reverse order. + /// + /// The pattern can be a simple `&str`, [`char`], or a closure that + /// determines the split. + /// Additional libraries might provide more complex patterns like + /// regular expressions. + /// + /// [`char`]: primitive.char.html + /// + /// Equivalent to [`split`], except that the trailing substring is + /// skipped if empty. + /// + /// [`split`]: #method.split + /// + /// This method can be used for string data that is _terminated_, + /// rather than _separated_ by a pattern. + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a + /// reverse search, and it will be double ended if a forward/reverse + /// search yields the same elements. + /// + /// For iterating from the front, the [`split_terminator`] method can be + /// used. + /// + /// [`split_terminator`]: #method.split_terminator + /// + /// # Examples + /// + /// ``` + /// let v: Vec<&str> = "A.B.".rsplit_terminator('.').collect(); + /// assert_eq!(v, ["B", "A"]); + /// + /// let v: Vec<&str> = "A..B..".rsplit_terminator(".").collect(); + /// assert_eq!(v, ["", "B", "", "A"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + StrExt::rsplit_terminator(self, pat) + } + + /// An iterator over substrings of the given string slice, separated by a + /// pattern, restricted to returning at most `n` items. + /// + /// If `n` substrings are returned, the last substring (the `n`th substring) + /// will contain the remainder of the string. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines the + /// split. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator will not be double ended, because it is + /// not efficient to support. + /// + /// If the pattern allows a reverse search, the [`rsplitn`] method can be + /// used. + /// + /// [`rsplitn`]: #method.rsplitn + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let v: Vec<&str> = "Mary had a little lambda".splitn(3, ' ').collect(); + /// assert_eq!(v, ["Mary", "had", "a little lambda"]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(3, "X").collect(); + /// assert_eq!(v, ["lion", "", "tigerXleopard"]); + /// + /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect(); + /// assert_eq!(v, ["abcXdef"]); + /// + /// let v: Vec<&str> = "".splitn(1, 'X').collect(); + /// assert_eq!(v, [""]); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// let v: Vec<&str> = "abc1defXghi".splitn(2, |c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["abc", "defXghi"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> { + StrExt::splitn(self, n, pat) + } + + /// An iterator over substrings of this string slice, separated by a + /// pattern, starting from the end of the string, restricted to returning + /// at most `n` items. + /// + /// If `n` substrings are returned, the last substring (the `n`th substring) + /// will contain the remainder of the string. + /// + /// The pattern can be a `&str`, [`char`], or a closure that + /// determines the split. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator will not be double ended, because it is not + /// efficient to support. + /// + /// For splitting from the front, the [`splitn`] method can be used. + /// + /// [`splitn`]: #method.splitn + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect(); + /// assert_eq!(v, ["lamb", "little", "Mary had a"]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(3, 'X').collect(); + /// assert_eq!(v, ["leopard", "tiger", "lionX"]); + /// + /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect(); + /// assert_eq!(v, ["leopard", "lion::tiger"]); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// let v: Vec<&str> = "abc1defXghi".rsplitn(2, |c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["ghi", "abc1def"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + StrExt::rsplitn(self, n, pat) + } + + /// An iterator over the disjoint matches of a pattern within the given string + /// slice. + /// + /// The pattern can be a `&str`, [`char`], or a closure that + /// determines if a character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern + /// allows a reverse search and forward/reverse search yields the same + /// elements. This is true for, eg, [`char`] but not for `&str`. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// [`char`]: primitive.char.html + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, the [`rmatches`] method can be used. + /// + /// [`rmatches`]: #method.rmatches + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect(); + /// assert_eq!(v, ["abc", "abc", "abc"]); + /// + /// let v: Vec<&str> = "1abc2abc3".matches(char::is_numeric).collect(); + /// assert_eq!(v, ["1", "2", "3"]); + /// ``` + #[stable(feature = "str_matches", since = "1.2.0")] + #[inline] + pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { + StrExt::matches(self, pat) } + /// An iterator over the disjoint matches of a pattern within this string slice, + /// yielded in reverse order. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines if + /// a character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a reverse + /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse + /// search yields the same elements. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// + /// For iterating from the front, the [`matches`] method can be used. + /// + /// [`matches`]: #method.matches + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let v: Vec<&str> = "abcXXXabcYYYabc".rmatches("abc").collect(); + /// assert_eq!(v, ["abc", "abc", "abc"]); + /// + /// let v: Vec<&str> = "1abc2abc3".rmatches(char::is_numeric).collect(); + /// assert_eq!(v, ["3", "2", "1"]); + /// ``` + #[stable(feature = "str_matches", since = "1.2.0")] #[inline] - fn is_alphanumeric(&self) -> bool { - self.chars().all(|c| c.is_alphanumeric()) + pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + StrExt::rmatches(self, pat) } + /// An iterator over the disjoint matches of a pattern within this string + /// slice as well as the index that the match starts at. + /// + /// For matches of `pat` within `self` that overlap, only the indices + /// corresponding to the first match are returned. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines + /// if a character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern + /// allows a reverse search and forward/reverse search yields the same + /// elements. This is true for, eg, [`char`] but not for `&str`. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, the [`rmatch_indices`] method can be used. + /// + /// [`rmatch_indices`]: #method.rmatch_indices + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect(); + /// assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]); + /// + /// let v: Vec<_> = "1abcabc2".match_indices("abc").collect(); + /// assert_eq!(v, [(1, "abc"), (4, "abc")]); + /// + /// let v: Vec<_> = "ababa".match_indices("aba").collect(); + /// assert_eq!(v, [(0, "aba")]); // only the first `aba` + /// ``` + #[stable(feature = "str_match_indices", since = "1.5.0")] #[inline] - fn trim(&self) -> &str { - self.trim_matches(|c: char| c.is_whitespace()) + pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { + StrExt::match_indices(self, pat) } + /// An iterator over the disjoint matches of a pattern within `self`, + /// yielded in reverse order along with the index of the match. + /// + /// For matches of `pat` within `self` that overlap, only the indices + /// corresponding to the last match are returned. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines if a + /// character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a reverse + /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse + /// search yields the same elements. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// + /// For iterating from the front, the [`match_indices`] method can be used. + /// + /// [`match_indices`]: #method.match_indices + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_indices("abc").collect(); + /// assert_eq!(v, [(12, "abc"), (6, "abc"), (0, "abc")]); + /// + /// let v: Vec<_> = "1abcabc2".rmatch_indices("abc").collect(); + /// assert_eq!(v, [(4, "abc"), (1, "abc")]); + /// + /// let v: Vec<_> = "ababa".rmatch_indices("aba").collect(); + /// assert_eq!(v, [(2, "aba")]); // only the last `aba` + /// ``` + #[stable(feature = "str_match_indices", since = "1.5.0")] #[inline] - fn trim_left(&self) -> &str { - self.trim_left_matches(|c: char| c.is_whitespace()) + pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + StrExt::rmatch_indices(self, pat) + } + + /// Returns a string slice with leading and trailing whitespace removed. + /// + /// 'Whitespace' is defined according to the terms of the Unicode Derived + /// Core Property `White_Space`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = " Hello\tworld\t"; + /// + /// assert_eq!("Hello\tworld", s.trim()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim(&self) -> &str { + StrExt::trim(self) + } + + /// Returns a string slice with leading whitespace removed. + /// + /// 'Whitespace' is defined according to the terms of the Unicode Derived + /// Core Property `White_Space`. + /// + /// # Text directionality + /// + /// A string is a sequence of bytes. 'Left' in this context means the first + /// position of that byte string; for a language like Arabic or Hebrew + /// which are 'right to left' rather than 'left to right', this will be + /// the _right_ side, not the left. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = " Hello\tworld\t"; + /// + /// assert_eq!("Hello\tworld\t", s.trim_left()); + /// ``` + /// + /// Directionality: + /// + /// ``` + /// let s = " English"; + /// assert!(Some('E') == s.trim_left().chars().next()); + /// + /// let s = " עברית"; + /// assert!(Some('ע') == s.trim_left().chars().next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim_left(&self) -> &str { + StrExt::trim_left(self) + } + + /// Returns a string slice with trailing whitespace removed. + /// + /// 'Whitespace' is defined according to the terms of the Unicode Derived + /// Core Property `White_Space`. + /// + /// # Text directionality + /// + /// A string is a sequence of bytes. 'Right' in this context means the last + /// position of that byte string; for a language like Arabic or Hebrew + /// which are 'right to left' rather than 'left to right', this will be + /// the _left_ side, not the right. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = " Hello\tworld\t"; + /// + /// assert_eq!(" Hello\tworld", s.trim_right()); + /// ``` + /// + /// Directionality: + /// + /// ``` + /// let s = "English "; + /// assert!(Some('h') == s.trim_right().chars().rev().next()); + /// + /// let s = "עברית "; + /// assert!(Some('ת') == s.trim_right().chars().rev().next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim_right(&self) -> &str { + StrExt::trim_right(self) + } + + /// Returns a string slice with all prefixes and suffixes that match a + /// pattern repeatedly removed. + /// + /// The pattern can be a [`char`] or a closure that determines if a + /// character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar"); + /// assert_eq!("123foo1bar123".trim_matches(char::is_numeric), "foo1bar"); + /// + /// let x: &[_] = &['1', '2']; + /// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar"); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// assert_eq!("1foo1barXX".trim_matches(|c| c == '1' || c == 'X'), "foo1bar"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str + where P::Searcher: DoubleEndedSearcher<'a> + { + StrExt::trim_matches(self, pat) + } + + /// Returns a string slice with all prefixes that match a pattern + /// repeatedly removed. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines if + /// a character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Text directionality + /// + /// A string is a sequence of bytes. 'Left' in this context means the first + /// position of that byte string; for a language like Arabic or Hebrew + /// which are 'right to left' rather than 'left to right', this will be + /// the _right_ side, not the left. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11"); + /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123"); + /// + /// let x: &[_] = &['1', '2']; + /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { + StrExt::trim_left_matches(self, pat) + } + + /// Returns a string slice with all suffixes that match a pattern + /// repeatedly removed. + /// + /// The pattern can be a `&str`, [`char`], or a closure that + /// determines if a character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Text directionality + /// + /// A string is a sequence of bytes. 'Right' in this context means the last + /// position of that byte string; for a language like Arabic or Hebrew + /// which are 'right to left' rather than 'left to right', this will be + /// the _left_ side, not the right. + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar"); + /// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar"); + /// + /// let x: &[_] = &['1', '2']; + /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar"); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str + where P::Searcher: ReverseSearcher<'a> + { + StrExt::trim_right_matches(self, pat) + } + + /// Parses this string slice into another type. + /// + /// Because `parse` is so general, it can cause problems with type + /// inference. As such, `parse` is one of the few times you'll see + /// the syntax affectionately known as the 'turbofish': `::<>`. This + /// helps the inference algorithm understand specifically which type + /// you're trying to parse into. + /// + /// `parse` can parse any type that implements the [`FromStr`] trait. + /// + /// [`FromStr`]: str/trait.FromStr.html + /// + /// # Errors + /// + /// Will return [`Err`] if it's not possible to parse this string slice into + /// the desired type. + /// + /// [`Err`]: str/trait.FromStr.html#associatedtype.Err + /// + /// # Examples + /// + /// Basic usage + /// + /// ``` + /// let four: u32 = "4".parse().unwrap(); + /// + /// assert_eq!(4, four); + /// ``` + /// + /// Using the 'turbofish' instead of annotating `four`: + /// + /// ``` + /// let four = "4".parse::(); + /// + /// assert_eq!(Ok(4), four); + /// ``` + /// + /// Failing to parse: + /// + /// ``` + /// let nope = "j".parse::(); + /// + /// assert!(nope.is_err()); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn parse(&self) -> Result { + StrExt::parse(self) } + /// Checks if all characters in this string are within the ASCII range. + /// + /// # Examples + /// + /// ``` + /// let ascii = "hello!\n"; + /// let non_ascii = "Grüße, Jürgen ❤"; + /// + /// assert!(ascii.is_ascii()); + /// assert!(!non_ascii.is_ascii()); + /// ``` + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] - fn trim_right(&self) -> &str { - self.trim_right_matches(|c: char| c.is_whitespace()) + pub fn is_ascii(&self) -> bool { + // We can treat each byte as character here: all multibyte characters + // start with a byte that is not in the ascii range, so we will stop + // there already. + self.bytes().all(|b| b.is_ascii()) + } + + /// Checks that two strings are an ASCII case-insensitive match. + /// + /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, + /// but without allocating and copying temporaries. + /// + /// # Examples + /// + /// ``` + /// assert!("Ferris".eq_ignore_ascii_case("FERRIS")); + /// assert!("Ferrös".eq_ignore_ascii_case("FERRöS")); + /// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS")); + /// ``` + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn eq_ignore_ascii_case(&self, other: &str) -> bool { + self.as_bytes().eq_ignore_ascii_case(other.as_bytes()) } + + /// Converts this string to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`to_ascii_uppercase`]. + /// + /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + pub fn make_ascii_uppercase(&mut self) { + let me = unsafe { self.as_bytes_mut() }; + me.make_ascii_uppercase() + } + + /// Converts this string to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`to_ascii_lowercase`]. + /// + /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + pub fn make_ascii_lowercase(&mut self) { + let me = unsafe { self.as_bytes_mut() }; + me.make_ascii_lowercase() + } +}} + +#[lang = "str"] +#[cfg(not(test))] +#[cfg(not(stage0))] +impl str { + str_core_methods!(); } + #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<[u8]> for str { #[inline] @@ -2665,3 +4330,72 @@ impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { #[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for SplitWhitespace<'a> {} + +/// An iterator of [`u16`] over the string encoded as UTF-16. +/// +/// [`u16`]: ../../std/primitive.u16.html +/// +/// This struct is created by the [`encode_utf16`] method on [`str`]. +/// See its documentation for more. +/// +/// [`encode_utf16`]: ../../std/primitive.str.html#method.encode_utf16 +/// [`str`]: ../../std/primitive.str.html +#[derive(Clone)] +#[stable(feature = "encode_utf16", since = "1.8.0")] +pub struct EncodeUtf16<'a> { + chars: Chars<'a>, + extra: u16, +} + +// FIXME: remove (inline) this method +// when updating to a bootstrap compiler that has the new lang items. +// For grepping purpose: #[cfg(stage0)] +impl<'a> EncodeUtf16<'a> { + #[unstable(feature = "core_str_ext", issue = "32110")] + #[doc(hidden)] + pub fn new(s: &'a str) -> Self { + EncodeUtf16 { chars: s.chars(), extra: 0 } + } +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a> fmt::Debug for EncodeUtf16<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("EncodeUtf16 { .. }") + } +} + +#[stable(feature = "encode_utf16", since = "1.8.0")] +impl<'a> Iterator for EncodeUtf16<'a> { + type Item = u16; + + #[inline] + fn next(&mut self) -> Option { + if self.extra != 0 { + let tmp = self.extra; + self.extra = 0; + return Some(tmp); + } + + let mut buf = [0; 2]; + self.chars.next().map(|ch| { + let n = ch.encode_utf16(&mut buf).len(); + if n == 2 { + self.extra = buf[1]; + } + buf[0] + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (low, high) = self.chars.size_hint(); + // every char gets either one u16 or two u16, + // so this iterator is between 1 or 2 times as + // long as the underlying iterator. + (low, high.and_then(|n| n.checked_mul(2))) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a> FusedIterator for EncodeUtf16<'a> {} diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 237a22925b4..24c7f3b0aba 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -214,6 +214,7 @@ language_item_table! { StrImplItem, "str", str_impl; SliceImplItem, "slice", slice_impl; SliceU8ImplItem, "slice_u8", slice_u8_impl; + StrAllocImplItem, "str_alloc", str_alloc_impl; SliceAllocImplItem, "slice_alloc", slice_alloc_impl; SliceU8AllocImplItem, "slice_u8_alloc", slice_u8_alloc_impl; ConstPtrImplItem, "const_ptr", const_ptr_impl; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index ea4c2c08817..c538004c838 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -471,6 +471,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { ty::TyStr => { let lang_def_id = lang_items.str_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); + + let lang_def_id = lang_items.str_alloc_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); } ty::TySlice(_) => { let lang_def_id = lang_items.slice_impl(); diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index 91f9e3e6fba..97e57ba668f 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -122,7 +122,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyStr => { self.check_primitive_impl(def_id, lang_items.str_impl(), - None, + lang_items.str_alloc_impl(), "str", "str", item.span); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 38af4350815..65f6b227a56 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -290,6 +290,7 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec Date: Sun, 8 Apr 2018 10:09:52 +0200 Subject: Add some f32 and f64 inherent methods in libcore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … previously in the unstable core::num::Float trait. Per https://github.com/rust-lang/rust/issues/32110#issuecomment-379503183, the `abs`, `signum`, and `powi` methods are *not* included for now since they rely on LLVM intrinsics and we haven’t determined yet whether those instrinsics lower to calls to libm functions on any platform. --- src/liballoc/vec.rs | 1 + src/libcore/lib.rs | 1 + src/libcore/num/f32.rs | 284 +++++++++++++++++++++++ src/libcore/num/f64.rs | 296 +++++++++++++++++++++++- src/librustc/middle/lang_items.rs | 2 + src/librustc_typeck/check/method/probe.rs | 6 + src/librustc_typeck/coherence/inherent_impls.rs | 4 +- src/librustdoc/clean/inline.rs | 2 + src/libstd/f32.rs | 283 +--------------------- src/libstd/f64.rs | 291 +---------------------- 10 files changed, 611 insertions(+), 559 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 7d1b2ed85c7..b184404c15b 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -74,6 +74,7 @@ use core::iter::{FromIterator, FusedIterator, TrustedLen}; use core::marker::PhantomData; use core::mem; #[cfg(not(test))] +#[cfg(stage0)] use core::num::Float; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{Index, IndexMut, RangeBounds}; diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5a107951b0b..215886069f5 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -71,6 +71,7 @@ #![feature(cfg_target_has_atomic)] #![feature(concat_idents)] #![feature(const_fn)] +#![feature(core_float)] #![feature(custom_attribute)] #![feature(doc_cfg)] #![feature(doc_spotlight)] diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 3586fa5442f..0edf63bce12 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -20,6 +20,7 @@ use intrinsics; use mem; use num::Float; +#[cfg(not(stage0))] use num::FpCategory; use num::FpCategory as Fp; /// The radix or base of the internal representation of `f32`. @@ -292,3 +293,286 @@ impl Float for f32 { unsafe { mem::transmute(v) } } } + +// FIXME: remove (inline) this macro and the Float trait +// when updating to a bootstrap compiler that has the new lang items. +#[cfg_attr(stage0, macro_export)] +#[unstable(feature = "core_float", issue = "32110")] +macro_rules! f32_core_methods { () => { + /// Returns `true` if this value is `NaN` and false otherwise. + /// + /// ``` + /// use std::f32; + /// + /// let nan = f32::NAN; + /// let f = 7.0_f32; + /// + /// assert!(nan.is_nan()); + /// assert!(!f.is_nan()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_nan(self) -> bool { Float::is_nan(self) } + + /// Returns `true` if this value is positive infinity or negative infinity and + /// false otherwise. + /// + /// ``` + /// use std::f32; + /// + /// let f = 7.0f32; + /// let inf = f32::INFINITY; + /// let neg_inf = f32::NEG_INFINITY; + /// let nan = f32::NAN; + /// + /// assert!(!f.is_infinite()); + /// assert!(!nan.is_infinite()); + /// + /// assert!(inf.is_infinite()); + /// assert!(neg_inf.is_infinite()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_infinite(self) -> bool { Float::is_infinite(self) } + + /// Returns `true` if this number is neither infinite nor `NaN`. + /// + /// ``` + /// use std::f32; + /// + /// let f = 7.0f32; + /// let inf = f32::INFINITY; + /// let neg_inf = f32::NEG_INFINITY; + /// let nan = f32::NAN; + /// + /// assert!(f.is_finite()); + /// + /// assert!(!nan.is_finite()); + /// assert!(!inf.is_finite()); + /// assert!(!neg_inf.is_finite()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_finite(self) -> bool { Float::is_finite(self) } + + /// Returns `true` if the number is neither zero, infinite, + /// [subnormal][subnormal], or `NaN`. + /// + /// ``` + /// use std::f32; + /// + /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 + /// let max = f32::MAX; + /// let lower_than_min = 1.0e-40_f32; + /// let zero = 0.0_f32; + /// + /// assert!(min.is_normal()); + /// assert!(max.is_normal()); + /// + /// assert!(!zero.is_normal()); + /// assert!(!f32::NAN.is_normal()); + /// assert!(!f32::INFINITY.is_normal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(!lower_than_min.is_normal()); + /// ``` + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_normal(self) -> bool { Float::is_normal(self) } + + /// Returns the floating point category of the number. If only one property + /// is going to be tested, it is generally faster to use the specific + /// predicate instead. + /// + /// ``` + /// use std::num::FpCategory; + /// use std::f32; + /// + /// let num = 12.4_f32; + /// let inf = f32::INFINITY; + /// + /// assert_eq!(num.classify(), FpCategory::Normal); + /// assert_eq!(inf.classify(), FpCategory::Infinite); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn classify(self) -> FpCategory { Float::classify(self) } + + /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with + /// positive sign bit and positive infinity. + /// + /// ``` + /// let f = 7.0_f32; + /// let g = -7.0_f32; + /// + /// assert!(f.is_sign_positive()); + /// assert!(!g.is_sign_positive()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_sign_positive(self) -> bool { Float::is_sign_positive(self) } + + /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with + /// negative sign bit and negative infinity. + /// + /// ``` + /// let f = 7.0f32; + /// let g = -7.0f32; + /// + /// assert!(!f.is_sign_negative()); + /// assert!(g.is_sign_negative()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_sign_negative(self) -> bool { Float::is_sign_negative(self) } + + /// Takes the reciprocal (inverse) of a number, `1/x`. + /// + /// ``` + /// use std::f32; + /// + /// let x = 2.0_f32; + /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn recip(self) -> f32 { Float::recip(self) } + + /// Converts radians to degrees. + /// + /// ``` + /// use std::f32::{self, consts}; + /// + /// let angle = consts::PI; + /// + /// let abs_difference = (angle.to_degrees() - 180.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] + #[inline] + pub fn to_degrees(self) -> f32 { Float::to_degrees(self) } + + /// Converts degrees to radians. + /// + /// ``` + /// use std::f32::{self, consts}; + /// + /// let angle = 180.0f32; + /// + /// let abs_difference = (angle.to_radians() - consts::PI).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] + #[inline] + pub fn to_radians(self) -> f32 { Float::to_radians(self) } + + /// Returns the maximum of the two numbers. + /// + /// ``` + /// let x = 1.0f32; + /// let y = 2.0f32; + /// + /// assert_eq!(x.max(y), y); + /// ``` + /// + /// If one of the arguments is NaN, then the other argument is returned. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn max(self, other: f32) -> f32 { + Float::max(self, other) + } + + /// Returns the minimum of the two numbers. + /// + /// ``` + /// let x = 1.0f32; + /// let y = 2.0f32; + /// + /// assert_eq!(x.min(y), x); + /// ``` + /// + /// If one of the arguments is NaN, then the other argument is returned. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn min(self, other: f32) -> f32 { + Float::min(self, other) + } + + /// Raw transmutation to `u32`. + /// + /// This is currently identical to `transmute::(self)` on all platforms. + /// + /// See `from_bits` for some discussion of the portability of this operation + /// (there are almost no issues). + /// + /// Note that this function is distinct from `as` casting, which attempts to + /// preserve the *numeric* value, and not the bitwise value. + /// + /// # Examples + /// + /// ``` + /// assert_ne!((1f32).to_bits(), 1f32 as u32); // to_bits() is not casting! + /// assert_eq!((12.5f32).to_bits(), 0x41480000); + /// + /// ``` + #[stable(feature = "float_bits_conv", since = "1.20.0")] + #[inline] + pub fn to_bits(self) -> u32 { + Float::to_bits(self) + } + + /// Raw transmutation from `u32`. + /// + /// This is currently identical to `transmute::(v)` on all platforms. + /// It turns out this is incredibly portable, for two reasons: + /// + /// * Floats and Ints have the same endianness on all supported platforms. + /// * IEEE-754 very precisely specifies the bit layout of floats. + /// + /// However there is one caveat: prior to the 2008 version of IEEE-754, how + /// to interpret the NaN signaling bit wasn't actually specified. Most platforms + /// (notably x86 and ARM) picked the interpretation that was ultimately + /// standardized in 2008, but some didn't (notably MIPS). As a result, all + /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. + /// + /// Rather than trying to preserve signaling-ness cross-platform, this + /// implementation favours preserving the exact bits. This means that + /// any payloads encoded in NaNs will be preserved even if the result of + /// this method is sent over the network from an x86 machine to a MIPS one. + /// + /// If the results of this method are only manipulated by the same + /// architecture that produced them, then there is no portability concern. + /// + /// If the input isn't NaN, then there is no portability concern. + /// + /// If you don't care about signalingness (very likely), then there is no + /// portability concern. + /// + /// Note that this function is distinct from `as` casting, which attempts to + /// preserve the *numeric* value, and not the bitwise value. + /// + /// # Examples + /// + /// ``` + /// use std::f32; + /// let v = f32::from_bits(0x41480000); + /// let difference = (v - 12.5).abs(); + /// assert!(difference <= 1e-5); + /// ``` + #[stable(feature = "float_bits_conv", since = "1.20.0")] + #[inline] + pub fn from_bits(v: u32) -> Self { + Float::from_bits(v) + } +}} + +#[lang = "f32"] +#[cfg(not(test))] +#[cfg(not(stage0))] +impl f32 { + f32_core_methods!(); +} diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 64c0d508b38..38f3d63ea8d 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -19,8 +19,9 @@ use intrinsics; use mem; -use num::FpCategory as Fp; use num::Float; +#[cfg(not(stage0))] use num::FpCategory; +use num::FpCategory as Fp; /// The radix or base of the internal representation of `f64`. #[stable(feature = "rust1", since = "1.0.0")] @@ -291,3 +292,296 @@ impl Float for f64 { unsafe { mem::transmute(v) } } } + +// FIXME: remove (inline) this macro and the Float trait +// when updating to a bootstrap compiler that has the new lang items. +#[cfg_attr(stage0, macro_export)] +#[unstable(feature = "core_float", issue = "32110")] +macro_rules! f64_core_methods { () => { + /// Returns `true` if this value is `NaN` and false otherwise. + /// + /// ``` + /// use std::f64; + /// + /// let nan = f64::NAN; + /// let f = 7.0_f64; + /// + /// assert!(nan.is_nan()); + /// assert!(!f.is_nan()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_nan(self) -> bool { Float::is_nan(self) } + + /// Returns `true` if this value is positive infinity or negative infinity and + /// false otherwise. + /// + /// ``` + /// use std::f64; + /// + /// let f = 7.0f64; + /// let inf = f64::INFINITY; + /// let neg_inf = f64::NEG_INFINITY; + /// let nan = f64::NAN; + /// + /// assert!(!f.is_infinite()); + /// assert!(!nan.is_infinite()); + /// + /// assert!(inf.is_infinite()); + /// assert!(neg_inf.is_infinite()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_infinite(self) -> bool { Float::is_infinite(self) } + + /// Returns `true` if this number is neither infinite nor `NaN`. + /// + /// ``` + /// use std::f64; + /// + /// let f = 7.0f64; + /// let inf: f64 = f64::INFINITY; + /// let neg_inf: f64 = f64::NEG_INFINITY; + /// let nan: f64 = f64::NAN; + /// + /// assert!(f.is_finite()); + /// + /// assert!(!nan.is_finite()); + /// assert!(!inf.is_finite()); + /// assert!(!neg_inf.is_finite()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_finite(self) -> bool { Float::is_finite(self) } + + /// Returns `true` if the number is neither zero, infinite, + /// [subnormal][subnormal], or `NaN`. + /// + /// ``` + /// use std::f64; + /// + /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64 + /// let max = f64::MAX; + /// let lower_than_min = 1.0e-308_f64; + /// let zero = 0.0f64; + /// + /// assert!(min.is_normal()); + /// assert!(max.is_normal()); + /// + /// assert!(!zero.is_normal()); + /// assert!(!f64::NAN.is_normal()); + /// assert!(!f64::INFINITY.is_normal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(!lower_than_min.is_normal()); + /// ``` + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_normal(self) -> bool { Float::is_normal(self) } + + /// Returns the floating point category of the number. If only one property + /// is going to be tested, it is generally faster to use the specific + /// predicate instead. + /// + /// ``` + /// use std::num::FpCategory; + /// use std::f64; + /// + /// let num = 12.4_f64; + /// let inf = f64::INFINITY; + /// + /// assert_eq!(num.classify(), FpCategory::Normal); + /// assert_eq!(inf.classify(), FpCategory::Infinite); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn classify(self) -> FpCategory { Float::classify(self) } + + /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with + /// positive sign bit and positive infinity. + /// + /// ``` + /// let f = 7.0_f64; + /// let g = -7.0_f64; + /// + /// assert!(f.is_sign_positive()); + /// assert!(!g.is_sign_positive()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_sign_positive(self) -> bool { Float::is_sign_positive(self) } + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")] + #[inline] + #[doc(hidden)] + pub fn is_positive(self) -> bool { Float::is_sign_positive(self) } + + /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with + /// negative sign bit and negative infinity. + /// + /// ``` + /// let f = 7.0_f64; + /// let g = -7.0_f64; + /// + /// assert!(!f.is_sign_negative()); + /// assert!(g.is_sign_negative()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_sign_negative(self) -> bool { Float::is_sign_negative(self) } + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")] + #[inline] + #[doc(hidden)] + pub fn is_negative(self) -> bool { Float::is_sign_negative(self) } + + /// Takes the reciprocal (inverse) of a number, `1/x`. + /// + /// ``` + /// let x = 2.0_f64; + /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn recip(self) -> f64 { Float::recip(self) } + + /// Converts radians to degrees. + /// + /// ``` + /// use std::f64::consts; + /// + /// let angle = consts::PI; + /// + /// let abs_difference = (angle.to_degrees() - 180.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_degrees(self) -> f64 { Float::to_degrees(self) } + + /// Converts degrees to radians. + /// + /// ``` + /// use std::f64::consts; + /// + /// let angle = 180.0_f64; + /// + /// let abs_difference = (angle.to_radians() - consts::PI).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_radians(self) -> f64 { Float::to_radians(self) } + + /// Returns the maximum of the two numbers. + /// + /// ``` + /// let x = 1.0_f64; + /// let y = 2.0_f64; + /// + /// assert_eq!(x.max(y), y); + /// ``` + /// + /// If one of the arguments is NaN, then the other argument is returned. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn max(self, other: f64) -> f64 { + Float::max(self, other) + } + + /// Returns the minimum of the two numbers. + /// + /// ``` + /// let x = 1.0_f64; + /// let y = 2.0_f64; + /// + /// assert_eq!(x.min(y), x); + /// ``` + /// + /// If one of the arguments is NaN, then the other argument is returned. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn min(self, other: f64) -> f64 { + Float::min(self, other) + } + + /// Raw transmutation to `u64`. + /// + /// This is currently identical to `transmute::(self)` on all platforms. + /// + /// See `from_bits` for some discussion of the portability of this operation + /// (there are almost no issues). + /// + /// Note that this function is distinct from `as` casting, which attempts to + /// preserve the *numeric* value, and not the bitwise value. + /// + /// # Examples + /// + /// ``` + /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting! + /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000); + /// + /// ``` + #[stable(feature = "float_bits_conv", since = "1.20.0")] + #[inline] + pub fn to_bits(self) -> u64 { + Float::to_bits(self) + } + + /// Raw transmutation from `u64`. + /// + /// This is currently identical to `transmute::(v)` on all platforms. + /// It turns out this is incredibly portable, for two reasons: + /// + /// * Floats and Ints have the same endianness on all supported platforms. + /// * IEEE-754 very precisely specifies the bit layout of floats. + /// + /// However there is one caveat: prior to the 2008 version of IEEE-754, how + /// to interpret the NaN signaling bit wasn't actually specified. Most platforms + /// (notably x86 and ARM) picked the interpretation that was ultimately + /// standardized in 2008, but some didn't (notably MIPS). As a result, all + /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. + /// + /// Rather than trying to preserve signaling-ness cross-platform, this + /// implementation favours preserving the exact bits. This means that + /// any payloads encoded in NaNs will be preserved even if the result of + /// this method is sent over the network from an x86 machine to a MIPS one. + /// + /// If the results of this method are only manipulated by the same + /// architecture that produced them, then there is no portability concern. + /// + /// If the input isn't NaN, then there is no portability concern. + /// + /// If you don't care about signalingness (very likely), then there is no + /// portability concern. + /// + /// Note that this function is distinct from `as` casting, which attempts to + /// preserve the *numeric* value, and not the bitwise value. + /// + /// # Examples + /// + /// ``` + /// use std::f64; + /// let v = f64::from_bits(0x4029000000000000); + /// let difference = (v - 12.5).abs(); + /// assert!(difference <= 1e-5); + /// ``` + #[stable(feature = "float_bits_conv", since = "1.20.0")] + #[inline] + pub fn from_bits(v: u64) -> Self { + Float::from_bits(v) + } +}} + +#[lang = "f64"] +#[cfg(not(test))] +#[cfg(not(stage0))] +impl f64 { + f64_core_methods!(); +} diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 24c7f3b0aba..c7412dbeeb3 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -233,6 +233,8 @@ language_item_table! { UsizeImplItem, "usize", usize_impl; F32ImplItem, "f32", f32_impl; F64ImplItem, "f64", f64_impl; + F32RuntimeImplItem, "f32_runtime", f32_runtime_impl; + F64RuntimeImplItem, "f64_runtime", f64_runtime_impl; SizedTraitLangItem, "sized", sized_trait; UnsizeTraitLangItem, "unsize", unsize_trait; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index c538004c838..073f36b9f3c 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -547,10 +547,16 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { ty::TyFloat(ast::FloatTy::F32) => { let lang_def_id = lang_items.f32_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); + + let lang_def_id = lang_items.f32_runtime_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); } ty::TyFloat(ast::FloatTy::F64) => { let lang_def_id = lang_items.f64_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); + + let lang_def_id = lang_items.f64_runtime_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); } _ => {} } diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index 97e57ba668f..532f1da4f30 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -258,7 +258,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyFloat(ast::FloatTy::F32) => { self.check_primitive_impl(def_id, lang_items.f32_impl(), - None, + lang_items.f32_runtime_impl(), "f32", "f32", item.span); @@ -266,7 +266,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyFloat(ast::FloatTy::F64) => { self.check_primitive_impl(def_id, lang_items.f64_impl(), - None, + lang_items.f64_runtime_impl(), "f64", "f64", item.span); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 65f6b227a56..23e0c2625ee 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -286,6 +286,8 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec bool { num::Float::is_nan(self) } - - /// Returns `true` if this value is positive infinity or negative infinity and - /// false otherwise. - /// - /// ``` - /// use std::f32; - /// - /// let f = 7.0f32; - /// let inf = f32::INFINITY; - /// let neg_inf = f32::NEG_INFINITY; - /// let nan = f32::NAN; - /// - /// assert!(!f.is_infinite()); - /// assert!(!nan.is_infinite()); - /// - /// assert!(inf.is_infinite()); - /// assert!(neg_inf.is_infinite()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_infinite(self) -> bool { num::Float::is_infinite(self) } - - /// Returns `true` if this number is neither infinite nor `NaN`. - /// - /// ``` - /// use std::f32; - /// - /// let f = 7.0f32; - /// let inf = f32::INFINITY; - /// let neg_inf = f32::NEG_INFINITY; - /// let nan = f32::NAN; - /// - /// assert!(f.is_finite()); - /// - /// assert!(!nan.is_finite()); - /// assert!(!inf.is_finite()); - /// assert!(!neg_inf.is_finite()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_finite(self) -> bool { num::Float::is_finite(self) } - - /// Returns `true` if the number is neither zero, infinite, - /// [subnormal][subnormal], or `NaN`. - /// - /// ``` - /// use std::f32; - /// - /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 - /// let max = f32::MAX; - /// let lower_than_min = 1.0e-40_f32; - /// let zero = 0.0_f32; - /// - /// assert!(min.is_normal()); - /// assert!(max.is_normal()); - /// - /// assert!(!zero.is_normal()); - /// assert!(!f32::NAN.is_normal()); - /// assert!(!f32::INFINITY.is_normal()); - /// // Values between `0` and `min` are Subnormal. - /// assert!(!lower_than_min.is_normal()); - /// ``` - /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_normal(self) -> bool { num::Float::is_normal(self) } - - /// Returns the floating point category of the number. If only one property - /// is going to be tested, it is generally faster to use the specific - /// predicate instead. - /// - /// ``` - /// use std::num::FpCategory; - /// use std::f32; - /// - /// let num = 12.4_f32; - /// let inf = f32::INFINITY; - /// - /// assert_eq!(num.classify(), FpCategory::Normal); - /// assert_eq!(inf.classify(), FpCategory::Infinite); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn classify(self) -> FpCategory { num::Float::classify(self) } + #[cfg(stage0)] + f32_core_methods!(); /// Returns the largest integer less than or equal to a number. /// @@ -257,7 +163,7 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn abs(self) -> f32 { num::Float::abs(self) } + pub fn abs(self) -> f32 { Float::abs(self) } /// Returns a number that represents the sign of `self`. /// @@ -277,35 +183,7 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn signum(self) -> f32 { num::Float::signum(self) } - - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with - /// positive sign bit and positive infinity. - /// - /// ``` - /// let f = 7.0_f32; - /// let g = -7.0_f32; - /// - /// assert!(f.is_sign_positive()); - /// assert!(!g.is_sign_positive()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) } - - /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with - /// negative sign bit and negative infinity. - /// - /// ``` - /// let f = 7.0f32; - /// let g = -7.0f32; - /// - /// assert!(!f.is_sign_negative()); - /// assert!(g.is_sign_negative()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_sign_negative(self) -> bool { num::Float::is_sign_negative(self) } + pub fn signum(self) -> f32 { Float::signum(self) } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error. This produces a more accurate result with better performance than @@ -380,20 +258,6 @@ impl f32 { } - /// Takes the reciprocal (inverse) of a number, `1/x`. - /// - /// ``` - /// use std::f32; - /// - /// let x = 2.0_f32; - /// let abs_difference = (x.recip() - (1.0/x)).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn recip(self) -> f32 { num::Float::recip(self) } - /// Raises a number to an integer power. /// /// Using this function is generally faster than using `powf` @@ -408,7 +272,7 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn powi(self, n: i32) -> f32 { num::Float::powi(self, n) } + pub fn powi(self, n: i32) -> f32 { Float::powi(self, n) } /// Raises a number to a floating point power. /// @@ -584,68 +448,6 @@ impl f32 { return unsafe { intrinsics::log10f32(self) }; } - /// Converts radians to degrees. - /// - /// ``` - /// use std::f32::{self, consts}; - /// - /// let angle = consts::PI; - /// - /// let abs_difference = (angle.to_degrees() - 180.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] - #[inline] - pub fn to_degrees(self) -> f32 { num::Float::to_degrees(self) } - - /// Converts degrees to radians. - /// - /// ``` - /// use std::f32::{self, consts}; - /// - /// let angle = 180.0f32; - /// - /// let abs_difference = (angle.to_radians() - consts::PI).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] - #[inline] - pub fn to_radians(self) -> f32 { num::Float::to_radians(self) } - - /// Returns the maximum of the two numbers. - /// - /// ``` - /// let x = 1.0f32; - /// let y = 2.0f32; - /// - /// assert_eq!(x.max(y), y); - /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn max(self, other: f32) -> f32 { - num::Float::max(self, other) - } - - /// Returns the minimum of the two numbers. - /// - /// ``` - /// let x = 1.0f32; - /// let y = 2.0f32; - /// - /// assert_eq!(x.min(y), x); - /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn min(self, other: f32) -> f32 { - num::Float::min(self, other) - } - /// The positive difference of two numbers. /// /// * If `self <= other`: `0:0` @@ -1046,73 +848,6 @@ impl f32 { pub fn atanh(self) -> f32 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } - - /// Raw transmutation to `u32`. - /// - /// This is currently identical to `transmute::(self)` on all platforms. - /// - /// See `from_bits` for some discussion of the portability of this operation - /// (there are almost no issues). - /// - /// Note that this function is distinct from `as` casting, which attempts to - /// preserve the *numeric* value, and not the bitwise value. - /// - /// # Examples - /// - /// ``` - /// assert_ne!((1f32).to_bits(), 1f32 as u32); // to_bits() is not casting! - /// assert_eq!((12.5f32).to_bits(), 0x41480000); - /// - /// ``` - #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[inline] - pub fn to_bits(self) -> u32 { - num::Float::to_bits(self) - } - - /// Raw transmutation from `u32`. - /// - /// This is currently identical to `transmute::(v)` on all platforms. - /// It turns out this is incredibly portable, for two reasons: - /// - /// * Floats and Ints have the same endianness on all supported platforms. - /// * IEEE-754 very precisely specifies the bit layout of floats. - /// - /// However there is one caveat: prior to the 2008 version of IEEE-754, how - /// to interpret the NaN signaling bit wasn't actually specified. Most platforms - /// (notably x86 and ARM) picked the interpretation that was ultimately - /// standardized in 2008, but some didn't (notably MIPS). As a result, all - /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. - /// - /// Rather than trying to preserve signaling-ness cross-platform, this - /// implementation favours preserving the exact bits. This means that - /// any payloads encoded in NaNs will be preserved even if the result of - /// this method is sent over the network from an x86 machine to a MIPS one. - /// - /// If the results of this method are only manipulated by the same - /// architecture that produced them, then there is no portability concern. - /// - /// If the input isn't NaN, then there is no portability concern. - /// - /// If you don't care about signalingness (very likely), then there is no - /// portability concern. - /// - /// Note that this function is distinct from `as` casting, which attempts to - /// preserve the *numeric* value, and not the bitwise value. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// let v = f32::from_bits(0x41480000); - /// let difference = (v - 12.5).abs(); - /// assert!(difference <= 1e-5); - /// ``` - #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[inline] - pub fn from_bits(v: u32) -> Self { - num::Float::from_bits(v) - } } #[cfg(test)] diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index a9585670ad0..d4a8f700a90 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -19,10 +19,11 @@ #![allow(missing_docs)] #[cfg(not(test))] -use core::num; +use core::num::Float; #[cfg(not(test))] use intrinsics; #[cfg(not(test))] +#[cfg(stage0)] use num::FpCategory; #[cfg(not(test))] use sys::cmath; @@ -39,106 +40,11 @@ pub use core::f64::{MIN, MIN_POSITIVE, MAX}; pub use core::f64::consts; #[cfg(not(test))] -#[lang = "f64"] +#[cfg_attr(stage0, lang = "f64")] +#[cfg_attr(not(stage0), lang = "f64_runtime")] impl f64 { - /// Returns `true` if this value is `NaN` and false otherwise. - /// - /// ``` - /// use std::f64; - /// - /// let nan = f64::NAN; - /// let f = 7.0_f64; - /// - /// assert!(nan.is_nan()); - /// assert!(!f.is_nan()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_nan(self) -> bool { num::Float::is_nan(self) } - - /// Returns `true` if this value is positive infinity or negative infinity and - /// false otherwise. - /// - /// ``` - /// use std::f64; - /// - /// let f = 7.0f64; - /// let inf = f64::INFINITY; - /// let neg_inf = f64::NEG_INFINITY; - /// let nan = f64::NAN; - /// - /// assert!(!f.is_infinite()); - /// assert!(!nan.is_infinite()); - /// - /// assert!(inf.is_infinite()); - /// assert!(neg_inf.is_infinite()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_infinite(self) -> bool { num::Float::is_infinite(self) } - - /// Returns `true` if this number is neither infinite nor `NaN`. - /// - /// ``` - /// use std::f64; - /// - /// let f = 7.0f64; - /// let inf: f64 = f64::INFINITY; - /// let neg_inf: f64 = f64::NEG_INFINITY; - /// let nan: f64 = f64::NAN; - /// - /// assert!(f.is_finite()); - /// - /// assert!(!nan.is_finite()); - /// assert!(!inf.is_finite()); - /// assert!(!neg_inf.is_finite()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_finite(self) -> bool { num::Float::is_finite(self) } - - /// Returns `true` if the number is neither zero, infinite, - /// [subnormal][subnormal], or `NaN`. - /// - /// ``` - /// use std::f64; - /// - /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64 - /// let max = f64::MAX; - /// let lower_than_min = 1.0e-308_f64; - /// let zero = 0.0f64; - /// - /// assert!(min.is_normal()); - /// assert!(max.is_normal()); - /// - /// assert!(!zero.is_normal()); - /// assert!(!f64::NAN.is_normal()); - /// assert!(!f64::INFINITY.is_normal()); - /// // Values between `0` and `min` are Subnormal. - /// assert!(!lower_than_min.is_normal()); - /// ``` - /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_normal(self) -> bool { num::Float::is_normal(self) } - - /// Returns the floating point category of the number. If only one property - /// is going to be tested, it is generally faster to use the specific - /// predicate instead. - /// - /// ``` - /// use std::num::FpCategory; - /// use std::f64; - /// - /// let num = 12.4_f64; - /// let inf = f64::INFINITY; - /// - /// assert_eq!(num.classify(), FpCategory::Normal); - /// assert_eq!(inf.classify(), FpCategory::Infinite); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn classify(self) -> FpCategory { num::Float::classify(self) } + #[cfg(stage0)] + f64_core_methods!(); /// Returns the largest integer less than or equal to a number. /// @@ -235,7 +141,7 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn abs(self) -> f64 { num::Float::abs(self) } + pub fn abs(self) -> f64 { Float::abs(self) } /// Returns a number that represents the sign of `self`. /// @@ -255,45 +161,7 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn signum(self) -> f64 { num::Float::signum(self) } - - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with - /// positive sign bit and positive infinity. - /// - /// ``` - /// let f = 7.0_f64; - /// let g = -7.0_f64; - /// - /// assert!(f.is_sign_positive()); - /// assert!(!g.is_sign_positive()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) } - - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")] - #[inline] - pub fn is_positive(self) -> bool { num::Float::is_sign_positive(self) } - - /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with - /// negative sign bit and negative infinity. - /// - /// ``` - /// let f = 7.0_f64; - /// let g = -7.0_f64; - /// - /// assert!(!f.is_sign_negative()); - /// assert!(g.is_sign_negative()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_sign_negative(self) -> bool { num::Float::is_sign_negative(self) } - - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")] - #[inline] - pub fn is_negative(self) -> bool { num::Float::is_sign_negative(self) } + pub fn signum(self) -> f64 { Float::signum(self) } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error. This produces a more accurate result with better performance than @@ -365,18 +233,6 @@ impl f64 { } } - /// Takes the reciprocal (inverse) of a number, `1/x`. - /// - /// ``` - /// let x = 2.0_f64; - /// let abs_difference = (x.recip() - (1.0/x)).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn recip(self) -> f64 { num::Float::recip(self) } - /// Raises a number to an integer power. /// /// Using this function is generally faster than using `powf` @@ -389,7 +245,7 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn powi(self, n: i32) -> f64 { num::Float::powi(self, n) } + pub fn powi(self, n: i32) -> f64 { Float::powi(self, n) } /// Raises a number to a floating point power. /// @@ -535,68 +391,6 @@ impl f64 { self.log_wrapper(|n| { unsafe { intrinsics::log10f64(n) } }) } - /// Converts radians to degrees. - /// - /// ``` - /// use std::f64::consts; - /// - /// let angle = consts::PI; - /// - /// let abs_difference = (angle.to_degrees() - 180.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_degrees(self) -> f64 { num::Float::to_degrees(self) } - - /// Converts degrees to radians. - /// - /// ``` - /// use std::f64::consts; - /// - /// let angle = 180.0_f64; - /// - /// let abs_difference = (angle.to_radians() - consts::PI).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_radians(self) -> f64 { num::Float::to_radians(self) } - - /// Returns the maximum of the two numbers. - /// - /// ``` - /// let x = 1.0_f64; - /// let y = 2.0_f64; - /// - /// assert_eq!(x.max(y), y); - /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn max(self, other: f64) -> f64 { - num::Float::max(self, other) - } - - /// Returns the minimum of the two numbers. - /// - /// ``` - /// let x = 1.0_f64; - /// let y = 2.0_f64; - /// - /// assert_eq!(x.min(y), x); - /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn min(self, other: f64) -> f64 { - num::Float::min(self, other) - } - /// The positive difference of two numbers. /// /// * If `self <= other`: `0:0` @@ -1000,73 +794,6 @@ impl f64 { } } } - - /// Raw transmutation to `u64`. - /// - /// This is currently identical to `transmute::(self)` on all platforms. - /// - /// See `from_bits` for some discussion of the portability of this operation - /// (there are almost no issues). - /// - /// Note that this function is distinct from `as` casting, which attempts to - /// preserve the *numeric* value, and not the bitwise value. - /// - /// # Examples - /// - /// ``` - /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting! - /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000); - /// - /// ``` - #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[inline] - pub fn to_bits(self) -> u64 { - num::Float::to_bits(self) - } - - /// Raw transmutation from `u64`. - /// - /// This is currently identical to `transmute::(v)` on all platforms. - /// It turns out this is incredibly portable, for two reasons: - /// - /// * Floats and Ints have the same endianness on all supported platforms. - /// * IEEE-754 very precisely specifies the bit layout of floats. - /// - /// However there is one caveat: prior to the 2008 version of IEEE-754, how - /// to interpret the NaN signaling bit wasn't actually specified. Most platforms - /// (notably x86 and ARM) picked the interpretation that was ultimately - /// standardized in 2008, but some didn't (notably MIPS). As a result, all - /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. - /// - /// Rather than trying to preserve signaling-ness cross-platform, this - /// implementation favours preserving the exact bits. This means that - /// any payloads encoded in NaNs will be preserved even if the result of - /// this method is sent over the network from an x86 machine to a MIPS one. - /// - /// If the results of this method are only manipulated by the same - /// architecture that produced them, then there is no portability concern. - /// - /// If the input isn't NaN, then there is no portability concern. - /// - /// If you don't care about signalingness (very likely), then there is no - /// portability concern. - /// - /// Note that this function is distinct from `as` casting, which attempts to - /// preserve the *numeric* value, and not the bitwise value. - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// let v = f64::from_bits(0x4029000000000000); - /// let difference = (v - 12.5).abs(); - /// assert!(difference <= 1e-5); - /// ``` - #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[inline] - pub fn from_bits(v: u64) -> Self { - num::Float::from_bits(v) - } } #[cfg(test)] -- cgit 1.4.1-3-g733a5 From 18ab16b5104403ef7a55a2d241c566e35c5ae57a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 10 Apr 2018 16:36:23 +0200 Subject: Move intrinsics-based float methods out of libcore into libstd Affected methods are `abs`, `signum`, and `powi`. CC https://github.com/rust-lang/rust/issues/32110#issuecomment-379503183 --- src/libcore/num/f32.rs | 27 ---------------------- src/libcore/num/f64.rs | 27 ---------------------- src/libcore/num/mod.rs | 18 --------------- src/librustc_typeck/diagnostics.rs | 10 ++++---- src/libstd/f32.rs | 17 +++++++++++--- src/libstd/f64.rs | 17 +++++++++++--- .../ui/macros/macro-backtrace-invalid-internals.rs | 4 ++-- .../macro-backtrace-invalid-internals.stderr | 16 ++++++------- .../method-on-ambiguous-numeric-type.rs | 8 +++---- .../method-on-ambiguous-numeric-type.stderr | 14 +++++------ 10 files changed, 54 insertions(+), 104 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 0edf63bce12..8d5f6f601da 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -17,7 +17,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use intrinsics; use mem; use num::Float; #[cfg(not(stage0))] use num::FpCategory; @@ -189,27 +188,6 @@ impl Float for f32 { } } - /// Computes the absolute value of `self`. Returns `Float::nan()` if the - /// number is `Float::nan()`. - #[inline] - fn abs(self) -> f32 { - unsafe { intrinsics::fabsf32(self) } - } - - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()` - /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()` - /// - `Float::nan()` if the number is `Float::nan()` - #[inline] - fn signum(self) -> f32 { - if self.is_nan() { - NAN - } else { - unsafe { intrinsics::copysignf32(1.0, self) } - } - } - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with /// positive sign bit and positive infinity. #[inline] @@ -232,11 +210,6 @@ impl Float for f32 { 1.0 / self } - #[inline] - fn powi(self, n: i32) -> f32 { - unsafe { intrinsics::powif32(self, n) } - } - /// Converts to degrees, assuming the number is in radians. #[inline] fn to_degrees(self) -> f32 { diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 38f3d63ea8d..08b869734d4 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -17,7 +17,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use intrinsics; use mem; use num::Float; #[cfg(not(stage0))] use num::FpCategory; @@ -189,27 +188,6 @@ impl Float for f64 { } } - /// Computes the absolute value of `self`. Returns `Float::nan()` if the - /// number is `Float::nan()`. - #[inline] - fn abs(self) -> f64 { - unsafe { intrinsics::fabsf64(self) } - } - - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()` - /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()` - /// - `Float::nan()` if the number is `Float::nan()` - #[inline] - fn signum(self) -> f64 { - if self.is_nan() { - NAN - } else { - unsafe { intrinsics::copysignf64(1.0, self) } - } - } - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with /// positive sign bit and positive infinity. #[inline] @@ -230,11 +208,6 @@ impl Float for f64 { 1.0 / self } - #[inline] - fn powi(self, n: i32) -> f64 { - unsafe { intrinsics::powif64(self, n) } - } - /// Converts to degrees, assuming the number is in radians. #[inline] fn to_degrees(self) -> f64 { diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index f2e8caaad14..55fad62d871 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4125,18 +4125,6 @@ pub trait Float: Sized { #[stable(feature = "core", since = "1.6.0")] fn classify(self) -> FpCategory; - /// Computes the absolute value of `self`. Returns `Float::nan()` if the - /// number is `Float::nan()`. - #[stable(feature = "core", since = "1.6.0")] - fn abs(self) -> Self; - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()` - /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()` - /// - `Float::nan()` if the number is `Float::nan()` - #[stable(feature = "core", since = "1.6.0")] - fn signum(self) -> Self; - /// Returns `true` if `self` is positive, including `+0.0` and /// `Float::infinity()`. #[stable(feature = "core", since = "1.6.0")] @@ -4150,12 +4138,6 @@ pub trait Float: Sized { #[stable(feature = "core", since = "1.6.0")] fn recip(self) -> Self; - /// Raise a number to an integer power. - /// - /// Using this function is generally faster than using `powf` - #[stable(feature = "core", since = "1.6.0")] - fn powi(self, n: i32) -> Self; - /// Convert radians to degrees. #[stable(feature = "deg_rad_conversions", since="1.7.0")] fn to_degrees(self) -> Self; diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index ae3b2b22ea1..e3f7ff5cb3f 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4526,23 +4526,23 @@ but the type of the numeric value or binding could not be identified. The error happens on numeric literals: ```compile_fail,E0689 -2.0.powi(2); +2.0.recip(); ``` and on numeric bindings without an identified concrete type: ```compile_fail,E0689 let x = 2.0; -x.powi(2); // same error as above +x.recip(); // same error as above ``` Because of this, you must give the numeric literal or binding a type: ``` -let _ = 2.0_f32.powi(2); +let _ = 2.0_f32.recip(); let x: f32 = 2.0; -let _ = x.powi(2); -let _ = (2.0 as f32).powi(2); +let _ = x.recip(); +let _ = (2.0 as f32).recip(); ``` "##, diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 82f4192de19..26644c76957 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -19,6 +19,7 @@ #![allow(missing_docs)] #[cfg(not(test))] +#[cfg(stage0)] use core::num::Float; #[cfg(not(test))] use intrinsics; @@ -163,7 +164,9 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn abs(self) -> f32 { Float::abs(self) } + pub fn abs(self) -> f32 { + unsafe { intrinsics::fabsf32(self) } + } /// Returns a number that represents the sign of `self`. /// @@ -183,7 +186,13 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn signum(self) -> f32 { Float::signum(self) } + pub fn signum(self) -> f32 { + if self.is_nan() { + NAN + } else { + unsafe { intrinsics::copysignf32(1.0, self) } + } + } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error. This produces a more accurate result with better performance than @@ -272,7 +281,9 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn powi(self, n: i32) -> f32 { Float::powi(self, n) } + pub fn powi(self, n: i32) -> f32 { + unsafe { intrinsics::powif32(self, n) } + } /// Raises a number to a floating point power. /// diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index d4a8f700a90..a7e63f59b1c 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -19,6 +19,7 @@ #![allow(missing_docs)] #[cfg(not(test))] +#[cfg(stage0)] use core::num::Float; #[cfg(not(test))] use intrinsics; @@ -141,7 +142,9 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn abs(self) -> f64 { Float::abs(self) } + pub fn abs(self) -> f64 { + unsafe { intrinsics::fabsf64(self) } + } /// Returns a number that represents the sign of `self`. /// @@ -161,7 +164,13 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn signum(self) -> f64 { Float::signum(self) } + pub fn signum(self) -> f64 { + if self.is_nan() { + NAN + } else { + unsafe { intrinsics::copysignf64(1.0, self) } + } + } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error. This produces a more accurate result with better performance than @@ -245,7 +254,9 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn powi(self, n: i32) -> f64 { Float::powi(self, n) } + pub fn powi(self, n: i32) -> f64 { + unsafe { intrinsics::powif64(self, n) } + } /// Raises a number to a floating point power. /// diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.rs b/src/test/ui/macros/macro-backtrace-invalid-internals.rs index bff64ad4892..090ff817eb0 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.rs +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.rs @@ -48,13 +48,13 @@ macro_rules! fake_anon_field_expr { macro_rules! real_method_stmt { () => { - 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` + 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` } } macro_rules! real_method_expr { () => { - 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` + 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` } } diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr index cb7d422b7f3..284960d2f6e 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr @@ -25,17 +25,17 @@ LL | (1).0 //~ ERROR doesn't have fields LL | fake_anon_field_stmt!(); | ------------------------ in this macro invocation -error[E0689]: can't call method `powi` on ambiguous numeric type `{float}` +error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` --> $DIR/macro-backtrace-invalid-internals.rs:51:15 | -LL | 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` - | ^^^^ +LL | 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` + | ^^^^^ ... LL | real_method_stmt!(); | -------------------- in this macro invocation help: you must specify a concrete type for this numeric value, like `f32` | -LL | 2.0_f32.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` +LL | 2.0_f32.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` | ^^^^^^^ error[E0599]: no method named `fake` found for type `{integer}` in the current scope @@ -65,17 +65,17 @@ LL | (1).0 //~ ERROR doesn't have fields LL | let _ = fake_anon_field_expr!(); | ----------------------- in this macro invocation -error[E0689]: can't call method `powi` on ambiguous numeric type `{float}` +error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` --> $DIR/macro-backtrace-invalid-internals.rs:57:15 | -LL | 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` - | ^^^^ +LL | 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` + | ^^^^^ ... LL | let _ = real_method_expr!(); | ------------------- in this macro invocation help: you must specify a concrete type for this numeric value, like `f32` | -LL | 2.0_f32.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` +LL | 2.0_f32.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` | ^^^^^^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs index fa5bafab871..2e452f9671f 100644 --- a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs +++ b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs @@ -9,10 +9,10 @@ // except according to those terms. fn main() { - let x = 2.0.powi(2); - //~^ ERROR can't call method `powi` on ambiguous numeric type `{float}` + let x = 2.0.recip(); + //~^ ERROR can't call method `recip` on ambiguous numeric type `{float}` let y = 2.0; - let x = y.powi(2); - //~^ ERROR can't call method `powi` on ambiguous numeric type `{float}` + let x = y.recip(); + //~^ ERROR can't call method `recip` on ambiguous numeric type `{float}` println!("{:?}", x); } diff --git a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr index 92ad2280615..477b4c3821d 100644 --- a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr +++ b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr @@ -1,18 +1,18 @@ -error[E0689]: can't call method `powi` on ambiguous numeric type `{float}` +error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` --> $DIR/method-on-ambiguous-numeric-type.rs:12:17 | -LL | let x = 2.0.powi(2); - | ^^^^ +LL | let x = 2.0.recip(); + | ^^^^^ help: you must specify a concrete type for this numeric value, like `f32` | -LL | let x = 2.0_f32.powi(2); +LL | let x = 2.0_f32.recip(); | ^^^^^^^ -error[E0689]: can't call method `powi` on ambiguous numeric type `{float}` +error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` --> $DIR/method-on-ambiguous-numeric-type.rs:15:15 | -LL | let x = y.powi(2); - | ^^^^ +LL | let x = y.recip(); + | ^^^^^ help: you must specify a type for this binding, like `f32` | LL | let y: f32 = 2.0; -- cgit 1.4.1-3-g733a5 From 70fdd1b5c0f6a0673fcf924b3d8880af034bdee0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 12 Apr 2018 08:36:31 +0200 Subject: Make the unstable StrExt and SliceExt traits private to libcore in not(stage0) `Float` still needs to be public for libcore unit tests. --- src/liballoc/lib.rs | 2 +- src/libcore/internal_macros.rs | 13 +++++++++ src/libcore/num/mod.rs | 31 +++++++++------------- src/libcore/slice/mod.rs | 7 +++-- src/libcore/str/mod.rs | 8 +++--- src/libcore/tests/lib.rs | 1 + src/libstd/lib.rs | 3 ++- .../method-suggestion-no-duplication.stderr | 4 +-- 8 files changed, 40 insertions(+), 29 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 702d7b70cd3..6399be98cd5 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -75,7 +75,7 @@ #![deny(missing_debug_implementations)] #![cfg_attr(test, allow(deprecated))] // rand -#![cfg_attr(not(test), feature(core_float))] +#![cfg_attr(all(not(test), stage0), feature(float_internals))] #![cfg_attr(not(test), feature(exact_size_is_empty))] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(rand, test))] diff --git a/src/libcore/internal_macros.rs b/src/libcore/internal_macros.rs index cb215a38e53..58eef649287 100644 --- a/src/libcore/internal_macros.rs +++ b/src/libcore/internal_macros.rs @@ -87,3 +87,16 @@ macro_rules! forward_ref_op_assign { } } +#[cfg(stage0)] +macro_rules! public_in_stage0 { + ( { $(#[$attr:meta])* } $($Item: tt)*) => { + $(#[$attr])* pub $($Item)* + } +} + +#[cfg(not(stage0))] +macro_rules! public_in_stage0 { + ( { $(#[$attr:meta])* } $($Item: tt)*) => { + $(#[$attr])* pub(crate) $($Item)* + } +} diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 55fad62d871..70c704267d2 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4098,65 +4098,58 @@ pub enum FpCategory { Normal, } -/// A built-in floating point number. +// Technically private and only exposed for coretests: #[doc(hidden)] -#[unstable(feature = "core_float", - reason = "stable interface is via `impl f{32,64}` in later crates", - issue = "32110")] +#[unstable(feature = "float_internals", + reason = "internal routines only exposed for testing", + issue = "0")] pub trait Float: Sized { /// Type used by `to_bits` and `from_bits`. - #[stable(feature = "core_float_bits", since = "1.25.0")] type Bits; /// Returns `true` if this value is NaN and false otherwise. - #[stable(feature = "core", since = "1.6.0")] fn is_nan(self) -> bool; + /// Returns `true` if this value is positive infinity or negative infinity and /// false otherwise. - #[stable(feature = "core", since = "1.6.0")] fn is_infinite(self) -> bool; + /// Returns `true` if this number is neither infinite nor NaN. - #[stable(feature = "core", since = "1.6.0")] fn is_finite(self) -> bool; + /// Returns `true` if this number is neither zero, infinite, denormal, or NaN. - #[stable(feature = "core", since = "1.6.0")] fn is_normal(self) -> bool; + /// Returns the category that this number falls into. - #[stable(feature = "core", since = "1.6.0")] fn classify(self) -> FpCategory; /// Returns `true` if `self` is positive, including `+0.0` and /// `Float::infinity()`. - #[stable(feature = "core", since = "1.6.0")] fn is_sign_positive(self) -> bool; + /// Returns `true` if `self` is negative, including `-0.0` and /// `Float::neg_infinity()`. - #[stable(feature = "core", since = "1.6.0")] fn is_sign_negative(self) -> bool; /// Take the reciprocal (inverse) of a number, `1/x`. - #[stable(feature = "core", since = "1.6.0")] fn recip(self) -> Self; /// Convert radians to degrees. - #[stable(feature = "deg_rad_conversions", since="1.7.0")] fn to_degrees(self) -> Self; + /// Convert degrees to radians. - #[stable(feature = "deg_rad_conversions", since="1.7.0")] fn to_radians(self) -> Self; /// Returns the maximum of the two numbers. - #[stable(feature = "core_float_min_max", since="1.20.0")] fn max(self, other: Self) -> Self; + /// Returns the minimum of the two numbers. - #[stable(feature = "core_float_min_max", since="1.20.0")] fn min(self, other: Self) -> Self; /// Raw transmutation to integer. - #[stable(feature = "core_float_bits", since="1.25.0")] fn to_bits(self) -> Self::Bits; + /// Raw transmutation from integer. - #[stable(feature = "core_float_bits", since="1.25.0")] fn from_bits(v: Self::Bits) -> Self; } diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 0a260c663c2..cc42acd77ae 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -68,12 +68,15 @@ struct Repr { // Extension traits // +public_in_stage0! { +{ /// Extension methods for slices. #[unstable(feature = "core_slice_ext", reason = "stable interface provided by `impl [T]` in later crates", issue = "32110")] #[allow(missing_docs)] // documented elsewhere -pub trait SliceExt { +} +trait SliceExt { type Item; #[stable(feature = "core", since = "1.6.0")] @@ -238,7 +241,7 @@ pub trait SliceExt { fn sort_unstable_by_key(&mut self, f: F) where F: FnMut(&Self::Item) -> B, B: Ord; -} +}} // Use macros to be generic over const/mut macro_rules! slice_offset { diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index d33eaace79d..a76de79107b 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2117,14 +2117,16 @@ mod traits { } - +public_in_stage0! { +{ /// Methods for string slices #[allow(missing_docs)] #[doc(hidden)] #[unstable(feature = "core_str_ext", reason = "stable interface provided by `impl str` in later crates", issue = "32110")] -pub trait StrExt { +} +trait StrExt { // NB there are no docs here are they're all located on the StrExt trait in // liballoc, not here. @@ -2224,7 +2226,7 @@ pub trait StrExt { fn trim_left(&self) -> &str; #[stable(feature = "rust1", since = "1.0.0")] fn trim_right(&self) -> &str; -} +}} // truncate `&str` to length at most equal to `max` // return `true` if it were truncated, and the new str. diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index bb875c7219a..2cc2ac289bf 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -17,6 +17,7 @@ #![feature(decode_utf8)] #![feature(exact_size_is_empty)] #![feature(fixed_size_array)] +#![feature(float_internals)] #![feature(flt2dec)] #![feature(fmt_internals)] #![feature(hashmap_internals)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 7d896695311..3b98abb9293 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -252,7 +252,7 @@ #![feature(collections_range)] #![feature(compiler_builtins_lib)] #![feature(const_fn)] -#![feature(core_float)] +#![cfg_attr(stage0, feature(core_float))] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] @@ -260,6 +260,7 @@ #![feature(fs_read_write)] #![feature(fixed_size_array)] #![feature(float_from_str_radix)] +#![cfg_attr(stage0, feature(float_internals))] #![feature(fn_traits)] #![feature(fnbox)] #![cfg_attr(stage0, feature(generic_param_attrs))] diff --git a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr index 438d29f0535..f7aaab4242c 100644 --- a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr +++ b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr @@ -8,10 +8,8 @@ LL | foo(|s| s.is_empty()); | ^^^^^^^^ | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following traits define an item `is_empty`, perhaps you need to implement one of them: + = note: the following trait defines an item `is_empty`, perhaps you need to implement it: candidate #1: `std::iter::ExactSizeIterator` - candidate #2: `core::slice::SliceExt` - candidate #3: `core::str::StrExt` error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 84b91d6f5c7a49159f46f9bec37b57bd7e0a61be Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 19 Apr 2018 19:56:10 +0200 Subject: add more aliases --- src/libcore/lib.rs | 1 + src/libcore/macros.rs | 1 + src/libcore/ops/arith.rs | 16 ++++++++++++++++ src/libcore/ops/index.rs | 6 ++++++ src/libcore/ops/try.rs | 1 + src/libstd/primitive_docs.rs | 7 +++++++ 6 files changed, 32 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index ea7a46f44ae..2f3a7ebbe77 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -98,6 +98,7 @@ #![feature(unboxed_closures)] #![feature(untagged_unions)] #![feature(unwind_attributes)] +#![feature(doc_alias)] #![cfg_attr(not(stage0), feature(mmx_target_feature))] #![cfg_attr(not(stage0), feature(tbm_target_feature))] diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 90a9cb3379b..346d404fa8c 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -295,6 +295,7 @@ macro_rules! debug_assert_ne { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = "?")] macro_rules! try { ($expr:expr) => (match $expr { $crate::result::Result::Ok(val) => val, diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs index 88db019b02f..a1f6030428f 100644 --- a/src/libcore/ops/arith.rs +++ b/src/libcore/ops/arith.rs @@ -87,6 +87,7 @@ message="cannot add `{RHS}` to `{Self}`", label="no implementation for `{Self} + {RHS}`", )] +#[doc(alias = "+")] pub trait Add { /// The resulting type after applying the `+` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -183,6 +184,7 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="cannot subtract `{RHS}` from `{Self}`", label="no implementation for `{Self} - {RHS}`")] +#[doc(alias = "-")] pub trait Sub { /// The resulting type after applying the `-` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -301,6 +303,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="cannot multiply `{RHS}` to `{Self}`", label="no implementation for `{Self} * {RHS}`")] +#[doc(alias = "*")] pub trait Mul { /// The resulting type after applying the `*` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -423,6 +426,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="cannot divide `{Self}` by `{RHS}`", label="no implementation for `{Self} / {RHS}`")] +#[doc(alias = "/")] pub trait Div { /// The resulting type after applying the `/` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -506,6 +510,7 @@ div_impl_float! { f32 f64 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="cannot mod `{Self}` by `{RHS}`", label="no implementation for `{Self} % {RHS}`")] +#[doc(alias = "%")] pub trait Rem { /// The resulting type after applying the `%` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -589,6 +594,7 @@ rem_impl_float! { f32 f64 } /// ``` #[lang = "neg"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = "-")] pub trait Neg { /// The resulting type after applying the `-` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -664,6 +670,8 @@ neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="cannot add-assign `{Rhs}` to `{Self}`", label="no implementation for `{Self} += {Rhs}`")] +#[doc(alias = "+")] +#[doc(alias = "+=")] pub trait AddAssign { /// Performs the `+=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -718,6 +726,8 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="cannot subtract-assign `{Rhs}` from `{Self}`", label="no implementation for `{Self} -= {Rhs}`")] +#[doc(alias = "-")] +#[doc(alias = "-=")] pub trait SubAssign { /// Performs the `-=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -763,6 +773,8 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="cannot multiply-assign `{Rhs}` to `{Self}`", label="no implementation for `{Self} *= {Rhs}`")] +#[doc(alias = "*")] +#[doc(alias = "*=")] pub trait MulAssign { /// Performs the `*=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -808,6 +820,8 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="cannot divide-assign `{Self}` by `{Rhs}`", label="no implementation for `{Self} /= {Rhs}`")] +#[doc(alias = "/")] +#[doc(alias = "/=")] pub trait DivAssign { /// Performs the `/=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -856,6 +870,8 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="cannot mod-assign `{Self}` by `{Rhs}``", label="no implementation for `{Self} %= {Rhs}`")] +#[doc(alias = "%")] +#[doc(alias = "%=")] pub trait RemAssign { /// Performs the `%=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] diff --git a/src/libcore/ops/index.rs b/src/libcore/ops/index.rs index d65c0aba504..0a0e92a9180 100644 --- a/src/libcore/ops/index.rs +++ b/src/libcore/ops/index.rs @@ -62,6 +62,9 @@ #[lang = "index"] #[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = "]")] +#[doc(alias = "[")] +#[doc(alias = "[]")] pub trait Index { /// The returned type after indexing. #[stable(feature = "rust1", since = "1.0.0")] @@ -146,6 +149,9 @@ pub trait Index { #[lang = "index_mut"] #[rustc_on_unimplemented = "the type `{Self}` cannot be mutably indexed by `{Idx}`"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = "[")] +#[doc(alias = "]")] +#[doc(alias = "[]")] pub trait IndexMut: Index { /// Performs the mutable indexing (`container[index]`) operation. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs index ef6a8fb6a61..4f2d30aa6a8 100644 --- a/src/libcore/ops/try.rs +++ b/src/libcore/ops/try.rs @@ -28,6 +28,7 @@ that implement `{Try}`", label="the `?` operator cannot be applied to type `{Self}`") )] +#[doc(alias = "?")] pub trait Try { /// The type of this value when viewed as successful. #[unstable(feature = "try_trait", issue = "42327")] diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index e2fcfb7c4b1..8248ee71474 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -502,6 +502,9 @@ mod prim_pointer { } mod prim_array { } #[doc(primitive = "slice")] +#[doc(alias = "[")] +#[doc(alias = "]")] +#[doc(alias = "[]")] // /// A dynamically-sized view into a contiguous sequence, `[T]`. /// @@ -600,6 +603,9 @@ mod prim_slice { } mod prim_str { } #[doc(primitive = "tuple")] +#[doc(alias = "(")] +#[doc(alias = ")")] +#[doc(alias = "()")] // /// A finite heterogeneous sequence, `(T, U, ..)`. /// @@ -822,6 +828,7 @@ mod prim_isize { } mod prim_usize { } #[doc(primitive = "reference")] +#[doc(alias = "&")] // /// References, both shared and mutable. /// -- cgit 1.4.1-3-g733a5 From 2843e648c236c0ed31f0155f0805f43f3ee7ed95 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 21 Apr 2018 23:22:27 +0200 Subject: turn `ManuallyDrop::new` into a constant function --- src/libcore/mem.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index e3f08926610..6d64d91312e 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -960,7 +960,7 @@ impl ManuallyDrop { /// ``` #[stable(feature = "manually_drop", since = "1.20.0")] #[inline] - pub fn new(value: T) -> ManuallyDrop { + pub const fn new(value: T) -> ManuallyDrop { ManuallyDrop { value: value } } -- cgit 1.4.1-3-g733a5 From e513c1bd314bbeb6295a7a759de8833b52ff854d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 20 Apr 2018 21:05:13 -0700 Subject: Replace GlobalAlloc::oom with a lang item --- src/liballoc/alloc.rs | 35 ++++++++++++++++---------------- src/liballoc/arc.rs | 4 ++-- src/liballoc/rc.rs | 4 ++-- src/liballoc_jemalloc/lib.rs | 5 ++--- src/liballoc_system/lib.rs | 2 +- src/libcore/alloc.rs | 11 ---------- src/librustc/middle/lang_items.rs | 3 ++- src/librustc/middle/weak_lang_items.rs | 1 + src/librustc_allocator/lib.rs | 5 ----- src/libstd/alloc.rs | 13 ++++++++++-- src/libstd/collections/hash/map.rs | 4 ++-- src/libstd/collections/hash/table.rs | 6 +++--- src/libstd/lib.rs | 3 ++- src/test/run-pass/allocator-alloc-one.rs | 6 ++---- src/test/run-pass/realloc-16687.rs | 6 +++--- src/test/run-pass/regions-mock-trans.rs | 4 ++-- 16 files changed, 53 insertions(+), 59 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 68a617e0ffe..a9c06523718 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -48,9 +48,6 @@ extern "Rust" { #[allocator] #[rustc_allocator_nounwind] fn __rust_alloc(size: usize, align: usize) -> *mut u8; - #[cold] - #[rustc_allocator_nounwind] - fn __rust_oom() -> !; #[rustc_allocator_nounwind] fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); #[rustc_allocator_nounwind] @@ -107,16 +104,6 @@ unsafe impl GlobalAlloc for Global { let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), &mut 0); ptr as *mut Opaque } - - #[inline] - fn oom(&self) -> ! { - unsafe { - #[cfg(not(stage0))] - __rust_oom(); - #[cfg(stage0)] - __rust_oom(&mut 0); - } - } } unsafe impl Alloc for Global { @@ -147,7 +134,7 @@ unsafe impl Alloc for Global { #[inline] fn oom(&mut self) -> ! { - GlobalAlloc::oom(self) + oom() } } @@ -165,7 +152,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { if !ptr.is_null() { ptr as *mut u8 } else { - Global.oom() + oom() } } } @@ -182,19 +169,33 @@ pub(crate) unsafe fn box_free(ptr: *mut T) { } } +#[cfg(stage0)] +pub fn oom() -> ! { + unsafe { ::core::intrinsics::abort() } +} + +#[cfg(not(stage0))] +pub fn oom() -> ! { + extern { + #[lang = "oom"] + fn oom_impl() -> !; + } + unsafe { oom_impl() } +} + #[cfg(test)] mod tests { extern crate test; use self::test::Bencher; use boxed::Box; - use alloc::{Global, Alloc, Layout}; + use alloc::{Global, Alloc, Layout, oom}; #[test] fn allocate_zeroed() { unsafe { let layout = Layout::from_size_align(1024, 1).unwrap(); let ptr = Global.alloc_zeroed(layout.clone()) - .unwrap_or_else(|_| Global.oom()); + .unwrap_or_else(|_| oom()); let mut i = ptr.cast::().as_ptr(); let end = i.offset(layout.size() as isize); diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 225b055d8ee..f5980f4599e 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -31,7 +31,7 @@ use core::hash::{Hash, Hasher}; use core::{isize, usize}; use core::convert::From; -use alloc::{Global, Alloc, Layout, box_free}; +use alloc::{Global, Alloc, Layout, box_free, oom}; use boxed::Box; use string::String; use vec::Vec; @@ -553,7 +553,7 @@ impl Arc { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|_| Global.oom()); + .unwrap_or_else(|_| oom()); // Initialize the real ArcInner let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner; diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index de0422d82bb..8fb8e111754 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -259,7 +259,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, NonNull}; use core::convert::From; -use alloc::{Global, Alloc, Layout, Opaque, box_free}; +use alloc::{Global, Alloc, Layout, Opaque, box_free, oom}; use string::String; use vec::Vec; @@ -668,7 +668,7 @@ impl Rc { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|_| Global.oom()); + .unwrap_or_else(|_| oom()); // Initialize the real RcBox let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut RcBox; diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 2b66c293f21..8b118a2cabb 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -30,8 +30,6 @@ extern crate libc; pub use contents::*; #[cfg(not(dummy_jemalloc))] mod contents { - use core::alloc::GlobalAlloc; - use alloc_system::System; use libc::{c_int, c_void, size_t}; // Note that the symbols here are prefixed by default on macOS and Windows (we @@ -100,10 +98,11 @@ mod contents { ptr } + #[cfg(stage0)] #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rde_oom() -> ! { - System.oom() + ::alloc_system::oom() } #[no_mangle] diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index fd8109e2a4a..aff98ae2f10 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -368,7 +368,7 @@ mod platform { } #[inline] -fn oom() -> ! { +pub fn oom() -> ! { write_to_stderr("fatal runtime error: memory allocation failed"); unsafe { ::core::intrinsics::abort(); diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 54440eaa40f..7d893676a6c 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -451,17 +451,6 @@ pub unsafe trait GlobalAlloc { } new_ptr } - - /// Aborts the thread or process, optionally performing - /// cleanup or logging diagnostic information before panicking or - /// aborting. - /// - /// `oom` is meant to be used by clients unable to cope with an - /// unsatisfied allocation request, and wish to abandon - /// computation rather than attempt to recover locally. - fn oom(&self) -> ! { - unsafe { ::intrinsics::abort() } - } } /// An implementation of `Alloc` can allocate, reallocate, and diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index c7412dbeeb3..95e92e21b09 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -303,7 +303,8 @@ language_item_table! { ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn; BoxFreeFnLangItem, "box_free", box_free_fn; - DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn; + DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn; + OomLangItem, "oom", oom; StartFnLangItem, "start", start_fn; diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index e19f4483f65..a2bceb19102 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -151,4 +151,5 @@ weak_lang_items! { panic_fmt, PanicFmtLangItem, rust_begin_unwind; eh_personality, EhPersonalityLangItem, rust_eh_personality; eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume; + oom, OomLangItem, rust_oom; } diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index 706eab72d44..f3103e21606 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -23,11 +23,6 @@ pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ inputs: &[AllocatorTy::Layout], output: AllocatorTy::ResultPtr, }, - AllocatorMethod { - name: "oom", - inputs: &[], - output: AllocatorTy::Bang, - }, AllocatorMethod { name: "dealloc", inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout], diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index ff578ec42d2..a8578404467 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -13,10 +13,18 @@ #![unstable(issue = "32838", feature = "allocator_api")] #[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap; -#[doc(inline)] pub use alloc_crate::alloc::Global; +#[doc(inline)] pub use alloc_crate::alloc::{Global, oom}; #[doc(inline)] pub use alloc_system::System; #[doc(inline)] pub use core::alloc::*; +#[cfg(not(stage0))] +#[cfg(not(test))] +#[doc(hidden)] +#[lang = "oom"] +pub extern fn rust_oom() -> ! { + rtabort!("memory allocation failed"); +} + #[cfg(not(test))] #[doc(hidden)] #[allow(unused_attributes)] @@ -35,10 +43,11 @@ pub mod __default_lib_allocator { System.alloc(layout) as *mut u8 } + #[cfg(stage0)] #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_oom() -> ! { - System.oom() + super::oom() } #[no_mangle] diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 4fe5c11beb4..a8c70489f44 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -11,7 +11,7 @@ use self::Entry::*; use self::VacantEntryState::*; -use alloc::{Global, Alloc, CollectionAllocErr}; +use alloc::{CollectionAllocErr, oom}; use cell::Cell; use borrow::Borrow; use cmp::max; @@ -784,7 +784,7 @@ impl HashMap pub fn reserve(&mut self, additional: usize) { match self.try_reserve(additional) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => Global.oom(), + Err(CollectionAllocErr::AllocErr) => oom(), Ok(()) => { /* yay */ } } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 115f9628a23..52c53dc3b12 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::{Global, Alloc, Layout, CollectionAllocErr}; +use alloc::{Global, Alloc, Layout, CollectionAllocErr, oom}; use cmp; use hash::{BuildHasher, Hash, Hasher}; use marker; @@ -770,7 +770,7 @@ impl RawTable { unsafe fn new_uninitialized(capacity: usize) -> RawTable { match Self::try_new_uninitialized(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => Global.oom(), + Err(CollectionAllocErr::AllocErr) => oom(), Ok(table) => { table } } } @@ -809,7 +809,7 @@ impl RawTable { pub fn new(capacity: usize) -> RawTable { match Self::try_new(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => Global.oom(), + Err(CollectionAllocErr::AllocErr) => oom(), Ok(table) => { table } } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 43a8d4446fa..1df7bc777d1 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -482,7 +482,6 @@ pub mod path; pub mod process; pub mod sync; pub mod time; -pub mod alloc; #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] @@ -496,6 +495,8 @@ pub mod heap { mod sys_common; mod sys; +pub mod alloc; + // Private support modules mod panicking; mod memchr; diff --git a/src/test/run-pass/allocator-alloc-one.rs b/src/test/run-pass/allocator-alloc-one.rs index d4fcdcf743b..12b115d0938 100644 --- a/src/test/run-pass/allocator-alloc-one.rs +++ b/src/test/run-pass/allocator-alloc-one.rs @@ -10,13 +10,11 @@ #![feature(allocator_api, nonnull)] -use std::alloc::{Alloc, Global}; +use std::alloc::{Alloc, Global, oom}; fn main() { unsafe { - let ptr = Global.alloc_one::().unwrap_or_else(|_| { - Global.oom() - }); + let ptr = Global.alloc_one::().unwrap_or_else(|_| oom()); *ptr.as_ptr() = 4; assert_eq!(*ptr.as_ptr(), 4); Global.dealloc_one(ptr); diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index afa3494c389..308792e5d89 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -15,7 +15,7 @@ #![feature(heap_api, allocator_api)] -use std::alloc::{Global, Alloc, Layout}; +use std::alloc::{Global, Alloc, Layout, oom}; use std::ptr::{self, NonNull}; fn main() { @@ -50,7 +50,7 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?})", layout); } - let ret = Global.alloc(layout.clone()).unwrap_or_else(|_| Global.oom()); + let ret = Global.alloc(layout.clone()).unwrap_or_else(|_| oom()); if PRINT { println!("allocate({:?}) = {:?}", layout, ret); @@ -73,7 +73,7 @@ unsafe fn test_triangle() -> bool { } let ret = Global.realloc(NonNull::new_unchecked(ptr).as_opaque(), old.clone(), new.size()) - .unwrap_or_else(|_| Global.oom()); + .unwrap_or_else(|_| oom()); if PRINT { println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", diff --git a/src/test/run-pass/regions-mock-trans.rs b/src/test/run-pass/regions-mock-trans.rs index 44be59f5c5b..60a7f70931d 100644 --- a/src/test/run-pass/regions-mock-trans.rs +++ b/src/test/run-pass/regions-mock-trans.rs @@ -12,7 +12,7 @@ #![feature(allocator_api)] -use std::alloc::{Alloc, Global, Layout}; +use std::alloc::{Alloc, Global, Layout, oom}; use std::ptr::NonNull; struct arena(()); @@ -33,7 +33,7 @@ struct Ccx { fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> { unsafe { let ptr = Global.alloc(Layout::new::()) - .unwrap_or_else(|_| Global.oom()); + .unwrap_or_else(|_| oom()); &*(ptr.as_ptr() as *const _) } } -- cgit 1.4.1-3-g733a5 From 9e8f683476d5a9d72c6c1e9383a519cf0fb27494 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 21 Apr 2018 09:47:41 -0700 Subject: Remove Alloc::oom --- src/Cargo.lock | 1 - src/liballoc/alloc.rs | 5 -- src/liballoc/heap.rs | 2 +- src/liballoc/raw_vec.rs | 14 ++--- src/liballoc_jemalloc/Cargo.toml | 1 - src/liballoc_jemalloc/lib.rs | 5 +- src/liballoc_system/lib.rs | 70 ---------------------- src/libcore/alloc.rs | 26 -------- .../compile-fail/allocator/not-an-allocator.rs | 1 - 9 files changed, 10 insertions(+), 115 deletions(-) (limited to 'src/libcore') diff --git a/src/Cargo.lock b/src/Cargo.lock index d7d23f0fa80..6f054dc61a5 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -19,7 +19,6 @@ dependencies = [ name = "alloc_jemalloc" version = "0.0.0" dependencies = [ - "alloc_system 0.0.0", "build_helper 0.1.0", "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index a9c06523718..c0372d24ed5 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -131,11 +131,6 @@ unsafe impl Alloc for Global { unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) } - - #[inline] - fn oom(&mut self) -> ! { - oom() - } } /// The allocator for unique pointers. diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index faac38ca7ce..16f0630b911 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -59,7 +59,7 @@ unsafe impl Alloc for T where T: CoreAlloc { } fn oom(&mut self, _: AllocErr) -> ! { - CoreAlloc::oom(self) + unsafe { ::core::intrinsics::abort() } } fn usable_size(&self, layout: &Layout) -> (usize, usize) { diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 24b7cd3db0c..7ef0a27fc72 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -14,7 +14,7 @@ use core::ops::Drop; use core::ptr::{self, NonNull, Unique}; use core::slice; -use alloc::{Alloc, Layout, Global}; +use alloc::{Alloc, Layout, Global, oom}; use alloc::CollectionAllocErr; use alloc::CollectionAllocErr::*; use boxed::Box; @@ -101,7 +101,7 @@ impl RawVec { }; match result { Ok(ptr) => ptr, - Err(_) => a.oom(), + Err(_) => oom(), } }; @@ -316,7 +316,7 @@ impl RawVec { new_size); match ptr_res { Ok(ptr) => (new_cap, ptr.cast().into()), - Err(_) => self.a.oom(), + Err(_) => oom(), } } None => { @@ -325,7 +325,7 @@ impl RawVec { let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; match self.a.alloc_array::(new_cap) { Ok(ptr) => (new_cap, ptr.into()), - Err(_) => self.a.oom(), + Err(_) => oom(), } } }; @@ -442,7 +442,7 @@ impl RawVec { pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) { match self.try_reserve_exact(used_cap, needed_extra_cap) { Err(CapacityOverflow) => capacity_overflow(), - Err(AllocErr) => self.a.oom(), + Err(AllocErr) => oom(), Ok(()) => { /* yay */ } } } @@ -552,7 +552,7 @@ impl RawVec { pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) { match self.try_reserve(used_cap, needed_extra_cap) { Err(CapacityOverflow) => capacity_overflow(), - Err(AllocErr) => self.a.oom(), + Err(AllocErr) => oom(), Ok(()) => { /* yay */ } } } @@ -667,7 +667,7 @@ impl RawVec { old_layout, new_size) { Ok(p) => self.ptr = p.cast().into(), - Err(_) => self.a.oom(), + Err(_) => oom(), } } self.cap = amount; diff --git a/src/liballoc_jemalloc/Cargo.toml b/src/liballoc_jemalloc/Cargo.toml index 02435170374..7986d5dd2eb 100644 --- a/src/liballoc_jemalloc/Cargo.toml +++ b/src/liballoc_jemalloc/Cargo.toml @@ -12,7 +12,6 @@ test = false doc = false [dependencies] -alloc_system = { path = "../liballoc_system" } core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 8b118a2cabb..4b8755877de 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -14,7 +14,7 @@ reason = "this library is unlikely to be stabilized in its current \ form or name", issue = "27783")] -#![feature(alloc_system)] +#![feature(core_intrinsics)] #![feature(libc)] #![feature(linkage)] #![feature(staged_api)] @@ -23,7 +23,6 @@ #![cfg_attr(not(dummy_jemalloc), feature(allocator_api))] #![rustc_alloc_kind = "exe"] -extern crate alloc_system; extern crate libc; #[cfg(not(dummy_jemalloc))] @@ -102,7 +101,7 @@ mod contents { #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rde_oom() -> ! { - ::alloc_system::oom() + ::core::intrinsics::abort(); } #[no_mangle] diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index aff98ae2f10..7376ac0f15d 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -71,11 +71,6 @@ unsafe impl Alloc for System { new_size: usize) -> Result, AllocErr> { NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } - - #[inline] - fn oom(&mut self) -> ! { - ::oom() - } } #[cfg(stage0)] @@ -103,11 +98,6 @@ unsafe impl<'a> Alloc for &'a System { new_size: usize) -> Result, AllocErr> { NonNull::new(GlobalAlloc::realloc(*self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } - - #[inline] - fn oom(&mut self) -> ! { - ::oom() - } } #[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))] @@ -366,63 +356,3 @@ mod platform { } } } - -#[inline] -pub fn oom() -> ! { - write_to_stderr("fatal runtime error: memory allocation failed"); - unsafe { - ::core::intrinsics::abort(); - } -} - -#[cfg(any(unix, target_os = "redox"))] -#[inline] -fn write_to_stderr(s: &str) { - extern crate libc; - - unsafe { - libc::write(libc::STDERR_FILENO, - s.as_ptr() as *const libc::c_void, - s.len()); - } -} - -#[cfg(windows)] -#[inline] -fn write_to_stderr(s: &str) { - use core::ptr; - - type LPVOID = *mut u8; - type HANDLE = LPVOID; - type DWORD = u32; - type BOOL = i32; - type LPDWORD = *mut DWORD; - type LPOVERLAPPED = *mut u8; - - const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD; - - extern "system" { - fn WriteFile(hFile: HANDLE, - lpBuffer: LPVOID, - nNumberOfBytesToWrite: DWORD, - lpNumberOfBytesWritten: LPDWORD, - lpOverlapped: LPOVERLAPPED) - -> BOOL; - fn GetStdHandle(which: DWORD) -> HANDLE; - } - - unsafe { - // WriteFile silently fails if it is passed an invalid - // handle, so there is no need to check the result of - // GetStdHandle. - WriteFile(GetStdHandle(STD_ERROR_HANDLE), - s.as_ptr() as LPVOID, - s.len() as DWORD, - ptr::null_mut(), - ptr::null_mut()); - } -} - -#[cfg(not(any(windows, unix, target_os = "redox")))] -#[inline] -fn write_to_stderr(_: &str) {} diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 7d893676a6c..674c4fb57c7 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -603,32 +603,6 @@ pub unsafe trait Alloc { /// to allocate that block of memory. unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); - /// Allocator-specific method for signaling an out-of-memory - /// condition. - /// - /// `oom` aborts the thread or process, optionally performing - /// cleanup or logging diagnostic information before panicking or - /// aborting. - /// - /// `oom` is meant to be used by clients unable to cope with an - /// unsatisfied allocation request, and wish to abandon - /// computation rather than attempt to recover locally. - /// - /// Implementations of the `oom` method are discouraged from - /// infinitely regressing in nested calls to `oom`. In - /// practice this means implementors should eschew allocating, - /// especially from `self` (directly or indirectly). - /// - /// Implementations of the allocation and reallocation methods - /// (e.g. `alloc`, `alloc_one`, `realloc`) are discouraged from - /// panicking (or aborting) in the event of memory exhaustion; - /// instead they should return an appropriate error from the - /// invoked method, and let the client decide whether to invoke - /// this `oom` method in response. - fn oom(&mut self) -> ! { - unsafe { ::intrinsics::abort() } - } - // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS == // usable_size diff --git a/src/test/compile-fail/allocator/not-an-allocator.rs b/src/test/compile-fail/allocator/not-an-allocator.rs index 1479d0b6264..140cad22f34 100644 --- a/src/test/compile-fail/allocator/not-an-allocator.rs +++ b/src/test/compile-fail/allocator/not-an-allocator.rs @@ -16,6 +16,5 @@ static A: usize = 0; //~| the trait bound `usize: //~| the trait bound `usize: //~| the trait bound `usize: -//~| the trait bound `usize: fn main() {} -- cgit 1.4.1-3-g733a5 From 43baa2c0419709c13f7764212596f94d9900ba36 Mon Sep 17 00:00:00 2001 From: Jonathan Behrens Date: Sun, 22 Apr 2018 15:39:28 -0400 Subject: Add as_nanos function to duration --- src/libcore/time.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/time.rs b/src/libcore/time.rs index e22fe450bb1..8ebdbbd8370 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -263,6 +263,22 @@ impl Duration { #[inline] pub fn subsec_nanos(&self) -> u32 { self.nanos } + /// Returns the total number of nanoseconds contained by this `Duration`. + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// + /// let duration = Duration::new(5, 730023852); + /// assert_eq!(duration.as_nanos(), 5730023852); + /// ``` + #[unstable(feature = "duration_nanos", issue = "0")] + #[inline] + pub fn as_nanos(&self) -> u128 { + self.secs as u128 * 1000_000_000 + self.nanos as u128 + } + /// Checked `Duration` addition. Computes `self + other`, returning [`None`] /// if overflow occurred. /// -- cgit 1.4.1-3-g733a5 From 57b2067b115ad062cd75232e5c824cb8bbd34478 Mon Sep 17 00:00:00 2001 From: Jonathan Behrens Date: Sun, 22 Apr 2018 15:43:52 -0400 Subject: Use NANOS_PER_SEC constant --- src/libcore/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 8ebdbbd8370..807a152a2aa 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -276,7 +276,7 @@ impl Duration { #[unstable(feature = "duration_nanos", issue = "0")] #[inline] pub fn as_nanos(&self) -> u128 { - self.secs as u128 * 1000_000_000 + self.nanos as u128 + self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos as u128 } /// Checked `Duration` addition. Computes `self + other`, returning [`None`] -- cgit 1.4.1-3-g733a5 From dc9e27d7488bcd28b7cc8ecf6c5ae349752faaf0 Mon Sep 17 00:00:00 2001 From: Jonathan Behrens Date: Sun, 22 Apr 2018 15:52:32 -0400 Subject: Add issue number --- src/libcore/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 807a152a2aa..4c9c3b30b51 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -273,7 +273,7 @@ impl Duration { /// let duration = Duration::new(5, 730023852); /// assert_eq!(duration.as_nanos(), 5730023852); /// ``` - #[unstable(feature = "duration_nanos", issue = "0")] + #[unstable(feature = "duration_nanos", issue = "50167")] #[inline] pub fn as_nanos(&self) -> u128 { self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos as u128 -- cgit 1.4.1-3-g733a5 From b66ab1ad61b887cde9370b83149d4ec7789729fb Mon Sep 17 00:00:00 2001 From: Jonathan Behrens Date: Sun, 22 Apr 2018 17:19:35 -0400 Subject: Doctest of feature requires that feature --- src/libcore/time.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libcore') diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 4c9c3b30b51..b2971e391cd 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -268,6 +268,7 @@ impl Duration { /// # Examples /// /// ``` + /// # #![feature(duration_nanos)] /// use std::time::Duration; /// /// let duration = Duration::new(5, 730023852); -- cgit 1.4.1-3-g733a5 From 91aa267eda21be36d7cae43b6809eba63f1aac4c Mon Sep 17 00:00:00 2001 From: Aaron Aaeng Date: Sat, 21 Apr 2018 16:06:48 -0600 Subject: Make must_use lint cover all binary/unary operators --- src/libcore/ops/arith.rs | 6 ++ src/libcore/ops/bit.rs | 6 ++ src/libcore/ops/deref.rs | 1 + src/librustc_lint/unused.rs | 42 +++++++---- src/test/ui/lint/must-use-ops.rs | 52 ++++++++++++++ src/test/ui/lint/must-use-ops.stderr | 132 +++++++++++++++++++++++++++++++++++ 6 files changed, 224 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/lint/must-use-ops.rs create mode 100644 src/test/ui/lint/must-use-ops.stderr (limited to 'src/libcore') diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs index 88db019b02f..8fd06e7bb4b 100644 --- a/src/libcore/ops/arith.rs +++ b/src/libcore/ops/arith.rs @@ -93,6 +93,7 @@ pub trait Add { type Output; /// Performs the `+` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn add(self, rhs: RHS) -> Self::Output; } @@ -189,6 +190,7 @@ pub trait Sub { type Output; /// Performs the `-` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn sub(self, rhs: RHS) -> Self::Output; } @@ -307,6 +309,7 @@ pub trait Mul { type Output; /// Performs the `*` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn mul(self, rhs: RHS) -> Self::Output; } @@ -429,6 +432,7 @@ pub trait Div { type Output; /// Performs the `/` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn div(self, rhs: RHS) -> Self::Output; } @@ -512,6 +516,7 @@ pub trait Rem { type Output = Self; /// Performs the `%` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn rem(self, rhs: RHS) -> Self::Output; } @@ -595,6 +600,7 @@ pub trait Neg { type Output; /// Performs the unary `-` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn neg(self) -> Self::Output; } diff --git a/src/libcore/ops/bit.rs b/src/libcore/ops/bit.rs index 81c4455cef4..9bde02abe64 100644 --- a/src/libcore/ops/bit.rs +++ b/src/libcore/ops/bit.rs @@ -46,6 +46,7 @@ pub trait Not { type Output; /// Performs the unary `!` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn not(self) -> Self::Output; } @@ -128,6 +129,7 @@ pub trait BitAnd { type Output; /// Performs the `&` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitand(self, rhs: RHS) -> Self::Output; } @@ -210,6 +212,7 @@ pub trait BitOr { type Output; /// Performs the `|` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitor(self, rhs: RHS) -> Self::Output; } @@ -295,6 +298,7 @@ pub trait BitXor { type Output; /// Performs the `^` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitxor(self, rhs: RHS) -> Self::Output; } @@ -381,6 +385,7 @@ pub trait Shl { type Output; /// Performs the `<<` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn shl(self, rhs: RHS) -> Self::Output; } @@ -488,6 +493,7 @@ pub trait Shr { type Output; /// Performs the `>>` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn shr(self, rhs: RHS) -> Self::Output; } diff --git a/src/libcore/ops/deref.rs b/src/libcore/ops/deref.rs index 4ce0740130b..3903e85768c 100644 --- a/src/libcore/ops/deref.rs +++ b/src/libcore/ops/deref.rs @@ -75,6 +75,7 @@ pub trait Deref { type Target: ?Sized; /// Dereferences the value. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn deref(&self) -> &Self::Target; } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index bf86f6a6952..5ec8305de78 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -91,23 +91,35 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { let def_id = def.def_id(); fn_warned = check_must_use(cx, def_id, s.span, "return value of "); } - - if let hir::ExprBinary(bin_op, ..) = expr.node { - match bin_op.node { - // Hardcoding the comparison operators here seemed more - // expedient than the refactoring that would be needed to - // look up the `#[must_use]` attribute which does exist on - // the comparison trait methods - hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => { - let msg = "unused comparison which must be used"; - cx.span_lint(UNUSED_MUST_USE, expr.span, msg); - op_warned = true; - }, - _ => {}, - } + let must_use_op = match expr.node { + // Hardcoding operators here seemed more expedient than the + // refactoring that would be needed to look up the `#[must_use]` + // attribute which does exist on the comparison trait methods + hir::ExprBinary(bin_op, ..) => { + match bin_op.node { + hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => { + Some("comparison") + }, + hir::BiAdd | hir::BiSub | hir::BiDiv | hir::BiMul | hir::BiRem => { + Some("arithmetic operation") + }, + hir::BiAnd | hir::BiOr => { + Some("logical operation") + }, + hir::BiBitXor | hir::BiBitAnd | hir::BiBitOr | hir::BiShl | hir::BiShr => { + Some("bitwise operation") + }, + } + }, + hir::ExprUnary(..) => Some("unary operation"), + _ => None + }; + if let Some(must_use_op) = must_use_op { + cx.span_lint(UNUSED_MUST_USE, expr.span, + &format!("unused {} which must be used", must_use_op)); + op_warned = true; } } - if !(ty_warned || fn_warned || op_warned) { cx.span_lint(UNUSED_RESULTS, s.span, "unused result"); } diff --git a/src/test/ui/lint/must-use-ops.rs b/src/test/ui/lint/must-use-ops.rs new file mode 100644 index 00000000000..4ed82ab3b40 --- /dev/null +++ b/src/test/ui/lint/must-use-ops.rs @@ -0,0 +1,52 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Issue #50124 - Test warning for unused operator expressions + +// compile-pass + +#![feature(fn_must_use)] +#![warn(unused_must_use)] + +fn main() { + let val = 1; + let val_pointer = &val; + +// Comparison Operators + val == 1; + val < 1; + val <= 1; + val != 1; + val >= 1; + val > 1; + +// Arithmetic Operators + val + 2; + val - 2; + val / 2; + val * 2; + val % 2; + +// Logical Operators + true && true; + false || true; + +// Bitwise Operators + 5 ^ val; + 5 & val; + 5 | val; + 5 << val; + 5 >> val; + +// Unary Operators + !val; + -val; + *val_pointer; +} diff --git a/src/test/ui/lint/must-use-ops.stderr b/src/test/ui/lint/must-use-ops.stderr new file mode 100644 index 00000000000..f444ef09075 --- /dev/null +++ b/src/test/ui/lint/must-use-ops.stderr @@ -0,0 +1,132 @@ +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:23:5 + | +LL | val == 1; + | ^^^^^^^^ + | +note: lint level defined here + --> $DIR/must-use-ops.rs:16:9 + | +LL | #![warn(unused_must_use)] + | ^^^^^^^^^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:24:5 + | +LL | val < 1; + | ^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:25:5 + | +LL | val <= 1; + | ^^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:26:5 + | +LL | val != 1; + | ^^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:27:5 + | +LL | val >= 1; + | ^^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:28:5 + | +LL | val > 1; + | ^^^^^^^ + +warning: unused arithmetic operation which must be used + --> $DIR/must-use-ops.rs:31:5 + | +LL | val + 2; + | ^^^^^^^ + +warning: unused arithmetic operation which must be used + --> $DIR/must-use-ops.rs:32:5 + | +LL | val - 2; + | ^^^^^^^ + +warning: unused arithmetic operation which must be used + --> $DIR/must-use-ops.rs:33:5 + | +LL | val / 2; + | ^^^^^^^ + +warning: unused arithmetic operation which must be used + --> $DIR/must-use-ops.rs:34:5 + | +LL | val * 2; + | ^^^^^^^ + +warning: unused arithmetic operation which must be used + --> $DIR/must-use-ops.rs:35:5 + | +LL | val % 2; + | ^^^^^^^ + +warning: unused logical operation which must be used + --> $DIR/must-use-ops.rs:38:5 + | +LL | true && true; + | ^^^^^^^^^^^^ + +warning: unused logical operation which must be used + --> $DIR/must-use-ops.rs:39:5 + | +LL | false || true; + | ^^^^^^^^^^^^^ + +warning: unused bitwise operation which must be used + --> $DIR/must-use-ops.rs:42:5 + | +LL | 5 ^ val; + | ^^^^^^^ + +warning: unused bitwise operation which must be used + --> $DIR/must-use-ops.rs:43:5 + | +LL | 5 & val; + | ^^^^^^^ + +warning: unused bitwise operation which must be used + --> $DIR/must-use-ops.rs:44:5 + | +LL | 5 | val; + | ^^^^^^^ + +warning: unused bitwise operation which must be used + --> $DIR/must-use-ops.rs:45:5 + | +LL | 5 << val; + | ^^^^^^^^ + +warning: unused bitwise operation which must be used + --> $DIR/must-use-ops.rs:46:5 + | +LL | 5 >> val; + | ^^^^^^^^ + +warning: unused unary operation which must be used + --> $DIR/must-use-ops.rs:49:5 + | +LL | !val; + | ^^^^ + +warning: unused unary operation which must be used + --> $DIR/must-use-ops.rs:50:5 + | +LL | -val; + | ^^^^ + +warning: unused unary operation which must be used + --> $DIR/must-use-ops.rs:51:5 + | +LL | *val_pointer; + | ^^^^^^^^^^^^ + -- cgit 1.4.1-3-g733a5 From fbb1c280bf5f3d4fc68f323860ade8fa48d96979 Mon Sep 17 00:00:00 2001 From: Daiki Mizukami Date: Tue, 24 Apr 2018 01:45:44 +0900 Subject: core: Fix overflow in `int::mod_euc` when `self < 0 && rhs == MIN` --- src/libcore/num/mod.rs | 6 +++++- src/libcore/tests/lib.rs | 1 + src/libcore/tests/num/int_macros.rs | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index aa4d4bc638b..4893e05badc 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1765,7 +1765,11 @@ assert_eq!((-a).mod_euc(-b), 1); pub fn mod_euc(self, rhs: Self) -> Self { let r = self % rhs; if r < 0 { - r + rhs.abs() + if rhs.is_negative() { + r - rhs + } else { + r + rhs + } } else { r } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 7d3852d2f2a..ccf647c358d 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -15,6 +15,7 @@ #![feature(core_private_diy_float)] #![feature(dec2flt)] #![feature(decode_utf8)] +#![feature(euclidean_division)] #![feature(exact_size_is_empty)] #![feature(fixed_size_array)] #![feature(float_internals)] diff --git a/src/libcore/tests/num/int_macros.rs b/src/libcore/tests/num/int_macros.rs index 8d791283ab8..71d2e794538 100644 --- a/src/libcore/tests/num/int_macros.rs +++ b/src/libcore/tests/num/int_macros.rs @@ -30,6 +30,11 @@ mod tests { num::test_num(10 as $T, 2 as $T); } + #[test] + fn test_mod_euc() { + assert!((-1 as $T).mod_euc(MIN) == MAX); + } + #[test] pub fn test_abs() { assert!((1 as $T).abs() == 1 as $T); -- cgit 1.4.1-3-g733a5 From 1c0db245e0c87c2158f4a4456bf8e0a7aa14b677 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 23 Apr 2018 20:23:04 +0200 Subject: Clarify the docs for Cell::update --- src/libcore/cell.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index e4a52d9c4a4..64dbcbf7ae4 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -257,7 +257,7 @@ impl Cell { unsafe{ *self.value.get() } } - /// Applies a function to the contained value. + /// Updates the contained value using a function and returns the new value. /// /// # Examples /// @@ -267,8 +267,9 @@ impl Cell { /// use std::cell::Cell; /// /// let c = Cell::new(5); - /// c.update(|x| x + 1); + /// let new = c.update(|x| x + 1); /// + /// assert_eq!(new, 6); /// assert_eq!(c.get(), 6); /// ``` #[inline] -- cgit 1.4.1-3-g733a5 From 104c64dc360f297fbdd4a467dac1c5006d76dece Mon Sep 17 00:00:00 2001 From: Daiki Mizukami Date: Tue, 24 Apr 2018 03:32:40 +0900 Subject: core: Minor cleanup --- src/libcore/num/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 4893e05badc..a062fbda5ba 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1765,7 +1765,7 @@ assert_eq!((-a).mod_euc(-b), 1); pub fn mod_euc(self, rhs: Self) -> Self { let r = self % rhs; if r < 0 { - if rhs.is_negative() { + if rhs < 0 { r - rhs } else { r + rhs -- cgit 1.4.1-3-g733a5 From 29e9de85d6ae185d7d66c7ba0f2c418082d2df5f Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 23 Apr 2018 20:34:49 +0200 Subject: Assign the tracking issue --- src/libcore/cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 64dbcbf7ae4..1ff187ed3f1 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -273,7 +273,7 @@ impl Cell { /// assert_eq!(c.get(), 6); /// ``` #[inline] - #[unstable(feature = "cell_update", issue = "0")] // FIXME: issue + #[unstable(feature = "cell_update", issue = "50186")] pub fn update(&self, f: F) -> T where F: FnOnce(T) -> T, -- cgit 1.4.1-3-g733a5 From 799eda4128ad4517782de261a62d4284268de050 Mon Sep 17 00:00:00 2001 From: Jonathan Behrens Date: Tue, 24 Apr 2018 15:17:06 -0400 Subject: Issue number should be for tracking issue not PR --- src/libcore/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/time.rs b/src/libcore/time.rs index b2971e391cd..f49917f848a 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -274,7 +274,7 @@ impl Duration { /// let duration = Duration::new(5, 730023852); /// assert_eq!(duration.as_nanos(), 5730023852); /// ``` - #[unstable(feature = "duration_nanos", issue = "50167")] + #[unstable(feature = "duration_nanos", issue = "50202")] #[inline] pub fn as_nanos(&self) -> u128 { self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos as u128 -- cgit 1.4.1-3-g733a5 From 011df4ac88b5ef31443f2bde8eea29b917445099 Mon Sep 17 00:00:00 2001 From: z4v1er <38393857+z4v1er@users.noreply.github.com> Date: Wed, 25 Apr 2018 13:51:51 +0300 Subject: Fix type --- src/libcore/slice/mod.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index cc42acd77ae..83e8a6e4b68 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -880,7 +880,6 @@ macro_rules! slice_core_methods { () => { #[inline] pub fn split_last(&self) -> Option<(&T, &[T])> { SliceExt::split_last(self) - } /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. -- cgit 1.4.1-3-g733a5 From 256096da9ee680366b839f912e8d3ecccc0da033 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Wed, 25 Apr 2018 16:33:02 -0500 Subject: Make Vec::new const --- src/liballoc/raw_vec.rs | 16 ++++++++++++++++ src/liballoc/vec.rs | 2 +- src/libcore/ptr.rs | 5 ++--- src/test/run-pass/vec-const-new.rs | 15 +++++++++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 src/test/run-pass/vec-const-new.rs (limited to 'src/libcore') diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 7ef0a27fc72..dc8ad9ee061 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -68,6 +68,16 @@ impl RawVec { } } + /// Like `empty` but parametrized over the choice of allocator for the returned `RawVec`. + pub const fn empty_in(a: A) -> Self { + // Unique::empty() doubles as "unallocated" and "zero-sized allocation" + RawVec { + ptr: Unique::empty(), + cap: 0, + a, + } + } + /// Like `with_capacity` but parameterized over the choice of /// allocator for the returned RawVec. #[inline] @@ -124,6 +134,12 @@ impl RawVec { Self::new_in(Global) } + /// Create a `RawVec` with capcity 0 (on the system heap), regardless of `T`, without + /// allocating. + pub fn empty() -> Self { + Self::empty_in(Global) + } + /// Creates a RawVec (on the system heap) with exactly the /// capacity and alignment requirements for a `[T; cap]`. This is /// equivalent to calling RawVec::new when `cap` is 0 or T is diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index b184404c15b..757606607bb 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -324,7 +324,7 @@ impl Vec { #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> Vec { Vec { - buf: RawVec::new(), + buf: RawVec::empty(), len: 0, } } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 74bb264cc67..b612a278a34 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2551,10 +2551,9 @@ impl Unique { /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. // FIXME: rename to dangling() to match NonNull? - pub fn empty() -> Self { + pub const fn empty() -> Self { unsafe { - let ptr = mem::align_of::() as *mut T; - Unique::new_unchecked(ptr) + Unique::new_unchecked(mem::align_of::() as *mut T) } } } diff --git a/src/test/run-pass/vec-const-new.rs b/src/test/run-pass/vec-const-new.rs new file mode 100644 index 00000000000..02d8cfdcf98 --- /dev/null +++ b/src/test/run-pass/vec-const-new.rs @@ -0,0 +1,15 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that Vec::new() can be used for constants + +const MY_VEC: Vec = Vec::new(); + +pub fn main() {} -- cgit 1.4.1-3-g733a5 From 30e3f1a620b06b6edd697c55858ea9f251a4332a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 25 Apr 2018 20:10:58 +0200 Subject: Add more doc aliases --- src/libcore/cmp.rs | 12 ++++++++++++ src/libcore/fmt/mod.rs | 2 ++ src/libcore/ops/bit.rs | 10 ++++++++++ src/libcore/ops/deref.rs | 3 +++ src/libcore/ops/range.rs | 6 ++++++ 5 files changed, 33 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index c91aa06609d..13e838773a5 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -106,6 +106,8 @@ use self::Ordering::*; /// ``` #[lang = "eq"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = "==")] +#[doc(alias = "!=")] #[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialEq { /// This method tests for `self` and `other` values to be equal, and is used @@ -160,6 +162,8 @@ pub trait PartialEq { /// } /// impl Eq for Book {} /// ``` +#[doc(alias = "==")] +#[doc(alias = "!=")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Eq: PartialEq { // this method is used solely by #[deriving] to assert @@ -428,6 +432,10 @@ impl Ord for Reverse { /// } /// ``` #[lang = "ord"] +#[doc(alias = "<")] +#[doc(alias = ">")] +#[doc(alias = "<=")] +#[doc(alias = ">=")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Ord: Eq + PartialOrd { /// This method returns an `Ordering` between `self` and `other`. @@ -599,6 +607,10 @@ impl PartialOrd for Ordering { /// ``` #[lang = "partial_ord"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = ">")] +#[doc(alias = "<")] +#[doc(alias = "<=")] +#[doc(alias = ">=")] #[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialOrd: PartialEq { /// This method returns an ordering between `self` and `other` values if one exists. diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index a8430f14410..99e3012c9bf 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -547,6 +547,7 @@ impl<'a> Display for Arguments<'a> { message="`{Self}` doesn't implement `{Debug}`", label="`{Self}` cannot be formatted using `:?` because it doesn't implement `{Debug}`", )] +#[doc(alias = "{:?}")] #[lang = "debug_trait"] pub trait Debug { /// Formats the value using the given formatter. @@ -612,6 +613,7 @@ pub trait Debug { label="`{Self}` cannot be formatted with the default formatter; \ try using `:?` instead if you are using a format string", )] +#[doc(alias = "{}")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Display { /// Formats the value using the given formatter. diff --git a/src/libcore/ops/bit.rs b/src/libcore/ops/bit.rs index 81c4455cef4..02b6f62db6e 100644 --- a/src/libcore/ops/bit.rs +++ b/src/libcore/ops/bit.rs @@ -119,6 +119,7 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(bv1 & bv2, expected); /// ``` #[lang = "bitand"] +#[doc(alias = "&")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} & {RHS}`", label="no implementation for `{Self} & {RHS}`")] @@ -201,6 +202,7 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(bv1 | bv2, expected); /// ``` #[lang = "bitor"] +#[doc(alias = "|")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} | {RHS}`", label="no implementation for `{Self} | {RHS}`")] @@ -286,6 +288,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(bv1 ^ bv2, expected); /// ``` #[lang = "bitxor"] +#[doc(alias = "^")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} ^ {RHS}`", label="no implementation for `{Self} ^ {RHS}`")] @@ -372,6 +375,7 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// SpinVector { vec: vec![2, 3, 4, 0, 1] }); /// ``` #[lang = "shl"] +#[doc(alias = "<<")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} << {RHS}`", label="no implementation for `{Self} << {RHS}`")] @@ -479,6 +483,7 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// SpinVector { vec: vec![3, 4, 0, 1, 2] }); /// ``` #[lang = "shr"] +#[doc(alias = ">>")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} >> {RHS}`", label="no implementation for `{Self} >> {RHS}`")] @@ -593,6 +598,7 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// assert_eq!(bv, expected); /// ``` #[lang = "bitand_assign"] +#[doc(alias = "&=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} &= {Rhs}`", label="no implementation for `{Self} &= {Rhs}`")] @@ -641,6 +647,7 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(prefs, PersonalPreferences { likes_cats: true, likes_dogs: true }); /// ``` #[lang = "bitor_assign"] +#[doc(alias = "|=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} |= {Rhs}`", label="no implementation for `{Self} |= {Rhs}`")] @@ -689,6 +696,7 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(personality, Personality { has_soul: true, likes_knitting: false}); /// ``` #[lang = "bitxor_assign"] +#[doc(alias = "^=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} ^= {Rhs}`", label="no implementation for `{Self} ^= {Rhs}`")] @@ -735,6 +743,7 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(scalar, Scalar(16)); /// ``` #[lang = "shl_assign"] +#[doc(alias = "<<=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} <<= {Rhs}`", label="no implementation for `{Self} <<= {Rhs}`")] @@ -802,6 +811,7 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// assert_eq!(scalar, Scalar(4)); /// ``` #[lang = "shr_assign"] +#[doc(alias = ">>=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} >>= {Rhs}`", label="no implementation for `{Self} >>= {Rhs}`")] diff --git a/src/libcore/ops/deref.rs b/src/libcore/ops/deref.rs index 4ce0740130b..332d154170f 100644 --- a/src/libcore/ops/deref.rs +++ b/src/libcore/ops/deref.rs @@ -68,6 +68,8 @@ /// assert_eq!('a', *x); /// ``` #[lang = "deref"] +#[doc(alias = "*")] +#[doc(alias = "&*")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Deref { /// The resulting type after dereferencing. @@ -162,6 +164,7 @@ impl<'a, T: ?Sized> Deref for &'a mut T { /// assert_eq!('b', *x); /// ``` #[lang = "deref_mut"] +#[doc(alias = "*")] #[stable(feature = "rust1", since = "1.0.0")] pub trait DerefMut: Deref { /// Mutably dereferences the value. diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 6f3e3b50885..d70f7ae66f9 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -45,6 +45,7 @@ use fmt; /// [`IntoIterator`]: ../iter/trait.Iterator.html /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html +#[doc(alias = "..")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFull; @@ -74,6 +75,7 @@ impl fmt::Debug for RangeFull { /// assert_eq!(arr[1.. ], [ 'b', 'c', 'd']); /// assert_eq!(arr[1..3], [ 'b', 'c' ]); // Range /// ``` +#[doc(alias = "..")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] pub struct Range { @@ -175,6 +177,7 @@ impl> Range { /// ``` /// /// [`Iterator`]: ../iter/trait.IntoIterator.html +#[doc(alias = "..")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFrom { @@ -256,6 +259,7 @@ impl> RangeFrom { /// [`IntoIterator`]: ../iter/trait.Iterator.html /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html +#[doc(alias = "..")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeTo { @@ -323,6 +327,7 @@ impl> RangeTo { /// assert_eq!(arr[ ..=2], [0,1,2 ]); /// assert_eq!(arr[1..=2], [ 1,2 ]); // RangeInclusive /// ``` +#[doc(alias = "..=")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeInclusive { @@ -449,6 +454,7 @@ impl> RangeInclusive { /// [`IntoIterator`]: ../iter/trait.Iterator.html /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html +#[doc(alias = "..=")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeToInclusive { -- cgit 1.4.1-3-g733a5 From 4c2e3144a98f7a636fd6a33fce122121431ad9b4 Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Thu, 26 Apr 2018 16:29:22 -0700 Subject: added DerefOption and DerefResult + tests to std --- src/libcore/option.rs | 21 ++++++++++++++-- src/libcore/result.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++- src/libcore/tests/option.rs | 11 +++++++++ src/libcore/tests/result.rs | 21 ++++++++++++++++ 4 files changed, 109 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 0dfdabee031..c3ef619d739 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -146,7 +146,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use iter::{FromIterator, FusedIterator, TrustedLen}; -use {mem, ops}; +use {mem, ops::{self, Deref}}; // Note that this is not a lang item per se, but it has a hidden dependency on // `Iterator`, which is one. The compiler assumes that the `next` method of @@ -914,7 +914,6 @@ fn expect_failed(msg: &str) -> ! { panic!("{}", msg) } - ///////////////////////////////////////////////////////////////////////////// // Trait implementations ///////////////////////////////////////////////////////////////////////////// @@ -979,6 +978,24 @@ impl From for Option { } } +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +/// Extension trait to get a reference of an Option via the Deref trait. +pub trait OptionDeref { + /// Converts from `&Option` to `Option<&T::Target>`. + /// + /// Leaves the original Option in-place, creating a new one with a reference + /// to the original one, additionally coercing the contents via `Deref`. + fn deref(&self) -> Option<&T::Target>; +} + +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +impl OptionDeref for Option +{ + fn deref(&self) -> Option<&T::Target> { + self.as_ref().map(|t| t.deref()) + } +} + ///////////////////////////////////////////////////////////////////////////// // The Option Iterators ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/result.rs b/src/libcore/result.rs index c152d4979b9..9877a2001a0 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -242,7 +242,7 @@ use fmt; use iter::{FromIterator, FusedIterator, TrustedLen}; -use ops; +use ops::{self, Deref}; /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]). /// @@ -999,6 +999,63 @@ impl<'a, T, E> IntoIterator for &'a mut Result { } } +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +/// Extension trait to get a reference to a Result via the Deref trait. +pub trait ResultDeref { + /// Converts from `&Result` to `Result<&T::Target, &E>`. + /// + /// Leaves the original Result in-place, creating a new one with a reference + /// to the original one, additionally coercing the `Ok` arm of the Result via + /// `Deref`. + fn deref_ok(&self) -> Result<&T::Target, &E> + where + T: Deref; + + /// Converts from `&Result` to `Result<&T, &E::Target>`. + /// + /// Leaves the original Result in-place, creating a new one with a reference + /// to the original one, additionally coercing the `Err` arm of the Result via + /// `Deref`. + fn deref_err(&self) -> Result<&T, &E::Target> + where + E: Deref; + + /// Converts from `&Result` to `Result<&T::Target, &E::Target>`. + /// + /// Leaves the original Result in-place, creating a new one with a reference + /// to the original one, additionally coercing both the `Ok` and `Err` arms + /// of the Result via `Deref`. + fn deref(&self) -> Result<&T::Target, &E::Target> + where + T: Deref, + E: Deref; +} + +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +impl ResultDeref for Result { + fn deref_ok(&self) -> Result<&T::Target, &E> + where + T: Deref, + { + self.as_ref().map(|t| t.deref()) + } + + fn deref_err(&self) -> Result<&T, &E::Target> + where + E: Deref, + { + self.as_ref().map_err(|e| e.deref()) + } + + fn deref(&self) -> Result<&T::Target, &E::Target> + where + T: Deref, + E: Deref, + { + self.as_ref().map(|t| t.deref()).map_err(|e| e.deref()) + } +} + ///////////////////////////////////////////////////////////////////////////// // The Result Iterators ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs index 22109e28edd..77d550c532a 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -297,3 +297,14 @@ fn test_try() { } assert_eq!(try_option_err(), Err(NoneError)); } + +#[test] +fn test_option_deref() { + // Some: &Option::Some(T) -> Option<&T::Deref::Target>::Some(&*T) + let ref_option = &Some(&42); + assert_eq!(ref_option.deref(), Some(&42)); + + // None: &Option>::None -> None + let ref_option = &None; + assert_eq!(ref_option.deref(), None); +} diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs index ce41bde8342..dd23467322d 100644 --- a/src/libcore/tests/result.rs +++ b/src/libcore/tests/result.rs @@ -231,3 +231,24 @@ fn test_try() { } assert_eq!(try_result_err(), Err(1)); } + +#[test] +fn test_result_deref() { + // Ok(T).deref_ok() -> Result<&T, &E::Deref::Target>::Ok(&T) + let ref_ok: &Result<&i32, &u8> = &Ok(&42); + assert_eq!(ref_ok.deref_ok(), Ok(&42)); + assert_eq!(ref_ok.deref_ok(), Ok(&42)); + assert_eq!(ref_ok.deref(), Ok(&42)); + + // Err(E) -> Result<&T, &E::Deref::Target>::Err(&*E) + let ref_err: &Result<&i32, &u8> = &Err(&41); + assert_eq!(ref_err.deref_err(), Err(&41)); + assert_eq!(ref_err.deref_err(), Err(&41)); + assert_eq!(ref_err.deref(), Err(&41)); + + // &Ok(T).deref_err() -> Result<&T, &E::Deref::Target>::Ok(&T) + assert_eq!(ref_ok.deref_err(), Ok(&&42)); + + // &Err(E) -> Result<&T::Deref::Target, &E>::Err(&E) + assert_eq!(ref_err.deref_ok(), Err(&&41)); +} -- cgit 1.4.1-3-g733a5 From 6c7ea4ca9b92e527873115951cfc8c864bbb71ad Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Thu, 26 Apr 2018 19:54:24 -0700 Subject: refactored to implement without trait --- src/libcore/option.rs | 29 +++++++--------- src/libcore/result.rs | 91 +++++++++++++++++++-------------------------------- 2 files changed, 45 insertions(+), 75 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/option.rs b/src/libcore/option.rs index c3ef619d739..506e54ba5e4 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -878,6 +878,17 @@ impl Option { } } +# [unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +impl Option { + /// Converts from `&Option` to `Option<&T::Target>`. + /// + /// Leaves the original Option in-place, creating a new one with a reference + /// to the original one, additionally coercing the contents via `Deref`. + pub fn deref(&self) -> Option<&T::Target> { + self.as_ref().map(|t| t.deref()) + } +} + impl Option> { /// Transposes an `Option` of a `Result` into a `Result` of an `Option`. /// @@ -978,24 +989,6 @@ impl From for Option { } } -#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] -/// Extension trait to get a reference of an Option via the Deref trait. -pub trait OptionDeref { - /// Converts from `&Option` to `Option<&T::Target>`. - /// - /// Leaves the original Option in-place, creating a new one with a reference - /// to the original one, additionally coercing the contents via `Deref`. - fn deref(&self) -> Option<&T::Target>; -} - -#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] -impl OptionDeref for Option -{ - fn deref(&self) -> Option<&T::Target> { - self.as_ref().map(|t| t.deref()) - } -} - ///////////////////////////////////////////////////////////////////////////// // The Option Iterators ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 9877a2001a0..fbf2035e83f 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -909,6 +909,40 @@ impl Result { } } +impl Result { + #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] + /// Converts from `&Result` to `Result<&T::Target, &E>`. + /// + /// Leaves the original Result in-place, creating a new one with a reference + /// to the original one, additionally coercing the `Ok` arm of the Result via + /// `Deref`. + pub fn deref_ok(&self) -> Result<&T::Target, &E> { + self.as_ref().map(|t| t.deref()) + } + + #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] + /// Converts from `&Result` to `Result<&T, &E::Target>`. + /// + /// Leaves the original Result in-place, creating a new one with a reference + /// to the original one, additionally coercing the `Err` arm of the Result via + /// `Deref`. + pub fn deref_err(&self) -> Result<&T, &E::Target> + { + self.as_ref().map_err(|e| e.deref()) + } + + #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] + /// Converts from `&Result` to `Result<&T::Target, &E::Target>`. + /// + /// Leaves the original Result in-place, creating a new one with a reference + /// to the original one, additionally coercing both the `Ok` and `Err` arms + /// of the Result via `Deref`. + pub fn deref(&self) -> Result<&T::Target, &E::Target> + { + self.as_ref().map(|t| t.deref()).map_err(|e| e.deref()) + } +} + impl Result, E> { /// Transposes a `Result` of an `Option` into an `Option` of a `Result`. /// @@ -999,63 +1033,6 @@ impl<'a, T, E> IntoIterator for &'a mut Result { } } -#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] -/// Extension trait to get a reference to a Result via the Deref trait. -pub trait ResultDeref { - /// Converts from `&Result` to `Result<&T::Target, &E>`. - /// - /// Leaves the original Result in-place, creating a new one with a reference - /// to the original one, additionally coercing the `Ok` arm of the Result via - /// `Deref`. - fn deref_ok(&self) -> Result<&T::Target, &E> - where - T: Deref; - - /// Converts from `&Result` to `Result<&T, &E::Target>`. - /// - /// Leaves the original Result in-place, creating a new one with a reference - /// to the original one, additionally coercing the `Err` arm of the Result via - /// `Deref`. - fn deref_err(&self) -> Result<&T, &E::Target> - where - E: Deref; - - /// Converts from `&Result` to `Result<&T::Target, &E::Target>`. - /// - /// Leaves the original Result in-place, creating a new one with a reference - /// to the original one, additionally coercing both the `Ok` and `Err` arms - /// of the Result via `Deref`. - fn deref(&self) -> Result<&T::Target, &E::Target> - where - T: Deref, - E: Deref; -} - -#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] -impl ResultDeref for Result { - fn deref_ok(&self) -> Result<&T::Target, &E> - where - T: Deref, - { - self.as_ref().map(|t| t.deref()) - } - - fn deref_err(&self) -> Result<&T, &E::Target> - where - E: Deref, - { - self.as_ref().map_err(|e| e.deref()) - } - - fn deref(&self) -> Result<&T::Target, &E::Target> - where - T: Deref, - E: Deref, - { - self.as_ref().map(|t| t.deref()).map_err(|e| e.deref()) - } -} - ///////////////////////////////////////////////////////////////////////////// // The Result Iterators ///////////////////////////////////////////////////////////////////////////// -- cgit 1.4.1-3-g733a5 From 527e84f300a2cc36b74dcfc6a23ea9352cbf2e0b Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Thu, 26 Apr 2018 20:41:10 -0700 Subject: cleaned up #[unstable] attributes --- src/libcore/result.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/result.rs b/src/libcore/result.rs index fbf2035e83f..9e302cb9f96 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -909,8 +909,8 @@ impl Result { } } +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] impl Result { - #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] /// Converts from `&Result` to `Result<&T::Target, &E>`. /// /// Leaves the original Result in-place, creating a new one with a reference @@ -920,7 +920,6 @@ impl Result { self.as_ref().map(|t| t.deref()) } - #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] /// Converts from `&Result` to `Result<&T, &E::Target>`. /// /// Leaves the original Result in-place, creating a new one with a reference @@ -931,7 +930,6 @@ impl Result { self.as_ref().map_err(|e| e.deref()) } - #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] /// Converts from `&Result` to `Result<&T::Target, &E::Target>`. /// /// Leaves the original Result in-place, creating a new one with a reference -- cgit 1.4.1-3-g733a5 From b812d44a01bbc7180c11c9fdc3de3926105cbe05 Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Thu, 26 Apr 2018 20:42:44 -0700 Subject: added #![feature(inner_deref)] to enable inner_deref-related unit tests --- src/libcore/lib.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 0e21a3327fd..55c5e1e7971 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -103,6 +103,7 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(doc_alias)] +#![feature(inner_deref)] #![cfg_attr(not(stage0), feature(mmx_target_feature))] #![cfg_attr(not(stage0), feature(tbm_target_feature))] -- cgit 1.4.1-3-g733a5 From 2bf9fbc8d61e2283cd6133b96cff2e04988bbe69 Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Fri, 27 Apr 2018 06:36:37 -0700 Subject: separated inner_deref Result impls --- src/libcore/result.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 9e302cb9f96..c545064aadb 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -910,7 +910,7 @@ impl Result { } #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] -impl Result { +impl Result { /// Converts from `&Result` to `Result<&T::Target, &E>`. /// /// Leaves the original Result in-place, creating a new one with a reference @@ -919,7 +919,10 @@ impl Result { pub fn deref_ok(&self) -> Result<&T::Target, &E> { self.as_ref().map(|t| t.deref()) } +} +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +impl Result { /// Converts from `&Result` to `Result<&T, &E::Target>`. /// /// Leaves the original Result in-place, creating a new one with a reference @@ -929,7 +932,10 @@ impl Result { { self.as_ref().map_err(|e| e.deref()) } +} +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +impl Result { /// Converts from `&Result` to `Result<&T::Target, &E::Target>`. /// /// Leaves the original Result in-place, creating a new one with a reference -- cgit 1.4.1-3-g733a5 From 8aa049e54be521c3826b0af15a87b3b4db1fb77b Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Fri, 27 Apr 2018 06:39:04 -0700 Subject: moved #![feature(inner_deref) to from libcore crate to libcore tests crate to enable related tests --- src/libcore/lib.rs | 1 - src/libcore/tests/lib.rs | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 55c5e1e7971..0e21a3327fd 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -103,7 +103,6 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(doc_alias)] -#![feature(inner_deref)] #![cfg_attr(not(stage0), feature(mmx_target_feature))] #![cfg_attr(not(stage0), feature(tbm_target_feature))] diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index e4d27717938..111cf58c2c6 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -46,6 +46,7 @@ #![feature(reverse_bits)] #![feature(inclusive_range_fields)] #![feature(iterator_find_map)] +#![feature(inner_deref)] extern crate core; extern crate test; -- cgit 1.4.1-3-g733a5 From 17124488c7c7582fb9ab22ed87b2759ee20a4602 Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Fri, 27 Apr 2018 07:07:26 -0700 Subject: fixed inner_deref test case for None --- src/libcore/tests/option.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs index 77d550c532a..e7e48b2daa2 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -305,6 +305,6 @@ fn test_option_deref() { assert_eq!(ref_option.deref(), Some(&42)); // None: &Option>::None -> None - let ref_option = &None; + let ref_option: &Option<&i32> = &None; assert_eq!(ref_option.deref(), None); } -- cgit 1.4.1-3-g733a5 From 3dbdccc6a9c1ead58325d415381b25c676386c34 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Sat, 10 Mar 2018 16:23:28 -0800 Subject: stabilize `#[must_use]` for functions and must-use operators This is in the matter of RFC 1940 and tracking issue #43302. --- .../src/language-features/fn-must-use.md | 30 ---- src/liballoc/lib.rs | 2 +- src/liballoc/tests/slice.rs | 1 + src/libcore/lib.rs | 2 +- src/librustc_lint/unused.rs | 104 +++++++------- src/libstd/ffi/c_str.rs | 2 + src/libstd/sync/mpsc/select.rs | 2 + src/libsyntax/feature_gate.rs | 22 +-- .../ui/feature-gate-fn_must_use-cap-lints-allow.rs | 22 --- ...feature-gate-fn_must_use-cap-lints-allow.stderr | 8 -- src/test/ui/feature-gate-fn_must_use.rs | 31 ----- src/test/ui/feature-gate-fn_must_use.stderr | 24 ---- .../issue-43106-gating-of-builtin-attrs.rs | 1 - .../issue-43106-gating-of-builtin-attrs.stderr | 154 ++++++++++----------- src/test/ui/fn_must_use.rs | 78 +++++++++++ src/test/ui/fn_must_use.stderr | 48 +++++++ src/test/ui/lint/must-use-ops.rs | 1 - src/test/ui/lint/must-use-ops.stderr | 44 +++--- .../rfc_1940-must_use_on_functions/fn_must_use.rs | 79 ----------- .../fn_must_use.stderr | 48 ------- src/test/ui/span/gated-features-attr-spans.rs | 23 --- src/test/ui/span/gated-features-attr-spans.stderr | 18 +-- 22 files changed, 284 insertions(+), 460 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/fn-must-use.md delete mode 100644 src/test/ui/feature-gate-fn_must_use-cap-lints-allow.rs delete mode 100644 src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr delete mode 100644 src/test/ui/feature-gate-fn_must_use.rs delete mode 100644 src/test/ui/feature-gate-fn_must_use.stderr create mode 100644 src/test/ui/fn_must_use.rs create mode 100644 src/test/ui/fn_must_use.stderr delete mode 100644 src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.rs delete mode 100644 src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.stderr (limited to 'src/libcore') diff --git a/src/doc/unstable-book/src/language-features/fn-must-use.md b/src/doc/unstable-book/src/language-features/fn-must-use.md deleted file mode 100644 index 71b6cd663a0..00000000000 --- a/src/doc/unstable-book/src/language-features/fn-must-use.md +++ /dev/null @@ -1,30 +0,0 @@ -# `fn_must_use` - -The tracking issue for this feature is [#43302]. - -[#43302]: https://github.com/rust-lang/rust/issues/43302 - ------------------------- - -The `fn_must_use` feature allows functions and methods to be annotated with -`#[must_use]`, indicating that the `unused_must_use` lint should require their -return values to be used (similarly to how types annotated with `must_use`, -most notably `Result`, are linted if not used). - -## Examples - -```rust -#![feature(fn_must_use)] - -#[must_use] -fn double(x: i32) -> i32 { - 2 * x -} - -fn main() { - double(4); // warning: unused return value of `double` which must be used - - let _ = double(4); // (no warning) -} - -``` diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 021395d0c82..fa74352c23c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -96,7 +96,7 @@ #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] #![feature(fmt_internals)] -#![feature(fn_must_use)] +#![cfg_attr(stage0, feature(fn_must_use))] #![feature(from_ref)] #![feature(fundamental)] #![feature(lang_items)] diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index 99d9c51efc7..6fd0b33f02a 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -1282,6 +1282,7 @@ fn test_box_slice_clone() { } #[test] +#[allow(unused_must_use)] // here, we care about the side effects of `.clone()` #[cfg_attr(target_os = "emscripten", ignore)] fn test_box_slice_clone_panics() { use std::sync::Arc; diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 0e21a3327fd..f4ed24cc3a3 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -76,7 +76,6 @@ #![feature(doc_cfg)] #![feature(doc_spotlight)] #![feature(extern_types)] -#![feature(fn_must_use)] #![feature(fundamental)] #![feature(intrinsics)] #![feature(iterator_flatten)] @@ -114,6 +113,7 @@ #![cfg_attr(stage0, feature(target_feature))] #![cfg_attr(stage0, feature(cfg_target_feature))] +#![cfg_attr(stage0, feature(fn_must_use))] #[prelude_import] #[allow(unused)] diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index c32e9cdce0e..9e1b75ba336 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -73,59 +73,59 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { let mut fn_warned = false; let mut op_warned = false; - if cx.tcx.features().fn_must_use { - let maybe_def = match expr.node { - hir::ExprCall(ref callee, _) => { - match callee.node { - hir::ExprPath(ref qpath) => { - let def = cx.tables.qpath_def(qpath, callee.hir_id); - if let Def::Fn(_) = def { - Some(def) - } else { // `Def::Local` if it was a closure, for which we - None // do not currently support must-use linting - } - }, - _ => None - } - }, - hir::ExprMethodCall(..) => { - cx.tables.type_dependent_defs().get(expr.hir_id).cloned() - }, - _ => None - }; - if let Some(def) = maybe_def { - let def_id = def.def_id(); - fn_warned = check_must_use(cx, def_id, s.span, "return value of "); - } - let must_use_op = match expr.node { - // Hardcoding operators here seemed more expedient than the - // refactoring that would be needed to look up the `#[must_use]` - // attribute which does exist on the comparison trait methods - hir::ExprBinary(bin_op, ..) => { - match bin_op.node { - hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => { - Some("comparison") - }, - hir::BiAdd | hir::BiSub | hir::BiDiv | hir::BiMul | hir::BiRem => { - Some("arithmetic operation") - }, - hir::BiAnd | hir::BiOr => { - Some("logical operation") - }, - hir::BiBitXor | hir::BiBitAnd | hir::BiBitOr | hir::BiShl | hir::BiShr => { - Some("bitwise operation") - }, - } - }, - hir::ExprUnary(..) => Some("unary operation"), - _ => None - }; - if let Some(must_use_op) = must_use_op { - cx.span_lint(UNUSED_MUST_USE, expr.span, - &format!("unused {} which must be used", must_use_op)); - op_warned = true; - } + let maybe_def = match expr.node { + hir::ExprCall(ref callee, _) => { + match callee.node { + hir::ExprPath(ref qpath) => { + let def = cx.tables.qpath_def(qpath, callee.hir_id); + if let Def::Fn(_) = def { + Some(def) + } else { // `Def::Local` if it was a closure, for which we + None // do not currently support must-use linting + } + }, + _ => None + } + }, + hir::ExprMethodCall(..) => { + cx.tables.type_dependent_defs().get(expr.hir_id).cloned() + }, + _ => None + }; + if let Some(def) = maybe_def { + let def_id = def.def_id(); + fn_warned = check_must_use(cx, def_id, s.span, "return value of "); } + let must_use_op = match expr.node { + // Hardcoding operators here seemed more expedient than the + // refactoring that would be needed to look up the `#[must_use]` + // attribute which does exist on the comparison trait methods + hir::ExprBinary(bin_op, ..) => { + match bin_op.node { + hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => { + Some("comparison") + }, + hir::BiAdd | hir::BiSub | hir::BiDiv | hir::BiMul | hir::BiRem => { + Some("arithmetic operation") + }, + hir::BiAnd | hir::BiOr => { + Some("logical operation") + }, + hir::BiBitXor | hir::BiBitAnd | hir::BiBitOr | hir::BiShl | hir::BiShr => { + Some("bitwise operation") + }, + } + }, + hir::ExprUnary(..) => Some("unary operation"), + _ => None + }; + + if let Some(must_use_op) = must_use_op { + cx.span_lint(UNUSED_MUST_USE, expr.span, + &format!("unused {} which must be used", must_use_op)); + op_warned = true; + } + if !(ty_warned || fn_warned || op_warned) { cx.span_lint(UNUSED_RESULTS, s.span, "unused result"); } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index c88c2bc9137..d4937c00012 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -988,6 +988,7 @@ impl CStr { /// behavior when `ptr` is used inside the `unsafe` block: /// /// ```no_run + /// # #![allow(unused_must_use)] /// use std::ffi::{CString}; /// /// let ptr = CString::new("Hello").unwrap().as_ptr(); @@ -1003,6 +1004,7 @@ impl CStr { /// To fix the problem, bind the `CString` to a local variable: /// /// ```no_run + /// # #![allow(unused_must_use)] /// use std::ffi::{CString}; /// /// let hello = CString::new("Hello").unwrap(); diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index a9f3cea243f..9310dad9172 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -518,6 +518,7 @@ mod tests { } } + #[allow(unused_must_use)] #[test] fn cloning() { let (tx1, rx1) = channel::(); @@ -540,6 +541,7 @@ mod tests { tx3.send(()).unwrap(); } + #[allow(unused_must_use)] #[test] fn cloning2() { let (tx1, rx1) = channel::(); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index a4a83712a08..f16b1ba440a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -369,9 +369,6 @@ declare_features! ( // #[doc(include="some-file")] (active, external_doc, "1.22.0", Some(44732), None), - // allow `#[must_use]` on functions and comparison operators (RFC 1940) - (active, fn_must_use, "1.21.0", Some(43302), None), - // Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008) (active, non_exhaustive, "1.22.0", Some(44109), None), @@ -591,6 +588,8 @@ declare_features! ( (accepted, target_feature, "1.27.0", None, None), // Trait object syntax with `dyn` prefix (accepted, dyn_trait, "1.27.0", Some(44662), None), + // allow `#[must_use]` on functions; and, must-use operators (RFC 1940) + (accepted, fn_must_use, "1.27.0", Some(43302), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1545,11 +1544,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { function may change over time, for now \ a top-level `fn main()` is required"); } - if let Some(attr) = attr::find_by_name(&i.attrs[..], "must_use") { - gate_feature_post!(&self, fn_must_use, attr.span, - "`#[must_use]` on functions is experimental", - GateStrength::Soft); - } } ast::ItemKind::Struct(..) => { @@ -1581,7 +1575,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "trait aliases are not yet fully implemented"); } - ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, ref impl_items) => { + ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => { if polarity == ast::ImplPolarity::Negative { gate_feature_post!(&self, optin_builtin_traits, i.span, @@ -1594,16 +1588,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { i.span, "specialization is unstable"); } - - for impl_item in impl_items { - if let ast::ImplItemKind::Method(..) = impl_item.node { - if let Some(attr) = attr::find_by_name(&impl_item.attrs[..], "must_use") { - gate_feature_post!(&self, fn_must_use, attr.span, - "`#[must_use]` on methods is experimental", - GateStrength::Soft); - } - } - } } ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => { diff --git a/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.rs b/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.rs deleted file mode 100644 index 1c04199c05f..00000000000 --- a/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: --cap-lints allow - -// This tests that the fn_must_use feature-gate warning respects the lint -// cap. (See discussion in Issue #44213.) - -#![feature(rustc_attrs)] - -#[must_use] // (no feature-gate warning because of the lint cap!) -fn need_to_use_it() -> bool { true } - -#[rustc_error] -fn main() {} //~ ERROR compilation successful diff --git a/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr b/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr deleted file mode 100644 index a2c1dedff38..00000000000 --- a/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: compilation successful - --> $DIR/feature-gate-fn_must_use-cap-lints-allow.rs:22:1 - | -LL | fn main() {} //~ ERROR compilation successful - | ^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/feature-gate-fn_must_use.rs b/src/test/ui/feature-gate-fn_must_use.rs deleted file mode 100644 index 72fdcc76cf4..00000000000 --- a/src/test/ui/feature-gate-fn_must_use.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(rustc_attrs)] - -struct MyStruct; - -impl MyStruct { - #[must_use] //~ WARN `#[must_use]` on methods is experimental - fn need_to_use_method() -> bool { true } -} - -#[must_use] //~ WARN `#[must_use]` on functions is experimental -fn need_to_use_it() -> bool { true } - - -// Feature gates are tidy-required to have a specially named (or -// comment-annotated) compile-fail test (which MUST fail), but for -// backwards-compatibility reasons, we want `#[must_use]` on functions to be -// compilable even if the `fn_must_use` feature is absent, thus necessitating -// the usage of `#[rustc_error]` here, pragmatically if awkwardly solving this -// dilemma until a superior solution can be devised. -#[rustc_error] -fn main() {} //~ ERROR compilation successful diff --git a/src/test/ui/feature-gate-fn_must_use.stderr b/src/test/ui/feature-gate-fn_must_use.stderr deleted file mode 100644 index 431c57abd26..00000000000 --- a/src/test/ui/feature-gate-fn_must_use.stderr +++ /dev/null @@ -1,24 +0,0 @@ -warning: `#[must_use]` on methods is experimental (see issue #43302) - --> $DIR/feature-gate-fn_must_use.rs:16:5 - | -LL | #[must_use] //~ WARN `#[must_use]` on methods is experimental - | ^^^^^^^^^^^ - | - = help: add #![feature(fn_must_use)] to the crate attributes to enable - -warning: `#[must_use]` on functions is experimental (see issue #43302) - --> $DIR/feature-gate-fn_must_use.rs:20:1 - | -LL | #[must_use] //~ WARN `#[must_use]` on functions is experimental - | ^^^^^^^^^^^ - | - = help: add #![feature(fn_must_use)] to the crate attributes to enable - -error: compilation successful - --> $DIR/feature-gate-fn_must_use.rs:31:1 - | -LL | fn main() {} //~ ERROR compilation successful - | ^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs index 21950402c8c..7b0c81dbab6 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs @@ -661,7 +661,6 @@ mod must_use { mod inner { #![must_use="1400"] } #[must_use = "1400"] fn f() { } - //~^ WARN `#[must_use]` on functions is experimental #[must_use = "1400"] struct S; diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr index 0beed627987..76ab50c9089 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr @@ -12,14 +12,6 @@ LL | mod inner { #![macro_escape] } | = help: consider an outer attribute, #[macro_use] mod ... -warning: `#[must_use]` on functions is experimental (see issue #43302) - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5 - | -LL | #[must_use = "1400"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(fn_must_use)] to the crate attributes to enable - warning: unknown lint: `x5400` --> $DIR/issue-43106-gating-of-builtin-attrs.rs:49:33 | @@ -799,433 +791,433 @@ LL | #[no_std = "2600"] | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:703:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:703:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:742:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:742:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:746:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:746:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:749:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:749:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:757:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:757:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:738:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:738:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:768:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:767:17 | LL | mod inner { #![no_main="0400"] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:768:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:767:17 | LL | mod inner { #![no_main="0400"] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:772:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:771:5 | LL | #[no_main = "0400"] fn f() { } | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:772:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:771:5 | LL | #[no_main = "0400"] fn f() { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:775:5 | LL | #[no_main = "0400"] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:775:5 | LL | #[no_main = "0400"] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:779:5 | LL | #[no_main = "0400"] type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:779:5 | LL | #[no_main = "0400"] type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:5 | LL | #[no_main = "0400"] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:5 | LL | #[no_main = "0400"] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:1 | LL | #[no_main = "0400"] | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:1 | LL | #[no_main = "0400"] | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:806:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:805:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:806:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:805:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:809:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:809:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:813:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:813:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:817:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:817:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:821:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:821:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:831:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:831:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:835:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:835:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:838:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:838:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:842:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:842:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:846:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:846:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1309,7 +1301,7 @@ LL | #![proc_macro_derive = "2500"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: compilation successful - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:858:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:857:1 | LL | / fn main() { //~ ERROR compilation successful LL | | println!("Hello World"); diff --git a/src/test/ui/fn_must_use.rs b/src/test/ui/fn_must_use.rs new file mode 100644 index 00000000000..def23046db2 --- /dev/null +++ b/src/test/ui/fn_must_use.rs @@ -0,0 +1,78 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +#![warn(unused_must_use)] + +#[derive(PartialEq, Eq)] +struct MyStruct { + n: usize, +} + +impl MyStruct { + #[must_use] + fn need_to_use_this_method_value(&self) -> usize { + self.n + } +} + +trait EvenNature { + #[must_use = "no side effects"] + fn is_even(&self) -> bool; +} + +impl EvenNature for MyStruct { + fn is_even(&self) -> bool { + self.n % 2 == 0 + } +} + +trait Replaceable { + fn replace(&mut self, substitute: usize) -> usize; +} + +impl Replaceable for MyStruct { + // ↓ N.b.: `#[must_use]` attribute on a particular trait implementation + // method won't work; the attribute should be on the method signature in + // the trait's definition. + #[must_use] + fn replace(&mut self, substitute: usize) -> usize { + let previously = self.n; + self.n = substitute; + previously + } +} + +#[must_use = "it's important"] +fn need_to_use_this_value() -> bool { + false +} + +fn main() { + need_to_use_this_value(); //~ WARN unused return value + + let mut m = MyStruct { n: 2 }; + let n = MyStruct { n: 3 }; + + m.need_to_use_this_method_value(); //~ WARN unused return value + m.is_even(); // trait method! + //~^ WARN unused return value + + m.replace(3); // won't warn (annotation needs to be in trait definition) + + // comparison methods are `must_use` + 2.eq(&3); //~ WARN unused return value + m.eq(&n); //~ WARN unused return value + + // lint includes comparison operators + 2 == 3; //~ WARN unused comparison + m == n; //~ WARN unused comparison +} diff --git a/src/test/ui/fn_must_use.stderr b/src/test/ui/fn_must_use.stderr new file mode 100644 index 00000000000..5026dac0a94 --- /dev/null +++ b/src/test/ui/fn_must_use.stderr @@ -0,0 +1,48 @@ +warning: unused return value of `need_to_use_this_value` which must be used: it's important + --> $DIR/fn_must_use.rs:60:5 + | +LL | need_to_use_this_value(); //~ WARN unused return value + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/fn_must_use.rs:13:9 + | +LL | #![warn(unused_must_use)] + | ^^^^^^^^^^^^^^^ + +warning: unused return value of `MyStruct::need_to_use_this_method_value` which must be used + --> $DIR/fn_must_use.rs:65:5 + | +LL | m.need_to_use_this_method_value(); //~ WARN unused return value + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: unused return value of `EvenNature::is_even` which must be used: no side effects + --> $DIR/fn_must_use.rs:66:5 + | +LL | m.is_even(); // trait method! + | ^^^^^^^^^^^^ + +warning: unused return value of `std::cmp::PartialEq::eq` which must be used + --> $DIR/fn_must_use.rs:72:5 + | +LL | 2.eq(&3); //~ WARN unused return value + | ^^^^^^^^^ + +warning: unused return value of `std::cmp::PartialEq::eq` which must be used + --> $DIR/fn_must_use.rs:73:5 + | +LL | m.eq(&n); //~ WARN unused return value + | ^^^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/fn_must_use.rs:76:5 + | +LL | 2 == 3; //~ WARN unused comparison + | ^^^^^^ + +warning: unused comparison which must be used + --> $DIR/fn_must_use.rs:77:5 + | +LL | m == n; //~ WARN unused comparison + | ^^^^^^ + diff --git a/src/test/ui/lint/must-use-ops.rs b/src/test/ui/lint/must-use-ops.rs index 4ed82ab3b40..c0575f817c8 100644 --- a/src/test/ui/lint/must-use-ops.rs +++ b/src/test/ui/lint/must-use-ops.rs @@ -12,7 +12,6 @@ // compile-pass -#![feature(fn_must_use)] #![warn(unused_must_use)] fn main() { diff --git a/src/test/ui/lint/must-use-ops.stderr b/src/test/ui/lint/must-use-ops.stderr index f444ef09075..5703536ef48 100644 --- a/src/test/ui/lint/must-use-ops.stderr +++ b/src/test/ui/lint/must-use-ops.stderr @@ -1,131 +1,131 @@ warning: unused comparison which must be used - --> $DIR/must-use-ops.rs:23:5 + --> $DIR/must-use-ops.rs:22:5 | LL | val == 1; | ^^^^^^^^ | note: lint level defined here - --> $DIR/must-use-ops.rs:16:9 + --> $DIR/must-use-ops.rs:15:9 | LL | #![warn(unused_must_use)] | ^^^^^^^^^^^^^^^ warning: unused comparison which must be used - --> $DIR/must-use-ops.rs:24:5 + --> $DIR/must-use-ops.rs:23:5 | LL | val < 1; | ^^^^^^^ warning: unused comparison which must be used - --> $DIR/must-use-ops.rs:25:5 + --> $DIR/must-use-ops.rs:24:5 | LL | val <= 1; | ^^^^^^^^ warning: unused comparison which must be used - --> $DIR/must-use-ops.rs:26:5 + --> $DIR/must-use-ops.rs:25:5 | LL | val != 1; | ^^^^^^^^ warning: unused comparison which must be used - --> $DIR/must-use-ops.rs:27:5 + --> $DIR/must-use-ops.rs:26:5 | LL | val >= 1; | ^^^^^^^^ warning: unused comparison which must be used - --> $DIR/must-use-ops.rs:28:5 + --> $DIR/must-use-ops.rs:27:5 | LL | val > 1; | ^^^^^^^ warning: unused arithmetic operation which must be used - --> $DIR/must-use-ops.rs:31:5 + --> $DIR/must-use-ops.rs:30:5 | LL | val + 2; | ^^^^^^^ warning: unused arithmetic operation which must be used - --> $DIR/must-use-ops.rs:32:5 + --> $DIR/must-use-ops.rs:31:5 | LL | val - 2; | ^^^^^^^ warning: unused arithmetic operation which must be used - --> $DIR/must-use-ops.rs:33:5 + --> $DIR/must-use-ops.rs:32:5 | LL | val / 2; | ^^^^^^^ warning: unused arithmetic operation which must be used - --> $DIR/must-use-ops.rs:34:5 + --> $DIR/must-use-ops.rs:33:5 | LL | val * 2; | ^^^^^^^ warning: unused arithmetic operation which must be used - --> $DIR/must-use-ops.rs:35:5 + --> $DIR/must-use-ops.rs:34:5 | LL | val % 2; | ^^^^^^^ warning: unused logical operation which must be used - --> $DIR/must-use-ops.rs:38:5 + --> $DIR/must-use-ops.rs:37:5 | LL | true && true; | ^^^^^^^^^^^^ warning: unused logical operation which must be used - --> $DIR/must-use-ops.rs:39:5 + --> $DIR/must-use-ops.rs:38:5 | LL | false || true; | ^^^^^^^^^^^^^ warning: unused bitwise operation which must be used - --> $DIR/must-use-ops.rs:42:5 + --> $DIR/must-use-ops.rs:41:5 | LL | 5 ^ val; | ^^^^^^^ warning: unused bitwise operation which must be used - --> $DIR/must-use-ops.rs:43:5 + --> $DIR/must-use-ops.rs:42:5 | LL | 5 & val; | ^^^^^^^ warning: unused bitwise operation which must be used - --> $DIR/must-use-ops.rs:44:5 + --> $DIR/must-use-ops.rs:43:5 | LL | 5 | val; | ^^^^^^^ warning: unused bitwise operation which must be used - --> $DIR/must-use-ops.rs:45:5 + --> $DIR/must-use-ops.rs:44:5 | LL | 5 << val; | ^^^^^^^^ warning: unused bitwise operation which must be used - --> $DIR/must-use-ops.rs:46:5 + --> $DIR/must-use-ops.rs:45:5 | LL | 5 >> val; | ^^^^^^^^ warning: unused unary operation which must be used - --> $DIR/must-use-ops.rs:49:5 + --> $DIR/must-use-ops.rs:48:5 | LL | !val; | ^^^^ warning: unused unary operation which must be used - --> $DIR/must-use-ops.rs:50:5 + --> $DIR/must-use-ops.rs:49:5 | LL | -val; | ^^^^ warning: unused unary operation which must be used - --> $DIR/must-use-ops.rs:51:5 + --> $DIR/must-use-ops.rs:50:5 | LL | *val_pointer; | ^^^^^^^^^^^^ diff --git a/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.rs b/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.rs deleted file mode 100644 index d20ebf0b740..00000000000 --- a/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-pass - -#![feature(fn_must_use)] -#![warn(unused_must_use)] - -#[derive(PartialEq, Eq)] -struct MyStruct { - n: usize, -} - -impl MyStruct { - #[must_use] - fn need_to_use_this_method_value(&self) -> usize { - self.n - } -} - -trait EvenNature { - #[must_use = "no side effects"] - fn is_even(&self) -> bool; -} - -impl EvenNature for MyStruct { - fn is_even(&self) -> bool { - self.n % 2 == 0 - } -} - -trait Replaceable { - fn replace(&mut self, substitute: usize) -> usize; -} - -impl Replaceable for MyStruct { - // ↓ N.b.: `#[must_use]` attribute on a particular trait implementation - // method won't work; the attribute should be on the method signature in - // the trait's definition. - #[must_use] - fn replace(&mut self, substitute: usize) -> usize { - let previously = self.n; - self.n = substitute; - previously - } -} - -#[must_use = "it's important"] -fn need_to_use_this_value() -> bool { - false -} - -fn main() { - need_to_use_this_value(); //~ WARN unused return value - - let mut m = MyStruct { n: 2 }; - let n = MyStruct { n: 3 }; - - m.need_to_use_this_method_value(); //~ WARN unused return value - m.is_even(); // trait method! - //~^ WARN unused return value - - m.replace(3); // won't warn (annotation needs to be in trait definition) - - // comparison methods are `must_use` - 2.eq(&3); //~ WARN unused return value - m.eq(&n); //~ WARN unused return value - - // lint includes comparison operators - 2 == 3; //~ WARN unused comparison - m == n; //~ WARN unused comparison -} diff --git a/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.stderr b/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.stderr deleted file mode 100644 index d0a8bb525b6..00000000000 --- a/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.stderr +++ /dev/null @@ -1,48 +0,0 @@ -warning: unused return value of `need_to_use_this_value` which must be used: it's important - --> $DIR/fn_must_use.rs:61:5 - | -LL | need_to_use_this_value(); //~ WARN unused return value - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: lint level defined here - --> $DIR/fn_must_use.rs:14:9 - | -LL | #![warn(unused_must_use)] - | ^^^^^^^^^^^^^^^ - -warning: unused return value of `MyStruct::need_to_use_this_method_value` which must be used - --> $DIR/fn_must_use.rs:66:5 - | -LL | m.need_to_use_this_method_value(); //~ WARN unused return value - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused return value of `EvenNature::is_even` which must be used: no side effects - --> $DIR/fn_must_use.rs:67:5 - | -LL | m.is_even(); // trait method! - | ^^^^^^^^^^^^ - -warning: unused return value of `std::cmp::PartialEq::eq` which must be used - --> $DIR/fn_must_use.rs:73:5 - | -LL | 2.eq(&3); //~ WARN unused return value - | ^^^^^^^^^ - -warning: unused return value of `std::cmp::PartialEq::eq` which must be used - --> $DIR/fn_must_use.rs:74:5 - | -LL | m.eq(&n); //~ WARN unused return value - | ^^^^^^^^^ - -warning: unused comparison which must be used - --> $DIR/fn_must_use.rs:77:5 - | -LL | 2 == 3; //~ WARN unused comparison - | ^^^^^^ - -warning: unused comparison which must be used - --> $DIR/fn_must_use.rs:78:5 - | -LL | m == n; //~ WARN unused comparison - | ^^^^^^ - diff --git a/src/test/ui/span/gated-features-attr-spans.rs b/src/test/ui/span/gated-features-attr-spans.rs index 83a4c5d5dd2..eff1f98eb71 100644 --- a/src/test/ui/span/gated-features-attr-spans.rs +++ b/src/test/ui/span/gated-features-attr-spans.rs @@ -8,33 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(attr_literals)] - -#[repr(align(16))] -struct Gem { - mohs_hardness: u8, - poofed: bool, - weapon: Weapon, -} - #[repr(simd)] //~ ERROR are experimental struct Weapon { name: String, damage: u32 } -impl Gem { - #[must_use] fn summon_weapon(&self) -> Weapon { self.weapon } - //~^ WARN is experimental -} - -#[must_use] //~ WARN is experimental -fn bubble(gem: Gem) -> Result { - if gem.poofed { - Ok(gem) - } else { - Err(()) - } -} - fn main() {} diff --git a/src/test/ui/span/gated-features-attr-spans.stderr b/src/test/ui/span/gated-features-attr-spans.stderr index 179daf83c3c..a99530529fc 100644 --- a/src/test/ui/span/gated-features-attr-spans.stderr +++ b/src/test/ui/span/gated-features-attr-spans.stderr @@ -1,27 +1,11 @@ error[E0658]: SIMD types are experimental and possibly buggy (see issue #27731) - --> $DIR/gated-features-attr-spans.rs:20:1 + --> $DIR/gated-features-attr-spans.rs:11:1 | LL | #[repr(simd)] //~ ERROR are experimental | ^^^^^^^^^^^^^ | = help: add #![feature(repr_simd)] to the crate attributes to enable -warning: `#[must_use]` on methods is experimental (see issue #43302) - --> $DIR/gated-features-attr-spans.rs:27:5 - | -LL | #[must_use] fn summon_weapon(&self) -> Weapon { self.weapon } - | ^^^^^^^^^^^ - | - = help: add #![feature(fn_must_use)] to the crate attributes to enable - -warning: `#[must_use]` on functions is experimental (see issue #43302) - --> $DIR/gated-features-attr-spans.rs:31:1 - | -LL | #[must_use] //~ WARN is experimental - | ^^^^^^^^^^^ - | - = help: add #![feature(fn_must_use)] to the crate attributes to enable - error: aborting due to previous error For more information about this error, try `rustc --explain E0658`. -- cgit 1.4.1-3-g733a5 From 269d2790946858dd1b504c21c54a267ac63dc15a Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 29 Apr 2018 10:15:40 -0700 Subject: Fix some broken links in docs. --- src/libcore/iter/iterator.rs | 2 ++ src/libcore/marker.rs | 2 ++ src/libstd/collections/hash/table.rs | 2 +- src/libstd/ffi/c_str.rs | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 6a77de2c986..b27bd3142e1 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1094,6 +1094,8 @@ pub trait Iterator { /// `flatten()` a three-dimensional array the result will be /// two-dimensional and not one-dimensional. To get a one-dimensional /// structure, you have to `flatten()` again. + /// + /// [`flat_map()`]: #method.flat_map #[inline] #[unstable(feature = "iterator_flatten", issue = "48213")] fn flatten(self) -> Flatten diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index feb689dbc1f..c074adfd570 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -602,6 +602,8 @@ unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} /// `Pin` pointer. /// /// This trait is automatically implemented for almost every type. +/// +/// [`Pin`]: ../mem/struct.Pin.html #[unstable(feature = "pin", issue = "49150")] pub unsafe auto trait Unpin {} diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 52c53dc3b12..b50652ed6b5 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -79,7 +79,7 @@ impl TaggedHashUintPtr { /// /// Essential invariants of this structure: /// -/// - if t.hashes[i] == EMPTY_BUCKET, then `Bucket::at_index(&t, i).raw` +/// - if `t.hashes[i] == EMPTY_BUCKET`, then `Bucket::at_index(&t, i).raw` /// points to 'undefined' contents. Don't read from it. This invariant is /// enforced outside this module with the `EmptyBucket`, `FullBucket`, /// and `SafeHash` types. diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index c88c2bc9137..8164f52d3c3 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -1118,6 +1118,7 @@ impl CStr { /// /// [`Cow`]: ../borrow/enum.Cow.html /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed + /// [`Owned`]: ../borrow/enum.Cow.html#variant.Owned /// [`str`]: ../primitive.str.html /// [`String`]: ../string/struct.String.html /// -- cgit 1.4.1-3-g733a5 From 5ab4c811caba9cfac1488919efae6c6675e68e4c Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Mon, 30 Apr 2018 07:36:27 -0400 Subject: str/slice: factor out overflow error messages --- src/libcore/slice/mod.rs | 12 ++++++++---- src/libcore/str/mod.rs | 18 ++++++++++-------- 2 files changed, 18 insertions(+), 12 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 83e8a6e4b68..93ebc23ac0b 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2262,6 +2262,12 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! { panic!("slice index starts at {} but ends at {}", index, end); } +#[inline(never)] +#[cold] +fn slice_index_overflow_fail() -> ! { + panic!("attempted to index slice up to maximum usize"); +} + /// A helper trait used for indexing operations. #[unstable(feature = "slice_get_slice", issue = "35729")] #[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] @@ -2538,15 +2544,13 @@ impl SliceIndex<[T]> for ops::RangeInclusive { #[inline] fn index(self, slice: &[T]) -> &[T] { - assert!(self.end != usize::max_value(), - "attempted to index slice up to maximum usize"); + if self.end == usize::max_value() { slice_index_overflow_fail(); } (self.start..self.end + 1).index(slice) } #[inline] fn index_mut(self, slice: &mut [T]) -> &mut [T] { - assert!(self.end != usize::max_value(), - "attempted to index slice up to maximum usize"); + if self.end == usize::max_value() { slice_index_overflow_fail(); } (self.start..self.end + 1).index_mut(slice) } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index b39d9feb35b..f7555700ebc 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1849,6 +1849,12 @@ mod traits { } } + #[inline(never)] + #[cold] + fn str_index_overflow_fail() -> ! { + panic!("attempted to index str up to maximum usize"); + } + #[stable(feature = "str_checked_slicing", since = "1.20.0")] impl SliceIndex for ops::RangeFull { type Output = str; @@ -2053,14 +2059,12 @@ mod traits { } #[inline] fn index(self, slice: &str) -> &Self::Output { - assert!(self.end != usize::max_value(), - "attempted to index str up to maximum usize"); + if self.end == usize::max_value() { str_index_overflow_fail(); } (self.start..self.end+1).index(slice) } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { - assert!(self.end != usize::max_value(), - "attempted to index str up to maximum usize"); + if self.end == usize::max_value() { str_index_overflow_fail(); } (self.start..self.end+1).index_mut(slice) } } @@ -2098,14 +2102,12 @@ mod traits { } #[inline] fn index(self, slice: &str) -> &Self::Output { - assert!(self.end != usize::max_value(), - "attempted to index str up to maximum usize"); + if self.end == usize::max_value() { str_index_overflow_fail(); } (..self.end+1).index(slice) } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { - assert!(self.end != usize::max_value(), - "attempted to index str up to maximum usize"); + if self.end == usize::max_value() { str_index_overflow_fail(); } (..self.end+1).index_mut(slice) } } -- cgit 1.4.1-3-g733a5 From 6b749b011350830f47a93f1efce986b3c02c4342 Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Mon, 30 Apr 2018 07:36:46 -0400 Subject: Clean up the other Slice*Inclusive impls for str A previous PR fixed one method that was legitimately buggy; this cleans up the rest to be less diverse, mirroring the corresponding impls on [T] to the greatest extent possible without introducing any unnecessary UTF-8 boundary checks at 0. --- src/libcore/str/mod.rs | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index f7555700ebc..df7b2f25a86 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2035,19 +2035,13 @@ mod traits { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { - if let Some(end) = self.end.checked_add(1) { - (self.start..end).get(slice) - } else { - None - } + if self.end == usize::max_value() { None } + else { (self.start..self.end+1).get(slice) } } #[inline] fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if let Some(end) = self.end.checked_add(1) { - (self.start..end).get_mut(slice) - } else { - None - } + if self.end == usize::max_value() { None } + else { (self.start..self.end+1).get_mut(slice) } } #[inline] unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { @@ -2076,29 +2070,21 @@ mod traits { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { - if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) { - Some(unsafe { self.get_unchecked(slice) }) - } else { - None - } + if self.end == usize::max_value() { None } + else { (..self.end+1).get(slice) } } #[inline] fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) { - Some(unsafe { self.get_unchecked_mut(slice) }) - } else { - None - } + if self.end == usize::max_value() { None } + else { (..self.end+1).get_mut(slice) } } #[inline] unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { - let ptr = slice.as_ptr(); - super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end + 1)) + (..self.end+1).get_unchecked(slice) } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { - let ptr = slice.as_ptr(); - super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1)) + (..self.end+1).get_unchecked_mut(slice) } #[inline] fn index(self, slice: &str) -> &Self::Output { -- cgit 1.4.1-3-g733a5 From 4fab1674c3db2cf4b2d1546a7120d8d56a85c355 Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Mon, 30 Apr 2018 07:36:56 -0400 Subject: update libcore's comment about str tests --- src/libcore/tests/str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/str.rs b/src/libcore/tests/str.rs index 08daafccc54..343c9596c53 100644 --- a/src/libcore/tests/str.rs +++ b/src/libcore/tests/str.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// All `str` tests live in collectionstests::str +// All `str` tests live in liballoc/tests -- cgit 1.4.1-3-g733a5 From ce66f5d9185aa2b81159fa61597bbb6e4cf2847f Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Mon, 30 Apr 2018 07:37:08 -0400 Subject: flesh out tests for SliceIndex m*n lines of implementation deserves m*n lines of tests --- src/liballoc/tests/str.rs | 477 +++++++++++++++++++++++++++++++++++---------- src/libcore/tests/slice.rs | 282 +++++++++++++++++++++++---- 2 files changed, 622 insertions(+), 137 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index c9536cbe168..bfba9a6b393 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -292,19 +292,194 @@ fn test_replace_pattern() { } mod slice_index { + // Test a slicing operation **that should succeed,** + // testing it on all of the indexing methods. + // + // DO NOT use this in `should_panic` tests, unless you are testing the macro itself. + macro_rules! assert_range_eq { + ($s:expr, $range:expr, $expected:expr) + => { + let mut s: String = $s.to_owned(); + let mut expected: String = $expected.to_owned(); + { + let s: &str = &s; + let expected: &str = &expected; + + assert_eq!(&s[$range], expected, "(in assertion for: index)"); + assert_eq!(s.get($range), Some(expected), "(in assertion for: get)"); + unsafe { + assert_eq!( + s.get_unchecked($range), expected, + "(in assertion for: get_unchecked)", + ); + } + } + { + let s: &mut str = &mut s; + let expected: &mut str = &mut expected; + + assert_eq!( + &mut s[$range], expected, + "(in assertion for: index_mut)", + ); + assert_eq!( + s.get_mut($range), Some(&mut expected[..]), + "(in assertion for: get_mut)", + ); + unsafe { + assert_eq!( + s.get_unchecked_mut($range), expected, + "(in assertion for: get_unchecked_mut)", + ); + } + } + } + } + + // Make sure the macro can actually detect bugs, + // because if it can't, then what are we even doing here? + // + // (Be aware this only demonstrates the ability to detect bugs + // in the FIRST method it calls, as the macro is not designed + // to be used in `should_panic`) + #[test] + #[should_panic(expected = "out of bounds")] + fn assert_range_eq_can_fail_by_panic() { + assert_range_eq!("abc", 0..5, "abc"); + } + + // (Be aware this only demonstrates the ability to detect bugs + // in the FIRST method it calls, as the macro is not designed + // to be used in `should_panic`) + #[test] + #[should_panic(expected = "==")] + fn assert_range_eq_can_fail_by_inequality() { + assert_range_eq!("abc", 0..2, "abc"); + } + + // Generates test cases for bad index operations. + // + // This generates `should_panic` test cases for Index/IndexMut + // and `None` test cases for get/get_mut. + macro_rules! panic_cases { + ($( + mod $case_name:ident { + let DATA = $data:expr; + + // optional: + // + // a similar input for which DATA[input] succeeds, and the corresponding + // output str. This helps validate "critical points" where an input range + // straddles the boundary between valid and invalid. + // (such as the input `len..len`, which is just barely valid) + $( + let GOOD_INPUT = $good:expr; + let GOOD_OUTPUT = $output:expr; + )* + + let BAD_INPUT = $bad:expr; + const EXPECT_MSG = $expect_msg:expr; // must be a literal + + !!generate_tests!! + } + )*) => {$( + mod $case_name { + #[test] + fn pass() { + let mut v: String = $data.into(); + + $( assert_range_eq!(v, $good, $output); )* + + { + let v: &str = &v; + assert_eq!(v.get($bad), None, "(in None assertion for get)"); + } + + { + let v: &mut str = &mut v; + assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)"); + } + } + + #[test] + #[should_panic(expected = $expect_msg)] + fn index_fail() { + let v: String = $data.into(); + let v: &str = &v; + let _v = &v[$bad]; + } + + #[test] + #[should_panic(expected = $expect_msg)] + fn index_mut_fail() { + let mut v: String = $data.into(); + let v: &mut str = &mut v; + let _v = &mut v[$bad]; + } + } + )*}; + } + + #[test] + fn simple_ascii() { + assert_range_eq!("abc", .., "abc"); + + assert_range_eq!("abc", 0..2, "ab"); + assert_range_eq!("abc", 0..=1, "ab"); + assert_range_eq!("abc", ..2, "ab"); + assert_range_eq!("abc", ..=1, "ab"); + + assert_range_eq!("abc", 1..3, "bc"); + assert_range_eq!("abc", 1..=2, "bc"); + assert_range_eq!("abc", 1..1, ""); + assert_range_eq!("abc", 1..=0, ""); + } + #[test] - fn test_slice() { - assert_eq!("ab", &"abc"[0..2]); - assert_eq!("bc", &"abc"[1..3]); - assert_eq!("", &"abc"[1..1]); - assert_eq!("\u{65e5}", &"\u{65e5}\u{672c}"[0..3]); + fn simple_unicode() { + // 日本 + assert_range_eq!("\u{65e5}\u{672c}", .., "\u{65e5}\u{672c}"); + + assert_range_eq!("\u{65e5}\u{672c}", 0..3, "\u{65e5}"); + assert_range_eq!("\u{65e5}\u{672c}", 0..=2, "\u{65e5}"); + assert_range_eq!("\u{65e5}\u{672c}", ..3, "\u{65e5}"); + assert_range_eq!("\u{65e5}\u{672c}", ..=2, "\u{65e5}"); + + assert_range_eq!("\u{65e5}\u{672c}", 3..6, "\u{672c}"); + assert_range_eq!("\u{65e5}\u{672c}", 3..=5, "\u{672c}"); + assert_range_eq!("\u{65e5}\u{672c}", 3.., "\u{672c}"); let data = "ประเทศไทย中华"; - assert_eq!("ป", &data[0..3]); - assert_eq!("ร", &data[3..6]); - assert_eq!("", &data[3..3]); - assert_eq!("华", &data[30..33]); + assert_range_eq!(data, 0..3, "ป"); + assert_range_eq!(data, 3..6, "ร"); + assert_range_eq!(data, 3..3, ""); + assert_range_eq!(data, 30..33, "华"); + /*0: 中 + 3: 华 + 6: V + 7: i + 8: ệ + 11: t + 12: + 13: N + 14: a + 15: m */ + let ss = "中华Việt Nam"; + assert_range_eq!(ss, 3..6, "华"); + assert_range_eq!(ss, 6..16, "Việt Nam"); + assert_range_eq!(ss, 6..=15, "Việt Nam"); + assert_range_eq!(ss, 6.., "Việt Nam"); + + assert_range_eq!(ss, 0..3, "中"); + assert_range_eq!(ss, 3..7, "华V"); + assert_range_eq!(ss, 3..=6, "华V"); + assert_range_eq!(ss, 3..3, ""); + assert_range_eq!(ss, 3..=2, ""); + } + + #[test] + fn simple_big() { fn a_million_letter_x() -> String { let mut i = 0; let mut rs = String::new(); @@ -324,33 +499,7 @@ mod slice_index { rs } let letters = a_million_letter_x(); - assert_eq!(half_a_million_letter_x(), &letters[0..3 * 500000]); - } - - #[test] - fn test_slice_2() { - let ss = "中华Việt Nam"; - - assert_eq!("华", &ss[3..6]); - assert_eq!("Việt Nam", &ss[6..16]); - - assert_eq!("ab", &"abc"[0..2]); - assert_eq!("bc", &"abc"[1..3]); - assert_eq!("", &"abc"[1..1]); - - assert_eq!("中", &ss[0..3]); - assert_eq!("华V", &ss[3..7]); - assert_eq!("", &ss[3..3]); - /*0: 中 - 3: 华 - 6: V - 7: i - 8: ệ - 11: t - 12: - 13: N - 14: a - 15: m */ + assert_range_eq!(letters, 0..3 * 500000, half_a_million_letter_x()); } #[test] @@ -359,55 +508,210 @@ mod slice_index { &"中华Việt Nam"[0..2]; } - #[test] - #[should_panic] - fn test_str_slice_rangetoinclusive_max_panics() { - &"hello"[..=usize::max_value()]; - } + panic_cases! { + mod rangefrom_len { + let DATA = "abcdef"; - #[test] - #[should_panic] - fn test_str_slice_rangeinclusive_max_panics() { - &"hello"[1..=usize::max_value()]; - } + let GOOD_INPUT = 6..; + let GOOD_OUTPUT = ""; - #[test] - #[should_panic] - fn test_str_slicemut_rangetoinclusive_max_panics() { - let mut s = "hello".to_owned(); - let s: &mut str = &mut s; - &mut s[..=usize::max_value()]; + let BAD_INPUT = 7..; + const EXPECT_MSG = "out of bounds"; + + !!generate_tests!! + } + + mod rangeto_len { + let DATA = "abcdef"; + + let GOOD_INPUT = ..6; + let GOOD_OUTPUT = "abcdef"; + + let BAD_INPUT = ..7; + const EXPECT_MSG = "out of bounds"; + + !!generate_tests!! + } + + mod rangetoinclusive_len { + let DATA = "abcdef"; + + let GOOD_INPUT = ..=5; + let GOOD_OUTPUT = "abcdef"; + + let BAD_INPUT = ..=6; + const EXPECT_MSG = "out of bounds"; + + !!generate_tests!! + } + + mod range_len_len { + let DATA = "abcdef"; + + let GOOD_INPUT = 6..6; + let GOOD_OUTPUT = ""; + + let BAD_INPUT = 7..7; + const EXPECT_MSG = "out of bounds"; + + !!generate_tests!! + } + + mod rangeinclusive_len_len { + let DATA = "abcdef"; + + let GOOD_INPUT = 6..=5; + let GOOD_OUTPUT = ""; + + let BAD_INPUT = 7..=6; + const EXPECT_MSG = "out of bounds"; + + !!generate_tests!! + } } - #[test] - #[should_panic] - fn test_str_slicemut_rangeinclusive_max_panics() { - let mut s = "hello".to_owned(); - let s: &mut str = &mut s; - &mut s[1..=usize::max_value()]; + panic_cases! { + mod range_neg_width { + let DATA = "abcdef"; + + let GOOD_INPUT = 4..4; + let GOOD_OUTPUT = ""; + + let BAD_INPUT = 4..3; + const EXPECT_MSG = "begin <= end (4 <= 3)"; + + !!generate_tests!! + } + + mod rangeinclusive_neg_width { + let DATA = "abcdef"; + + let GOOD_INPUT = 4..=3; + let GOOD_OUTPUT = ""; + + let BAD_INPUT = 4..=2; + const EXPECT_MSG = "begin <= end (4 <= 3)"; + + !!generate_tests!! + } } - #[test] - fn test_str_get_maxinclusive() { - let mut s = "hello".to_owned(); - { - let s: &str = &s; - assert_eq!(s.get(..=usize::max_value()), None); - assert_eq!(s.get(1..=usize::max_value()), None); + mod overflow { + panic_cases! { + + mod rangeinclusive { + let DATA = "hello"; + + let BAD_INPUT = 1..=usize::max_value(); + const EXPECT_MSG = "maximum usize"; + + !!generate_tests!! + } + + mod rangetoinclusive { + let DATA = "hello"; + + let BAD_INPUT = ..=usize::max_value(); + const EXPECT_MSG = "maximum usize"; + + !!generate_tests!! + } } - { - let s: &mut str = &mut s; - assert_eq!(s.get(..=usize::max_value()), None); - assert_eq!(s.get(1..=usize::max_value()), None); + } + + mod boundary { + const DATA: &'static str = "abcαβγ"; + + const BAD_START: usize = 4; + const GOOD_START: usize = 3; + const BAD_END: usize = 6; + const GOOD_END: usize = 7; + const BAD_END_INCL: usize = BAD_END - 1; + const GOOD_END_INCL: usize = GOOD_END - 1; + + // it is especially important to test all of the different range types here + // because some of the logic may be duplicated as part of micro-optimizations + // to dodge unicode boundary checks on half-ranges. + panic_cases! { + mod range_1 { + let DATA = super::DATA; + + let BAD_INPUT = super::BAD_START..super::GOOD_END; + const EXPECT_MSG = + "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; + + !!generate_tests!! + } + + mod range_2 { + let DATA = super::DATA; + + let BAD_INPUT = super::GOOD_START..super::BAD_END; + const EXPECT_MSG = + "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; + + !!generate_tests!! + } + + mod rangefrom { + let DATA = super::DATA; + + let BAD_INPUT = super::BAD_START..; + const EXPECT_MSG = + "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; + + !!generate_tests!! + } + + mod rangeto { + let DATA = super::DATA; + + let BAD_INPUT = ..super::BAD_END; + const EXPECT_MSG = + "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; + + !!generate_tests!! + } + + mod rangeinclusive_1 { + let DATA = super::DATA; + + let BAD_INPUT = super::BAD_START..=super::GOOD_END_INCL; + const EXPECT_MSG = + "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; + + !!generate_tests!! + } + + mod rangeinclusive_2 { + let DATA = super::DATA; + + let BAD_INPUT = super::GOOD_START..=super::BAD_END_INCL; + const EXPECT_MSG = + "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; + + !!generate_tests!! + } + + mod rangetoinclusive { + let DATA = super::DATA; + + let BAD_INPUT = ..=super::BAD_END_INCL; + const EXPECT_MSG = + "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; + + !!generate_tests!! + } } } const LOREM_PARAGRAPH: &'static str = "\ - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \ - ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \ - eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \ - sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \ - tempus vel, gravida nec quam."; + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem \ + sit amet dolor ultricies condimentum. Praesent iaculis purus elit, ac malesuada \ + quam malesuada in. Duis sed orci eros. Suspendisse sit amet magna mollis, mollis \ + nunc luctus, imperdiet mi. Integer fringilla non sem ut lacinia. Fusce varius \ + tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec tempus vel, \ + gravida nec quam."; // check the panic includes the prefix of the sliced string #[test] @@ -421,31 +725,6 @@ mod slice_index { fn test_slice_fail_truncated_2() { &LOREM_PARAGRAPH[..1024]; } - - #[test] - #[should_panic(expected="byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of")] - fn test_slice_fail_boundary_1() { - &"abcαβγ"[4..]; - } - - #[test] - #[should_panic(expected="byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of")] - fn test_slice_fail_boundary_2() { - &"abcαβγ"[2..6]; - } - - #[test] - fn test_slice_from() { - assert_eq!(&"abcd"[0..], "abcd"); - assert_eq!(&"abcd"[2..], "cd"); - assert_eq!(&"abcd"[4..], ""); - } - #[test] - fn test_slice_to() { - assert_eq!(&"abcd"[..0], ""); - assert_eq!(&"abcd"[..2], "ab"); - assert_eq!(&"abcd"[..4], "abcd"); - } } #[test] diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 53fdfa06827..5272c7427d9 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -376,48 +376,254 @@ fn test_windows_zip() { assert_eq!(res, [14, 18, 22, 26]); } -#[test] -fn get_range() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - assert_eq!(v.get(..), Some(&[0, 1, 2, 3, 4, 5][..])); - assert_eq!(v.get(..2), Some(&[0, 1][..])); - assert_eq!(v.get(2..), Some(&[2, 3, 4, 5][..])); - assert_eq!(v.get(1..4), Some(&[1, 2, 3][..])); - assert_eq!(v.get(7..), None); - assert_eq!(v.get(7..10), None); -} +mod slice_index { + // Test a slicing operation that should succeed, + // testing it on all of the indexing methods. + macro_rules! assert_range_eq { + ($arr:expr, $range:expr, $expected:expr) + => { + let mut arr = $arr; + let mut expected = $expected; + { + let s: &[_] = &arr; + let expected: &[_] = &expected; + + assert_eq!(&s[$range], expected, "(in assertion for: index)"); + assert_eq!(s.get($range), Some(expected), "(in assertion for: get)"); + unsafe { + assert_eq!( + s.get_unchecked($range), expected, + "(in assertion for: get_unchecked)", + ); + } + } + { + let s: &mut [_] = &mut arr; + let expected: &mut [_] = &mut expected; + + assert_eq!( + &mut s[$range], expected, + "(in assertion for: index_mut)", + ); + assert_eq!( + s.get_mut($range), Some(&mut expected[..]), + "(in assertion for: get_mut)", + ); + unsafe { + assert_eq!( + s.get_unchecked_mut($range), expected, + "(in assertion for: get_unchecked_mut)", + ); + } + } + } + } -#[test] -fn get_mut_range() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - assert_eq!(v.get_mut(..), Some(&mut [0, 1, 2, 3, 4, 5][..])); - assert_eq!(v.get_mut(..2), Some(&mut [0, 1][..])); - assert_eq!(v.get_mut(2..), Some(&mut [2, 3, 4, 5][..])); - assert_eq!(v.get_mut(1..4), Some(&mut [1, 2, 3][..])); - assert_eq!(v.get_mut(7..), None); - assert_eq!(v.get_mut(7..10), None); -} - -#[test] -fn get_unchecked_range() { - unsafe { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - assert_eq!(v.get_unchecked(..), &[0, 1, 2, 3, 4, 5][..]); - assert_eq!(v.get_unchecked(..2), &[0, 1][..]); - assert_eq!(v.get_unchecked(2..), &[2, 3, 4, 5][..]); - assert_eq!(v.get_unchecked(1..4), &[1, 2, 3][..]); + // Make sure the macro can actually detect bugs, + // because if it can't, then what are we even doing here? + // + // (Be aware this only demonstrates the ability to detect bugs + // in the FIRST method it calls, as the macro is not designed + // to be used in `should_panic`) + #[test] + #[should_panic(expected = "out of range")] + fn assert_range_eq_can_fail_by_panic() { + assert_range_eq!([0, 1, 2], 0..5, [0, 1, 2]); } -} -#[test] -fn get_unchecked_mut_range() { - unsafe { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - assert_eq!(v.get_unchecked_mut(..), &mut [0, 1, 2, 3, 4, 5][..]); - assert_eq!(v.get_unchecked_mut(..2), &mut [0, 1][..]); - assert_eq!(v.get_unchecked_mut(2..), &mut[2, 3, 4, 5][..]); - assert_eq!(v.get_unchecked_mut(1..4), &mut [1, 2, 3][..]); + // (Be aware this only demonstrates the ability to detect bugs + // in the FIRST method it calls, as the macro is not designed + // to be used in `should_panic`) + #[test] + #[should_panic(expected = "==")] + fn assert_range_eq_can_fail_by_inequality() { + assert_range_eq!([0, 1, 2], 0..2, [0, 1, 2]); + } + + // Test cases for bad index operations. + // + // This generates `should_panic` test cases for Index/IndexMut + // and `None` test cases for get/get_mut. + macro_rules! panic_cases { + ($( + mod $case_name:ident { + let DATA: $Data: ty = $data:expr; + + // optional: + // + // a similar input for which DATA[input] succeeds, and the corresponding + // output as an array. This helps validate "critical points" where an + // input range straddles the boundary between valid and invalid. + // (such as the input `len..len`, which is just barely valid) + $( + let GOOD_INPUT = $good:expr; + let GOOD_OUTPUT = $output:expr; + )* + + let BAD_INPUT = $bad:expr; + const EXPECT_MSG = $expect_msg:expr; + + !!generate_tests!! + } + )*) => {$( + mod $case_name { + #[test] + fn pass() { + let mut v: $Data = $data; + + $( assert_range_eq!($data, $good, $output); )* + + { + let v: &[_] = &v; + assert_eq!(v.get($bad), None, "(in None assertion for get)"); + } + + { + let v: &mut [_] = &mut v; + assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)"); + } + } + + #[test] + #[should_panic(expected = $expect_msg)] + fn index_fail() { + let v: $Data = $data; + let v: &[_] = &v; + let _v = &v[$bad]; + } + + #[test] + #[should_panic(expected = $expect_msg)] + fn index_mut_fail() { + let mut v: $Data = $data; + let v: &mut [_] = &mut v; + let _v = &mut v[$bad]; + } + } + )*}; + } + + #[test] + fn simple() { + let v = [0, 1, 2, 3, 4, 5]; + + assert_range_eq!(v, .., [0, 1, 2, 3, 4, 5]); + assert_range_eq!(v, ..2, [0, 1]); + assert_range_eq!(v, ..=1, [0, 1]); + assert_range_eq!(v, 2.., [2, 3, 4, 5]); + assert_range_eq!(v, 1..4, [1, 2, 3]); + assert_range_eq!(v, 1..=3, [1, 2, 3]); + } + + panic_cases! { + mod rangefrom_len { + let DATA: [i32; 6] = [0, 1, 2, 3, 4, 5]; + + let GOOD_INPUT = 6..; + let GOOD_OUTPUT = []; + + let BAD_INPUT = 7..; + const EXPECT_MSG = "but ends at"; // perhaps not ideal + + !!generate_tests!! + } + + mod rangeto_len { + let DATA: [i32; 6] = [0, 1, 2, 3, 4, 5]; + + let GOOD_INPUT = ..6; + let GOOD_OUTPUT = [0, 1, 2, 3, 4, 5]; + + let BAD_INPUT = ..7; + const EXPECT_MSG = "out of range"; + + !!generate_tests!! + } + + mod rangetoinclusive_len { + let DATA: [i32; 6] = [0, 1, 2, 3, 4, 5]; + + let GOOD_INPUT = ..=5; + let GOOD_OUTPUT = [0, 1, 2, 3, 4, 5]; + + let BAD_INPUT = ..=6; + const EXPECT_MSG = "out of range"; + + !!generate_tests!! + } + + mod range_len_len { + let DATA: [i32; 6] = [0, 1, 2, 3, 4, 5]; + + let GOOD_INPUT = 6..6; + let GOOD_OUTPUT = []; + + let BAD_INPUT = 7..7; + const EXPECT_MSG = "out of range"; + + !!generate_tests!! + } + + mod rangeinclusive_len_len{ + let DATA: [i32; 6] = [0, 1, 2, 3, 4, 5]; + + let GOOD_INPUT = 6..=5; + let GOOD_OUTPUT = []; + + let BAD_INPUT = 7..=6; + const EXPECT_MSG = "out of range"; + + !!generate_tests!! + } } + + panic_cases! { + mod range_neg_width { + let DATA: [i32; 6] = [0, 1, 2, 3, 4, 5]; + + let GOOD_INPUT = 4..4; + let GOOD_OUTPUT = []; + + let BAD_INPUT = 4..3; + const EXPECT_MSG = "but ends at"; + + !!generate_tests!! + } + + mod rangeinclusive_neg_width { + let DATA: [i32; 6] = [0, 1, 2, 3, 4, 5]; + + let GOOD_INPUT = 4..=3; + let GOOD_OUTPUT = []; + + let BAD_INPUT = 4..=2; + const EXPECT_MSG = "but ends at"; + + !!generate_tests!! + } + } + + panic_cases! { + mod rangeinclusive_overflow { + let DATA: [i32; 2] = [0, 1]; + + // note: using 0 specifically ensures that the result of overflowing is 0..0, + // so that `get` doesn't simply return None for the wrong reason. + let BAD_INPUT = 0 ..= ::std::usize::MAX; + const EXPECT_MSG = "maximum usize"; + + !!generate_tests!! + } + + mod rangetoinclusive_overflow { + let DATA: [i32; 2] = [0, 1]; + + let BAD_INPUT = ..= ::std::usize::MAX; + const EXPECT_MSG = "maximum usize"; + + !!generate_tests!! + } + } // panic_cases! } #[test] -- cgit 1.4.1-3-g733a5 From fba903a435ea6e0e3736541cb487586262835e48 Mon Sep 17 00:00:00 2001 From: kennytm Date: Fri, 6 Apr 2018 02:03:22 +0800 Subject: Make the fields of RangeInclusive private. Added new()/start()/end() methods to RangeInclusive. Changed the lowering of `..=` to use RangeInclusive::new(). --- src/liballoc/lib.rs | 2 +- src/liballoc/tests/lib.rs | 2 +- src/libcore/ops/range.rs | 60 +++++++++++++++++++++++++++++++++++++++++++- src/libcore/tests/lib.rs | 2 +- src/librustc/hir/lowering.rs | 16 +++++++++++- src/librustc_trans/lib.rs | 2 +- 6 files changed, 78 insertions(+), 6 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 021395d0c82..c94fe2a2f83 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -122,7 +122,7 @@ #![feature(on_unimplemented)] #![feature(exact_chunks)] #![feature(pointer_methods)] -#![feature(inclusive_range_fields)] +#![feature(inclusive_range_methods)] #![cfg_attr(stage0, feature(generic_param_attrs))] #![cfg_attr(not(test), feature(fn_traits, i128))] diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 32272169307..1c8ff316e55 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -25,7 +25,7 @@ #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(exact_chunks)] -#![feature(inclusive_range_fields)] +#![feature(inclusive_range_methods)] extern crate alloc_system; extern crate core; diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index d70f7ae66f9..c1bd1ef2d1d 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -320,7 +320,7 @@ impl> RangeTo { /// ``` /// #![feature(inclusive_range_fields)] /// -/// assert_eq!((3..=5), std::ops::RangeInclusive { start: 3, end: 5 }); +/// assert_eq!((3..=5), std::ops::RangeInclusive::new(3, 5)); /// assert_eq!(3 + 4 + 5, (3..=5).sum()); /// /// let arr = [0, 1, 2, 3]; @@ -331,14 +331,72 @@ impl> RangeTo { #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeInclusive { + // FIXME: The current representation follows RFC 1980, + // but it is known that LLVM is not able to optimize loops following that RFC. + // Consider adding an extra `bool` field to indicate emptiness of the range. + // See #45222 for performance test cases. + #[cfg(not(stage0))] + pub(crate) start: Idx, + #[cfg(not(stage0))] + pub(crate) end: Idx, /// The lower bound of the range (inclusive). + #[cfg(stage0)] #[unstable(feature = "inclusive_range_fields", issue = "49022")] pub start: Idx, /// The upper bound of the range (inclusive). + #[cfg(stage0)] #[unstable(feature = "inclusive_range_fields", issue = "49022")] pub end: Idx, } +impl RangeInclusive { + /// Creates a new inclusive range. Equivalent to writing `start..=end`. + /// + /// # Examples + /// + /// ``` + /// #![feature(inclusive_range_methods)] + /// use std::ops::RangeInclusive; + /// + /// assert_eq!(3..=5, RangeInclusive::new(3, 5)); + /// ``` + #[unstable(feature = "inclusive_range_methods", issue = "49022")] + #[inline] + pub fn new(start: Idx, end: Idx) -> Self { + Self { start, end } + } + + /// Returns the lower bound of the range (inclusive). + /// + /// # Examples + /// + /// ``` + /// #![feature(inclusive_range_methods)] + /// + /// assert_eq!((3..=5).start(), &3); + /// ``` + #[unstable(feature = "inclusive_range_methods", issue = "49022")] + #[inline] + pub fn start(&self) -> &Idx { + &self.start + } + + /// Returns the upper bound of the range (inclusive). + /// + /// # Examples + /// + /// ``` + /// #![feature(inclusive_range_methods)] + /// + /// assert_eq!((3..=5).end(), &5); + /// ``` + #[unstable(feature = "inclusive_range_methods", issue = "49022")] + #[inline] + pub fn end(&self) -> &Idx { + &self.end + } +} + #[stable(feature = "inclusive_range", since = "1.26.0")] impl fmt::Debug for RangeInclusive { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index e4d27717938..f6750c590b3 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -44,7 +44,7 @@ #![feature(exact_chunks)] #![cfg_attr(stage0, feature(atomic_nand))] #![feature(reverse_bits)] -#![feature(inclusive_range_fields)] +#![feature(inclusive_range_methods)] #![feature(iterator_find_map)] extern crate core; diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e4b9fc1385d..196f7879980 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3119,6 +3119,20 @@ impl<'a> LoweringContext<'a> { ExprKind::Index(ref el, ref er) => { hir::ExprIndex(P(self.lower_expr(el)), P(self.lower_expr(er))) } + // Desugar `..=` to `std::ops::RangeInclusive::new(, )` + ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => { + // FIXME: Use head_sp directly after RangeInclusive::new() is stabilized in stage0. + let span = self.allow_internal_unstable(CompilerDesugaringKind::DotFill, e.span); + let id = self.lower_node_id(e.id); + let e1 = self.lower_expr(e1); + let e2 = self.lower_expr(e2); + let ty_path = P(self.std_path(span, &["ops", "RangeInclusive"], false)); + let ty = self.ty_path(id, span, hir::QPath::Resolved(None, ty_path)); + let new_seg = P(hir::PathSegment::from_name(Symbol::intern("new"))); + let new_path = hir::QPath::TypeRelative(ty, new_seg); + let new = P(self.expr(span, hir::ExprPath(new_path), ThinVec::new())); + hir::ExprCall(new, hir_vec![e1, e2]) + } ExprKind::Range(ref e1, ref e2, lims) => { use syntax::ast::RangeLimits::*; @@ -3128,7 +3142,7 @@ impl<'a> LoweringContext<'a> { (&None, &Some(..), HalfOpen) => "RangeTo", (&Some(..), &Some(..), HalfOpen) => "Range", (&None, &Some(..), Closed) => "RangeToInclusive", - (&Some(..), &Some(..), Closed) => "RangeInclusive", + (&Some(..), &Some(..), Closed) => unreachable!(), (_, &None, Closed) => self.diagnostic() .span_fatal(e.span, "inclusive range with no end") .raise(), diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 96a10e8b99d..9259fef279f 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -29,7 +29,7 @@ #![feature(rustc_diagnostic_macros)] #![feature(slice_sort_by_cached_key)] #![feature(optin_builtin_traits)] -#![feature(inclusive_range_fields)] +#![feature(inclusive_range_methods)] use rustc::dep_graph::WorkProduct; use syntax_pos::symbol::Symbol; -- cgit 1.4.1-3-g733a5 From 030aa9b112b5b52207186b375d9fc09607bbed48 Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Mon, 30 Apr 2018 07:37:29 -0400 Subject: revise macro in slice tests --- src/libcore/tests/slice.rs | 154 ++++++++++++++++++--------------------------- 1 file changed, 62 insertions(+), 92 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 5272c7427d9..d2bda65de55 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -376,9 +376,12 @@ fn test_windows_zip() { assert_eq!(res, [14, 18, 22, 26]); } +// The current implementation of SliceIndex fails to handle methods +// orthogonally from range types; therefore, it is worth testing +// all of the indexing operations on each input. mod slice_index { - // Test a slicing operation that should succeed, - // testing it on all of the indexing methods. + // This checks all six indexing methods, given an input range that + // should succeed. (it is NOT suitable for testing invalid inputs) macro_rules! assert_range_eq { ($arr:expr, $range:expr, $expected:expr) => { @@ -423,7 +426,7 @@ mod slice_index { // because if it can't, then what are we even doing here? // // (Be aware this only demonstrates the ability to detect bugs - // in the FIRST method it calls, as the macro is not designed + // in the FIRST method that panics, as the macro is not designed // to be used in `should_panic`) #[test] #[should_panic(expected = "out of range")] @@ -446,30 +449,29 @@ mod slice_index { // and `None` test cases for get/get_mut. macro_rules! panic_cases { ($( - mod $case_name:ident { - let DATA: $Data: ty = $data:expr; + // each test case needs a unique name to namespace the tests + in mod $case_name:ident { + data: $data:expr; // optional: // - // a similar input for which DATA[input] succeeds, and the corresponding - // output as an array. This helps validate "critical points" where an - // input range straddles the boundary between valid and invalid. + // one or more similar inputs for which data[input] succeeds, + // and the corresponding output as an array. This helps validate + // "critical points" where an input range straddles the boundary + // between valid and invalid. // (such as the input `len..len`, which is just barely valid) $( - let GOOD_INPUT = $good:expr; - let GOOD_OUTPUT = $output:expr; + good: data[$good:expr] == $output:expr; )* - let BAD_INPUT = $bad:expr; - const EXPECT_MSG = $expect_msg:expr; - - !!generate_tests!! + bad: data[$bad:expr]; + message: $expect_msg:expr; } )*) => {$( mod $case_name { #[test] fn pass() { - let mut v: $Data = $data; + let mut v = $data; $( assert_range_eq!($data, $good, $output); )* @@ -487,7 +489,7 @@ mod slice_index { #[test] #[should_panic(expected = $expect_msg)] fn index_fail() { - let v: $Data = $data; + let v = $data; let v: &[_] = &v; let _v = &v[$bad]; } @@ -495,7 +497,7 @@ mod slice_index { #[test] #[should_panic(expected = $expect_msg)] fn index_mut_fail() { - let mut v: $Data = $data; + let mut v = $data; let v: &mut [_] = &mut v; let _v = &mut v[$bad]; } @@ -516,112 +518,80 @@ mod slice_index { } panic_cases! { - mod rangefrom_len { - let DATA: [i32; 6] = [0, 1, 2, 3, 4, 5]; - - let GOOD_INPUT = 6..; - let GOOD_OUTPUT = []; + in mod rangefrom_len { + data: [0, 1, 2, 3, 4, 5]; - let BAD_INPUT = 7..; - const EXPECT_MSG = "but ends at"; // perhaps not ideal - - !!generate_tests!! + good: data[6..] == []; + bad: data[7..]; + message: "but ends at"; // perhaps not ideal } - mod rangeto_len { - let DATA: [i32; 6] = [0, 1, 2, 3, 4, 5]; - - let GOOD_INPUT = ..6; - let GOOD_OUTPUT = [0, 1, 2, 3, 4, 5]; + in mod rangeto_len { + data: [0, 1, 2, 3, 4, 5]; - let BAD_INPUT = ..7; - const EXPECT_MSG = "out of range"; - - !!generate_tests!! + good: data[..6] == [0, 1, 2, 3, 4, 5]; + bad: data[..7]; + message: "out of range"; } - mod rangetoinclusive_len { - let DATA: [i32; 6] = [0, 1, 2, 3, 4, 5]; - - let GOOD_INPUT = ..=5; - let GOOD_OUTPUT = [0, 1, 2, 3, 4, 5]; + in mod rangetoinclusive_len { + data: [0, 1, 2, 3, 4, 5]; - let BAD_INPUT = ..=6; - const EXPECT_MSG = "out of range"; - - !!generate_tests!! + good: data[..=5] == [0, 1, 2, 3, 4, 5]; + bad: data[..=6]; + message: "out of range"; } - mod range_len_len { - let DATA: [i32; 6] = [0, 1, 2, 3, 4, 5]; - - let GOOD_INPUT = 6..6; - let GOOD_OUTPUT = []; + in mod range_len_len { + data: [0, 1, 2, 3, 4, 5]; - let BAD_INPUT = 7..7; - const EXPECT_MSG = "out of range"; - - !!generate_tests!! + good: data[6..6] == []; + bad: data[7..7]; + message: "out of range"; } - mod rangeinclusive_len_len{ - let DATA: [i32; 6] = [0, 1, 2, 3, 4, 5]; - - let GOOD_INPUT = 6..=5; - let GOOD_OUTPUT = []; - - let BAD_INPUT = 7..=6; - const EXPECT_MSG = "out of range"; + in mod rangeinclusive_len_len { + data: [0, 1, 2, 3, 4, 5]; - !!generate_tests!! + good: data[6..=5] == []; + bad: data[7..=6]; + message: "out of range"; } } panic_cases! { - mod range_neg_width { - let DATA: [i32; 6] = [0, 1, 2, 3, 4, 5]; - - let GOOD_INPUT = 4..4; - let GOOD_OUTPUT = []; - - let BAD_INPUT = 4..3; - const EXPECT_MSG = "but ends at"; + in mod range_neg_width { + data: [0, 1, 2, 3, 4, 5]; - !!generate_tests!! + good: data[4..4] == []; + bad: data[4..3]; + message: "but ends at"; } - mod rangeinclusive_neg_width { - let DATA: [i32; 6] = [0, 1, 2, 3, 4, 5]; + in mod rangeinclusive_neg_width { + data: [0, 1, 2, 3, 4, 5]; - let GOOD_INPUT = 4..=3; - let GOOD_OUTPUT = []; - - let BAD_INPUT = 4..=2; - const EXPECT_MSG = "but ends at"; - - !!generate_tests!! + good: data[4..=3] == []; + bad: data[4..=2]; + message: "but ends at"; } } panic_cases! { - mod rangeinclusive_overflow { - let DATA: [i32; 2] = [0, 1]; + in mod rangeinclusive_overflow { + data: [0, 1]; // note: using 0 specifically ensures that the result of overflowing is 0..0, // so that `get` doesn't simply return None for the wrong reason. - let BAD_INPUT = 0 ..= ::std::usize::MAX; - const EXPECT_MSG = "maximum usize"; - - !!generate_tests!! + bad: data[0 ..= ::std::usize::MAX]; + message: "maximum usize"; } - mod rangetoinclusive_overflow { - let DATA: [i32; 2] = [0, 1]; - - let BAD_INPUT = ..= ::std::usize::MAX; - const EXPECT_MSG = "maximum usize"; + in mod rangetoinclusive_overflow { + data: [0, 1]; - !!generate_tests!! + bad: data[..= ::std::usize::MAX]; + message: "maximum usize"; } } // panic_cases! } -- cgit 1.4.1-3-g733a5 From c916ee8511339dd231d90d7fe6be2cc6995284b9 Mon Sep 17 00:00:00 2001 From: kennytm Date: Fri, 6 Apr 2018 05:21:47 +0800 Subject: Removed direct field usage of RangeInclusive in rustc itself. --- src/libcore/lib.rs | 1 + src/libcore/ops/range.rs | 2 +- src/libcore/tests/ops.rs | 8 +++--- src/librustc/lib.rs | 2 +- src/librustc/ty/layout.rs | 44 ++++++++++++++---------------- src/librustc_mir/interpret/eval_context.rs | 6 ++-- src/librustc_mir/lib.rs | 2 +- src/librustc_target/abi/mod.rs | 4 +-- src/librustc_target/lib.rs | 2 +- src/librustc_trans/abi.rs | 4 +-- src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/mir/place.rs | 12 ++++---- src/librustc_trans/mir/rvalue.rs | 4 +-- 13 files changed, 45 insertions(+), 48 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 0e21a3327fd..5a6e0050835 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -103,6 +103,7 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(doc_alias)] +#![feature(inclusive_range_methods)] #![cfg_attr(not(stage0), feature(mmx_target_feature))] #![cfg_attr(not(stage0), feature(tbm_target_feature))] diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index c1bd1ef2d1d..59ee40fdda4 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -318,7 +318,7 @@ impl> RangeTo { /// # Examples /// /// ``` -/// #![feature(inclusive_range_fields)] +/// #![feature(inclusive_range_methods)] /// /// assert_eq!((3..=5), std::ops::RangeInclusive::new(3, 5)); /// assert_eq!(3 + 4 + 5, (3..=5).sum()); diff --git a/src/libcore/tests/ops.rs b/src/libcore/tests/ops.rs index bed08f86d72..d66193b1687 100644 --- a/src/libcore/tests/ops.rs +++ b/src/libcore/tests/ops.rs @@ -50,21 +50,21 @@ fn test_full_range() { #[test] fn test_range_inclusive() { - let mut r = RangeInclusive { start: 1i8, end: 2 }; + let mut r = RangeInclusive::new(1i8, 2); assert_eq!(r.next(), Some(1)); assert_eq!(r.next(), Some(2)); assert_eq!(r.next(), None); - r = RangeInclusive { start: 127i8, end: 127 }; + r = RangeInclusive::new(127i8, 127); assert_eq!(r.next(), Some(127)); assert_eq!(r.next(), None); - r = RangeInclusive { start: -128i8, end: -128 }; + r = RangeInclusive::new(-128i8, -128); assert_eq!(r.next_back(), Some(-128)); assert_eq!(r.next_back(), None); // degenerate - r = RangeInclusive { start: 1, end: -1 }; + r = RangeInclusive::new(1, -1); assert_eq!(r.size_hint(), (0, Some(0))); assert_eq!(r.next(), None); } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 24892dfcc8f..9dc9fb1144e 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -69,7 +69,7 @@ #![feature(trusted_len)] #![feature(catch_expr)] #![feature(test)] -#![feature(inclusive_range_fields)] +#![feature(inclusive_range_methods)] #![recursion_limit="512"] diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 55137e28911..47b52cacd56 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -19,7 +19,6 @@ use std::cmp; use std::fmt; use std::i128; use std::mem; -use std::ops::RangeInclusive; use ich::StableHashingContext; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, @@ -492,7 +491,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { ty::TyFloat(FloatTy::F64) => scalar(F64), ty::TyFnPtr(_) => { let mut ptr = scalar_unit(Pointer); - ptr.valid_range.start = 1; + ptr.valid_range = 1..=*ptr.valid_range.end(); tcx.intern_layout(LayoutDetails::scalar(self, ptr)) } @@ -506,7 +505,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { let mut data_ptr = scalar_unit(Pointer); if !ty.is_unsafe_ptr() { - data_ptr.valid_range.start = 1; + data_ptr.valid_range = 1..=*data_ptr.valid_range.end(); } let pointee = tcx.normalize_erasing_regions(param_env, pointee); @@ -524,7 +523,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } ty::TyDynamic(..) => { let mut vtable = scalar_unit(Pointer); - vtable.valid_range.start = 1; + vtable.valid_range = 1..=*vtable.valid_range.end(); vtable } _ => return Err(LayoutError::Unknown(unsized_part)) @@ -751,8 +750,8 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { match st.abi { Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { - if scalar.valid_range.start == 0 { - scalar.valid_range.start = 1; + if *scalar.valid_range.start() == 0 { + scalar.valid_range = 1..=*scalar.valid_range.end(); } } _ => {} @@ -788,18 +787,15 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } } } - if niche_variants.start > v { - niche_variants.start = v; - } - niche_variants.end = v; + niche_variants = *niche_variants.start().min(&v)..=v; } - if niche_variants.start > niche_variants.end { + if niche_variants.start() > niche_variants.end() { dataful_variant = None; } if let Some(i) = dataful_variant { - let count = (niche_variants.end - niche_variants.start + 1) as u128; + let count = (niche_variants.end() - niche_variants.start() + 1) as u128; for (field_index, &field) in variants[i].iter().enumerate() { let (offset, niche, niche_start) = match self.find_niche(field, count)? { @@ -1659,10 +1655,10 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let max_value = !0u128 >> (128 - bits); // Find out how many values are outside the valid range. - let niches = if v.start <= v.end { - v.start + (max_value - v.end) + let niches = if v.start() <= v.end() { + v.start() + (max_value - v.end()) } else { - v.start - v.end - 1 + v.start() - v.end() - 1 }; // Give up if we can't fit `count` consecutive niches. @@ -1670,11 +1666,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { return None; } - let niche_start = v.end.wrapping_add(1) & max_value; - let niche_end = v.end.wrapping_add(count) & max_value; + let niche_start = v.end().wrapping_add(1) & max_value; + let niche_end = v.end().wrapping_add(count) & max_value; Some((offset, Scalar { value, - valid_range: v.start..=niche_end + valid_range: *v.start()..=niche_end }, niche_start)) }; @@ -1744,14 +1740,14 @@ impl<'a> HashStable> for Variants { } NicheFilling { dataful_variant, - niche_variants: RangeInclusive { start, end }, + ref niche_variants, ref niche, niche_start, ref variants, } => { dataful_variant.hash_stable(hcx, hasher); - start.hash_stable(hcx, hasher); - end.hash_stable(hcx, hasher); + niche_variants.start().hash_stable(hcx, hasher); + niche_variants.end().hash_stable(hcx, hasher); niche.hash_stable(hcx, hasher); niche_start.hash_stable(hcx, hasher); variants.hash_stable(hcx, hasher); @@ -1814,10 +1810,10 @@ impl<'a> HashStable> for Scalar { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let Scalar { value, valid_range: RangeInclusive { start, end } } = *self; + let Scalar { value, ref valid_range } = *self; value.hash_stable(hcx, hasher); - start.hash_stable(hcx, hasher); - end.hash_stable(hcx, hasher); + valid_range.start().hash_stable(hcx, hasher); + valid_range.end().hash_stable(hcx, hasher); } } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index f6e9994b5da..c8cebf8328d 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -917,8 +917,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M niche_start, .. } => { - let variants_start = niche_variants.start as u128; - let variants_end = niche_variants.end as u128; + let variants_start = *niche_variants.start() as u128; + let variants_end = *niche_variants.end() as u128; match raw_discr { PrimVal::Ptr(_) => { assert!(niche_start == 0); @@ -984,7 +984,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M if variant_index != dataful_variant { let (niche_dest, niche) = self.place_field(dest, mir::Field::new(0), layout)?; - let niche_value = ((variant_index - niche_variants.start) as u128) + let niche_value = ((variant_index - niche_variants.start()) as u128) .wrapping_add(niche_start); self.write_primval(niche_dest, PrimVal::Bytes(niche_value), niche.ty)?; } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 75b7a10097d..a6dc4c74f36 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -31,7 +31,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(range_contains)] #![feature(rustc_diagnostic_macros)] #![feature(nonzero)] -#![feature(inclusive_range_fields)] +#![feature(inclusive_range_methods)] #![feature(crate_visibility_modifier)] #![feature(never_type)] #![cfg_attr(stage0, feature(try_trait))] diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 346e5667a7b..f73085196f4 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -555,8 +555,8 @@ impl Scalar { let bits = self.value.size(cx).bits(); assert!(bits <= 128); let mask = !0u128 >> (128 - bits); - let start = self.valid_range.start; - let end = self.valid_range.end; + let start = *self.valid_range.start(); + let end = *self.valid_range.end(); assert_eq!(start, start & mask); assert_eq!(end, end & mask); start..(end.wrapping_add(1) & mask) diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs index 927d5c7e15a..45f2ee13bbd 100644 --- a/src/librustc_target/lib.rs +++ b/src/librustc_target/lib.rs @@ -29,7 +29,7 @@ #![feature(const_fn)] #![feature(fs_read_write)] #![feature(inclusive_range)] -#![feature(inclusive_range_fields)] +#![feature(inclusive_range_methods)] #![feature(slice_patterns)] #[macro_use] diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 1d0d7ec601f..1838dae049a 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -388,8 +388,8 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { return; } - if scalar.valid_range.start < scalar.valid_range.end { - if scalar.valid_range.start > 0 { + if scalar.valid_range.start() < scalar.valid_range.end() { + if *scalar.valid_range.start() > 0 { attrs.set(ArgAttribute::NonNull); } } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 123b9cf7931..2fc6c9d4433 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1236,7 +1236,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { self.layout, self.layout.fields.offset(0), self.layout.field(cx, 0).size); - name.push_str(&adt.variants[niche_variants.start].name.as_str()); + name.push_str(&adt.variants[*niche_variants.start()].name.as_str()); // Create the (singleton) list of descriptions of union members. vec![ diff --git a/src/librustc_trans/mir/place.rs b/src/librustc_trans/mir/place.rs index 8532c0b149d..79859aee64d 100644 --- a/src/librustc_trans/mir/place.rs +++ b/src/librustc_trans/mir/place.rs @@ -99,7 +99,7 @@ impl<'a, 'tcx> PlaceRef<'tcx> { bx.range_metadata(load, range); } } - layout::Pointer if vr.start < vr.end && !vr.contains(&0) => { + layout::Pointer if vr.start() < vr.end() && !vr.contains(&0) => { bx.nonnull_metadata(load); } _ => {} @@ -287,7 +287,7 @@ impl<'a, 'tcx> PlaceRef<'tcx> { .. } => { let niche_llty = discr.layout.immediate_llvm_type(bx.cx); - if niche_variants.start == niche_variants.end { + if niche_variants.start() == niche_variants.end() { // FIXME(eddyb) Check the actual primitive type here. let niche_llval = if niche_start == 0 { // HACK(eddyb) Using `C_null` as it works on all types. @@ -296,13 +296,13 @@ impl<'a, 'tcx> PlaceRef<'tcx> { C_uint_big(niche_llty, niche_start) }; bx.select(bx.icmp(llvm::IntEQ, lldiscr, niche_llval), - C_uint(cast_to, niche_variants.start as u64), + C_uint(cast_to, *niche_variants.start() as u64), C_uint(cast_to, dataful_variant as u64)) } else { // Rebase from niche values to discriminant values. - let delta = niche_start.wrapping_sub(niche_variants.start as u128); + let delta = niche_start.wrapping_sub(*niche_variants.start() as u128); let lldiscr = bx.sub(lldiscr, C_uint_big(niche_llty, delta)); - let lldiscr_max = C_uint(niche_llty, niche_variants.end as u64); + let lldiscr_max = C_uint(niche_llty, *niche_variants.end() as u64); bx.select(bx.icmp(llvm::IntULE, lldiscr, lldiscr_max), bx.intcast(lldiscr, cast_to, false), C_uint(cast_to, dataful_variant as u64)) @@ -352,7 +352,7 @@ impl<'a, 'tcx> PlaceRef<'tcx> { let niche = self.project_field(bx, 0); let niche_llty = niche.layout.immediate_llvm_type(bx.cx); - let niche_value = ((variant_index - niche_variants.start) as u128) + let niche_value = ((variant_index - *niche_variants.start()) as u128) .wrapping_add(niche_start); // FIXME(eddyb) Check the actual primitive type here. let niche_llval = if niche_value == 0 { diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 79e906ca975..4fa54dc276d 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -301,7 +301,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { if let layout::Int(_, s) = scalar.value { signed = s; - if scalar.valid_range.end > scalar.valid_range.start { + if scalar.valid_range.end() > scalar.valid_range.start() { // We want `table[e as usize]` to not // have bound checks, and this is the most // convenient place to put the `assume`. @@ -309,7 +309,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { base::call_assume(&bx, bx.icmp( llvm::IntULE, llval, - C_uint_big(ll_t_in, scalar.valid_range.end) + C_uint_big(ll_t_in, *scalar.valid_range.end()) )); } } -- cgit 1.4.1-3-g733a5 From f70b2ebd08f47c504681ca5f62c3ccdacdd69763 Mon Sep 17 00:00:00 2001 From: kennytm Date: Sat, 7 Apr 2018 14:19:34 +0800 Subject: new() should be const; start()/end() after iteration is unspecified. --- src/libcore/ops/range.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 59ee40fdda4..b01a769eda7 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -362,12 +362,20 @@ impl RangeInclusive { /// ``` #[unstable(feature = "inclusive_range_methods", issue = "49022")] #[inline] - pub fn new(start: Idx, end: Idx) -> Self { + pub const fn new(start: Idx, end: Idx) -> Self { Self { start, end } } /// Returns the lower bound of the range (inclusive). /// + /// When using an inclusive range for iteration, the values of `start()` and + /// [`end()`] are unspecified after the iteration ended. To determine + /// whether the inclusive range is empty, use the [`is_empty()`] method + /// instead of comparing `start() > end()`. + /// + /// [`end()`]: #method.end + /// [`is_empty()`]: #method.is_empty + /// /// # Examples /// /// ``` @@ -383,6 +391,14 @@ impl RangeInclusive { /// Returns the upper bound of the range (inclusive). /// + /// When using an inclusive range for iteration, the values of [`start()`] + /// and `end()` are unspecified after the iteration ended. To determine + /// whether the inclusive range is empty, use the [`is_empty()`] method + /// instead of comparing `start() > end()`. + /// + /// [`start()`]: #method.start + /// [`is_empty()`]: #method.is_empty + /// /// # Examples /// /// ``` -- cgit 1.4.1-3-g733a5 From c025fdebbada2757deccdd97219ff0313631f2ed Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Mon, 30 Apr 2018 12:51:43 -0700 Subject: fixed some and added more tests --- src/libcore/option.rs | 2 +- src/libcore/tests/option.rs | 8 ++ src/libcore/tests/result.rs | 102 +++++++++++++++++---- .../issue-50264-inner-deref-trait/option_deref.rs | 16 ++++ .../issue-50264-inner-deref-trait/result_deref.rs | 16 ++++ .../result_deref_err.rs | 16 ++++ .../result_deref_ok.rs | 16 ++++ 7 files changed, 158 insertions(+), 18 deletions(-) create mode 100644 src/test/compile-fail/issue-50264-inner-deref-trait/option_deref.rs create mode 100644 src/test/compile-fail/issue-50264-inner-deref-trait/result_deref.rs create mode 100644 src/test/compile-fail/issue-50264-inner-deref-trait/result_deref_err.rs create mode 100644 src/test/compile-fail/issue-50264-inner-deref-trait/result_deref_ok.rs (limited to 'src/libcore') diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 506e54ba5e4..deb0380171c 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -878,7 +878,7 @@ impl Option { } } -# [unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] impl Option { /// Converts from `&Option` to `Option<&T::Target>`. /// diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs index e7e48b2daa2..ced7b03636a 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -304,7 +304,15 @@ fn test_option_deref() { let ref_option = &Some(&42); assert_eq!(ref_option.deref(), Some(&42)); + let ref_option = &Some(String::from("a result")); + assert_eq!(ref_option.deref(), Some("a result")); + + let ref_option = &Some(vec![1, 2, 3, 4, 5]); + assert_eq!(ref_option.deref(), Some(&[1, 2, 3, 4, 5][..])); + // None: &Option>::None -> None let ref_option: &Option<&i32> = &None; assert_eq!(ref_option.deref(), None); + + } diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs index dd23467322d..fd0dd21401b 100644 --- a/src/libcore/tests/result.rs +++ b/src/libcore/tests/result.rs @@ -234,21 +234,89 @@ fn test_try() { #[test] fn test_result_deref() { - // Ok(T).deref_ok() -> Result<&T, &E::Deref::Target>::Ok(&T) - let ref_ok: &Result<&i32, &u8> = &Ok(&42); - assert_eq!(ref_ok.deref_ok(), Ok(&42)); - assert_eq!(ref_ok.deref_ok(), Ok(&42)); - assert_eq!(ref_ok.deref(), Ok(&42)); - - // Err(E) -> Result<&T, &E::Deref::Target>::Err(&*E) - let ref_err: &Result<&i32, &u8> = &Err(&41); - assert_eq!(ref_err.deref_err(), Err(&41)); - assert_eq!(ref_err.deref_err(), Err(&41)); - assert_eq!(ref_err.deref(), Err(&41)); - - // &Ok(T).deref_err() -> Result<&T, &E::Deref::Target>::Ok(&T) - assert_eq!(ref_ok.deref_err(), Ok(&&42)); - - // &Err(E) -> Result<&T::Deref::Target, &E>::Err(&E) - assert_eq!(ref_err.deref_ok(), Err(&&41)); + // &Result::Ok(T).deref_ok() -> + // Result<&T::Deref::Target, &E>::Ok(&*T) + let ref_ok = &Result::Ok::<&i32, u8>(&42); + let expected_result = Result::Ok::<&i32, &u8>(&42); + assert_eq!(ref_ok.deref_ok(), expected_result); + + let ref_ok = &Result::Ok::(String::from("a result")); + let expected_result = Result::Ok::<&str, &u32>("a result"); + assert_eq!(ref_ok.deref_ok(), expected_result); + + let ref_ok = &Result::Ok::, u32>(vec![1, 2, 3, 4, 5]); + let expected_result = Result::Ok::<&[i32], &u32>(&[1, 2, 3, 4, 5][..]); + assert_eq!(ref_ok.deref_ok(), expected_result); + + // &Result::Ok(T).deref() -> + // Result<&T::Deref::Target, &E::Deref::Target>::Ok(&*T) + let ref_ok = &Result::Ok::<&i32, &u8>(&42); + let expected_result = Result::Ok::<&i32, &u8>(&42); + assert_eq!(ref_ok.deref(), expected_result); + + let ref_ok = &Result::Ok::(String::from("a result")); + let expected_result = Result::Ok::<&str, &u32>("a result"); + assert_eq!(ref_ok.deref(), expected_result); + + let ref_ok = &Result::Ok::, &u32>(vec![1, 2, 3, 4, 5]); + let expected_result = Result::Ok::<&[i32], &u32>(&[1, 2, 3, 4, 5][..]); + assert_eq!(ref_ok.deref(), expected_result); + + // &Result::Err(T).deref_err() -> + // Result<&T, &E::Deref::Target>::Err(&*E) + let ref_err = &Result::Err::(&41); + let expected_result = Result::Err::<&u8, &i32>(&41); + assert_eq!(ref_err.deref_err(), expected_result); + + let ref_err = &Result::Err::(String::from("an error")); + let expected_result = Result::Err::<&u32, &str>("an error"); + assert_eq!(ref_err.deref_err(), expected_result); + + let ref_err = &Result::Err::>(vec![5, 4, 3, 2, 1]); + let expected_result = Result::Err::<&u32, &[i32]>(&[5, 4, 3, 2, 1][..]); + assert_eq!(ref_err.deref_err(), expected_result); + + // &Result::Err(T).deref_err() -> + // Result<&T, &E::Deref::Target>::Err(&*E) + let ref_err = &Result::Err::<&u8, &i32>(&41); + let expected_result = Result::Err::<&u8, &i32>(&41); + assert_eq!(ref_err.deref(), expected_result); + + let ref_err = &Result::Err::<&u32, String>(String::from("an error")); + let expected_result = Result::Err::<&u32, &str>("an error"); + assert_eq!(ref_err.deref(), expected_result); + + let ref_err = &Result::Err::<&u32, Vec>(vec![5, 4, 3, 2, 1]); + let expected_result = Result::Err::<&u32, &[i32]>(&[5, 4, 3, 2, 1][..]); + assert_eq!(ref_err.deref(), expected_result); + + // *Odd corner cases (tested for completeness)* + + // &Result::Ok(T).deref_err() -> + // Result<&T, &E::Deref::Target>::Ok(&T) + let ref_ok = &Result::Ok::(42); + let expected_result = Result::Ok::<&i32, &u8>(&42); + assert_eq!(ref_ok.deref_err(), expected_result); + + let ref_ok = &Result::Ok::<&str, &u32>("a result"); + let expected_result = Result::Ok::<&&str, &u32>(&"a result"); + assert_eq!(ref_ok.deref_err(), expected_result); + + let ref_ok = &Result::Ok::<[i32; 5], &u32>([1, 2, 3, 4, 5]); + let expected_result = Result::Ok::<&[i32; 5], &u32>(&[1, 2, 3, 4, 5]); + assert_eq!(ref_ok.deref_err(), expected_result); + + // &Result::Err(E).deref_ok() -> + // Result<&T::Deref::Target, &E>::Err(&E) + let ref_err = &Result::Err::<&u8, i32>(41); + let expected_result = Result::Err::<&u8, &i32>(&41); + assert_eq!(ref_err.deref_ok(), expected_result); + + let ref_err = &Result::Err::<&u32, &str>("an error"); + let expected_result = Result::Err::<&u32, &&str>(&"an error"); + assert_eq!(ref_err.deref_ok(), expected_result); + + let ref_err = &Result::Err::<&u32, [i32; 5]>([5, 4, 3, 2, 1]); + let expected_result = Result::Err::<&u32, &[i32; 5]>(&[5, 4, 3, 2, 1]); + assert_eq!(ref_err.deref_ok(), expected_result); } diff --git a/src/test/compile-fail/issue-50264-inner-deref-trait/option_deref.rs b/src/test/compile-fail/issue-50264-inner-deref-trait/option_deref.rs new file mode 100644 index 00000000000..4c67fb3bef1 --- /dev/null +++ b/src/test/compile-fail/issue-50264-inner-deref-trait/option_deref.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(inner_deref)] + +fn main() { + let _result = &Some(42).deref(); +//~^ ERROR no method named `deref` found for type `std::option::Option<{integer}>` +} diff --git a/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref.rs b/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref.rs new file mode 100644 index 00000000000..73bdf0b9209 --- /dev/null +++ b/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(inner_deref)] + +fn main() { + let _result = &Ok(42).deref(); +//~^ ERROR no method named `deref` found +} diff --git a/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref_err.rs b/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref_err.rs new file mode 100644 index 00000000000..5d1e7472d8f --- /dev/null +++ b/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref_err.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(inner_deref)] + +fn main() { + let _result = &Err(41).deref_err(); +//~^ ERROR no method named `deref_err` found +} diff --git a/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref_ok.rs b/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref_ok.rs new file mode 100644 index 00000000000..bee8e0c062b --- /dev/null +++ b/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref_ok.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(inner_deref)] + +fn main() { + let _result = &Ok(42).deref_ok(); +//~^ ERROR no method named `deref_ok` found +} -- cgit 1.4.1-3-g733a5 From f29e62aadf9efa961b3da9d960fb35f748aed0d5 Mon Sep 17 00:00:00 2001 From: Vadzim Dambrouski Date: Tue, 1 May 2018 17:48:31 +0300 Subject: Fix a warning in libcore on 16bit targets. This code is assuming that usize >= 32bits, but it is not the case on 16bit targets. It is producing a warning that will fail the compilation on MSP430 if deny(warnings) is enabled. It is very unlikely that someone would actually use this code on a microcontroller, but since unicode was merged into libcore we have compile it on 16bit targets. --- src/libcore/unicode/bool_trie.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/unicode/bool_trie.rs b/src/libcore/unicode/bool_trie.rs index 3e45b08f399..0e6437fded5 100644 --- a/src/libcore/unicode/bool_trie.rs +++ b/src/libcore/unicode/bool_trie.rs @@ -42,15 +42,15 @@ pub struct BoolTrie { } impl BoolTrie { pub fn lookup(&self, c: char) -> bool { - let c = c as usize; + let c = c as u32; if c < 0x800 { - trie_range_leaf(c, self.r1[c >> 6]) + trie_range_leaf(c, self.r1[(c >> 6) as usize]) } else if c < 0x10000 { - let child = self.r2[(c >> 6) - 0x20]; + let child = self.r2[(c >> 6) as usize - 0x20]; trie_range_leaf(c, self.r3[child as usize]) } else { - let child = self.r4[(c >> 12) - 0x10]; - let leaf = self.r5[((child as usize) << 6) + ((c >> 6) & 0x3f)]; + let child = self.r4[(c >> 12) as usize - 0x10]; + let leaf = self.r5[((child as usize) << 6) + ((c >> 6) as usize & 0x3f)]; trie_range_leaf(c, self.r6[leaf as usize]) } } @@ -63,14 +63,14 @@ pub struct SmallBoolTrie { impl SmallBoolTrie { pub fn lookup(&self, c: char) -> bool { - let c = c as usize; - match self.r1.get(c >> 6) { + let c = c as u32; + match self.r1.get((c >> 6) as usize) { Some(&child) => trie_range_leaf(c, self.r2[child as usize]), None => false, } } } -fn trie_range_leaf(c: usize, bitmap_chunk: u64) -> bool { +fn trie_range_leaf(c: u32, bitmap_chunk: u64) -> bool { ((bitmap_chunk >> (c & 63)) & 1) != 0 } -- cgit 1.4.1-3-g733a5 From 1cefb5ce310fe7f799d0926d2644a25a567d2ddb Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 2 May 2018 23:53:40 +0200 Subject: nano-optimization for memchr::repeat_byte --- src/libcore/slice/memchr.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/memchr.rs b/src/libcore/slice/memchr.rs index 69c9cb37dcf..469404f7f6b 100644 --- a/src/libcore/slice/memchr.rs +++ b/src/libcore/slice/memchr.rs @@ -39,21 +39,10 @@ fn repeat_byte(b: u8) -> usize { (b as usize) << 8 | b as usize } -#[cfg(target_pointer_width = "32")] +#[cfg(not(target_pointer_width = "16"))] #[inline] fn repeat_byte(b: u8) -> usize { - let mut rep = (b as usize) << 8 | b as usize; - rep = rep << 16 | rep; - rep -} - -#[cfg(target_pointer_width = "64")] -#[inline] -fn repeat_byte(b: u8) -> usize { - let mut rep = (b as usize) << 8 | b as usize; - rep = rep << 16 | rep; - rep = rep << 32 | rep; - rep + (b as usize) * (::usize::MAX / 255) } /// Return the first index matching the byte `x` in `text`. -- cgit 1.4.1-3-g733a5 From e1d5509bf381d978a1894b6ba869c3b56dd3eeca Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Wed, 2 May 2018 19:16:29 -0700 Subject: Added comments providing justification for support of calling deref_* with wrong variant --- src/libcore/tests/result.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs index fd0dd21401b..f8b5ea5e16e 100644 --- a/src/libcore/tests/result.rs +++ b/src/libcore/tests/result.rs @@ -290,7 +290,11 @@ fn test_result_deref() { let expected_result = Result::Err::<&u32, &[i32]>(&[5, 4, 3, 2, 1][..]); assert_eq!(ref_err.deref(), expected_result); - // *Odd corner cases (tested for completeness)* + // The following cases test calling deref_* with the wrong variant (i.e. + // `deref_ok()` with a `Result::Err()`, or `deref_err()` with a `Result::Ok()`. + // While unusual, these cases are supported to ensure that an `inner_deref` + // call can still be made even when one of the Result types does not implement + // `Deref` (for example, std::io::Error). // &Result::Ok(T).deref_err() -> // Result<&T, &E::Deref::Target>::Ok(&T) -- cgit 1.4.1-3-g733a5 From 8e38d02d986a5fa5ef51b6995058d7327aa0da4b Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Thu, 3 May 2018 06:49:30 -0400 Subject: update concat_idents doc stubs --- src/libcore/macros.rs | 4 ++-- src/libstd/macros.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index f9371ed0575..c830c22ee5f 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -606,8 +606,8 @@ mod builtin { #[macro_export] #[cfg(dox)] macro_rules! concat_idents { - ($($e:ident),*) => ({ /* compiler built-in */ }); - ($($e:ident,)*) => ({ /* compiler built-in */ }); + ($($e:ident),+) => ({ /* compiler built-in */ }); + ($($e:ident,)+) => ({ /* compiler built-in */ }); } /// Concatenates literals into a static string slice. diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 6902ec82047..d1274a40900 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -450,8 +450,8 @@ pub mod builtin { #[unstable(feature = "concat_idents_macro", issue = "29599")] #[macro_export] macro_rules! concat_idents { - ($($e:ident),*) => ({ /* compiler built-in */ }); - ($($e:ident,)*) => ({ /* compiler built-in */ }); + ($($e:ident),+) => ({ /* compiler built-in */ }); + ($($e:ident,)+) => ({ /* compiler built-in */ }); } /// Concatenates literals into a static string slice. -- cgit 1.4.1-3-g733a5 From 1e38eee63b0a0a3429a59dd756c852116b4d3615 Mon Sep 17 00:00:00 2001 From: Kornel Date: Fri, 4 May 2018 12:43:52 +0100 Subject: Suggest more helpful formatting string --- src/libcore/fmt/mod.rs | 11 ++++++----- src/test/ui/on-unimplemented/no-debug.stderr | 11 +++++++---- 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 99e3012c9bf..5820fe58932 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -542,10 +542,10 @@ impl<'a> Display for Arguments<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( - on(crate_local, label="`{Self}` cannot be formatted using `:?`; \ - add `#[derive(Debug)]` or manually implement `{Debug}`"), + on(crate_local, label="`{Self}` cannot be formatted using `{{:?}}`", + note="add `#[derive(Debug)]` or manually implement `{Debug}`"), message="`{Self}` doesn't implement `{Debug}`", - label="`{Self}` cannot be formatted using `:?` because it doesn't implement `{Debug}`", + label="`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{Debug}`", )] #[doc(alias = "{:?}")] #[lang = "debug_trait"] @@ -610,8 +610,9 @@ pub trait Debug { /// ``` #[rustc_on_unimplemented( message="`{Self}` doesn't implement `{Display}`", - label="`{Self}` cannot be formatted with the default formatter; \ - try using `:?` instead if you are using a format string", + label="`{Self}` cannot be formatted with the default formatter", + note="in format strings you may be able to use `{{:?}}` \ + (or {{:#?}} for pretty-print) instead", )] #[doc(alias = "{}")] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/ui/on-unimplemented/no-debug.stderr b/src/test/ui/on-unimplemented/no-debug.stderr index 5d8f80e57b0..275cd91a435 100644 --- a/src/test/ui/on-unimplemented/no-debug.stderr +++ b/src/test/ui/on-unimplemented/no-debug.stderr @@ -2,16 +2,17 @@ error[E0277]: `Foo` doesn't implement `std::fmt::Debug` --> $DIR/no-debug.rs:20:27 | LL | println!("{:?} {:?}", Foo, Bar); - | ^^^ `Foo` cannot be formatted using `:?`; add `#[derive(Debug)]` or manually implement `std::fmt::Debug` + | ^^^ `Foo` cannot be formatted using `{:?}` | = help: the trait `std::fmt::Debug` is not implemented for `Foo` + = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` = note: required by `std::fmt::Debug::fmt` error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Debug` --> $DIR/no-debug.rs:20:32 | LL | println!("{:?} {:?}", Foo, Bar); - | ^^^ `no_debug::Bar` cannot be formatted using `:?` because it doesn't implement `std::fmt::Debug` + | ^^^ `no_debug::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `no_debug::Bar` = note: required by `std::fmt::Debug::fmt` @@ -20,18 +21,20 @@ error[E0277]: `Foo` doesn't implement `std::fmt::Display` --> $DIR/no-debug.rs:21:23 | LL | println!("{} {}", Foo, Bar); - | ^^^ `Foo` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string + | ^^^ `Foo` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for `Foo` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: required by `std::fmt::Display::fmt` error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Display` --> $DIR/no-debug.rs:21:28 | LL | println!("{} {}", Foo, Bar); - | ^^^ `no_debug::Bar` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string + | ^^^ `no_debug::Bar` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for `no_debug::Bar` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: required by `std::fmt::Display::fmt` error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From 6c8ec842cc2dbd0f4dbf99dbd47717fb48cf5b88 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 5 May 2018 19:45:22 +0200 Subject: Remove some transmutes --- src/libcore/tests/num/flt2dec/random.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/num/flt2dec/random.rs b/src/libcore/tests/num/flt2dec/random.rs index 315ac4d7d99..a1928657dab 100644 --- a/src/libcore/tests/num/flt2dec/random.rs +++ b/src/libcore/tests/num/flt2dec/random.rs @@ -11,7 +11,6 @@ #![cfg(not(target_arch = "wasm32"))] use std::i16; -use std::mem; use std::str; use core::num::flt2dec::MAX_SIG_DIGITS; @@ -75,8 +74,7 @@ pub fn f32_random_equivalence_test(f: F, g: G, k: usize, n: usize) let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); let f32_range = Range::new(0x0000_0001u32, 0x7f80_0000); iterate("f32_random_equivalence_test", k, n, f, g, |_| { - let i: u32 = f32_range.ind_sample(&mut rng); - let x: f32 = unsafe {mem::transmute(i)}; + let x = f32::from_bits(f32_range.ind_sample(&mut rng)); decode_finite(x) }); } @@ -87,8 +85,7 @@ pub fn f64_random_equivalence_test(f: F, g: G, k: usize, n: usize) let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); let f64_range = Range::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000); iterate("f64_random_equivalence_test", k, n, f, g, |_| { - let i: u64 = f64_range.ind_sample(&mut rng); - let x: f64 = unsafe {mem::transmute(i)}; + let x = f64::from_bits(f64_range.ind_sample(&mut rng)); decode_finite(x) }); } @@ -105,7 +102,8 @@ pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e. all finite ranges let (npassed, nignored) = iterate("f32_exhaustive_equivalence_test", k, 0x7f7f_ffff, f, g, |i: usize| { - let x: f32 = unsafe {mem::transmute(i as u32 + 1)}; + + let x = f32::from_bits(i as u32 + 1); decode_finite(x) }); assert_eq!((npassed, nignored), (2121451881, 17643158)); -- cgit 1.4.1-3-g733a5 From 3ddd67ba5356b96806f039e1e8997af63c3a6ee1 Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Tue, 1 May 2018 13:43:05 +0200 Subject: Move libcore/time tests from `time.rs` to `tests/time.rs` All other tests of libcore reside in the tests/ directory, too. Apparently the tests of `time.rs` weren't run before, at least not by `x.py test src/libcore`. --- src/libcore/tests/lib.rs | 1 + src/libcore/tests/time.rs | 122 ++++++++++++++++++++++++++++++++++++++++++++++ src/libcore/time.rs | 116 ------------------------------------------- 3 files changed, 123 insertions(+), 116 deletions(-) create mode 100644 src/libcore/tests/time.rs (limited to 'src/libcore') diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index f6750c590b3..340879c6b85 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -74,4 +74,5 @@ mod result; mod slice; mod str; mod str_lossy; +mod time; mod tuple; diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs new file mode 100644 index 00000000000..9e6f284859c --- /dev/null +++ b/src/libcore/tests/time.rs @@ -0,0 +1,122 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::time::Duration; + +#[test] +fn creation() { + assert!(Duration::from_secs(1) != Duration::from_secs(0)); + assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), + Duration::from_secs(3)); + assert_eq!(Duration::from_millis(10) + Duration::from_secs(4), + Duration::new(4, 10 * 1_000_000)); + assert_eq!(Duration::from_millis(4000), Duration::new(4, 0)); +} + +#[test] +fn secs() { + assert_eq!(Duration::new(0, 0).as_secs(), 0); + assert_eq!(Duration::from_secs(1).as_secs(), 1); + assert_eq!(Duration::from_millis(999).as_secs(), 0); + assert_eq!(Duration::from_millis(1001).as_secs(), 1); +} + +#[test] +fn nanos() { + assert_eq!(Duration::new(0, 0).subsec_nanos(), 0); + assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); + assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); + assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); + assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000); + assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000); +} + +#[test] +fn add() { + assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), + Duration::new(0, 1)); + assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), + Duration::new(1, 1)); +} + +#[test] +fn checked_add() { + assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), + Some(Duration::new(0, 1))); + assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)), + Some(Duration::new(1, 1))); + assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::core::u64::MAX, 0)), None); +} + +#[test] +fn sub() { + assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), + Duration::new(0, 1)); + assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), + Duration::new(0, 1)); + assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), + Duration::new(0, 999_999_999)); +} + +#[test] +fn checked_sub() { + let zero = Duration::new(0, 0); + let one_nano = Duration::new(0, 1); + let one_sec = Duration::new(1, 0); + assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1))); + assert_eq!(one_sec.checked_sub(one_nano), + Some(Duration::new(0, 999_999_999))); + assert_eq!(zero.checked_sub(one_nano), None); + assert_eq!(zero.checked_sub(one_sec), None); +} + +#[test] #[should_panic] +fn sub_bad1() { + Duration::new(0, 0) - Duration::new(0, 1); +} + +#[test] #[should_panic] +fn sub_bad2() { + Duration::new(0, 0) - Duration::new(1, 0); +} + +#[test] +fn mul() { + assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2)); + assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3)); + assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4)); + assert_eq!(Duration::new(0, 500_000_001) * 4000, + Duration::new(2000, 4000)); +} + +#[test] +fn checked_mul() { + assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2))); + assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3))); + assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4))); + assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), + Some(Duration::new(2000, 4000))); + assert_eq!(Duration::new(::core::u64::MAX - 1, 0).checked_mul(2), None); +} + +#[test] +fn div() { + assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); + assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); + assert_eq!(Duration::new(99, 999_999_000) / 100, + Duration::new(0, 999_999_990)); +} + +#[test] +fn checked_div() { + assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); + assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); + assert_eq!(Duration::new(2, 0).checked_div(0), None); +} diff --git a/src/libcore/time.rs b/src/libcore/time.rs index e22fe450bb1..8e8b1691c65 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -481,119 +481,3 @@ impl<'a> Sum<&'a Duration> for Duration { iter.fold(Duration::new(0, 0), |a, b| a + *b) } } - -#[cfg(test)] -mod tests { - use super::Duration; - - #[test] - fn creation() { - assert!(Duration::from_secs(1) != Duration::from_secs(0)); - assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), - Duration::from_secs(3)); - assert_eq!(Duration::from_millis(10) + Duration::from_secs(4), - Duration::new(4, 10 * 1_000_000)); - assert_eq!(Duration::from_millis(4000), Duration::new(4, 0)); - } - - #[test] - fn secs() { - assert_eq!(Duration::new(0, 0).as_secs(), 0); - assert_eq!(Duration::from_secs(1).as_secs(), 1); - assert_eq!(Duration::from_millis(999).as_secs(), 0); - assert_eq!(Duration::from_millis(1001).as_secs(), 1); - } - - #[test] - fn nanos() { - assert_eq!(Duration::new(0, 0).subsec_nanos(), 0); - assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); - assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); - assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); - assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000); - assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000); - } - - #[test] - fn add() { - assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), - Duration::new(0, 1)); - assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), - Duration::new(1, 1)); - } - - #[test] - fn checked_add() { - assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), - Some(Duration::new(0, 1))); - assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)), - Some(Duration::new(1, 1))); - assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None); - } - - #[test] - fn sub() { - assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), - Duration::new(0, 1)); - assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), - Duration::new(0, 1)); - assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), - Duration::new(0, 999_999_999)); - } - - #[test] - fn checked_sub() { - let zero = Duration::new(0, 0); - let one_nano = Duration::new(0, 1); - let one_sec = Duration::new(1, 0); - assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1))); - assert_eq!(one_sec.checked_sub(one_nano), - Some(Duration::new(0, 999_999_999))); - assert_eq!(zero.checked_sub(one_nano), None); - assert_eq!(zero.checked_sub(one_sec), None); - } - - #[test] #[should_panic] - fn sub_bad1() { - Duration::new(0, 0) - Duration::new(0, 1); - } - - #[test] #[should_panic] - fn sub_bad2() { - Duration::new(0, 0) - Duration::new(1, 0); - } - - #[test] - fn mul() { - assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2)); - assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3)); - assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4)); - assert_eq!(Duration::new(0, 500_000_001) * 4000, - Duration::new(2000, 4000)); - } - - #[test] - fn checked_mul() { - assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2))); - assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3))); - assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4))); - assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), - Some(Duration::new(2000, 4000))); - assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None); - } - - #[test] - fn div() { - assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); - assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); - assert_eq!(Duration::new(99, 999_999_000) / 100, - Duration::new(0, 999_999_990)); - } - - #[test] - fn checked_div() { - assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); - assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); - assert_eq!(Duration::new(2, 0).checked_div(0), None); - } -} -- cgit 1.4.1-3-g733a5 From 10ab98da8c8e53ab7b89eff489e09d352522889e Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Tue, 1 May 2018 15:07:15 +0200 Subject: Fix warning in `core::time` tests --- src/libcore/tests/time.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs index 9e6f284859c..042c523f25f 100644 --- a/src/libcore/tests/time.rs +++ b/src/libcore/tests/time.rs @@ -77,14 +77,16 @@ fn checked_sub() { assert_eq!(zero.checked_sub(one_sec), None); } -#[test] #[should_panic] +#[test] +#[should_panic] fn sub_bad1() { - Duration::new(0, 0) - Duration::new(0, 1); + let _ = Duration::new(0, 0) - Duration::new(0, 1); } -#[test] #[should_panic] +#[test] +#[should_panic] fn sub_bad2() { - Duration::new(0, 0) - Duration::new(1, 0); + let _ = Duration::new(0, 0) - Duration::new(1, 0); } #[test] -- cgit 1.4.1-3-g733a5 From 13e07a4e180e964717a0f71f0fc40260bab7d84a Mon Sep 17 00:00:00 2001 From: kennytm Date: Sun, 6 May 2018 00:53:48 +0800 Subject: Move the tests in src/libcore/slice/memchr.rs as well. --- src/libcore/slice/memchr.rs | 82 ------------------------------------------ src/libcore/tests/slice.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 82 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/memchr.rs b/src/libcore/slice/memchr.rs index 469404f7f6b..7b62e7b0620 100644 --- a/src/libcore/slice/memchr.rs +++ b/src/libcore/slice/memchr.rs @@ -135,85 +135,3 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option { // find the byte before the point the body loop stopped text[..offset].iter().rposition(|elt| *elt == x) } - -// test fallback implementations on all platforms -#[test] -fn matches_one() { - assert_eq!(Some(0), memchr(b'a', b"a")); -} - -#[test] -fn matches_begin() { - assert_eq!(Some(0), memchr(b'a', b"aaaa")); -} - -#[test] -fn matches_end() { - assert_eq!(Some(4), memchr(b'z', b"aaaaz")); -} - -#[test] -fn matches_nul() { - assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); -} - -#[test] -fn matches_past_nul() { - assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); -} - -#[test] -fn no_match_empty() { - assert_eq!(None, memchr(b'a', b"")); -} - -#[test] -fn no_match() { - assert_eq!(None, memchr(b'a', b"xyz")); -} - -#[test] -fn matches_one_reversed() { - assert_eq!(Some(0), memrchr(b'a', b"a")); -} - -#[test] -fn matches_begin_reversed() { - assert_eq!(Some(3), memrchr(b'a', b"aaaa")); -} - -#[test] -fn matches_end_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); -} - -#[test] -fn matches_nul_reversed() { - assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); -} - -#[test] -fn matches_past_nul_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); -} - -#[test] -fn no_match_empty_reversed() { - assert_eq!(None, memrchr(b'a', b"")); -} - -#[test] -fn no_match_reversed() { - assert_eq!(None, memrchr(b'a', b"xyz")); -} - -#[test] -fn each_alignment_reversed() { - let mut data = [1u8; 64]; - let needle = 2; - let pos = 40; - data[pos] = needle; - for start in 0..16 { - assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); - } -} diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 53fdfa06827..c81e5e97cbb 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -550,3 +550,89 @@ fn sort_unstable() { v.sort_unstable(); assert!(v == [0xDEADBEEF]); } + +pub mod memchr { + use core::slice::memchr::{memchr, memrchr}; + + // test fallback implementations on all platforms + #[test] + fn matches_one() { + assert_eq!(Some(0), memchr(b'a', b"a")); + } + + #[test] + fn matches_begin() { + assert_eq!(Some(0), memchr(b'a', b"aaaa")); + } + + #[test] + fn matches_end() { + assert_eq!(Some(4), memchr(b'z', b"aaaaz")); + } + + #[test] + fn matches_nul() { + assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); + } + + #[test] + fn matches_past_nul() { + assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); + } + + #[test] + fn no_match_empty() { + assert_eq!(None, memchr(b'a', b"")); + } + + #[test] + fn no_match() { + assert_eq!(None, memchr(b'a', b"xyz")); + } + + #[test] + fn matches_one_reversed() { + assert_eq!(Some(0), memrchr(b'a', b"a")); + } + + #[test] + fn matches_begin_reversed() { + assert_eq!(Some(3), memrchr(b'a', b"aaaa")); + } + + #[test] + fn matches_end_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); + } + + #[test] + fn matches_nul_reversed() { + assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); + } + + #[test] + fn matches_past_nul_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); + } + + #[test] + fn no_match_empty_reversed() { + assert_eq!(None, memrchr(b'a', b"")); + } + + #[test] + fn no_match_reversed() { + assert_eq!(None, memrchr(b'a', b"xyz")); + } + + #[test] + fn each_alignment_reversed() { + let mut data = [1u8; 64]; + let needle = 2; + let pos = 40; + data[pos] = needle; + for start in 0..16 { + assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); + } + } +} -- cgit 1.4.1-3-g733a5 From 02f6a0335f99378b2e7d630e00aabdeb57a5bd25 Mon Sep 17 00:00:00 2001 From: kennytm Date: Sun, 6 May 2018 01:02:05 +0800 Subject: Some final touches to ensure `./x.py test --stage 0 src/lib*` works --- src/libcore/lib.rs | 1 + src/libcore/tests/lib.rs | 1 + src/libcore/tests/num/uint_macros.rs | 1 + src/libstd/lib.rs | 4 ++-- 4 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 04dd42583d4..37f9dcc7e32 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -50,6 +50,7 @@ // Since libcore defines many fundamental lang items, all tests live in a // separate crate, libcoretest, to avoid bizarre issues. +#![cfg(not(test))] #![stable(feature = "core", since = "1.6.0")] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 340879c6b85..5e98e40e0d5 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -46,6 +46,7 @@ #![feature(reverse_bits)] #![feature(inclusive_range_methods)] #![feature(iterator_find_map)] +#![feature(slice_internals)] extern crate core; extern crate test; diff --git a/src/libcore/tests/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs index ca6906f7310..257f6ea20d4 100644 --- a/src/libcore/tests/num/uint_macros.rs +++ b/src/libcore/tests/num/uint_macros.rs @@ -98,6 +98,7 @@ mod tests { } #[test] + #[cfg(not(stage0))] fn test_reverse_bits() { assert_eq!(A.reverse_bits().reverse_bits(), A); assert_eq!(B.reverse_bits().reverse_bits(), B); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index fc05833e285..d41739ab02c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -330,10 +330,10 @@ // with a rustc without jemalloc. // FIXME(#44236) shouldn't need MSVC logic #![cfg_attr(all(not(target_env = "msvc"), - any(stage0, feature = "force_alloc_system")), + any(all(stage0, not(test)), feature = "force_alloc_system")), feature(global_allocator))] #[cfg(all(not(target_env = "msvc"), - any(stage0, feature = "force_alloc_system")))] + any(all(stage0, not(test)), feature = "force_alloc_system")))] #[global_allocator] static ALLOC: alloc_system::System = alloc_system::System; -- cgit 1.4.1-3-g733a5 From 169f58b712e793ea43b90a6008a21b777bf4102f Mon Sep 17 00:00:00 2001 From: kennytm Date: Sun, 6 May 2018 03:29:19 +0800 Subject: Added some simple documentation. --- src/bootstrap/README.md | 4 ++++ src/libcore/lib.rs | 8 ++++++++ 2 files changed, 12 insertions(+) (limited to 'src/libcore') diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 9ff681ac680..98c353eb6ec 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -64,6 +64,10 @@ The script accepts commands, flags, and arguments to determine what to do: # execute tests in the standard library in stage0 ./x.py test --stage 0 src/libstd + # execute tests in the core and standard library in stage0, + # without running doc tests (thus avoid depending on building the compiler) + ./x.py test --stage 0 --no-doc src/libcore src/libstd + # execute all doc tests ./x.py test src/doc ``` diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 37f9dcc7e32..54f35d17974 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -50,6 +50,14 @@ // Since libcore defines many fundamental lang items, all tests live in a // separate crate, libcoretest, to avoid bizarre issues. +// +// Here we explicitly #[cfg]-out this whole crate when testing. If we don't do +// this, both the generated test artifact and the linked libtest (which +// transitively includes libcore) will both define the same set of lang items, +// and this will cause the E0152 "duplicate lang item found" error. See +// discussion in #50466 for details. +// +// This cfg won't affect doc tests. #![cfg(not(test))] #![stable(feature = "core", since = "1.6.0")] -- cgit 1.4.1-3-g733a5 From 9eeb13fdd1c10de7f489e7fc910686c6d492398e Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Sun, 6 May 2018 13:46:20 +0200 Subject: Improve `Debug` impl of `core::time::Duration` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior to this, Duration simply derived Debug. Since Duration doesn't implement `Display`, the only way to inspect its value is to use `Debug`. Unfortunately, the derived `Debug` impl is far from optimal for humans. In many cases, Durations are used for some quick'n'dirty benchmarking (or in general: measuring the time of some code). Correctly understanding the output of Duration's Debug impl is not easy (e.g. is "{ secs: 0, nanos: 968360102 }" or "{ secs: 0, nanos 98507324 }" shorter?). This commit replaces the derived impl with a manual one. It prints the duration as seconds (i.e. "3.1803s") if the duration is longer than a second, otherwise it prints it in either ms, µs or ns (depending on the duration's length). This already helps readability a lot and it never omits information that is stored. This `Debug` impl does *not* respect the following formatting parameters: - fill/align/padding: difficult to implement, probably not worth it - alternate # flag: not clear what this should do --- src/libcore/tests/time.rs | 112 ++++++++++++++++++++++++++++++++++++++++++++++ src/libcore/time.rs | 78 +++++++++++++++++++++++++++++++- 2 files changed, 189 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs index 042c523f25f..bfb5369cf8f 100644 --- a/src/libcore/tests/time.rs +++ b/src/libcore/tests/time.rs @@ -122,3 +122,115 @@ fn checked_div() { assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); assert_eq!(Duration::new(2, 0).checked_div(0), None); } + +#[test] +fn debug_formatting_extreme_values() { + assert_eq!( + format!("{:?}", Duration::new(18_446_744_073_709_551_615, 123_456_789)), + "18446744073709551615.123456789s" + ); +} + +#[test] +fn debug_formatting_secs() { + assert_eq!(format!("{:?}", Duration::new(7, 000_000_000)), "7s"); + assert_eq!(format!("{:?}", Duration::new(7, 100_000_000)), "7.1s"); + assert_eq!(format!("{:?}", Duration::new(7, 000_010_000)), "7.00001s"); + assert_eq!(format!("{:?}", Duration::new(7, 000_000_001)), "7.000000001s"); + assert_eq!(format!("{:?}", Duration::new(7, 123_456_789)), "7.123456789s"); + + assert_eq!(format!("{:?}", Duration::new(88, 000_000_000)), "88s"); + assert_eq!(format!("{:?}", Duration::new(88, 100_000_000)), "88.1s"); + assert_eq!(format!("{:?}", Duration::new(88, 000_010_000)), "88.00001s"); + assert_eq!(format!("{:?}", Duration::new(88, 000_000_001)), "88.000000001s"); + assert_eq!(format!("{:?}", Duration::new(88, 123_456_789)), "88.123456789s"); + + assert_eq!(format!("{:?}", Duration::new(999, 000_000_000)), "999s"); + assert_eq!(format!("{:?}", Duration::new(999, 100_000_000)), "999.1s"); + assert_eq!(format!("{:?}", Duration::new(999, 000_010_000)), "999.00001s"); + assert_eq!(format!("{:?}", Duration::new(999, 000_000_001)), "999.000000001s"); + assert_eq!(format!("{:?}", Duration::new(999, 123_456_789)), "999.123456789s"); +} + +#[test] +fn debug_formatting_millis() { + assert_eq!(format!("{:?}", Duration::new(0, 7_000_000)), "7ms"); + assert_eq!(format!("{:?}", Duration::new(0, 7_100_000)), "7.1ms"); + assert_eq!(format!("{:?}", Duration::new(0, 7_000_001)), "7.000001ms"); + assert_eq!(format!("{:?}", Duration::new(0, 7_123_456)), "7.123456ms"); + + assert_eq!(format!("{:?}", Duration::new(0, 88_000_000)), "88ms"); + assert_eq!(format!("{:?}", Duration::new(0, 88_100_000)), "88.1ms"); + assert_eq!(format!("{:?}", Duration::new(0, 88_000_001)), "88.000001ms"); + assert_eq!(format!("{:?}", Duration::new(0, 88_123_456)), "88.123456ms"); + + assert_eq!(format!("{:?}", Duration::new(0, 999_000_000)), "999ms"); + assert_eq!(format!("{:?}", Duration::new(0, 999_100_000)), "999.1ms"); + assert_eq!(format!("{:?}", Duration::new(0, 999_000_001)), "999.000001ms"); + assert_eq!(format!("{:?}", Duration::new(0, 999_123_456)), "999.123456ms"); +} + +#[test] +fn debug_formatting_micros() { + assert_eq!(format!("{:?}", Duration::new(0, 7_000)), "7µs"); + assert_eq!(format!("{:?}", Duration::new(0, 7_100)), "7.1µs"); + assert_eq!(format!("{:?}", Duration::new(0, 7_001)), "7.001µs"); + assert_eq!(format!("{:?}", Duration::new(0, 7_123)), "7.123µs"); + + assert_eq!(format!("{:?}", Duration::new(0, 88_000)), "88µs"); + assert_eq!(format!("{:?}", Duration::new(0, 88_100)), "88.1µs"); + assert_eq!(format!("{:?}", Duration::new(0, 88_001)), "88.001µs"); + assert_eq!(format!("{:?}", Duration::new(0, 88_123)), "88.123µs"); + + assert_eq!(format!("{:?}", Duration::new(0, 999_000)), "999µs"); + assert_eq!(format!("{:?}", Duration::new(0, 999_100)), "999.1µs"); + assert_eq!(format!("{:?}", Duration::new(0, 999_001)), "999.001µs"); + assert_eq!(format!("{:?}", Duration::new(0, 999_123)), "999.123µs"); +} + +#[test] +fn debug_formatting_nanos() { + assert_eq!(format!("{:?}", Duration::new(0, 0)), "0ns"); + assert_eq!(format!("{:?}", Duration::new(0, 1)), "1ns"); + assert_eq!(format!("{:?}", Duration::new(0, 88)), "88ns"); + assert_eq!(format!("{:?}", Duration::new(0, 999)), "999ns"); +} + +#[test] +fn debug_formatting_precision_zero() { + assert_eq!(format!("{:.0?}", Duration::new(0, 0)), "0ns"); + assert_eq!(format!("{:.0?}", Duration::new(0, 123)), "123ns"); + + assert_eq!(format!("{:.0?}", Duration::new(0, 1_001)), "1µs"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_999)), "1µs"); + + assert_eq!(format!("{:.0?}", Duration::new(0, 1_000_001)), "1ms"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_999_999)), "1ms"); + + assert_eq!(format!("{:.0?}", Duration::new(1, 000_000_001)), "1s"); + assert_eq!(format!("{:.0?}", Duration::new(1, 999_999_999)), "1s"); +} + +#[test] +fn debug_formatting_precision_two() { + // This might seem inconsistent with the other units, but printing + // fractional digits for nano seconds would imply more precision than is + // actually stored. + assert_eq!(format!("{:.2?}", Duration::new(0, 0)), "0ns"); + assert_eq!(format!("{:.2?}", Duration::new(0, 123)), "123ns"); + + assert_eq!(format!("{:.2?}", Duration::new(0, 1_000)), "1.00µs"); + assert_eq!(format!("{:.2?}", Duration::new(0, 7_001)), "7.00µs"); + assert_eq!(format!("{:.2?}", Duration::new(0, 7_100)), "7.10µs"); + assert_eq!(format!("{:.2?}", Duration::new(0, 1_999)), "1.99µs"); + + assert_eq!(format!("{:.2?}", Duration::new(0, 1_000_000)), "1.00ms"); + assert_eq!(format!("{:.2?}", Duration::new(0, 3_001_000)), "3.00ms"); + assert_eq!(format!("{:.2?}", Duration::new(0, 3_100_000)), "3.10ms"); + assert_eq!(format!("{:.2?}", Duration::new(0, 1_999_999)), "1.99ms"); + + assert_eq!(format!("{:.2?}", Duration::new(1, 000_000_000)), "1.00s"); + assert_eq!(format!("{:.2?}", Duration::new(4, 001_000_000)), "4.00s"); + assert_eq!(format!("{:.2?}", Duration::new(2, 100_000_000)), "2.10s"); + assert_eq!(format!("{:.2?}", Duration::new(8, 999_999_999)), "8.99s"); +} diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 8e8b1691c65..a0a48e8493c 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -21,6 +21,7 @@ //! assert_eq!(Duration::new(5, 0), Duration::from_secs(5)); //! ``` +use fmt; use iter::Sum; use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign}; @@ -59,7 +60,7 @@ const MICROS_PER_SEC: u64 = 1_000_000; /// let ten_millis = Duration::from_millis(10); /// ``` #[stable(feature = "duration", since = "1.3.0")] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct Duration { secs: u64, nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC @@ -481,3 +482,78 @@ impl<'a> Sum<&'a Duration> for Duration { iter.fold(Duration::new(0, 0), |a, b| a + *b) } } + +#[stable(feature = "duration_debug_impl", since = "1.27.0")] +impl fmt::Debug for Duration { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// Formats a floating point number in decimal notation. + /// + /// The number is given as the `integer_part` and a fractional part. + /// The value of the fractional part is `fractional_part / divisor`. So + /// `integer_part` = 3, `fractional_part` = 12 and `divisor` = 100 + /// represents the number `3.012`. Trailing zeros are omitted. + /// + /// `divisor` must not be above 100_000_000. It also should be a power + /// of 10, everything else doesn't make sense. `fractional_part` has + /// to be less than `10 * divisor`! + fn fmt_decimal( + f: &mut fmt::Formatter, + integer_part: u64, + mut fractional_part: u32, + mut divisor: u32, + ) -> fmt::Result { + // Encode the fractional part into a temporary buffer. The buffer + // only need to hold 9 elements, because `fractional_part` has to + // be smaller than 10^9. The buffer is prefilled with '0' digits + // to simplify the code below. + let mut buf = [b'0'; 9]; + + // The next digit is written at this position + let mut pos = 0; + + // We can stop when there are no non-zero digits left or (when a + // precision was set and we already emitted that many digits). + while fractional_part > 0 && f.precision().map(|p| p > pos).unwrap_or(true) { + // Write new digit into the buffer + buf[pos] = b'0' + (fractional_part / divisor) as u8; + + fractional_part %= divisor; + divisor /= 10; + pos += 1; + } + + // If we haven't emitted a single fractional digit and the precision + // wasn't set to a non-zero value, we don't print the decimal point. + let end = f.precision().unwrap_or(pos); + if end == 0 { + write!(f, "{}", integer_part) + } else { + // We are only writing ASCII digits into the buffer and it was + // initialized with '0's, so it contains valid UTF8. + let s = unsafe { + ::str::from_utf8_unchecked(&buf[..end]) + }; + + write!(f, "{}.{}", integer_part, s) + } + } + + // Print leading '+' sign if requested + if f.sign_plus() { + write!(f, "+")?; + } + + if self.secs > 0 { + fmt_decimal(f, self.secs, self.nanos, 100_000_000)?; + f.write_str("s") + } else if self.nanos >= 1_000_000 { + fmt_decimal(f, self.nanos as u64 / 1_000_000, self.nanos % 1_000_000, 100_000)?; + f.write_str("ms") + } else if self.nanos >= 1_000 { + fmt_decimal(f, self.nanos as u64 / 1_000, self.nanos % 1_000, 100)?; + f.write_str("µs") + } else { + write!(f, "{}ns", self.nanos) + } + } +} -- cgit 1.4.1-3-g733a5 From b61a4c20c6acd963070adb083b12d5e21a5843d3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 7 May 2018 12:11:22 +0200 Subject: make the const constructor unstable --- src/libcore/mem.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libcore') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 6d64d91312e..6836f8622b0 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -959,6 +959,7 @@ impl ManuallyDrop { /// ManuallyDrop::new(Box::new(())); /// ``` #[stable(feature = "manually_drop", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_manually_drop_new")] #[inline] pub const fn new(value: T) -> ManuallyDrop { ManuallyDrop { value: value } -- cgit 1.4.1-3-g733a5 From 9f26376281035fde5bf332a4326fadcdb48b7ef7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 May 2018 12:44:26 +0200 Subject: Rename Pin to PinMut MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As discussed at [1] §3 and [2] and [3], a formal look at pinning requires considering a distinguished "shared pinned" mode/typestate. Given that, it seems desirable to at least eventually actually expose that typestate as a reference type. This renames Pin to PinMut, freeing the name Pin in case we want to use it for a shared pinned reference later on. [1] https://www.ralfj.de/blog/2018/04/10/safe-intrusive-collections-with-pinning.html [2] https://github.com/rust-lang/rfcs/pull/2349#issuecomment-379250361 [3] https://github.com/rust-lang/rust/issues/49150#issuecomment-380488275 --- src/liballoc/boxed.rs | 6 +++--- src/libcore/mem.rs | 48 ++++++++++++++++++++++++------------------------ 2 files changed, 27 insertions(+), 27 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 1b4f86dcfac..a1567344235 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -62,7 +62,7 @@ use core::fmt; use core::hash::{Hash, Hasher}; use core::iter::FusedIterator; use core::marker::{Unpin, Unsize}; -use core::mem::{self, Pin}; +use core::mem::{self, PinMut}; use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; use core::ptr::{self, NonNull, Unique}; use core::convert::From; @@ -771,8 +771,8 @@ impl PinBox { #[unstable(feature = "pin", issue = "49150")] impl PinBox { /// Get a pinned reference to the data in this PinBox. - pub fn as_pin<'a>(&'a mut self) -> Pin<'a, T> { - unsafe { Pin::new_unchecked(&mut *self.inner) } + pub fn as_pin_mut<'a>(&'a mut self) -> PinMut<'a, T> { + unsafe { PinMut::new_unchecked(&mut *self.inner) } } /// Get a mutable reference to the data inside this PinBox. diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 10efab82ddf..5d344c48cb8 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1101,53 +1101,53 @@ impl ::hash::Hash for ManuallyDrop { /// value implements the `Unpin` trait. #[unstable(feature = "pin", issue = "49150")] #[fundamental] -pub struct Pin<'a, T: ?Sized + 'a> { +pub struct PinMut<'a, T: ?Sized + 'a> { inner: &'a mut T, } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized + Unpin> Pin<'a, T> { - /// Construct a new `Pin` around a reference to some data of a type that +impl<'a, T: ?Sized + Unpin> PinMut<'a, T> { + /// Construct a new `PinMut` around a reference to some data of a type that /// implements `Unpin`. #[unstable(feature = "pin", issue = "49150")] - pub fn new(reference: &'a mut T) -> Pin<'a, T> { - Pin { inner: reference } + pub fn new(reference: &'a mut T) -> PinMut<'a, T> { + PinMut { inner: reference } } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized> Pin<'a, T> { - /// Construct a new `Pin` around a reference to some data of a type that +impl<'a, T: ?Sized> PinMut<'a, T> { + /// Construct a new `PinMut` around a reference to some data of a type that /// may or may not implement `Unpin`. /// /// This constructor is unsafe because we do not know what will happen with /// that data after the reference ends. If you cannot guarantee that the /// data will never move again, calling this constructor is invalid. #[unstable(feature = "pin", issue = "49150")] - pub unsafe fn new_unchecked(reference: &'a mut T) -> Pin<'a, T> { - Pin { inner: reference } + pub unsafe fn new_unchecked(reference: &'a mut T) -> PinMut<'a, T> { + PinMut { inner: reference } } - /// Borrow a Pin for a shorter lifetime than it already has. + /// Borrow a PinMut for a shorter lifetime than it already has. #[unstable(feature = "pin", issue = "49150")] - pub fn borrow<'b>(this: &'b mut Pin<'a, T>) -> Pin<'b, T> { - Pin { inner: this.inner } + pub fn borrow<'b>(this: &'b mut PinMut<'a, T>) -> PinMut<'b, T> { + PinMut { inner: this.inner } } - /// Get a mutable reference to the data inside of this `Pin`. + /// Get a mutable reference to the data inside of this `PinMut`. /// /// This function is unsafe. You must guarantee that you will never move /// the data out of the mutable reference you receive when you call this /// function. #[unstable(feature = "pin", issue = "49150")] - pub unsafe fn get_mut<'b>(this: &'b mut Pin<'a, T>) -> &'b mut T { + pub unsafe fn get_mut<'b>(this: &'b mut PinMut<'a, T>) -> &'b mut T { this.inner } /// Construct a new pin by mapping the interior value. /// - /// For example, if you wanted to get a `Pin` of a field of something, you + /// For example, if you wanted to get a `PinMut` of a field of something, you /// could use this to get access to that field in one line of code. /// /// This function is unsafe. You must guarantee that the data you return @@ -1155,15 +1155,15 @@ impl<'a, T: ?Sized> Pin<'a, T> { /// because it is one of the fields of that value), and also that you do /// not move out of the argument you receive to the interior function. #[unstable(feature = "pin", issue = "49150")] - pub unsafe fn map<'b, U, F>(this: &'b mut Pin<'a, T>, f: F) -> Pin<'b, U> where + pub unsafe fn map<'b, U, F>(this: &'b mut PinMut<'a, T>, f: F) -> PinMut<'b, U> where F: FnOnce(&mut T) -> &mut U { - Pin { inner: f(this.inner) } + PinMut { inner: f(this.inner) } } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized> Deref for Pin<'a, T> { +impl<'a, T: ?Sized> Deref for PinMut<'a, T> { type Target = T; fn deref(&self) -> &T { @@ -1172,35 +1172,35 @@ impl<'a, T: ?Sized> Deref for Pin<'a, T> { } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized + Unpin> DerefMut for Pin<'a, T> { +impl<'a, T: ?Sized + Unpin> DerefMut for PinMut<'a, T> { fn deref_mut(&mut self) -> &mut T { self.inner } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: fmt::Debug + ?Sized> fmt::Debug for Pin<'a, T> { +impl<'a, T: fmt::Debug + ?Sized> fmt::Debug for PinMut<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: fmt::Display + ?Sized> fmt::Display for Pin<'a, T> { +impl<'a, T: fmt::Display + ?Sized> fmt::Display for PinMut<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&**self, f) } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized> fmt::Pointer for Pin<'a, T> { +impl<'a, T: ?Sized> fmt::Pointer for PinMut<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&(&*self.inner as *const T), f) } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for Pin<'a, T> {} +impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for PinMut<'a, T> {} #[unstable(feature = "pin", issue = "49150")] -unsafe impl<'a, T: ?Sized> Unpin for Pin<'a, T> {} +unsafe impl<'a, T: ?Sized> Unpin for PinMut<'a, T> {} -- cgit 1.4.1-3-g733a5 From 84ce206db6a1b452c3277963e8eafd99baba0668 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 May 2018 12:51:59 +0200 Subject: Change PinMut::map to be able to preserve the original reference's lifetime Suggested by @dylanede at . --- src/libcore/mem.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 5d344c48cb8..a062ec7ee3d 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1155,7 +1155,7 @@ impl<'a, T: ?Sized> PinMut<'a, T> { /// because it is one of the fields of that value), and also that you do /// not move out of the argument you receive to the interior function. #[unstable(feature = "pin", issue = "49150")] - pub unsafe fn map<'b, U, F>(this: &'b mut PinMut<'a, T>, f: F) -> PinMut<'b, U> where + pub unsafe fn map(this: PinMut<'a, T>, f: F) -> PinMut<'a, U> where F: FnOnce(&mut T) -> &mut U { PinMut { inner: f(this.inner) } -- cgit 1.4.1-3-g733a5 From 17206a7e64a3f3c8bb63e099e837ba7cda07947e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 May 2018 13:20:30 +0200 Subject: PinMut::get_mut can also preserve the lifetime --- src/libcore/mem.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index a062ec7ee3d..74eb219e45d 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1141,7 +1141,7 @@ impl<'a, T: ?Sized> PinMut<'a, T> { /// the data out of the mutable reference you receive when you call this /// function. #[unstable(feature = "pin", issue = "49150")] - pub unsafe fn get_mut<'b>(this: &'b mut PinMut<'a, T>) -> &'b mut T { + pub unsafe fn get_mut(this: PinMut<'a, T>) -> &'a mut T { this.inner } -- cgit 1.4.1-3-g733a5 From 8619e19dc485185fee09baebf5788e427d0036e9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 May 2018 13:56:24 +0200 Subject: Rename PinMut::borrow to PinMut::reborrow and make it a method --- src/libcore/mem.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 74eb219e45d..6cbe26afae9 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1129,10 +1129,13 @@ impl<'a, T: ?Sized> PinMut<'a, T> { PinMut { inner: reference } } - /// Borrow a PinMut for a shorter lifetime than it already has. + /// Reborrow a `PinMut` for a shorter lifetime. + /// + /// For example, `PinMut::get_mut(x.reborrow())` (unsafely) returns a + /// short-lived mutable reference reborrowing from `x`. #[unstable(feature = "pin", issue = "49150")] - pub fn borrow<'b>(this: &'b mut PinMut<'a, T>) -> PinMut<'b, T> { - PinMut { inner: this.inner } + pub fn reborrow<'b>(&'b mut self) -> PinMut<'b, T> { + PinMut { inner: self.inner } } /// Get a mutable reference to the data inside of this `PinMut`. -- cgit 1.4.1-3-g733a5 From 939c25a522ddeaae60f905c787a1f28ceb5d7ee8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 May 2018 14:30:29 +0200 Subject: Unpin: Fix references to Pin type --- src/libcore/marker.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index c074adfd570..db5f50a99ca 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -595,15 +595,15 @@ unsafe impl Freeze for *mut T {} unsafe impl<'a, T: ?Sized> Freeze for &'a T {} unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} -/// Types which can be moved out of a `Pin`. +/// Types which can be moved out of a `PinMut`. /// -/// The `Unpin` trait is used to control the behavior of the [`Pin`] type. If a +/// The `Unpin` trait is used to control the behavior of the [`PinMut`] type. If a /// type implements `Unpin`, it is safe to move a value of that type out of the -/// `Pin` pointer. +/// `PinMut` pointer. /// /// This trait is automatically implemented for almost every type. /// -/// [`Pin`]: ../mem/struct.Pin.html +/// [`PinMut`]: ../mem/struct.PinMut.html #[unstable(feature = "pin", issue = "49150")] pub unsafe auto trait Unpin {} -- cgit 1.4.1-3-g733a5 From 1abed9cebf27f1f68e8711cb15ba9c2587b4da68 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 7 May 2018 09:18:12 -0700 Subject: Add explanation for #[must_use] on Result --- src/libcore/result.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/result.rs b/src/libcore/result.rs index c152d4979b9..e0cc669d035 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -251,7 +251,7 @@ use ops; /// [`Ok`]: enum.Result.html#variant.Ok /// [`Err`]: enum.Result.html#variant.Err #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] -#[must_use] +#[must_use = "this `Result` may be an `Err` variant, which should be handled"] #[stable(feature = "rust1", since = "1.0.0")] pub enum Result { /// Contains the success value -- cgit 1.4.1-3-g733a5 From 6e49c837f614a8670a5773428b4934eb280bca61 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 7 May 2018 09:26:03 -0700 Subject: Add explanation for #[must_use] on Debug builders --- src/libcore/fmt/builders.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index a1f4c6995da..e8ea2e743da 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -84,7 +84,7 @@ impl<'a> fmt::Write for PadAdapter<'a> { /// // prints "Foo { bar: 10, baz: "Hello World" }" /// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() }); /// ``` -#[must_use] +#[must_use = "must eventually call `finish()` on Debug builders"] #[allow(missing_debug_implementations)] #[stable(feature = "debug_builders", since = "1.2.0")] pub struct DebugStruct<'a, 'b: 'a> { @@ -181,7 +181,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { /// // prints "Foo(10, "Hello World")" /// println!("{:?}", Foo(10, "Hello World".to_string())); /// ``` -#[must_use] +#[must_use = "must eventually call `finish()` on Debug builders"] #[allow(missing_debug_implementations)] #[stable(feature = "debug_builders", since = "1.2.0")] pub struct DebugTuple<'a, 'b: 'a> { @@ -319,7 +319,7 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> { /// // prints "{10, 11}" /// println!("{:?}", Foo(vec![10, 11])); /// ``` -#[must_use] +#[must_use = "must eventually call `finish()` on Debug builders"] #[allow(missing_debug_implementations)] #[stable(feature = "debug_builders", since = "1.2.0")] pub struct DebugSet<'a, 'b: 'a> { @@ -390,7 +390,7 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { /// // prints "[10, 11]" /// println!("{:?}", Foo(vec![10, 11])); /// ``` -#[must_use] +#[must_use = "must eventually call `finish()` on Debug builders"] #[allow(missing_debug_implementations)] #[stable(feature = "debug_builders", since = "1.2.0")] pub struct DebugList<'a, 'b: 'a> { @@ -461,7 +461,7 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> { /// // prints "{"A": 10, "B": 11}" /// println!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])); /// ``` -#[must_use] +#[must_use = "must eventually call `finish()` on Debug builders"] #[allow(missing_debug_implementations)] #[stable(feature = "debug_builders", since = "1.2.0")] pub struct DebugMap<'a, 'b: 'a> { -- cgit 1.4.1-3-g733a5 From 23b6e465b9546b99c8b7609bfa4eeaf2094eed09 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Tue, 8 May 2018 12:05:07 -0400 Subject: Add more logarithm constants --- src/libcore/num/f32.rs | 8 ++++++++ src/libcore/num/f64.rs | 8 ++++++++ 2 files changed, 16 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 8d5f6f601da..672119eba7f 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -128,10 +128,18 @@ pub mod consts { #[stable(feature = "rust1", since = "1.0.0")] pub const LOG2_E: f32 = 1.44269504088896340735992468100189214_f32; + /// log2(10) + #[unstable(feature = "extra_log_consts", issue = "50540")] + pub const LOG2_10: f32 = 3.32192809488736234787031942948939018_f32; + /// log10(e) #[stable(feature = "rust1", since = "1.0.0")] pub const LOG10_E: f32 = 0.434294481903251827651128918916605082_f32; + /// log10(2) + #[unstable(feature = "extra_log_consts", issue = "50540")] + pub const LOG10_2: f32 = 0.301029995663981195213738894724493027_f32; + /// ln(2) #[stable(feature = "rust1", since = "1.0.0")] pub const LN_2: f32 = 0.693147180559945309417232121458176568_f32; diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 08b869734d4..220b23a1e6a 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -124,10 +124,18 @@ pub mod consts { #[stable(feature = "rust1", since = "1.0.0")] pub const E: f64 = 2.71828182845904523536028747135266250_f64; + /// log2(10) + #[unstable(feature = "extra_log_consts", issue = "50540")] + pub const LOG2_10: f64 = 3.32192809488736234787031942948939018_f64; + /// log2(e) #[stable(feature = "rust1", since = "1.0.0")] pub const LOG2_E: f64 = 1.44269504088896340735992468100189214_f64; + /// log10(2) + #[unstable(feature = "extra_log_consts", issue = "50540")] + pub const LOG10_2: f64 = 0.301029995663981195213738894724493027_f64; + /// log10(e) #[stable(feature = "rust1", since = "1.0.0")] pub const LOG10_E: f64 = 0.434294481903251827651128918916605082_f64; -- cgit 1.4.1-3-g733a5 From a00e68ddc667e6ab110dd07c45ee10ca8ef90bbc Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Mon, 26 Mar 2018 16:46:04 -0400 Subject: Add missing Wrapping methods, use doc_comment! --- src/libcore/num/mod.rs | 27 +- src/libcore/num/wrapping.rs | 658 +++++++++++++++++++++++++++++++------------- 2 files changed, 486 insertions(+), 199 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index a062fbda5ba..38f1688f0d5 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -188,8 +188,6 @@ impl fmt::UpperHex for Wrapping { } } -mod wrapping; - // All these modules are technically private and only exposed for coretests: pub mod flt2dec; pub mod dec2flt; @@ -203,6 +201,8 @@ macro_rules! doc_comment { }; } +mod wrapping; + // `Int` + `SignedInt` implemented for signed integers macro_rules! int_impl { ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr, @@ -3423,6 +3423,29 @@ $EndFeature, " } } + doc_comment! { + concat!("Returns the smallest power of two greater than or equal to `n`. If +the next power of two is greater than the type's maximum value, +the return value is wrapped to `0`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +", $Feature, " +assert_eq!(2", stringify!($SelfT), ".wrapping_next_power_of_two(), 2); +assert_eq!(3", stringify!($SelfT), ".wrapping_next_power_of_two(), 4); +assert_eq!(", stringify!($SelfT), "::max_value().wrapping_next_power_of_two(), 0);", +$EndFeature, " +```"), + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn wrapping_next_power_of_two(self) -> Self { + self.one_less_than_next_power_of_two().wrapping_add(1) + } + } + /// Return the memory representation of this integer as a byte array. /// /// The target platform’s native endianness is used. diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index 826883fdc3f..6d5783282b0 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -112,17 +112,19 @@ macro_rules! sh_impl_all { //sh_impl_unsigned! { $t, u16 } //sh_impl_unsigned! { $t, u32 } //sh_impl_unsigned! { $t, u64 } + //sh_impl_unsigned! { $t, u128 } sh_impl_unsigned! { $t, usize } //sh_impl_signed! { $t, i8 } //sh_impl_signed! { $t, i16 } //sh_impl_signed! { $t, i32 } //sh_impl_signed! { $t, i64 } + //sh_impl_signed! { $t, i128 } //sh_impl_signed! { $t, isize } )*) } -sh_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } +sh_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } // FIXME(30524): impl Op for Wrapping, impl OpAssign for Wrapping macro_rules! wrapping_impl { @@ -326,88 +328,111 @@ wrapping_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } macro_rules! wrapping_int_impl { ($($t:ty)*) => ($( impl Wrapping<$t> { - /// Returns the number of ones in the binary representation of - /// `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// let n: Wrapping = Wrapping(-0b1000_0000); - /// - /// assert_eq!(n.count_ones(), 1); - /// ``` - #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn count_ones(self) -> u32 { - self.0.count_ones() + doc_comment! { + concat!("Returns the smallest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert_eq!(>::min_value(), ", +"Wrapping(", stringify!($t), "::min_value())); +```"), + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + #[inline] + pub const fn min_value() -> Self { + Wrapping(<$t>::min_value()) + } } - /// Returns the number of zeros in the binary representation of - /// `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// let n: Wrapping = Wrapping(-0b1000_0000); - /// - /// assert_eq!(n.count_zeros(), 7); - /// ``` - #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn count_zeros(self) -> u32 { - self.0.count_zeros() + doc_comment! { + concat!("Returns the largest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert_eq!(>::max_value(), ", +"Wrapping(", stringify!($t), "::max_value())); +```"), + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + #[inline] + pub const fn max_value() -> Self { + Wrapping(<$t>::max_value()) + } } - /// Returns the number of leading zeros in the binary representation - /// of `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// let n: Wrapping = Wrapping(-1); - /// - /// assert_eq!(n.leading_zeros(), 0); - /// ``` - #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn leading_zeros(self) -> u32 { - self.0.leading_zeros() + doc_comment! { + concat!("Returns the number of ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +let n = Wrapping(0b01001100", stringify!($t), "); + +assert_eq!(n.count_ones(), 3); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn count_ones(self) -> u32 { + self.0.count_ones() + } } - /// Returns the number of trailing zeros in the binary representation - /// of `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// let n: Wrapping = Wrapping(-4); - /// - /// assert_eq!(n.trailing_zeros(), 2); - /// ``` - #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn trailing_zeros(self) -> u32 { - self.0.trailing_zeros() + doc_comment! { + concat!("Returns the number of zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert_eq!(Wrapping(!0", stringify!($t), ").count_zeros(), 0); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn count_zeros(self) -> u32 { + self.0.count_zeros() + } + } + + doc_comment! { + concat!("Returns the number of trailing zeros in the binary representation +of `self`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +let n = Wrapping(0b0101000", stringify!($t), "); + +assert_eq!(n.trailing_zeros(), 3); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn trailing_zeros(self) -> u32 { + self.0.trailing_zeros() + } } /// Shifts the bits to the left by a specified amount, `n`, @@ -484,145 +509,178 @@ macro_rules! wrapping_int_impl { Wrapping(self.0.swap_bytes()) } - /// Converts an integer from big endian to the target's endianness. - /// - /// On big endian this is a no-op. On little endian the bytes are - /// swapped. + /// Reverses the bit pattern of the integer. /// /// # Examples /// + /// Please note that this example is shared between integer types. + /// Which explains why `i16` is used here. + /// /// Basic usage: /// /// ``` - /// #![feature(wrapping_int_impl)] + /// #![feature(reverse_bits)] /// use std::num::Wrapping; /// - /// let n: Wrapping = Wrapping(0x0123456789ABCDEF); + /// let n = Wrapping(0b0000000_01010101i16); + /// assert_eq!(n, Wrapping(85)); + /// + /// let m = n.reverse_bits(); /// - /// if cfg!(target_endian = "big") { - /// assert_eq!(Wrapping::::from_be(n), n); - /// } else { - /// assert_eq!(Wrapping::::from_be(n), n.swap_bytes()); - /// } + /// assert_eq!(m.0 as u16, 0b10101010_00000000); + /// assert_eq!(m, Wrapping(-22016)); /// ``` + #[unstable(feature = "reverse_bits", issue = "48763")] + #[cfg(not(stage0))] #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn from_be(x: Self) -> Self { - Wrapping(<$t>::from_be(x.0)) + pub fn reverse_bits(self) -> Self { + Wrapping(self.0.reverse_bits()) } - /// Converts an integer from little endian to the target's endianness. - /// - /// On little endian this is a no-op. On big endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// let n: Wrapping = Wrapping(0x0123456789ABCDEF); - /// - /// if cfg!(target_endian = "little") { - /// assert_eq!(Wrapping::::from_le(n), n); - /// } else { - /// assert_eq!(Wrapping::::from_le(n), n.swap_bytes()); - /// } - /// ``` - #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn from_le(x: Self) -> Self { - Wrapping(<$t>::from_le(x.0)) + doc_comment! { + concat!("Converts an integer from big endian to the target's endianness. + +On big endian this is a no-op. On little endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +let n = Wrapping(0x1A", stringify!($t), "); + +if cfg!(target_endian = \"big\") { + assert_eq!(>::from_be(n), n) +} else { + assert_eq!(>::from_be(n), n.swap_bytes()) +} +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn from_be(x: Self) -> Self { + Wrapping(<$t>::from_be(x.0)) + } } - /// Converts `self` to big endian from the target's endianness. - /// - /// On big endian this is a no-op. On little endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// let n: Wrapping = Wrapping(0x0123456789ABCDEF); - /// - /// if cfg!(target_endian = "big") { - /// assert_eq!(n.to_be(), n); - /// } else { - /// assert_eq!(n.to_be(), n.swap_bytes()); - /// } - /// ``` - #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn to_be(self) -> Self { - Wrapping(self.0.to_be()) + doc_comment! { + concat!("Converts an integer from little endian to the target's endianness. + +On little endian this is a no-op. On big endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +let n = Wrapping(0x1A", stringify!($t), "); + +if cfg!(target_endian = \"little\") { + assert_eq!(>::from_le(n), n) +} else { + assert_eq!(>::from_le(n), n.swap_bytes()) +} +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn from_le(x: Self) -> Self { + Wrapping(<$t>::from_le(x.0)) + } } - /// Converts `self` to little endian from the target's endianness. - /// - /// On little endian this is a no-op. On big endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// let n: Wrapping = Wrapping(0x0123456789ABCDEF); - /// - /// if cfg!(target_endian = "little") { - /// assert_eq!(n.to_le(), n); - /// } else { - /// assert_eq!(n.to_le(), n.swap_bytes()); - /// } - /// ``` - #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn to_le(self) -> Self { - Wrapping(self.0.to_le()) + doc_comment! { + concat!("Converts `self` to big endian from the target's endianness. + +On big endian this is a no-op. On little endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +let n = Wrapping(0x1A", stringify!($t), "); + +if cfg!(target_endian = \"big\") { + assert_eq!(n.to_be(), n) +} else { + assert_eq!(n.to_be(), n.swap_bytes()) +} +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn to_be(self) -> Self { + Wrapping(self.0.to_be()) + } } - /// Raises self to the power of `exp`, using exponentiation by - /// squaring. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// let x: Wrapping = Wrapping(2); // or any other integer type - /// - /// assert_eq!(x.pow(4), Wrapping(16)); - /// ``` - /// - /// Results that are too large are wrapped: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// // 5 ^ 4 = 625, which is too big for a u8 - /// let x: Wrapping = Wrapping(5); - /// - /// assert_eq!(x.pow(4).0, 113); - /// ``` - #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn pow(self, exp: u32) -> Self { - Wrapping(self.0.wrapping_pow(exp)) + doc_comment! { + concat!("Converts `self` to little endian from the target's endianness. + +On little endian this is a no-op. On big endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +let n = Wrapping(0x1A", stringify!($t), "); + +if cfg!(target_endian = \"little\") { + assert_eq!(n.to_le(), n) +} else { + assert_eq!(n.to_le(), n.swap_bytes()) +} +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn to_le(self) -> Self { + Wrapping(self.0.to_le()) + } + } + + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert_eq!(Wrapping(3", stringify!($t), ").pow(4), Wrapping(81)); +``` + +Results that are too large are wrapped: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert_eq!(Wrapping(3i8).pow(5), Wrapping(-13)); +assert_eq!(Wrapping(3i8).pow(6), Wrapping(-39)); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn pow(self, exp: u32) -> Self { + Wrapping(self.0.wrapping_pow(exp)) + } } } )*) @@ -630,6 +688,210 @@ macro_rules! wrapping_int_impl { wrapping_int_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } +macro_rules! wrapping_int_impl_signed { + ($($t:ty)*) => ($( + impl Wrapping<$t> { + doc_comment! { + concat!("Returns the number of leading zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +let n = Wrapping(", stringify!($t), "::max_value()) >> 2; + +assert_eq!(n.leading_zeros(), 3); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn leading_zeros(self) -> u32 { + self.0.leading_zeros() + } + } + + doc_comment! { + concat!("Computes the absolute value of `self`, wrapping around at +the boundary of the type. + +The only case where such wrapping can occur is when one takes the absolute value of the negative +minimal value for the type this is a positive value that is too large to represent in the type. In +such a case, this function returns `MIN` itself. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert_eq!(Wrapping(100", stringify!($t), ").abs(), Wrapping(100)); +assert_eq!(Wrapping(-100", stringify!($t), ").abs(), Wrapping(100)); +assert_eq!(Wrapping(", stringify!($t), "::min_value()).abs(), Wrapping(", stringify!($t), +"::min_value())); +assert_eq!(Wrapping(-128i8).abs().0 as u8, 128u8); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn abs(self) -> Wrapping<$t> { + Wrapping(self.0.wrapping_abs()) + } + } + + doc_comment! { + concat!("Returns a number representing sign of `self`. + + - `0` if the number is zero + - `1` if the number is positive + - `-1` if the number is negative + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert_eq!(Wrapping(10", stringify!($t), ").signum(), Wrapping(1)); +assert_eq!(Wrapping(0", stringify!($t), ").signum(), Wrapping(0)); +assert_eq!(Wrapping(-10", stringify!($t), ").signum(), Wrapping(-1)); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn signum(self) -> Wrapping<$t> { + Wrapping(self.0.signum()) + } + } + + doc_comment! { + concat!("Returns `true` if `self` is positive and `false` if the number is zero or +negative. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert!(Wrapping(10", stringify!($t), ").is_positive()); +assert!(!Wrapping(-10", stringify!($t), ").is_positive()); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn is_positive(self) -> bool { + self.0.is_positive() + } + } + + doc_comment! { + concat!("Returns `true` if `self` is negative and `false` if the number is zero or +positive. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert!(Wrapping(-10", stringify!($t), ").is_negative()); +assert!(!Wrapping(10", stringify!($t), ").is_negative()); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn is_negative(self) -> bool { + self.0.is_negative() + } + } + } + )*) +} + +wrapping_int_impl_signed! { isize i8 i16 i32 i64 i128 } + +macro_rules! wrapping_int_impl_unsigned { + ($($t:ty)*) => ($( + impl Wrapping<$t> { + doc_comment! { + concat!("Returns the number of leading zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +let n = Wrapping(", stringify!($t), "::max_value()) >> 2; + +assert_eq!(n.leading_zeros(), 2); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn leading_zeros(self) -> u32 { + self.0.leading_zeros() + } + } + + doc_comment! { + concat!("Returns `true` if and only if `self == 2^k` for some `k`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert!(Wrapping(16", stringify!($t), ").is_power_of_two()); +assert!(!Wrapping(10", stringify!($t), ").is_power_of_two()); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn is_power_of_two(self) -> bool { + self.0.is_power_of_two() + } + } + + doc_comment! { + concat!("Returns the smallest power of two greater than or equal to `self`. + +When return value overflows (i.e. `self > (1 << (N-1))` for type +`uN`), overflows to `2^N = 0`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert_eq!(Wrapping(2", stringify!($t), ").next_power_of_two(), Wrapping(2)); +assert_eq!(Wrapping(3", stringify!($t), ").next_power_of_two(), Wrapping(4)); +assert_eq!(Wrapping(200_u8).next_power_of_two(), Wrapping(0)); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn next_power_of_two(self) -> Self { + Wrapping(self.0.wrapping_next_power_of_two()) + } + } + } + )*) +} + +wrapping_int_impl_unsigned! { usize u8 u16 u32 u64 u128 } mod shift_max { #![allow(non_upper_case_globals)] @@ -656,11 +918,13 @@ mod shift_max { pub const i16: u32 = (1 << 4) - 1; pub const i32: u32 = (1 << 5) - 1; pub const i64: u32 = (1 << 6) - 1; + pub const i128: u32 = (1 << 7) - 1; pub use self::platform::isize; pub const u8: u32 = i8; pub const u16: u32 = i16; pub const u32: u32 = i32; pub const u64: u32 = i64; + pub const u128: u32 = i128; pub use self::platform::usize; } -- cgit 1.4.1-3-g733a5 From 23aa4831026b96869d0e0c283d39ba5fb35e786f Mon Sep 17 00:00:00 2001 From: Sebastian Köln Date: Wed, 9 May 2018 18:03:13 +0200 Subject: add fn `into_inner(self) -> (Idx, Idx)` to RangeInclusive (#49022) --- src/libcore/ops/range.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index b01a769eda7..697e6a3efde 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -411,6 +411,21 @@ impl RangeInclusive { pub fn end(&self) -> &Idx { &self.end } + + /// Destructures the RangeInclusive into (lower bound, upper (inclusive) bound). + /// + /// # Examples + /// + /// ``` + /// #![feature(inclusive_range_methods)] + /// + /// assert_eq!((3..=5).into_inner(), (3, 5)); + /// ``` + #[unstable(feature = "inclusive_range_methods", issue = "49022")] + #[inline] + pub fn into_inner(self) -> (Idx, Idx) { + (self.start, self.end) + } } #[stable(feature = "inclusive_range", since = "1.26.0")] -- cgit 1.4.1-3-g733a5 From e350ba48ed80c000fd2d2b5ac37e53a9efe1f587 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 9 May 2018 14:14:43 -0700 Subject: Use the "Safety" heading instead of "Undefined Behavior" --- src/libcore/intrinsics.rs | 30 ++++++++---------------------- src/libcore/ptr.rs | 44 +------------------------------------------- 2 files changed, 9 insertions(+), 65 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 8c510842c2a..df3f6c43031 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -971,12 +971,6 @@ extern "rust-intrinsic" { /// /// # Safety /// - /// `copy_nonoverlapping` is unsafe because it dereferences a raw pointer. - /// The caller must ensure that `src` points to a valid sequence of type - /// `T`. - /// - /// # Undefined Behavior - /// /// Behavior is undefined if any of the following conditions are violated: /// /// * The region of memory which begins at `src` and has a length of @@ -986,17 +980,19 @@ extern "rust-intrinsic" { /// `count * size_of::()` bytes must be valid (but may or may not be /// initialized). /// + /// * The two regions of memory must *not* overlap. + /// /// * `src` must be properly aligned. /// /// * `dst` must be properly aligned. /// - /// * The two regions of memory must *not* overlap. + /// Additionally, if `T` is not [`Copy`], only the region at `src` *or* the + /// region at `dst` can be used or dropped after calling + /// `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise copies of + /// `T`, regardless of whether `T: Copy`, which can result in undefined + /// behavior if both copies are used. /// - /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy.html), only - /// the region at `src` *or* the region at `dst` can be used or dropped - /// after calling `copy_nonoverlapping`. `copy_nonoverlapping` creates - /// bitwise copies of `T`, regardless of whether `T: Copy`, which can result - /// in undefined behavior if both copies are used. + /// [`Copy`]: ../marker/trait.Copy.html /// /// # Examples /// @@ -1060,11 +1056,6 @@ extern "rust-intrinsic" { /// /// # Safety /// - /// `copy` is unsafe because it dereferences a raw pointer. The caller must - /// ensure that `src` points to a valid sequence of type `T`. - /// - /// # Undefined Behavior - /// /// Behavior is undefined if any of the following conditions are violated: /// /// * The region of memory which begins at `src` and has a length of @@ -1112,11 +1103,6 @@ extern "rust-intrinsic" { /// /// # Safety /// - /// `write_bytes` is unsafe because it dereferences a raw pointer. The - /// caller must ensure that the poiinter points to a valid value of type `T`. - /// - /// # Undefined Behavior - /// /// Behavior is undefined if any of the following conditions are violated: /// /// * The region of memory which begins at `dst` and has a length of diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 3d15e4b1658..50627ee464d 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -54,11 +54,6 @@ pub use intrinsics::write_bytes; /// /// # Safety /// -/// `drop_in_place` is unsafe because it dereferences a raw pointer. The caller -/// must ensure that the pointer points to a valid value of type `T`. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `to_drop` must point to valid memory. @@ -153,11 +148,6 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// /// # Safety /// -/// `swap` is unsafe because it dereferences a raw pointer. The caller must -/// ensure that both pointers point to valid values of type `T`. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `x` and `y` must point to valid, initialized memory. @@ -307,14 +297,9 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// operates on raw pointers instead of references. When references are /// available, [`mem::replace`] should be preferred. /// -/// # Safety -/// -/// `replace` is unsafe because it dereferences a raw pointer. The caller -/// must ensure that the pointer points to a valid value of type `T`. -/// /// [`mem::replace`]: ../mem/fn.replace.html /// -/// # Undefined Behavior +/// # Safety /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -350,11 +335,6 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// /// # Safety /// -/// `read` is unsafe because it dereferences a raw pointer. The caller -/// must ensure that the pointer points to a valid value of type `T`. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `src` must point to valid, initialized memory. @@ -440,11 +420,6 @@ pub unsafe fn read(src: *const T) -> T { /// /// # Safety /// -/// `read_unaligned` is unsafe because it dereferences a raw pointer. The caller -/// must ensure that the pointer points to a valid value of type `T`. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `src` must point to valid, initialized memory. @@ -523,10 +498,6 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// /// # Safety /// -/// `write` is unsafe because it dereferences a raw pointer. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. @@ -600,10 +571,6 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// # Safety /// -/// `write_unaligned` is unsafe because it dereferences a raw pointer. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. @@ -671,11 +638,6 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// # Safety /// -/// `read_volatile` is unsafe because it dereferences a raw pointer. The caller -/// must ensure that the pointer points to a valid value of type `T`. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `src` must point to valid, initialized memory. @@ -741,10 +703,6 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// # Safety /// -/// `write_volatile` is unsafe because it dereferences a raw pointer. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. -- cgit 1.4.1-3-g733a5 From 8010604b2d888ac839147fe27de76cdcc713aa1b Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 9 May 2018 18:03:56 -0400 Subject: move See also links to top --- src/liballoc/slice.rs | 4 ++-- src/liballoc/str.rs | 4 ++-- src/libcore/num/f32.rs | 4 ++-- src/libcore/num/f64.rs | 4 ++-- src/libstd/f32.rs | 4 ++-- src/libstd/f64.rs | 4 ++-- src/libstd/primitive_docs.rs | 16 ++++++++-------- 7 files changed, 20 insertions(+), 20 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index d50a3458f20..6caf12aa7eb 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -10,6 +10,8 @@ //! A dynamically-sized view into a contiguous sequence, `[T]`. //! +//! *[See also the slice primitive type](../../std/primitive.slice.html).* +//! //! Slices are a view into a block of memory represented as a pointer and a //! length. //! @@ -78,8 +80,6 @@ //! * Further methods that return iterators are [`.split`], [`.splitn`], //! [`.chunks`], [`.windows`] and more. //! -//! *[See also the slice primitive type](../../std/primitive.slice.html).* -//! //! [`Clone`]: ../../std/clone/trait.Clone.html //! [`Eq`]: ../../std/cmp/trait.Eq.html //! [`Ord`]: ../../std/cmp/trait.Ord.html diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 9e693c89be9..42efdea74b1 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -10,6 +10,8 @@ //! Unicode string slices. //! +//! *[See also the `str` primitive type](../../std/primitive.str.html).* +//! //! The `&str` type is one of the two main string types, the other being `String`. //! Unlike its `String` counterpart, its contents are borrowed. //! @@ -29,8 +31,6 @@ //! ``` //! let hello_world: &'static str = "Hello, world!"; //! ``` -//! -//! *[See also the `str` primitive type](../../std/primitive.str.html).* #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 672119eba7f..4a7dc13f0f2 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -11,9 +11,9 @@ //! This module provides constants which are specific to the implementation //! of the `f32` floating point data type. //! -//! Mathematically significant numbers are provided in the `consts` sub-module. -//! //! *[See also the `f32` primitive type](../../std/primitive.f32.html).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 220b23a1e6a..801de5e87bd 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -11,9 +11,9 @@ //! This module provides constants which are specific to the implementation //! of the `f64` floating point data type. //! -//! Mathematically significant numbers are provided in the `consts` sub-module. -//! //! *[See also the `f64` primitive type](../../std/primitive.f64.html).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 26644c76957..f4d897b0111 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -11,9 +11,9 @@ //! This module provides constants which are specific to the implementation //! of the `f32` floating point data type. //! -//! Mathematically significant numbers are provided in the `consts` sub-module. -//! //! *[See also the `f32` primitive type](../../std/primitive.f32.html).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index a7e63f59b1c..bd24e84dbed 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -11,9 +11,9 @@ //! This module provides constants which are specific to the implementation //! of the `f64` floating point data type. //! -//! Mathematically significant numbers are provided in the `consts` sub-module. -//! //! *[See also the `f64` primitive type](../../std/primitive.f64.html).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 437d7d74cae..6e329d85539 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -370,6 +370,8 @@ mod prim_unit { } // /// Raw, unsafe pointers, `*const T`, and `*mut T`. /// +/// *[See also the `std::ptr` module](ptr/index.html).* +/// /// Working with raw pointers in Rust is uncommon, /// typically limited to a few patterns. /// @@ -444,8 +446,6 @@ mod prim_unit { } /// but C APIs hand out a lot of pointers generally, so are a common source /// of raw pointers in Rust. /// -/// *[See also the `std::ptr` module](ptr/index.html).* -/// /// [`null`]: ../std/ptr/fn.null.html /// [`null_mut`]: ../std/ptr/fn.null_mut.html /// [`is_null`]: ../std/primitive.pointer.html#method.is_null @@ -563,6 +563,8 @@ mod prim_array { } // /// A dynamically-sized view into a contiguous sequence, `[T]`. /// +/// *[See also the `std::slice` module](slice/index.html).* +/// /// Slices are a view into a block of memory represented as a pointer and a /// length. /// @@ -585,8 +587,6 @@ mod prim_array { } /// assert_eq!(x, &[1, 7, 3]); /// ``` /// -/// *[See also the `std::slice` module](slice/index.html).* -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_slice { } @@ -862,11 +862,11 @@ mod prim_u128 { } // /// The pointer-sized signed integer type. /// +/// *[See also the `std::isize` module](isize/index.html).* +/// /// The size of this primitive is how many bytes it takes to reference any /// location in memory. For example, on a 32 bit target, this is 4 bytes /// and on a 64 bit target, this is 8 bytes. -/// -/// *[See also the `std::isize` module](isize/index.html).* #[stable(feature = "rust1", since = "1.0.0")] mod prim_isize { } @@ -874,11 +874,11 @@ mod prim_isize { } // /// The pointer-sized unsigned integer type. /// +/// *[See also the `std::usize` module](usize/index.html).* +/// /// The size of this primitive is how many bytes it takes to reference any /// location in memory. For example, on a 32 bit target, this is 4 bytes /// and on a 64 bit target, this is 8 bytes. -/// -/// *[See also the `std::usize` module](usize/index.html).* #[stable(feature = "rust1", since = "1.0.0")] mod prim_usize { } -- cgit 1.4.1-3-g733a5 From 827251e92bef9bd613cf44e2dc074fa1dc71ea0f Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 9 May 2018 15:52:16 -0700 Subject: Shorten ownership safety discussion in `read_volatile` Non-`Copy` types should not be in volatile memory. --- src/libcore/ptr.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 50627ee464d..f3cf2068766 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -622,6 +622,11 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// to not be elided or reordered by the compiler across other volatile /// operations. /// +/// Memory read with `read_volatile` should almost always be written to using +/// [`write_volatile`]. +/// +/// [`write_volatile`]: ./fn.write_volatile.html +/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model, @@ -644,16 +649,13 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// * `src` must be properly aligned. /// -/// Additionally, if `T` is not [`Copy`], only the returned value *or* the -/// pointed-to value can be used or dropped after calling `read_volatile`. -/// `read_volatile` creates a bitwise copy of `T`, regardless of whether `T: -/// Copy`, which can result in undefined behavior if both copies are used. -/// Note that `*src = foo` counts as a use because it will attempt to drop the -/// value previously at `*src`. [`write_volatile`] can be used to overwrite -/// data without causing it to be dropped. +/// Like [`read`], `read_volatile` creates a bitwise copy of the pointed-to +/// object, regardless of whether `T` is [`Copy`]. Using both values can cause +/// undefined behavior. However, storing non-[`Copy`] data in I/O memory is +/// almost certainly incorrect. /// /// [`Copy`]: ../marker/trait.Copy.html -/// [`write_volatile`]: ./fn.write_volatile.html +/// [`read`]: ./fn.read.html /// /// # Examples /// @@ -680,6 +682,9 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// to not be elided or reordered by the compiler across other volatile /// operations. /// +/// Memory written with `write_volatile` should almost always be read from using +/// [`read_volatile`]. +/// /// `write_volatile` does not drop the contents of `dst`. This is safe, but it /// could leak allocations or resources, so care must be taken not to overwrite /// an object that should be dropped. @@ -687,6 +692,8 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// Additionally, it does not drop `src`. Semantically, `src` is moved into the /// location pointed to by `dst`. /// +/// [`read_volatile`]: ./fn.read_volatile.html +/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model, -- cgit 1.4.1-3-g733a5 From 4d8d0a6f85ee66c7b65c53de3039aa38d99f05af Mon Sep 17 00:00:00 2001 From: Roman Stoliar Date: Tue, 8 May 2018 23:47:50 +0300 Subject: const time added rustc_const_unstable attribute extended tests added conversion test fixed tidy test added feature attribute --- src/libcore/tests/time.rs | 42 +++++++++++++++++++++++++-- src/libcore/time.rs | 12 +++++--- src/test/ui/const-eval/duration_conversion.rs | 28 ++++++++++++++++++ 3 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/const-eval/duration_conversion.rs (limited to 'src/libcore') diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs index 042c523f25f..0f3b95236f0 100644 --- a/src/libcore/tests/time.rs +++ b/src/libcore/tests/time.rs @@ -23,9 +23,43 @@ fn creation() { #[test] fn secs() { assert_eq!(Duration::new(0, 0).as_secs(), 0); + assert_eq!(Duration::new(0, 500_000_005).as_secs(), 0); + assert_eq!(Duration::new(0, 1_050_000_001).as_secs(), 1); assert_eq!(Duration::from_secs(1).as_secs(), 1); assert_eq!(Duration::from_millis(999).as_secs(), 0); assert_eq!(Duration::from_millis(1001).as_secs(), 1); + assert_eq!(Duration::from_micros(999_999).as_secs(), 0); + assert_eq!(Duration::from_micros(1_000_001).as_secs(), 1); + assert_eq!(Duration::from_nanos(999_999_999).as_secs(), 0); + assert_eq!(Duration::from_nanos(1_000_000_001).as_secs(), 1); +} + +#[test] +fn millis() { + assert_eq!(Duration::new(0, 0).subsec_millis(), 0); + assert_eq!(Duration::new(0, 500_000_005).subsec_millis(), 500); + assert_eq!(Duration::new(0, 1_050_000_001).subsec_millis(), 50); + assert_eq!(Duration::from_secs(1).subsec_millis(), 0); + assert_eq!(Duration::from_millis(999).subsec_millis(), 999); + assert_eq!(Duration::from_millis(1001).subsec_millis(), 1); + assert_eq!(Duration::from_micros(999_999).subsec_millis(), 999); + assert_eq!(Duration::from_micros(1_001_000).subsec_millis(), 1); + assert_eq!(Duration::from_nanos(999_999_999).subsec_millis(), 999); + assert_eq!(Duration::from_nanos(1_001_000_000).subsec_millis(), 1); +} + +#[test] +fn micros() { + assert_eq!(Duration::new(0, 0).subsec_micros(), 0); + assert_eq!(Duration::new(0, 500_000_005).subsec_micros(), 500_000); + assert_eq!(Duration::new(0, 1_050_000_001).subsec_micros(), 50_000); + assert_eq!(Duration::from_secs(1).subsec_micros(), 0); + assert_eq!(Duration::from_millis(999).subsec_micros(), 999_000); + assert_eq!(Duration::from_millis(1001).subsec_micros(), 1_000); + assert_eq!(Duration::from_micros(999_999).subsec_micros(), 999_999); + assert_eq!(Duration::from_micros(1_000_001).subsec_micros(), 1); + assert_eq!(Duration::from_nanos(999_999_999).subsec_micros(), 999_999); + assert_eq!(Duration::from_nanos(1_000_001_000).subsec_micros(), 1); } #[test] @@ -34,8 +68,12 @@ fn nanos() { assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); - assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000); - assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000); + assert_eq!(Duration::from_millis(999).subsec_nanos(), 999_000_000); + assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1_000_000); + assert_eq!(Duration::from_micros(999_999).subsec_nanos(), 999_999_000); + assert_eq!(Duration::from_micros(1_000_001).subsec_nanos(), 1000); + assert_eq!(Duration::from_nanos(999_999_999).subsec_nanos(), 999_999_999); + assert_eq!(Duration::from_nanos(1_000_000_001).subsec_nanos(), 1); } #[test] diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 8e8b1691c65..c0b2b2a0bc6 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -203,8 +203,9 @@ impl Duration { /// /// [`subsec_nanos`]: #method.subsec_nanos #[stable(feature = "duration", since = "1.3.0")] + #[rustc_const_unstable(feature="duration_getters")] #[inline] - pub fn as_secs(&self) -> u64 { self.secs } + pub const fn as_secs(&self) -> u64 { self.secs } /// Returns the fractional part of this `Duration`, in milliseconds. /// @@ -222,8 +223,9 @@ impl Duration { /// assert_eq!(duration.subsec_millis(), 432); /// ``` #[stable(feature = "duration_extras", since = "1.27.0")] + #[rustc_const_unstable(feature="duration_getters")] #[inline] - pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI } + pub const fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI } /// Returns the fractional part of this `Duration`, in microseconds. /// @@ -241,8 +243,9 @@ impl Duration { /// assert_eq!(duration.subsec_micros(), 234_567); /// ``` #[stable(feature = "duration_extras", since = "1.27.0")] + #[rustc_const_unstable(feature="duration_getters")] #[inline] - pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO } + pub const fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO } /// Returns the fractional part of this `Duration`, in nanoseconds. /// @@ -260,8 +263,9 @@ impl Duration { /// assert_eq!(duration.subsec_nanos(), 10_000_000); /// ``` #[stable(feature = "duration", since = "1.3.0")] + #[rustc_const_unstable(feature="duration_getters")] #[inline] - pub fn subsec_nanos(&self) -> u32 { self.nanos } + pub const fn subsec_nanos(&self) -> u32 { self.nanos } /// Checked `Duration` addition. Computes `self + other`, returning [`None`] /// if overflow occurred. diff --git a/src/test/ui/const-eval/duration_conversion.rs b/src/test/ui/const-eval/duration_conversion.rs new file mode 100644 index 00000000000..4481b758404 --- /dev/null +++ b/src/test/ui/const-eval/duration_conversion.rs @@ -0,0 +1,28 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +#![feature(duration_getters)] + +use std::time::Duration; + +fn main() { + const _ONE_SECOND: Duration = Duration::from_nanos(1_000_000_000); + const _ONE_MILLISECOND: Duration = Duration::from_nanos(1_000_000); + const _ONE_MICROSECOND: Duration = Duration::from_nanos(1_000); + const _ONE_NANOSECOND: Duration = Duration::from_nanos(1); + const _ONE: usize = _ONE_SECOND.as_secs() as usize; + const _TWO: usize = _ONE_MILLISECOND.subsec_millis() as usize; + const _THREE: usize = _ONE_MICROSECOND.subsec_micros() as usize; + const _FOUR: usize = _ONE_NANOSECOND.subsec_nanos() as usize; + const _0: [[u8; _ONE]; _TWO] = [[1; _ONE]; _TWO]; + const _1: [[u8; _THREE]; _FOUR] = [[3; _THREE]; _FOUR]; +} -- cgit 1.4.1-3-g733a5 From 61d1c14633dd1602513784e8cafe007ef01733bb Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 13 May 2018 15:45:33 -0400 Subject: Fix incorrect statement about return value for Iterator::zip. Fixes https://github.com/rust-lang/rust/issues/50225. --- src/libcore/iter/iterator.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index b27bd3142e1..d22c5376211 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -366,8 +366,7 @@ pub trait Iterator { /// /// In other words, it zips two iterators together, into a single one. /// - /// When either iterator returns [`None`], all further calls to [`next`] - /// will return [`None`]. + /// If either iterator returns [`None`], [`next`] will return [`None`]. /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 120cd2cfd67310571982236bccb1e7679ef9beea Mon Sep 17 00:00:00 2001 From: Matt Kraai Date: Mon, 14 May 2018 07:15:48 -0700 Subject: Uncapitalize "You" --- src/libcore/iter/traits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index ddbb5998942..173dfc36f04 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -587,7 +587,7 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { /// that information can be useful. For example, if you want to iterate /// backwards, a good start is to know where the end is. /// -/// When implementing an `ExactSizeIterator`, You must also implement +/// When implementing an `ExactSizeIterator`, you must also implement /// [`Iterator`]. When doing so, the implementation of [`size_hint`] *must* /// return the exact size of the iterator. /// -- cgit 1.4.1-3-g733a5 From a74e1686d979fbf5688de549a9b2a951b1fb278f Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 25 Apr 2018 15:00:59 -0700 Subject: Add implementation of Extend for () --- src/libcore/iter/traits.rs | 7 +++++++ src/test/run-pass/extend-for-unit.rs | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/test/run-pass/extend-for-unit.rs (limited to 'src/libcore') diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index ddbb5998942..b9987212070 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -352,6 +352,13 @@ pub trait Extend { fn extend>(&mut self, iter: T); } +#[stable(feature = "extend_for_unit", since = "1.28.0")] +impl Extend<()> for () { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(drop) + } +} + /// An iterator able to yield elements from both ends. /// /// Something that implements `DoubleEndedIterator` has one extra capability diff --git a/src/test/run-pass/extend-for-unit.rs b/src/test/run-pass/extend-for-unit.rs new file mode 100644 index 00000000000..d1a0614bd8a --- /dev/null +++ b/src/test/run-pass/extend-for-unit.rs @@ -0,0 +1,20 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn main() { + let mut x = 0; + { + let iter = (0..5).map(|_| { + x += 1; + }); + ().extend(iter); + } + assert_eq!(x, 5); +} -- cgit 1.4.1-3-g733a5 From 8ab2d15f6753054797c88f07028e4802c43b70ab Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Tue, 8 May 2018 21:30:38 -0400 Subject: Add Option::xor method --- src/libcore/option.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 0dfdabee031..28f37f72d6f 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -705,6 +705,42 @@ impl Option { } } + /// Returns [`Some`] if exactly one of `self`, `optb` is [`Some`], otherwise returns `None`. + /// + /// [`Some`]: #variant.Some + /// [`None`]: #variant.None + /// + /// # Examples + /// + /// ``` + /// #![feature(option_xor)] + /// + /// let x = Some(2); + /// let y: Option = None; + /// assert_eq!(x.xor(y), Some(2)); + /// + /// let x: Option = None; + /// let y = Some(2); + /// assert_eq!(x.xor(y), Some(2)); + /// + /// let x = Some(2); + /// let y = Some(2); + /// assert_eq!(x.xor(y), None); + /// + /// let x: Option = None; + /// let y: Option = None; + /// assert_eq!(x.xor(y), None); + /// ``` + #[inline] + #[unstable(feature = "option_xor", issue = "50512")] + pub fn xor(self, optb: Option) -> Option { + match (self, optb) { + (Some(a), None) => Some(a), + (None, Some(b)) => Some(b), + _ => None, + } + } + ///////////////////////////////////////////////////////////////////////// // Entry-like operations to insert if None and return a reference ///////////////////////////////////////////////////////////////////////// -- cgit 1.4.1-3-g733a5 From 99cf5a92acba672845a3563c4abf98e663eaf5cd Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Tue, 15 May 2018 12:52:16 -0400 Subject: Separate feature gate for wrapping_next_power_of_two --- src/libcore/num/mod.rs | 5 +++-- src/libcore/num/wrapping.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 38f1688f0d5..97fcd8ebb50 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3433,14 +3433,15 @@ the return value is wrapped to `0`. Basic usage: ``` -#![feature(wrapping_int_impl)] +#![feature(wrapping_next_power_of_two)] ", $Feature, " assert_eq!(2", stringify!($SelfT), ".wrapping_next_power_of_two(), 2); assert_eq!(3", stringify!($SelfT), ".wrapping_next_power_of_two(), 4); assert_eq!(", stringify!($SelfT), "::max_value().wrapping_next_power_of_two(), 0);", $EndFeature, " ```"), - #[unstable(feature = "wrapping_int_impl", issue = "32463")] + #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", + reason = "needs decision on wrapping behaviour")] pub fn wrapping_next_power_of_two(self) -> Self { self.one_less_than_next_power_of_two().wrapping_add(1) } diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index 6d5783282b0..d7f87d37f5b 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -874,7 +874,7 @@ When return value overflows (i.e. `self > (1 << (N-1))` for type Basic usage: ``` -#![feature(wrapping_int_impl)] +#![feature(wrapping_next_power_of_two)] use std::num::Wrapping; assert_eq!(Wrapping(2", stringify!($t), ").next_power_of_two(), Wrapping(2)); @@ -882,7 +882,8 @@ assert_eq!(Wrapping(3", stringify!($t), ").next_power_of_two(), Wrapping(4)); assert_eq!(Wrapping(200_u8).next_power_of_two(), Wrapping(0)); ```"), #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] + #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", + reason = "needs decision on wrapping behaviour")] pub fn next_power_of_two(self) -> Self { Wrapping(self.0.wrapping_next_power_of_two()) } -- cgit 1.4.1-3-g733a5 From a2896bf814d8fda797abb4d5cbd7972510516de8 Mon Sep 17 00:00:00 2001 From: SHA Miao Date: Wed, 16 May 2018 14:18:53 +0800 Subject: fix a typo in signed-integer::from_str_radix() just a small typo. --- src/libcore/num/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index a062fbda5ba..a1168d74e4b 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -252,7 +252,7 @@ depending on `radix`: * `0-9` * `a-z` - * `a-z` + * `A-Z` # Panics -- cgit 1.4.1-3-g733a5 From 2a28ac31e9abe0a01861bfffed85872431cc6b72 Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Wed, 16 May 2018 14:46:37 +0200 Subject: Implement rounding for `Duration`s Debug output Rounding is done like for printing floating point numbers. If the first digit which isn't printed (due to the precision parameter) is larger than '4', the number is rounded up. --- src/libcore/tests/time.rs | 22 ++++++++++++++++------ src/libcore/time.rs | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 7 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs index bfb5369cf8f..b0abdc749f6 100644 --- a/src/libcore/tests/time.rs +++ b/src/libcore/tests/time.rs @@ -202,13 +202,19 @@ fn debug_formatting_precision_zero() { assert_eq!(format!("{:.0?}", Duration::new(0, 123)), "123ns"); assert_eq!(format!("{:.0?}", Duration::new(0, 1_001)), "1µs"); - assert_eq!(format!("{:.0?}", Duration::new(0, 1_999)), "1µs"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_499)), "1µs"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_500)), "2µs"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_999)), "2µs"); assert_eq!(format!("{:.0?}", Duration::new(0, 1_000_001)), "1ms"); - assert_eq!(format!("{:.0?}", Duration::new(0, 1_999_999)), "1ms"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_499_999)), "1ms"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_500_000)), "2ms"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_999_999)), "2ms"); assert_eq!(format!("{:.0?}", Duration::new(1, 000_000_001)), "1s"); - assert_eq!(format!("{:.0?}", Duration::new(1, 999_999_999)), "1s"); + assert_eq!(format!("{:.0?}", Duration::new(1, 499_999_999)), "1s"); + assert_eq!(format!("{:.0?}", Duration::new(1, 500_000_000)), "2s"); + assert_eq!(format!("{:.0?}", Duration::new(1, 999_999_999)), "2s"); } #[test] @@ -222,15 +228,19 @@ fn debug_formatting_precision_two() { assert_eq!(format!("{:.2?}", Duration::new(0, 1_000)), "1.00µs"); assert_eq!(format!("{:.2?}", Duration::new(0, 7_001)), "7.00µs"); assert_eq!(format!("{:.2?}", Duration::new(0, 7_100)), "7.10µs"); - assert_eq!(format!("{:.2?}", Duration::new(0, 1_999)), "1.99µs"); + assert_eq!(format!("{:.2?}", Duration::new(0, 7_109)), "7.11µs"); + assert_eq!(format!("{:.2?}", Duration::new(0, 7_199)), "7.20µs"); + assert_eq!(format!("{:.2?}", Duration::new(0, 1_999)), "2.00µs"); assert_eq!(format!("{:.2?}", Duration::new(0, 1_000_000)), "1.00ms"); assert_eq!(format!("{:.2?}", Duration::new(0, 3_001_000)), "3.00ms"); assert_eq!(format!("{:.2?}", Duration::new(0, 3_100_000)), "3.10ms"); - assert_eq!(format!("{:.2?}", Duration::new(0, 1_999_999)), "1.99ms"); + assert_eq!(format!("{:.2?}", Duration::new(0, 1_999_999)), "2.00ms"); assert_eq!(format!("{:.2?}", Duration::new(1, 000_000_000)), "1.00s"); assert_eq!(format!("{:.2?}", Duration::new(4, 001_000_000)), "4.00s"); assert_eq!(format!("{:.2?}", Duration::new(2, 100_000_000)), "2.10s"); - assert_eq!(format!("{:.2?}", Duration::new(8, 999_999_999)), "8.99s"); + assert_eq!(format!("{:.2?}", Duration::new(2, 104_990_000)), "2.10s"); + assert_eq!(format!("{:.2?}", Duration::new(2, 105_000_000)), "2.11s"); + assert_eq!(format!("{:.2?}", Duration::new(8, 999_999_999)), "9.00s"); } diff --git a/src/libcore/time.rs b/src/libcore/time.rs index a0a48e8493c..34bf3637f29 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -498,7 +498,7 @@ impl fmt::Debug for Duration { /// to be less than `10 * divisor`! fn fmt_decimal( f: &mut fmt::Formatter, - integer_part: u64, + mut integer_part: u64, mut fractional_part: u32, mut divisor: u32, ) -> fmt::Result { @@ -522,6 +522,40 @@ impl fmt::Debug for Duration { pos += 1; } + // If a precision < 9 was specified, there may be some non-zero + // digits left that weren't written into the buffer. In that case we + // need to perform rounding to match the semantics of printing + // normal floating point numbers. However, we only need to do work + // when rounding up. This happens if the first digit of the + // remaining ones is >= 5. + if fractional_part > 0 && fractional_part >= divisor * 5 { + // Round up the number contained in the buffer. We go through + // the buffer backwards and keep track of the carry. + let mut rev_pos = pos; + let mut carry = true; + while carry && rev_pos > 0 { + rev_pos -= 1; + + // If the digit in the buffer is not '9', we just need to + // increment it and can stop then (since we don't have a + // carry anymore). Otherwise, we set it to '0' (overflow) + // and continue. + if buf[rev_pos] < b'9' { + buf[rev_pos] += 1; + carry = false; + } else { + buf[rev_pos] = b'0'; + } + } + + // If we still have the carry bit set, that means that we set + // the whole buffer to '0's and need to increment the integer + // part. + if carry { + integer_part += 1; + } + } + // If we haven't emitted a single fractional digit and the precision // wasn't set to a non-zero value, we don't print the decimal point. let end = f.precision().unwrap_or(pos); -- cgit 1.4.1-3-g733a5 From 59e71141029162fe4b4a3ed4cad430dace3fb995 Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Wed, 16 May 2018 15:08:39 +0200 Subject: Fix `Debug` impl of `Duration` for precisions > 9 Previously, the code would panic for high precision values. Now it has the same behavior as printing normal floating point values: if a high precision is specified, '0's are added. --- src/libcore/tests/time.rs | 16 +++++++++++----- src/libcore/time.rs | 19 +++++++++++++------ 2 files changed, 24 insertions(+), 11 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs index b0abdc749f6..ef3e1acfbf5 100644 --- a/src/libcore/tests/time.rs +++ b/src/libcore/tests/time.rs @@ -219,11 +219,8 @@ fn debug_formatting_precision_zero() { #[test] fn debug_formatting_precision_two() { - // This might seem inconsistent with the other units, but printing - // fractional digits for nano seconds would imply more precision than is - // actually stored. - assert_eq!(format!("{:.2?}", Duration::new(0, 0)), "0ns"); - assert_eq!(format!("{:.2?}", Duration::new(0, 123)), "123ns"); + assert_eq!(format!("{:.2?}", Duration::new(0, 0)), "0.00ns"); + assert_eq!(format!("{:.2?}", Duration::new(0, 123)), "123.00ns"); assert_eq!(format!("{:.2?}", Duration::new(0, 1_000)), "1.00µs"); assert_eq!(format!("{:.2?}", Duration::new(0, 7_001)), "7.00µs"); @@ -244,3 +241,12 @@ fn debug_formatting_precision_two() { assert_eq!(format!("{:.2?}", Duration::new(2, 105_000_000)), "2.11s"); assert_eq!(format!("{:.2?}", Duration::new(8, 999_999_999)), "9.00s"); } + +#[test] +fn debug_formatting_precision_high() { + assert_eq!(format!("{:.5?}", Duration::new(0, 23_678)), "23.67800µs"); + + assert_eq!(format!("{:.9?}", Duration::new(1, 000_000_000)), "1.000000000s"); + assert_eq!(format!("{:.10?}", Duration::new(4, 001_000_000)), "4.0010000000s"); + assert_eq!(format!("{:.20?}", Duration::new(4, 001_000_000)), "4.00100000000000000000s"); +} diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 34bf3637f29..9703c61fe92 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -511,9 +511,9 @@ impl fmt::Debug for Duration { // The next digit is written at this position let mut pos = 0; - // We can stop when there are no non-zero digits left or (when a - // precision was set and we already emitted that many digits). - while fractional_part > 0 && f.precision().map(|p| p > pos).unwrap_or(true) { + // We keep writing digits into the buffer while there are non-zero + // digits left and we haven't written enough digits yet. + while fractional_part > 0 && pos < f.precision().unwrap_or(9) { // Write new digit into the buffer buf[pos] = b'0' + (fractional_part / divisor) as u8; @@ -556,9 +556,13 @@ impl fmt::Debug for Duration { } } + // Determine the end of the buffer: if precision is set, we just + // use as many digits from the buffer (capped to 9). If it isn't + // set, we only use all digits up to the last non-zero one. + let end = f.precision().map(|p| ::cmp::min(p, 9)).unwrap_or(pos); + // If we haven't emitted a single fractional digit and the precision // wasn't set to a non-zero value, we don't print the decimal point. - let end = f.precision().unwrap_or(pos); if end == 0 { write!(f, "{}", integer_part) } else { @@ -568,7 +572,9 @@ impl fmt::Debug for Duration { ::str::from_utf8_unchecked(&buf[..end]) }; - write!(f, "{}.{}", integer_part, s) + // If the user request a precision > 9, we pad '0's at the end. + let w = f.precision().unwrap_or(pos); + write!(f, "{}.{:0 Date: Fri, 16 Feb 2018 11:33:22 +0100 Subject: Make core::nonzero private It is now an implementation detail of ptr::NonNull and num::NonZero* --- src/libcore/lib.rs | 2 +- src/libcore/nonzero.rs | 96 +--------------------- src/libcore/num/mod.rs | 4 +- src/libcore/ptr.rs | 11 +-- .../run-pass/ctfe/tuple-struct-constructors.rs | 7 +- 5 files changed, 10 insertions(+), 110 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 54f35d17974..06fbfcecba8 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -171,7 +171,6 @@ pub mod prelude; pub mod intrinsics; pub mod mem; -pub mod nonzero; pub mod ptr; pub mod hint; @@ -221,6 +220,7 @@ pub mod heap { // note: does not need to be public mod iter_private; +mod nonzero; mod tuple; mod unit; diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 19836d98844..ee5230cef8d 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -9,103 +9,13 @@ // except according to those terms. //! Exposes the NonZero lang item which provides optimization hints. -#![unstable(feature = "nonzero", reason = "deprecated", issue = "49137")] -#![rustc_deprecated(reason = "use `std::ptr::NonNull` or `std::num::NonZero*` instead", - since = "1.26.0")] -#![allow(deprecated)] use ops::CoerceUnsized; -/// Unsafe trait to indicate what types are usable with the NonZero struct -pub unsafe trait Zeroable { - /// Whether this value is zero - fn is_zero(&self) -> bool; -} - -macro_rules! impl_zeroable_for_pointer_types { - ( $( $Ptr: ty )+ ) => { - $( - /// For fat pointers to be considered "zero", only the "data" part needs to be null. - unsafe impl Zeroable for $Ptr { - #[inline] - fn is_zero(&self) -> bool { - (*self).is_null() - } - } - )+ - } -} - -macro_rules! impl_zeroable_for_integer_types { - ( $( $Int: ty )+ ) => { - $( - unsafe impl Zeroable for $Int { - #[inline] - fn is_zero(&self) -> bool { - *self == 0 - } - } - )+ - } -} - -impl_zeroable_for_pointer_types! { - *const T - *mut T -} - -impl_zeroable_for_integer_types! { - usize u8 u16 u32 u64 u128 - isize i8 i16 i32 i64 i128 -} - /// A wrapper type for raw pointers and integers that will never be /// NULL or 0 that might allow certain optimizations. #[lang = "non_zero"] -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] -pub struct NonZero(pub(crate) T); - -impl NonZero { - /// Creates an instance of NonZero with the provided value. - /// You must indeed ensure that the value is actually "non-zero". - #[inline] - pub const unsafe fn new_unchecked(inner: T) -> Self { - NonZero(inner) - } - - /// Creates an instance of NonZero with the provided value. - #[inline] - pub fn new(inner: T) -> Option { - if inner.is_zero() { - None - } else { - Some(NonZero(inner)) - } - } - - /// Gets the inner value. - pub fn get(self) -> T { - self.0 - } -} - -impl, U: Zeroable> CoerceUnsized> for NonZero {} - -impl<'a, T: ?Sized> From<&'a mut T> for NonZero<*mut T> { - fn from(reference: &'a mut T) -> Self { - NonZero(reference) - } -} - -impl<'a, T: ?Sized> From<&'a mut T> for NonZero<*const T> { - fn from(reference: &'a mut T) -> Self { - let ptr: *mut T = reference; - NonZero(ptr) - } -} +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub(crate) struct NonZero(pub(crate) T); -impl<'a, T: ?Sized> From<&'a T> for NonZero<*const T> { - fn from(reference: &'a T) -> Self { - NonZero(reference) - } -} +impl, U> CoerceUnsized> for NonZero {} diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index a062fbda5ba..ef914a0fc5c 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -16,7 +16,7 @@ use convert::TryFrom; use fmt; use intrinsics; use mem; -#[allow(deprecated)] use nonzero::NonZero; +use nonzero::NonZero; use ops; use str::FromStr; @@ -49,11 +49,9 @@ macro_rules! nonzero_integers { /// ``` #[$stability] #[$deprecation] - #[allow(deprecated)] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct $Ty(NonZero<$Int>); - #[allow(deprecated)] impl $Ty { /// Create a non-zero without checking the value. /// diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 83dfac7a3a2..63bcc024020 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -23,7 +23,7 @@ use fmt; use hash; use marker::{PhantomData, Unsize}; use mem; -#[allow(deprecated)] use nonzero::NonZero; +use nonzero::NonZero; use cmp::Ordering::{self, Less, Equal, Greater}; @@ -2742,7 +2742,6 @@ impl PartialOrd for *mut T { #[unstable(feature = "ptr_internals", issue = "0", reason = "use NonNull instead and consider PhantomData \ (if you also use #[may_dangle]), Send, and/or Sync")] -#[allow(deprecated)] #[doc(hidden)] pub struct Unique { pointer: NonZero<*const T>, @@ -2790,7 +2789,6 @@ impl Unique { } #[unstable(feature = "ptr_internals", issue = "0")] -#[allow(deprecated)] impl Unique { /// Creates a new `Unique`. /// @@ -2855,7 +2853,6 @@ impl fmt::Pointer for Unique { } #[unstable(feature = "ptr_internals", issue = "0")] -#[allow(deprecated)] impl<'a, T: ?Sized> From<&'a mut T> for Unique { fn from(reference: &'a mut T) -> Self { Unique { pointer: NonZero(reference as _), _marker: PhantomData } @@ -2863,7 +2860,6 @@ impl<'a, T: ?Sized> From<&'a mut T> for Unique { } #[unstable(feature = "ptr_internals", issue = "0")] -#[allow(deprecated)] impl<'a, T: ?Sized> From<&'a T> for Unique { fn from(reference: &'a T) -> Self { Unique { pointer: NonZero(reference as _), _marker: PhantomData } @@ -2896,7 +2892,7 @@ impl<'a, T: ?Sized> From> for Unique { /// provide a public API that follows the normal shared XOR mutable rules of Rust. #[stable(feature = "nonnull", since = "1.25.0")] pub struct NonNull { - #[allow(deprecated)] pointer: NonZero<*const T>, + pointer: NonZero<*const T>, } /// `NonNull` pointers are not `Send` because the data they reference may be aliased. @@ -2923,7 +2919,6 @@ impl NonNull { } } -#[allow(deprecated)] impl NonNull { /// Creates a new `NonNull`. /// @@ -3054,7 +3049,6 @@ impl From> for NonNull { } #[stable(feature = "nonnull", since = "1.25.0")] -#[allow(deprecated)] impl<'a, T: ?Sized> From<&'a mut T> for NonNull { fn from(reference: &'a mut T) -> Self { NonNull { pointer: NonZero(reference as _) } @@ -3062,7 +3056,6 @@ impl<'a, T: ?Sized> From<&'a mut T> for NonNull { } #[stable(feature = "nonnull", since = "1.25.0")] -#[allow(deprecated)] impl<'a, T: ?Sized> From<&'a T> for NonNull { fn from(reference: &'a T) -> Self { NonNull { pointer: NonZero(reference as _) } diff --git a/src/test/run-pass/ctfe/tuple-struct-constructors.rs b/src/test/run-pass/ctfe/tuple-struct-constructors.rs index ecc5d376636..ee1ce192fe0 100644 --- a/src/test/run-pass/ctfe/tuple-struct-constructors.rs +++ b/src/test/run-pass/ctfe/tuple-struct-constructors.rs @@ -10,11 +10,10 @@ // https://github.com/rust-lang/rust/issues/41898 -#![feature(nonzero, const_fn)] -extern crate core; -use core::nonzero::NonZero; +#![feature(nonzero)] +use std::num::NonZeroU64; fn main() { - const FOO: NonZero = unsafe { NonZero::new_unchecked(2) }; + const FOO: NonZeroU64 = unsafe { NonZeroU64::new_unchecked(2) }; if let FOO = FOO {} } -- cgit 1.4.1-3-g733a5 From c536639c1e1ce7e2b4816a40f2e954c581431456 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 24 Mar 2018 11:36:29 +0100 Subject: Remove unstable deprecated num::NonZeroI* types --- src/libcore/num/mod.rs | 18 +----------------- src/libstd/num.rs | 5 +---- 2 files changed, 2 insertions(+), 21 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index ef914a0fc5c..342f57b50f0 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -24,7 +24,6 @@ macro_rules! impl_nonzero_fmt { ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { $( #[$stability] - #[allow(deprecated)] impl fmt::$Trait for $Ty { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -36,7 +35,7 @@ macro_rules! impl_nonzero_fmt { } macro_rules! nonzero_integers { - ( #[$stability: meta] #[$deprecation: meta] $( $Ty: ident($Int: ty); )+ ) => { + ( #[$stability: meta] $( $Ty: ident($Int: ty); )+ ) => { $( /// An integer that is known not to equal zero. /// @@ -48,7 +47,6 @@ macro_rules! nonzero_integers { /// assert_eq!(size_of::>(), size_of::()); /// ``` #[$stability] - #[$deprecation] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct $Ty(NonZero<$Int>); @@ -94,7 +92,6 @@ macro_rules! nonzero_integers { nonzero_integers! { #[unstable(feature = "nonzero", issue = "49137")] - #[allow(deprecated)] // Redundant, works around "error: inconsistent lockstep iteration" NonZeroU8(u8); NonZeroU16(u16); NonZeroU32(u32); @@ -103,19 +100,6 @@ nonzero_integers! { NonZeroUsize(usize); } -nonzero_integers! { - #[unstable(feature = "nonzero", issue = "49137")] - #[rustc_deprecated(since = "1.26.0", reason = "\ - signed non-zero integers are considered for removal due to lack of known use cases. \ - If you’re using them, please comment on https://github.com/rust-lang/rust/issues/49137")] - NonZeroI8(i8); - NonZeroI16(i16); - NonZeroI32(i32); - NonZeroI64(i64); - NonZeroI128(i128); - NonZeroIsize(isize); -} - /// Provides intentionally-wrapped arithmetic on `T`. /// /// Operations like `+` on `u32` values is intended to never overflow, diff --git a/src/libstd/num.rs b/src/libstd/num.rs index 4b975dd912a..aa806b947b0 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -23,10 +23,7 @@ pub use core::num::Wrapping; #[unstable(feature = "nonzero", issue = "49137")] #[allow(deprecated)] -pub use core::num::{ - NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, - NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize, -}; +pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize}; #[cfg(test)] use fmt; #[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem}; -- cgit 1.4.1-3-g733a5 From 89d9ca9b50e01cbc5dc78a26f15cc8c435bbc5a4 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 16 May 2018 18:07:35 +0200 Subject: Stabilize num::NonZeroU* Tracking issue: https://github.com/rust-lang/rust/issues/49137 --- src/liballoc/lib.rs | 1 - src/libcore/num/mod.rs | 16 +++++++--------- src/libcore/tests/lib.rs | 1 - src/librustc/lib.rs | 1 - src/librustc_data_structures/lib.rs | 1 - src/librustc_mir/lib.rs | 1 - src/libstd/lib.rs | 1 - src/libstd/num.rs | 3 +-- src/test/run-pass/ctfe/tuple-struct-constructors.rs | 1 - src/test/run-pass/enum-null-pointer-opt.rs | 2 -- src/test/ui/print_type_sizes/niche-filling.rs | 1 - 11 files changed, 8 insertions(+), 21 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index bb78c14b905..f7dd9d4f010 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -102,7 +102,6 @@ #![feature(lang_items)] #![feature(libc)] #![feature(needs_allocator)] -#![feature(nonzero)] #![feature(optin_builtin_traits)] #![feature(pattern)] #![feature(pin)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 342f57b50f0..ae8b3087240 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -21,9 +21,9 @@ use ops; use str::FromStr; macro_rules! impl_nonzero_fmt { - ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { + ( ( $( $Trait: ident ),+ ) for $Ty: ident ) => { $( - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] impl fmt::$Trait for $Ty { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -35,7 +35,7 @@ macro_rules! impl_nonzero_fmt { } macro_rules! nonzero_integers { - ( #[$stability: meta] $( $Ty: ident($Int: ty); )+ ) => { + ( $( $Ty: ident($Int: ty); )+ ) => { $( /// An integer that is known not to equal zero. /// @@ -46,7 +46,7 @@ macro_rules! nonzero_integers { /// use std::mem::size_of; /// assert_eq!(size_of::>(), size_of::()); /// ``` - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct $Ty(NonZero<$Int>); @@ -56,14 +56,14 @@ macro_rules! nonzero_integers { /// # Safety /// /// The value must not be zero. - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] #[inline] pub const unsafe fn new_unchecked(n: $Int) -> Self { $Ty(NonZero(n)) } /// Create a non-zero if the given value is not zero. - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] #[inline] pub fn new(n: $Int) -> Option { if n != 0 { @@ -74,7 +74,7 @@ macro_rules! nonzero_integers { } /// Returns the value as a primitive type. - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] #[inline] pub fn get(self) -> $Int { self.0 .0 @@ -83,7 +83,6 @@ macro_rules! nonzero_integers { } impl_nonzero_fmt! { - #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty } )+ @@ -91,7 +90,6 @@ macro_rules! nonzero_integers { } nonzero_integers! { - #[unstable(feature = "nonzero", issue = "49137")] NonZeroU8(u8); NonZeroU16(u16); NonZeroU32(u32); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 5e98e40e0d5..7fb4b503c01 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -26,7 +26,6 @@ #![feature(iterator_step_by)] #![feature(iterator_flatten)] #![feature(iterator_repeat_with)] -#![feature(nonzero)] #![feature(pattern)] #![feature(range_is_empty)] #![feature(raw)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 26ac9d6ee9e..ac6ff6831ad 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -56,7 +56,6 @@ #![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(non_exhaustive)] -#![feature(nonzero)] #![feature(proc_macro_internals)] #![feature(quote)] #![feature(optin_builtin_traits)] diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index b2e7450e76c..328ff76c1cd 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -21,7 +21,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(collections_range)] -#![feature(nonzero)] #![feature(unboxed_closures)] #![feature(fn_traits)] #![feature(unsize)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index fbc0facbc49..ecced1b8168 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -30,7 +30,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(exhaustive_patterns)] #![feature(range_contains)] #![feature(rustc_diagnostic_macros)] -#![feature(nonzero)] #![feature(inclusive_range_methods)] #![feature(crate_visibility_modifier)] #![feature(never_type)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d41739ab02c..9cdc6a21622 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -277,7 +277,6 @@ #![feature(needs_panic_runtime)] #![feature(never_type)] #![feature(exhaustive_patterns)] -#![feature(nonzero)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] diff --git a/src/libstd/num.rs b/src/libstd/num.rs index aa806b947b0..3f90c1fa3b1 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -21,8 +21,7 @@ pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError} #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::Wrapping; -#[unstable(feature = "nonzero", issue = "49137")] -#[allow(deprecated)] +#[stable(feature = "nonzero", since = "1.28.0")] pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize}; #[cfg(test)] use fmt; diff --git a/src/test/run-pass/ctfe/tuple-struct-constructors.rs b/src/test/run-pass/ctfe/tuple-struct-constructors.rs index ee1ce192fe0..d5f3e88fd52 100644 --- a/src/test/run-pass/ctfe/tuple-struct-constructors.rs +++ b/src/test/run-pass/ctfe/tuple-struct-constructors.rs @@ -10,7 +10,6 @@ // https://github.com/rust-lang/rust/issues/41898 -#![feature(nonzero)] use std::num::NonZeroU64; fn main() { diff --git a/src/test/run-pass/enum-null-pointer-opt.rs b/src/test/run-pass/enum-null-pointer-opt.rs index 12f17a1575e..34ed589d418 100644 --- a/src/test/run-pass/enum-null-pointer-opt.rs +++ b/src/test/run-pass/enum-null-pointer-opt.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(nonzero, core)] - use std::mem::size_of; use std::num::NonZeroUsize; use std::ptr::NonNull; diff --git a/src/test/ui/print_type_sizes/niche-filling.rs b/src/test/ui/print_type_sizes/niche-filling.rs index 1aad0b760b1..17e7a21cd02 100644 --- a/src/test/ui/print_type_sizes/niche-filling.rs +++ b/src/test/ui/print_type_sizes/niche-filling.rs @@ -22,7 +22,6 @@ // padding and overall computed sizes can be quite different. #![feature(start)] -#![feature(nonzero)] #![allow(dead_code)] use std::num::NonZeroU32; -- cgit 1.4.1-3-g733a5 From b63d7e2b1c4019e40051036bcb1fd5f254a8f6e2 Mon Sep 17 00:00:00 2001 From: Irina Popa Date: Tue, 8 May 2018 16:10:16 +0300 Subject: Rename trans to codegen everywhere. --- src/Cargo.lock | 94 +- src/Cargo.toml | 2 +- src/bootstrap/builder.rs | 2 +- src/bootstrap/check.rs | 10 +- src/bootstrap/compile.rs | 16 +- src/doc/rustc-ux-guidelines.md | 2 +- src/liballoc/alloc.rs | 2 +- src/libcore/intrinsics.rs | 2 +- src/librustc/Cargo.toml | 6 +- src/librustc/cfg/construct.rs | 6 +- src/librustc/dep_graph/dep_node.rs | 6 +- src/librustc/dep_graph/graph.rs | 4 +- src/librustc/hir/check_attr.rs | 2 +- src/librustc/hir/mod.rs | 17 +- src/librustc/ich/impls_hir.rs | 6 +- src/librustc/ich/mod.rs | 6 +- src/librustc/infer/anon_types/mod.rs | 2 +- src/librustc/lint/context.rs | 8 +- src/librustc/lint/mod.rs | 6 +- src/librustc/middle/dependency_format.rs | 2 +- src/librustc/middle/mem_categorization.rs | 4 +- src/librustc/middle/reachable.rs | 18 +- src/librustc/middle/region.rs | 2 +- src/librustc/mir/interpret/mod.rs | 2 +- src/librustc/mir/interpret/value.rs | 2 +- src/librustc/mir/mod.rs | 4 +- src/librustc/mir/mono.rs | 9 +- src/librustc/session/config.rs | 32 +- src/librustc/session/mod.rs | 12 +- src/librustc/traits/codegen/mod.rs | 184 ++ src/librustc/traits/mod.rs | 10 +- src/librustc/traits/project.rs | 6 +- src/librustc/traits/query/normalize.rs | 2 +- .../traits/query/normalize_erasing_regions.rs | 2 +- src/librustc/traits/structural_impls.rs | 2 +- src/librustc/traits/trans/mod.rs | 184 -- src/librustc/ty/adjustment.rs | 4 +- src/librustc/ty/cast.rs | 2 +- src/librustc/ty/context.rs | 4 +- src/librustc/ty/erase_regions.rs | 3 +- src/librustc/ty/fold.rs | 2 +- src/librustc/ty/instance.rs | 16 +- src/librustc/ty/layout.rs | 6 +- src/librustc/ty/maps/config.rs | 8 +- src/librustc/ty/maps/mod.rs | 22 +- src/librustc/ty/maps/on_disk_cache.rs | 4 +- src/librustc/ty/maps/plumbing.rs | 12 +- src/librustc/ty/mod.rs | 8 +- src/librustc/ty/sty.rs | 6 +- src/librustc/util/ppaux.rs | 4 +- src/librustc_borrowck/borrowck/README.md | 2 +- src/librustc_codegen_llvm/Cargo.toml | 49 + src/librustc_codegen_llvm/README.md | 7 + src/librustc_codegen_llvm/abi.rs | 696 ++++++ src/librustc_codegen_llvm/allocator.rs | 103 + src/librustc_codegen_llvm/asm.rs | 127 ++ src/librustc_codegen_llvm/attributes.rs | 259 +++ src/librustc_codegen_llvm/back/archive.rs | 325 +++ src/librustc_codegen_llvm/back/bytecode.rs | 160 ++ src/librustc_codegen_llvm/back/command.rs | 175 ++ src/librustc_codegen_llvm/back/link.rs | 1630 +++++++++++++ src/librustc_codegen_llvm/back/linker.rs | 1037 +++++++++ src/librustc_codegen_llvm/back/lto.rs | 773 +++++++ src/librustc_codegen_llvm/back/rpath.rs | 282 +++ src/librustc_codegen_llvm/back/symbol_export.rs | 396 ++++ src/librustc_codegen_llvm/back/wasm.rs | 261 +++ src/librustc_codegen_llvm/back/write.rs | 2390 +++++++++++++++++++ src/librustc_codegen_llvm/base.rs | 1411 ++++++++++++ src/librustc_codegen_llvm/build.rs | 16 + src/librustc_codegen_llvm/builder.rs | 1425 ++++++++++++ src/librustc_codegen_llvm/callee.rs | 232 ++ src/librustc_codegen_llvm/common.rs | 448 ++++ src/librustc_codegen_llvm/consts.rs | 322 +++ src/librustc_codegen_llvm/context.rs | 666 ++++++ .../debuginfo/create_scope_map.rs | 136 ++ src/librustc_codegen_llvm/debuginfo/doc.rs | 189 ++ src/librustc_codegen_llvm/debuginfo/gdb.rs | 88 + src/librustc_codegen_llvm/debuginfo/metadata.rs | 1773 +++++++++++++++ src/librustc_codegen_llvm/debuginfo/mod.rs | 542 +++++ src/librustc_codegen_llvm/debuginfo/namespace.rs | 66 + src/librustc_codegen_llvm/debuginfo/source_loc.rs | 107 + src/librustc_codegen_llvm/debuginfo/type_names.rs | 224 ++ src/librustc_codegen_llvm/debuginfo/utils.rs | 65 + src/librustc_codegen_llvm/declare.rs | 223 ++ src/librustc_codegen_llvm/diagnostics.rs | 55 + src/librustc_codegen_llvm/glue.rs | 122 + src/librustc_codegen_llvm/intrinsic.rs | 1465 ++++++++++++ src/librustc_codegen_llvm/lib.rs | 392 ++++ src/librustc_codegen_llvm/llvm_util.rs | 255 +++ src/librustc_codegen_llvm/metadata.rs | 124 + src/librustc_codegen_llvm/meth.rs | 115 + src/librustc_codegen_llvm/mir/analyze.rs | 361 +++ src/librustc_codegen_llvm/mir/block.rs | 895 ++++++++ src/librustc_codegen_llvm/mir/constant.rs | 271 +++ src/librustc_codegen_llvm/mir/mod.rs | 652 ++++++ src/librustc_codegen_llvm/mir/operand.rs | 427 ++++ src/librustc_codegen_llvm/mir/place.rs | 498 ++++ src/librustc_codegen_llvm/mir/rvalue.rs | 952 ++++++++ src/librustc_codegen_llvm/mir/statement.rs | 91 + src/librustc_codegen_llvm/mono_item.rs | 193 ++ src/librustc_codegen_llvm/time_graph.rs | 278 +++ src/librustc_codegen_llvm/type_.rs | 300 +++ src/librustc_codegen_llvm/type_of.rs | 506 +++++ src/librustc_codegen_llvm/value.rs | 24 + src/librustc_codegen_utils/Cargo.toml | 23 + src/librustc_codegen_utils/codegen_backend.rs | 296 +++ src/librustc_codegen_utils/lib.rs | 63 + src/librustc_codegen_utils/link.rs | 191 ++ src/librustc_codegen_utils/symbol_names.rs | 435 ++++ src/librustc_codegen_utils/symbol_names_test.rs | 79 + src/librustc_driver/Cargo.toml | 2 +- src/librustc_driver/driver.rs | 42 +- src/librustc_driver/lib.rs | 74 +- src/librustc_driver/pretty.rs | 8 +- src/librustc_driver/test.rs | 2 +- src/librustc_incremental/assert_dep_graph.rs | 6 +- src/librustc_incremental/assert_module_sources.rs | 18 +- src/librustc_incremental/persist/dirty_clean.rs | 4 +- src/librustc_lint/types.rs | 2 +- src/librustc_llvm/ffi.rs | 2 +- src/librustc_llvm/lib.rs | 2 +- src/librustc_metadata/diagnostics.rs | 6 +- src/librustc_metadata/encoder.rs | 9 +- src/librustc_mir/build/expr/as_rvalue.rs | 2 +- src/librustc_mir/build/expr/mod.rs | 4 +- src/librustc_mir/build/matches/mod.rs | 4 +- src/librustc_mir/build/mod.rs | 2 +- src/librustc_mir/build/scope.rs | 6 +- src/librustc_mir/hair/cx/block.rs | 2 +- src/librustc_mir/hair/cx/mod.rs | 2 +- src/librustc_mir/hair/mod.rs | 8 +- src/librustc_mir/monomorphize/collector.rs | 14 +- src/librustc_mir/monomorphize/item.rs | 18 +- src/librustc_mir/monomorphize/mod.rs | 20 +- src/librustc_mir/monomorphize/partitioning.rs | 120 +- src/librustc_mir/shim.rs | 4 +- src/librustc_mir/transform/add_call_guards.rs | 2 +- src/librustc_mir/transform/elaborate_drops.rs | 2 +- src/librustc_mir/transform/erase_regions.rs | 2 +- src/librustc_mir/transform/inline.rs | 16 +- src/librustc_mir/transform/mod.rs | 2 +- src/librustc_mir/transform/simplify.rs | 2 +- src/librustc_trans/Cargo.toml | 49 - src/librustc_trans/README.md | 7 - src/librustc_trans/abi.rs | 696 ------ src/librustc_trans/allocator.rs | 103 - src/librustc_trans/asm.rs | 129 -- src/librustc_trans/attributes.rs | 259 --- src/librustc_trans/back/archive.rs | 325 --- src/librustc_trans/back/bytecode.rs | 160 -- src/librustc_trans/back/command.rs | 175 -- src/librustc_trans/back/link.rs | 1626 ------------- src/librustc_trans/back/linker.rs | 1037 --------- src/librustc_trans/back/lto.rs | 773 ------- src/librustc_trans/back/rpath.rs | 282 --- src/librustc_trans/back/symbol_export.rs | 395 ---- src/librustc_trans/back/wasm.rs | 261 --- src/librustc_trans/back/write.rs | 2392 -------------------- src/librustc_trans/base.rs | 1411 ------------ src/librustc_trans/build.rs | 16 - src/librustc_trans/builder.rs | 1425 ------------ src/librustc_trans/callee.rs | 232 -- src/librustc_trans/common.rs | 449 ---- src/librustc_trans/consts.rs | 322 --- src/librustc_trans/context.rs | 666 ------ src/librustc_trans/debuginfo/create_scope_map.rs | 136 -- src/librustc_trans/debuginfo/doc.rs | 189 -- src/librustc_trans/debuginfo/gdb.rs | 88 - src/librustc_trans/debuginfo/metadata.rs | 1773 --------------- src/librustc_trans/debuginfo/mod.rs | 542 ----- src/librustc_trans/debuginfo/namespace.rs | 66 - src/librustc_trans/debuginfo/source_loc.rs | 107 - src/librustc_trans/debuginfo/type_names.rs | 224 -- src/librustc_trans/debuginfo/utils.rs | 65 - src/librustc_trans/declare.rs | 223 -- src/librustc_trans/diagnostics.rs | 55 - src/librustc_trans/glue.rs | 122 - src/librustc_trans/intrinsic.rs | 1465 ------------ src/librustc_trans/lib.rs | 390 ---- src/librustc_trans/llvm_util.rs | 255 --- src/librustc_trans/metadata.rs | 124 - src/librustc_trans/meth.rs | 115 - src/librustc_trans/mir/analyze.rs | 361 --- src/librustc_trans/mir/block.rs | 895 -------- src/librustc_trans/mir/constant.rs | 271 --- src/librustc_trans/mir/mod.rs | 652 ------ src/librustc_trans/mir/operand.rs | 427 ---- src/librustc_trans/mir/place.rs | 499 ---- src/librustc_trans/mir/rvalue.rs | 952 -------- src/librustc_trans/mir/statement.rs | 91 - src/librustc_trans/time_graph.rs | 278 --- src/librustc_trans/trans_item.rs | 193 -- src/librustc_trans/type_.rs | 300 --- src/librustc_trans/type_of.rs | 506 ----- src/librustc_trans/value.rs | 24 - src/librustc_trans_utils/Cargo.toml | 23 - src/librustc_trans_utils/lib.rs | 63 - src/librustc_trans_utils/link.rs | 191 -- src/librustc_trans_utils/symbol_names.rs | 435 ---- src/librustc_trans_utils/symbol_names_test.rs | 79 - src/librustc_trans_utils/trans_crate.rs | 296 --- src/librustc_typeck/check/intrinsic.rs | 2 +- src/librustc_typeck/check/op.rs | 2 +- src/librustc_typeck/coherence/builtin.rs | 2 +- src/librustc_typeck/collect.rs | 38 +- src/librustc_typeck/diagnostics.rs | 4 +- src/librustdoc/core.rs | 10 +- src/librustdoc/lib.rs | 2 +- src/librustdoc/test.rs | 16 +- src/libsyntax/feature_gate.rs | 4 +- src/libsyntax_ext/format.rs | 28 +- src/libsyntax_ext/format_foreign.rs | 4 +- src/libsyntax_ext/global_asm.rs | 2 +- src/rustllvm/PassWrapper.cpp | 2 +- .../item-collection/cross-crate-closures.rs | 18 +- .../cross-crate-generic-functions.rs | 12 +- .../item-collection/cross-crate-trait-method.rs | 24 +- .../item-collection/drop_in_place_intrinsic.rs | 14 +- .../item-collection/function-as-argument.rs | 24 +- .../item-collection/generic-drop-glue.rs | 26 +- .../item-collection/generic-functions.rs | 30 +- .../codegen-units/item-collection/generic-impl.rs | 38 +- .../impl-in-non-instantiated-generic.rs | 6 +- .../instantiation-through-vtable.rs | 16 +- .../item-collection/items-within-generic-items.rs | 14 +- .../item-collection/non-generic-closures.rs | 26 +- .../item-collection/non-generic-drop-glue.rs | 12 +- .../item-collection/non-generic-functions.rs | 26 +- .../item-collection/overloaded-operators.rs | 14 +- .../codegen-units/item-collection/static-init.rs | 9 +- .../item-collection/statics-and-consts.rs | 14 +- .../item-collection/trait-implementations.rs | 24 +- .../item-collection/trait-method-as-argument.rs | 32 +- .../item-collection/trait-method-default-impl.rs | 20 +- .../item-collection/transitive-drop-glue.rs | 28 +- .../item-collection/tuple-drop-glue.rs | 14 +- .../item-collection/unreferenced-const-fn.rs | 4 +- .../unreferenced-inline-function.rs | 5 +- src/test/codegen-units/item-collection/unsizing.rs | 20 +- .../item-collection/unused-traits-and-generics.rs | 4 +- .../codegen-units/partitioning/extern-drop-glue.rs | 12 +- .../codegen-units/partitioning/extern-generic.rs | 16 +- .../partitioning/inlining-from-extern-crate.rs | 18 +- .../codegen-units/partitioning/local-drop-glue.rs | 16 +- .../codegen-units/partitioning/local-generic.rs | 18 +- .../partitioning/local-inlining-but-not-all.rs | 10 +- .../codegen-units/partitioning/local-inlining.rs | 10 +- .../partitioning/local-transitive-inlining.rs | 10 +- .../partitioning/methods-are-with-self-type.rs | 22 +- .../codegen-units/partitioning/regular-modules.rs | 44 +- .../codegen-units/partitioning/shared-generics.rs | 8 +- src/test/codegen-units/partitioning/statics.rs | 22 +- .../partitioning/vtable-through-const.rs | 20 +- src/test/compile-fail/const-err.rs | 2 +- src/test/compile-fail/const-eval-overflow2.rs | 2 +- src/test/compile-fail/const-eval-overflow2b.rs | 2 +- src/test/compile-fail/const-eval-overflow2c.rs | 2 +- .../compile-fail/dep-graph-assoc-type-codegen.rs | 47 + .../compile-fail/dep-graph-assoc-type-trans.rs | 47 - src/test/debuginfo/struct-with-destructor.rs | 2 +- .../debuginfo/var-captured-in-sendable-closure.rs | 2 +- src/test/incremental/cache_file_headers.rs | 4 +- .../incremental/change_add_field/struct_point.rs | 16 +- .../incremental/change_private_fn/struct_point.rs | 2 +- .../change_private_impl_method/struct_point.rs | 2 +- .../struct_point.rs | 2 +- .../change_pub_inherent_method_sig/struct_point.rs | 6 +- .../incremental/change_symbol_export_status.rs | 2 +- src/test/incremental/commandline-args.rs | 2 +- src/test/incremental/inlined_hir_34991/main.rs | 2 +- src/test/incremental/issue-38222.rs | 2 +- src/test/incremental/issue-49595/issue_49595.rs | 4 +- src/test/incremental/remapped_paths_cc/main.rs | 2 +- src/test/incremental/spike-neg1.rs | 2 +- src/test/incremental/spike-neg2.rs | 8 +- src/test/incremental/spike.rs | 2 +- .../run-fail/mir_codegen_calls_converging_drops.rs | 34 + .../mir_codegen_calls_converging_drops_2.rs | 38 + src/test/run-fail/mir_codegen_calls_diverging.rs | 23 + .../run-fail/mir_codegen_calls_diverging_drops.rs | 32 + src/test/run-fail/mir_codegen_no_landing_pads.rs | 37 + .../mir_codegen_no_landing_pads_diverging.rs | 37 + .../run-fail/mir_trans_calls_converging_drops.rs | 34 - .../run-fail/mir_trans_calls_converging_drops_2.rs | 38 - src/test/run-fail/mir_trans_calls_diverging.rs | 23 - .../run-fail/mir_trans_calls_diverging_drops.rs | 32 - src/test/run-fail/mir_trans_no_landing_pads.rs | 37 - .../mir_trans_no_landing_pads_diverging.rs | 37 - src/test/run-fail/rhs-type.rs | 2 +- .../hotplug_codegen_backend/the_backend.rs | 26 +- src/test/run-make-fulldeps/issue-19371/foo.rs | 16 +- src/test/run-make-fulldeps/issue-7349/Makefile | 2 +- src/test/run-pass-fulldeps/compiler-calls.rs | 6 +- .../associated-types-region-erasure-issue-20582.rs | 2 +- src/test/run-pass/atomic-compare_exchange.rs | 2 +- src/test/run-pass/codegen-object-shim.rs | 14 + src/test/run-pass/codegen-tag-static-padding.rs | 67 + src/test/run-pass/compiletest-skip-codegen.rs | 17 + src/test/run-pass/compiletest-skip-trans.rs | 17 - src/test/run-pass/conditional-compile.rs | 2 +- src/test/run-pass/issue-18425.rs | 2 +- src/test/run-pass/issue-18514.rs | 2 +- src/test/run-pass/issue-18652.rs | 2 +- src/test/run-pass/issue-18661.rs | 2 +- src/test/run-pass/issue-20644.rs | 2 +- src/test/run-pass/issue-24085.rs | 2 +- src/test/run-pass/issue-34569.rs | 2 +- src/test/run-pass/issue-36381.rs | 2 +- src/test/run-pass/issue-38002.rs | 2 +- src/test/run-pass/issue-5243.rs | 2 +- .../run-pass/issue24687-embed-debuginfo/main.rs | 2 +- .../method-two-trait-defer-resolution-2.rs | 2 +- src/test/run-pass/mir_codegen_array.rs | 19 + src/test/run-pass/mir_codegen_array_2.rs | 18 + src/test/run-pass/mir_codegen_call_converging.rs | 26 + src/test/run-pass/mir_codegen_calls.rs | 200 ++ src/test/run-pass/mir_codegen_calls_variadic.rs | 31 + src/test/run-pass/mir_codegen_critical_edge.rs | 52 + src/test/run-pass/mir_codegen_spike1.rs | 21 + src/test/run-pass/mir_codegen_switch.rs | 44 + src/test/run-pass/mir_codegen_switchint.rs | 21 + src/test/run-pass/mir_overflow_off.rs | 2 +- src/test/run-pass/mir_trans_array.rs | 19 - src/test/run-pass/mir_trans_array_2.rs | 18 - src/test/run-pass/mir_trans_call_converging.rs | 26 - src/test/run-pass/mir_trans_calls.rs | 200 -- src/test/run-pass/mir_trans_calls_variadic.rs | 31 - src/test/run-pass/mir_trans_critical_edge.rs | 52 - src/test/run-pass/mir_trans_spike1.rs | 21 - src/test/run-pass/mir_trans_switch.rs | 44 - src/test/run-pass/mir_trans_switchint.rs | 21 - src/test/run-pass/pattern-bound-var-in-for-each.rs | 4 +- src/test/run-pass/regions-mock-codegen.rs | 62 + src/test/run-pass/regions-mock-trans.rs | 62 - src/test/run-pass/sepcomp-fns-backwards.rs | 2 +- src/test/run-pass/small-enum-range-edge.rs | 2 +- src/test/run-pass/trans-object-shim.rs | 14 - src/test/run-pass/trans-tag-static-padding.rs | 67 - src/test/run-pass/union/union-const-codegen.rs | 25 + src/test/run-pass/union/union-const-trans.rs | 25 - src/test/run-pass/zero-sized-tuple-struct.rs | 2 +- src/tools/compiletest/src/header.rs | 12 +- src/tools/compiletest/src/runtest.rs | 24 +- src/tools/tidy/src/deps.rs | 2 +- 344 files changed, 27633 insertions(+), 27634 deletions(-) create mode 100644 src/librustc/traits/codegen/mod.rs delete mode 100644 src/librustc/traits/trans/mod.rs create mode 100644 src/librustc_codegen_llvm/Cargo.toml create mode 100644 src/librustc_codegen_llvm/README.md create mode 100644 src/librustc_codegen_llvm/abi.rs create mode 100644 src/librustc_codegen_llvm/allocator.rs create mode 100644 src/librustc_codegen_llvm/asm.rs create mode 100644 src/librustc_codegen_llvm/attributes.rs create mode 100644 src/librustc_codegen_llvm/back/archive.rs create mode 100644 src/librustc_codegen_llvm/back/bytecode.rs create mode 100644 src/librustc_codegen_llvm/back/command.rs create mode 100644 src/librustc_codegen_llvm/back/link.rs create mode 100644 src/librustc_codegen_llvm/back/linker.rs create mode 100644 src/librustc_codegen_llvm/back/lto.rs create mode 100644 src/librustc_codegen_llvm/back/rpath.rs create mode 100644 src/librustc_codegen_llvm/back/symbol_export.rs create mode 100644 src/librustc_codegen_llvm/back/wasm.rs create mode 100644 src/librustc_codegen_llvm/back/write.rs create mode 100644 src/librustc_codegen_llvm/base.rs create mode 100644 src/librustc_codegen_llvm/build.rs create mode 100644 src/librustc_codegen_llvm/builder.rs create mode 100644 src/librustc_codegen_llvm/callee.rs create mode 100644 src/librustc_codegen_llvm/common.rs create mode 100644 src/librustc_codegen_llvm/consts.rs create mode 100644 src/librustc_codegen_llvm/context.rs create mode 100644 src/librustc_codegen_llvm/debuginfo/create_scope_map.rs create mode 100644 src/librustc_codegen_llvm/debuginfo/doc.rs create mode 100644 src/librustc_codegen_llvm/debuginfo/gdb.rs create mode 100644 src/librustc_codegen_llvm/debuginfo/metadata.rs create mode 100644 src/librustc_codegen_llvm/debuginfo/mod.rs create mode 100644 src/librustc_codegen_llvm/debuginfo/namespace.rs create mode 100644 src/librustc_codegen_llvm/debuginfo/source_loc.rs create mode 100644 src/librustc_codegen_llvm/debuginfo/type_names.rs create mode 100644 src/librustc_codegen_llvm/debuginfo/utils.rs create mode 100644 src/librustc_codegen_llvm/declare.rs create mode 100644 src/librustc_codegen_llvm/diagnostics.rs create mode 100644 src/librustc_codegen_llvm/glue.rs create mode 100644 src/librustc_codegen_llvm/intrinsic.rs create mode 100644 src/librustc_codegen_llvm/lib.rs create mode 100644 src/librustc_codegen_llvm/llvm_util.rs create mode 100644 src/librustc_codegen_llvm/metadata.rs create mode 100644 src/librustc_codegen_llvm/meth.rs create mode 100644 src/librustc_codegen_llvm/mir/analyze.rs create mode 100644 src/librustc_codegen_llvm/mir/block.rs create mode 100644 src/librustc_codegen_llvm/mir/constant.rs create mode 100644 src/librustc_codegen_llvm/mir/mod.rs create mode 100644 src/librustc_codegen_llvm/mir/operand.rs create mode 100644 src/librustc_codegen_llvm/mir/place.rs create mode 100644 src/librustc_codegen_llvm/mir/rvalue.rs create mode 100644 src/librustc_codegen_llvm/mir/statement.rs create mode 100644 src/librustc_codegen_llvm/mono_item.rs create mode 100644 src/librustc_codegen_llvm/time_graph.rs create mode 100644 src/librustc_codegen_llvm/type_.rs create mode 100644 src/librustc_codegen_llvm/type_of.rs create mode 100644 src/librustc_codegen_llvm/value.rs create mode 100644 src/librustc_codegen_utils/Cargo.toml create mode 100644 src/librustc_codegen_utils/codegen_backend.rs create mode 100644 src/librustc_codegen_utils/lib.rs create mode 100644 src/librustc_codegen_utils/link.rs create mode 100644 src/librustc_codegen_utils/symbol_names.rs create mode 100644 src/librustc_codegen_utils/symbol_names_test.rs delete mode 100644 src/librustc_trans/Cargo.toml delete mode 100644 src/librustc_trans/README.md delete mode 100644 src/librustc_trans/abi.rs delete mode 100644 src/librustc_trans/allocator.rs delete mode 100644 src/librustc_trans/asm.rs delete mode 100644 src/librustc_trans/attributes.rs delete mode 100644 src/librustc_trans/back/archive.rs delete mode 100644 src/librustc_trans/back/bytecode.rs delete mode 100644 src/librustc_trans/back/command.rs delete mode 100644 src/librustc_trans/back/link.rs delete mode 100644 src/librustc_trans/back/linker.rs delete mode 100644 src/librustc_trans/back/lto.rs delete mode 100644 src/librustc_trans/back/rpath.rs delete mode 100644 src/librustc_trans/back/symbol_export.rs delete mode 100644 src/librustc_trans/back/wasm.rs delete mode 100644 src/librustc_trans/back/write.rs delete mode 100644 src/librustc_trans/base.rs delete mode 100644 src/librustc_trans/build.rs delete mode 100644 src/librustc_trans/builder.rs delete mode 100644 src/librustc_trans/callee.rs delete mode 100644 src/librustc_trans/common.rs delete mode 100644 src/librustc_trans/consts.rs delete mode 100644 src/librustc_trans/context.rs delete mode 100644 src/librustc_trans/debuginfo/create_scope_map.rs delete mode 100644 src/librustc_trans/debuginfo/doc.rs delete mode 100644 src/librustc_trans/debuginfo/gdb.rs delete mode 100644 src/librustc_trans/debuginfo/metadata.rs delete mode 100644 src/librustc_trans/debuginfo/mod.rs delete mode 100644 src/librustc_trans/debuginfo/namespace.rs delete mode 100644 src/librustc_trans/debuginfo/source_loc.rs delete mode 100644 src/librustc_trans/debuginfo/type_names.rs delete mode 100644 src/librustc_trans/debuginfo/utils.rs delete mode 100644 src/librustc_trans/declare.rs delete mode 100644 src/librustc_trans/diagnostics.rs delete mode 100644 src/librustc_trans/glue.rs delete mode 100644 src/librustc_trans/intrinsic.rs delete mode 100644 src/librustc_trans/lib.rs delete mode 100644 src/librustc_trans/llvm_util.rs delete mode 100644 src/librustc_trans/metadata.rs delete mode 100644 src/librustc_trans/meth.rs delete mode 100644 src/librustc_trans/mir/analyze.rs delete mode 100644 src/librustc_trans/mir/block.rs delete mode 100644 src/librustc_trans/mir/constant.rs delete mode 100644 src/librustc_trans/mir/mod.rs delete mode 100644 src/librustc_trans/mir/operand.rs delete mode 100644 src/librustc_trans/mir/place.rs delete mode 100644 src/librustc_trans/mir/rvalue.rs delete mode 100644 src/librustc_trans/mir/statement.rs delete mode 100644 src/librustc_trans/time_graph.rs delete mode 100644 src/librustc_trans/trans_item.rs delete mode 100644 src/librustc_trans/type_.rs delete mode 100644 src/librustc_trans/type_of.rs delete mode 100644 src/librustc_trans/value.rs delete mode 100644 src/librustc_trans_utils/Cargo.toml delete mode 100644 src/librustc_trans_utils/lib.rs delete mode 100644 src/librustc_trans_utils/link.rs delete mode 100644 src/librustc_trans_utils/symbol_names.rs delete mode 100644 src/librustc_trans_utils/symbol_names_test.rs delete mode 100644 src/librustc_trans_utils/trans_crate.rs create mode 100644 src/test/compile-fail/dep-graph-assoc-type-codegen.rs delete mode 100644 src/test/compile-fail/dep-graph-assoc-type-trans.rs create mode 100644 src/test/run-fail/mir_codegen_calls_converging_drops.rs create mode 100644 src/test/run-fail/mir_codegen_calls_converging_drops_2.rs create mode 100644 src/test/run-fail/mir_codegen_calls_diverging.rs create mode 100644 src/test/run-fail/mir_codegen_calls_diverging_drops.rs create mode 100644 src/test/run-fail/mir_codegen_no_landing_pads.rs create mode 100644 src/test/run-fail/mir_codegen_no_landing_pads_diverging.rs delete mode 100644 src/test/run-fail/mir_trans_calls_converging_drops.rs delete mode 100644 src/test/run-fail/mir_trans_calls_converging_drops_2.rs delete mode 100644 src/test/run-fail/mir_trans_calls_diverging.rs delete mode 100644 src/test/run-fail/mir_trans_calls_diverging_drops.rs delete mode 100644 src/test/run-fail/mir_trans_no_landing_pads.rs delete mode 100644 src/test/run-fail/mir_trans_no_landing_pads_diverging.rs create mode 100644 src/test/run-pass/codegen-object-shim.rs create mode 100644 src/test/run-pass/codegen-tag-static-padding.rs create mode 100644 src/test/run-pass/compiletest-skip-codegen.rs delete mode 100644 src/test/run-pass/compiletest-skip-trans.rs create mode 100644 src/test/run-pass/mir_codegen_array.rs create mode 100644 src/test/run-pass/mir_codegen_array_2.rs create mode 100644 src/test/run-pass/mir_codegen_call_converging.rs create mode 100644 src/test/run-pass/mir_codegen_calls.rs create mode 100644 src/test/run-pass/mir_codegen_calls_variadic.rs create mode 100644 src/test/run-pass/mir_codegen_critical_edge.rs create mode 100644 src/test/run-pass/mir_codegen_spike1.rs create mode 100644 src/test/run-pass/mir_codegen_switch.rs create mode 100644 src/test/run-pass/mir_codegen_switchint.rs delete mode 100644 src/test/run-pass/mir_trans_array.rs delete mode 100644 src/test/run-pass/mir_trans_array_2.rs delete mode 100644 src/test/run-pass/mir_trans_call_converging.rs delete mode 100644 src/test/run-pass/mir_trans_calls.rs delete mode 100644 src/test/run-pass/mir_trans_calls_variadic.rs delete mode 100644 src/test/run-pass/mir_trans_critical_edge.rs delete mode 100644 src/test/run-pass/mir_trans_spike1.rs delete mode 100644 src/test/run-pass/mir_trans_switch.rs delete mode 100644 src/test/run-pass/mir_trans_switchint.rs create mode 100644 src/test/run-pass/regions-mock-codegen.rs delete mode 100644 src/test/run-pass/regions-mock-trans.rs delete mode 100644 src/test/run-pass/trans-object-shim.rs delete mode 100644 src/test/run-pass/trans-tag-static-padding.rs create mode 100644 src/test/run-pass/union/union-const-codegen.rs delete mode 100644 src/test/run-pass/union/union-const-trans.rs (limited to 'src/libcore') diff --git a/src/Cargo.lock b/src/Cargo.lock index 76ca287b815..00cc530e632 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1896,6 +1896,52 @@ dependencies = [ "syntax_pos 0.0.0", ] +[[package]] +name = "rustc_codegen_llvm" +version = "0.0.0" +dependencies = [ + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc 0.0.0", + "rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_allocator 0.0.0", + "rustc_apfloat 0.0.0", + "rustc_codegen_utils 0.0.0", + "rustc_data_structures 0.0.0", + "rustc_errors 0.0.0", + "rustc_incremental 0.0.0", + "rustc_llvm 0.0.0", + "rustc_mir 0.0.0", + "rustc_platform_intrinsics 0.0.0", + "rustc_target 0.0.0", + "serialize 0.0.0", + "syntax 0.0.0", + "syntax_pos 0.0.0", + "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_codegen_utils" +version = "0.0.0" +dependencies = [ + "ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc 0.0.0", + "rustc_data_structures 0.0.0", + "rustc_incremental 0.0.0", + "rustc_mir 0.0.0", + "rustc_target 0.0.0", + "syntax 0.0.0", + "syntax_pos 0.0.0", +] + [[package]] name = "rustc_cratesio_shim" version = "0.0.0" @@ -1932,6 +1978,7 @@ dependencies = [ "rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_borrowck 0.0.0", + "rustc_codegen_utils 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_incremental 0.0.0", @@ -1945,7 +1992,6 @@ dependencies = [ "rustc_save_analysis 0.0.0", "rustc_target 0.0.0", "rustc_traits 0.0.0", - "rustc_trans_utils 0.0.0", "rustc_typeck 0.0.0", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", @@ -2155,52 +2201,6 @@ dependencies = [ "syntax_pos 0.0.0", ] -[[package]] -name = "rustc_trans" -version = "0.0.0" -dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_allocator 0.0.0", - "rustc_apfloat 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_incremental 0.0.0", - "rustc_llvm 0.0.0", - "rustc_mir 0.0.0", - "rustc_platform_intrinsics 0.0.0", - "rustc_target 0.0.0", - "rustc_trans_utils 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc_trans_utils" -version = "0.0.0" -dependencies = [ - "ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_incremental 0.0.0", - "rustc_mir 0.0.0", - "rustc_target 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - [[package]] name = "rustc_tsan" version = "0.0.0" diff --git a/src/Cargo.toml b/src/Cargo.toml index 35858ee2868..1518e8d910f 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -4,7 +4,7 @@ members = [ "rustc", "libstd", "libtest", - "librustc_trans", + "librustc_codegen_llvm", "tools/cargotest", "tools/clippy", "tools/compiletest", diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index e5824010ef2..cc1e66332a3 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -844,7 +844,7 @@ impl<'a> Builder<'a> { // default via `-ldylib=winapi_foo`. That is, they're linked with the // `dylib` type with a `winapi_` prefix (so the winapi ones don't // conflict with the system MinGW ones). This consequently means that - // the binaries we ship of things like rustc_trans (aka the rustc_trans + // the binaries we ship of things like rustc_codegen_llvm (aka the rustc_codegen_llvm // DLL) when linked against *again*, for example with procedural macros // or plugins, will trigger the propagation logic of `-ldylib`, passing // `-lwinapi_foo` to the linker again. This isn't actually available in diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 64354ae29aa..a516af58b1e 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -118,7 +118,7 @@ impl Step for CodegenBackend { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.all_krates("rustc_trans") + run.all_krates("rustc_codegen_llvm") } fn make_run(run: RunConfig) { @@ -139,12 +139,12 @@ impl Step for CodegenBackend { let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check"); let features = builder.rustc_features().to_string(); - cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_trans/Cargo.toml")); + cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml")); rustc_cargo_env(builder, &mut cargo); // We won't build LLVM if it's not available, as it shouldn't affect `check`. - let _folder = builder.fold_output(|| format!("stage{}-rustc_trans", compiler.stage)); + let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage)); run_cargo(builder, cargo.arg("--features").arg(features), &codegen_backend_stamp(builder, compiler, target, backend), @@ -259,14 +259,14 @@ pub fn librustc_stamp(builder: &Builder, compiler: Compiler, target: Interned, backend: Interned) -> PathBuf { builder.cargo_out(compiler, Mode::Librustc, target) - .join(format!(".librustc_trans-{}-check.stamp", backend)) + .join(format!(".librustc_codegen_llvm-{}-check.stamp", backend)) } /// Cargo's output path for rustdoc in a given stage, compiled by a particular diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 1248c2b50be..8e0227f8fe1 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -603,7 +603,7 @@ impl Step for CodegenBackend { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.all_krates("rustc_trans") + run.all_krates("rustc_codegen_llvm") } fn make_run(run: RunConfig) { @@ -637,7 +637,7 @@ impl Step for CodegenBackend { let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build"); let mut features = builder.rustc_features().to_string(); cargo.arg("--manifest-path") - .arg(builder.src.join("src/librustc_trans/Cargo.toml")); + .arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml")); rustc_cargo_env(builder, &mut cargo); features += &build_codegen_backend(&builder, &mut cargo, &compiler, target, backend); @@ -645,7 +645,7 @@ impl Step for CodegenBackend { let tmp_stamp = builder.cargo_out(compiler, Mode::Librustc, target) .join(".tmp.stamp"); - let _folder = builder.fold_output(|| format!("stage{}-rustc_trans", compiler.stage)); + let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage)); let files = run_cargo(builder, cargo.arg("--features").arg(features), &tmp_stamp, @@ -656,7 +656,7 @@ impl Step for CodegenBackend { let mut files = files.into_iter() .filter(|f| { let filename = f.file_name().unwrap().to_str().unwrap(); - is_dylib(filename) && filename.contains("rustc_trans-") + is_dylib(filename) && filename.contains("rustc_codegen_llvm-") }); let codegen_backend = match files.next() { Some(f) => f, @@ -697,7 +697,7 @@ pub fn build_codegen_backend(builder: &Builder, compiler.stage, &compiler.host, target, backend)); // Pass down configuration from the LLVM build into the build of - // librustc_llvm and librustc_trans. + // librustc_llvm and librustc_codegen_llvm. if builder.is_rust_llvm(target) { cargo.env("LLVM_RUSTLLVM", "1"); } @@ -762,7 +762,7 @@ fn copy_codegen_backends_to_sysroot(builder: &Builder, t!(t!(File::open(&stamp)).read_to_string(&mut dylib)); let file = Path::new(&dylib); let filename = file.file_name().unwrap().to_str().unwrap(); - // change `librustc_trans-xxxxxx.so` to `librustc_trans-llvm.so` + // change `librustc_codegen_llvm-xxxxxx.so` to `librustc_codegen_llvm-llvm.so` let target_filename = { let dash = filename.find("-").unwrap(); let dot = filename.find(".").unwrap(); @@ -808,14 +808,14 @@ pub fn librustc_stamp(builder: &Builder, compiler: Compiler, target: Interned, backend: Interned) -> PathBuf { builder.cargo_out(compiler, Mode::Librustc, target) - .join(format!(".librustc_trans-{}.stamp", backend)) + .join(format!(".librustc_codegen_llvm-{}.stamp", backend)) } pub fn compiler_file(builder: &Builder, diff --git a/src/doc/rustc-ux-guidelines.md b/src/doc/rustc-ux-guidelines.md index b62762ef69e..93e94e55863 100644 --- a/src/doc/rustc-ux-guidelines.md +++ b/src/doc/rustc-ux-guidelines.md @@ -69,7 +69,7 @@ for details on how to format and write long error codes. [librustc_passes](https://github.com/rust-lang/rust/blob/master/src/librustc_passes/diagnostics.rs), [librustc_privacy](https://github.com/rust-lang/rust/blob/master/src/librustc_privacy/diagnostics.rs), [librustc_resolve](https://github.com/rust-lang/rust/blob/master/src/librustc_resolve/diagnostics.rs), - [librustc_trans](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/diagnostics.rs), + [librustc_codegen_llvm](https://github.com/rust-lang/rust/blob/master/src/librustc_codegen_llvm/diagnostics.rs), [librustc_plugin](https://github.com/rust-lang/rust/blob/master/src/librustc_plugin/diagnostics.rs), [librustc_typeck](https://github.com/rust-lang/rust/blob/master/src/librustc_typeck/diagnostics.rs). * Explanations have full markdown support. Use it, especially to highlight diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index f59c9f7fd61..09d16b26520 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -134,7 +134,7 @@ unsafe impl Alloc for Global { } /// The allocator for unique pointers. -// This function must not unwind. If it does, MIR trans will fail. +// This function must not unwind. If it does, MIR codegen will fail. #[cfg(not(test))] #[lang = "exchange_malloc"] #[inline] diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 7d3e7af1a18..5ec6cb6c710 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -10,7 +10,7 @@ //! rustc compiler intrinsics. //! -//! The corresponding definitions are in librustc_trans/intrinsic.rs. +//! The corresponding definitions are in librustc_codegen_llvm/intrinsic.rs. //! //! # Volatiles //! diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index af108188ce0..8f9a8bd5c01 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -35,13 +35,13 @@ byteorder = { version = "1.1", features = ["i128"]} # rlib/dylib pair but all crates.io crates tend to just be rlibs. This means # we've got a problem for dependency graphs that look like: # -# foo - rustc_trans +# foo - rustc_codegen_llvm # / \ # rustc ---- rustc_driver # \ / # foo - rustc_metadata # -# Here the crate `foo` is linked into the `rustc_trans` and the +# Here the crate `foo` is linked into the `rustc_codegen_llvm` and the # `rustc_metadata` dylibs, meaning we've got duplicate copies! When we then # go to link `rustc_driver` the compiler notices this and gives us a compiler # error. @@ -49,7 +49,7 @@ byteorder = { version = "1.1", features = ["i128"]} # To work around this problem we just add these crates.io dependencies to the # `rustc` crate which is a shared dependency above. That way the crate `foo` # shows up in the dylib for the `rustc` crate, deduplicating it and allowing -# crates like `rustc_trans` to use `foo` *through* the `rustc` crate. +# crates like `rustc_codegen_llvm` to use `foo` *through* the `rustc` crate. # # tl;dr; this is not needed to get `rustc` to compile, but if you remove it then # later crate stop compiling. If you can remove this and everything diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 7e03288f572..20e4b1343c1 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -452,13 +452,13 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { // The CFG for match expression is quite complex, so no ASCII // art for it (yet). // - // The CFG generated below matches roughly what trans puts - // out. Each pattern and guard is visited in parallel, with + // The CFG generated below matches roughly what MIR contains. + // Each pattern and guard is visited in parallel, with // arms containing multiple patterns generating multiple nodes // for the same guard expression. The guard expressions chain // into each other from top to bottom, with a specific // exception to allow some additional valid programs - // (explained below). Trans differs slightly in that the + // (explained below). MIR differs slightly in that the // pattern matching may continue after a guard but the visible // behaviour should be the same. // diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 4847a7f4ddb..9cd9d44874b 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -565,7 +565,7 @@ define_dep_nodes!( <'tcx> [] IsUnreachableLocalDefinition(DefId), [] IsMirAvailable(DefId), [] ItemAttrs(DefId), - [] TransFnAttrs(DefId), + [] CodegenFnAttrs(DefId), [] FnArgNames(DefId), [] RenderedConst(DefId), [] DylibDepFormats(CrateNum), @@ -637,8 +637,8 @@ define_dep_nodes!( <'tcx> [eval_always] AllTraits, [input] AllCrateNums, [] ExportedSymbols(CrateNum), - [eval_always] CollectAndPartitionTranslationItems, - [] IsTranslatedItem(DefId), + [eval_always] CollectAndPartitionMonoItems, + [] IsCodegenedItem(DefId), [] CodegenUnit(InternedString), [] CompileCodegenUnit(InternedString), [input] OutputFilenames, diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 797332e699d..26470ddc82a 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -856,10 +856,10 @@ impl DepGraph { /// each partition. In the first run, we create partitions based on /// the symbols that need to be compiled. For each partition P, we /// hash the symbols in P and create a `WorkProduct` record associated -/// with `DepNode::TransPartition(P)`; the hash is the set of symbols +/// with `DepNode::CodegenUnit(P)`; the hash is the set of symbols /// in P. /// -/// The next time we compile, if the `DepNode::TransPartition(P)` is +/// The next time we compile, if the `DepNode::CodegenUnit(P)` is /// judged to be clean (which means none of the things we read to /// generate the partition were found to be dirty), it will be loaded /// into previous work products. We will then regenerate the set of diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 24a1256c9d3..591cb9d5ad6 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -58,7 +58,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { /// Check any attribute. fn check_attributes(&self, item: &hir::Item, target: Target) { if target == Target::Fn { - self.tcx.trans_fn_attrs(self.tcx.hir.local_def_id(item.id)); + self.tcx.codegen_fn_attrs(self.tcx.hir.local_def_id(item.id)); } else if let Some(a) = item.attrs.iter().find(|a| a.check_name("target_feature")) { self.tcx.sess.struct_span_err(a.span, "attribute should be applied to a function") .span_label(item.span, "not a function") diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index c48fb7ab7eb..edd5e668d5e 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -2244,8 +2244,8 @@ pub fn provide(providers: &mut Providers) { } #[derive(Clone, RustcEncodable, RustcDecodable, Hash)] -pub struct TransFnAttrs { - pub flags: TransFnAttrFlags, +pub struct CodegenFnAttrs { + pub flags: CodegenFnAttrFlags, pub inline: InlineAttr, pub export_name: Option, pub target_features: Vec, @@ -2254,7 +2254,7 @@ pub struct TransFnAttrs { bitflags! { #[derive(RustcEncodable, RustcDecodable)] - pub struct TransFnAttrFlags: u8 { + pub struct CodegenFnAttrFlags: u8 { const COLD = 0b0000_0001; const ALLOCATOR = 0b0000_0010; const UNWIND = 0b0000_0100; @@ -2266,10 +2266,10 @@ bitflags! { } } -impl TransFnAttrs { - pub fn new() -> TransFnAttrs { - TransFnAttrs { - flags: TransFnAttrFlags::empty(), +impl CodegenFnAttrs { + pub fn new() -> CodegenFnAttrs { + CodegenFnAttrs { + flags: CodegenFnAttrFlags::empty(), inline: InlineAttr::None, export_name: None, target_features: vec![], @@ -2287,7 +2287,6 @@ impl TransFnAttrs { /// True if `#[no_mangle]` or `#[export_name(...)]` is present. pub fn contains_extern_indicator(&self) -> bool { - self.flags.contains(TransFnAttrFlags::NO_MANGLE) || self.export_name.is_some() + self.flags.contains(CodegenFnAttrFlags::NO_MANGLE) || self.export_name.is_some() } } - diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index ed01704e6a4..30f725a6b50 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -1155,12 +1155,12 @@ impl<'a> ToStableHashKey> for hir::TraitCandidate { } } -impl<'hir> HashStable> for hir::TransFnAttrs +impl<'hir> HashStable> for hir::CodegenFnAttrs { fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) { - let hir::TransFnAttrs { + let hir::CodegenFnAttrs { flags, inline, export_name, @@ -1176,7 +1176,7 @@ impl<'hir> HashStable> for hir::TransFnAttrs } } -impl<'hir> HashStable> for hir::TransFnAttrFlags +impl<'hir> HashStable> for hir::CodegenFnAttrFlags { fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index a0c6bbbb239..d58eb64c366 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -30,7 +30,7 @@ pub const ATTR_CLEAN: &'static str = "rustc_clean"; pub const ATTR_IF_THIS_CHANGED: &'static str = "rustc_if_this_changed"; pub const ATTR_THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need"; pub const ATTR_PARTITION_REUSED: &'static str = "rustc_partition_reused"; -pub const ATTR_PARTITION_TRANSLATED: &'static str = "rustc_partition_translated"; +pub const ATTR_PARTITION_CODEGENED: &'static str = "rustc_partition_codegened"; pub const DEP_GRAPH_ASSERT_ATTRS: &'static [&'static str] = &[ @@ -39,7 +39,7 @@ pub const DEP_GRAPH_ASSERT_ATTRS: &'static [&'static str] = &[ ATTR_DIRTY, ATTR_CLEAN, ATTR_PARTITION_REUSED, - ATTR_PARTITION_TRANSLATED, + ATTR_PARTITION_CODEGENED, ]; pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ @@ -49,5 +49,5 @@ pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ ATTR_DIRTY, ATTR_CLEAN, ATTR_PARTITION_REUSED, - ATTR_PARTITION_TRANSLATED, + ATTR_PARTITION_CODEGENED, ]; diff --git a/src/librustc/infer/anon_types/mod.rs b/src/librustc/infer/anon_types/mod.rs index d681e2e3d34..4cc5e885b8a 100644 --- a/src/librustc/infer/anon_types/mod.rs +++ b/src/librustc/infer/anon_types/mod.rs @@ -614,7 +614,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ReverseMapper<'cx, 'gcx, 'tcx> // compiler; those regions are ignored for the // outlives relation, and hence don't affect trait // selection or auto traits, and they are erased - // during trans. + // during codegen. let generics = self.tcx.generics_of(def_id); let substs = self.tcx.mk_substs(substs.substs.iter().enumerate().map( diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index f90baa2ccd9..381bb161e42 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -10,15 +10,15 @@ //! Implementation of lint checking. //! -//! The lint checking is mostly consolidated into one pass which runs just -//! before translation to LLVM bytecode. Throughout compilation, lint warnings +//! The lint checking is mostly consolidated into one pass which runs +//! after all other analyses. Throughout compilation, lint warnings //! can be added via the `add_lint` method on the Session structure. This //! requires a span and an id of the node that the lint is being added to. The //! lint isn't actually emitted at that time because it is unknown what the //! actual lint level at that location is. //! -//! To actually emit lint warnings/errors, a separate pass is used just before -//! translation. A context keeps track of the current state of all lint levels. +//! To actually emit lint warnings/errors, a separate pass is used. +//! A context keeps track of the current state of all lint levels. //! Upon entering a node of the ast which can modify the lint settings, the //! previous lint state is pushed onto a stack and the ast is then recursed //! upon. As the ast is traversed, this keeps track of the current lint level diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index d6c6f9dc0f6..7645d3486c2 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -16,15 +16,15 @@ //! other phases of the compiler, which are generally required to hold in order //! to compile the program at all. //! -//! Most lints can be written as `LintPass` instances. These run just before -//! translation to LLVM bytecode. The `LintPass`es built into rustc are defined +//! Most lints can be written as `LintPass` instances. These run after +//! all other analyses. The `LintPass`es built into rustc are defined //! within `builtin.rs`, which has further comments on how to add such a lint. //! rustc can also load user-defined lint plugins via the plugin mechanism. //! //! Some of rustc's lints are defined elsewhere in the compiler and work by //! calling `add_lint()` on the overall `Session` object. This works when //! it happens before the main lint pass, which emits the lints stored by -//! `add_lint()`. To emit lints after the main lint pass (from trans, for +//! `add_lint()`. To emit lints after the main lint pass (from codegen, for //! example) requires more effort. See `emit_lint` and `GatherNodeLevels` //! in `context.rs`. diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index 4996a6acff8..4c99b46ddff 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -109,7 +109,7 @@ fn calculate_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let sess = &tcx.sess; - if !sess.opts.output_types.should_trans() { + if !sess.opts.output_types.should_codegen() { return Vec::new(); } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index a4c38333da1..e9d27c182a2 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -46,9 +46,9 @@ //! //! ## By-reference upvars //! -//! One part of the translation which may be non-obvious is that we translate +//! One part of the codegen which may be non-obvious is that we translate //! closure upvars into the dereference of a borrowed pointer; this more closely -//! resembles the runtime translation. So, for example, if we had: +//! resembles the runtime codegen. So, for example, if we had: //! //! let mut x = 3; //! let y = 5; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 0aeb15b49fb..249651ef65d 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -15,7 +15,7 @@ // makes all other generics or inline functions that it references // reachable as well. -use hir::TransFnAttrs; +use hir::CodegenFnAttrs; use hir::map as hir_map; use hir::def::Def; use hir::def_id::{DefId, CrateNum}; @@ -44,7 +44,7 @@ fn generics_require_inlining(generics: &hir::Generics) -> bool { // Returns true if the given item must be inlined because it may be // monomorphized or it was marked with `#[inline]`. This will only return // true for functions. -fn item_might_be_inlined(item: &hir::Item, attrs: TransFnAttrs) -> bool { +fn item_might_be_inlined(item: &hir::Item, attrs: CodegenFnAttrs) -> bool { if attrs.requests_inline() { return true } @@ -61,15 +61,15 @@ fn item_might_be_inlined(item: &hir::Item, attrs: TransFnAttrs) -> bool { fn method_might_be_inlined<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item: &hir::ImplItem, impl_src: DefId) -> bool { - let trans_fn_attrs = tcx.trans_fn_attrs(impl_item.hir_id.owner_def_id()); - if trans_fn_attrs.requests_inline() || + let codegen_fn_attrs = tcx.codegen_fn_attrs(impl_item.hir_id.owner_def_id()); + if codegen_fn_attrs.requests_inline() || generics_require_inlining(&impl_item.generics) { return true } if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_src) { match tcx.hir.find(impl_node_id) { Some(hir_map::NodeItem(item)) => - item_might_be_inlined(&item, trans_fn_attrs), + item_might_be_inlined(&item, codegen_fn_attrs), Some(..) | None => span_bug!(impl_item.span, "impl did is not an item") } @@ -163,7 +163,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { Some(hir_map::NodeItem(item)) => { match item.node { hir::ItemFn(..) => - item_might_be_inlined(&item, self.tcx.trans_fn_attrs(def_id)), + item_might_be_inlined(&item, self.tcx.codegen_fn_attrs(def_id)), _ => false, } } @@ -179,7 +179,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { match impl_item.node { hir::ImplItemKind::Const(..) => true, hir::ImplItemKind::Method(..) => { - let attrs = self.tcx.trans_fn_attrs(def_id); + let attrs = self.tcx.codegen_fn_attrs(def_id); if generics_require_inlining(&impl_item.generics) || attrs.requests_inline() { true @@ -233,7 +233,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { false }; let def_id = self.tcx.hir.local_def_id(item.id); - let is_extern = self.tcx.trans_fn_attrs(def_id).contains_extern_indicator(); + let is_extern = self.tcx.codegen_fn_attrs(def_id).contains_extern_indicator(); if reachable || is_extern { self.reachable_symbols.insert(search_item); } @@ -251,7 +251,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { match item.node { hir::ItemFn(.., body) => { let def_id = self.tcx.hir.local_def_id(item.id); - if item_might_be_inlined(&item, self.tcx.trans_fn_attrs(def_id)) { + if item_might_be_inlined(&item, self.tcx.codegen_fn_attrs(def_id)) { self.visit_nested_body(body); } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 52217600759..71d7abed6c9 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1279,7 +1279,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, loop { // Note: give all the expressions matching `ET` with the // extended temporary lifetime, not just the innermost rvalue, - // because in trans if we must compile e.g. `*rvalue()` + // because in codegen if we must compile e.g. `*rvalue()` // into a temporary, we request the temporary scope of the // outer expression. visitor.scope_tree.record_rvalue_scope(expr.hir_id.local_id, blk_scope); diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index afdd1c167c6..31885c1e020 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -249,7 +249,7 @@ pub struct Allocation { pub undef_mask: UndefMask, /// The alignment of the allocation to detect unaligned reads. pub align: Align, - /// Whether the allocation (of a static) should be put into mutable memory when translating + /// Whether the allocation (of a static) should be put into mutable memory when codegenning /// /// Only happens for `static mut` or `static` with interior mutability pub runtime_mutability: Mutability, diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 2cd4bf9d18c..7bd84a607e7 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -75,7 +75,7 @@ impl<'tcx> ConstValue<'tcx> { /// /// For optimization of a few very common cases, there is also a representation for a pair of /// primitive values (`ByValPair`). It allows Miri to avoid making allocations for checked binary -/// operations and fat pointers. This idea was taken from rustc's trans. +/// operations and fat pointers. This idea was taken from rustc's codegen. #[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] pub enum Value { ByRef(Pointer, Align), diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index eb12444bcb4..40e9b687f0c 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -696,7 +696,7 @@ pub struct BasicBlockData<'tcx> { pub terminator: Option>, /// If true, this block lies on an unwind path. This is used - /// during trans where distinct kinds of basic blocks may be + /// during codegen where distinct kinds of basic blocks may be /// generated (particularly for MSVC cleanup). Unwind blocks must /// only branch to other unwind blocks. pub is_cleanup: bool, @@ -1614,7 +1614,7 @@ pub enum CastKind { UnsafeFnPointer, /// "Unsize" -- convert a thin-or-fat pointer to a fat pointer. - /// trans must figure out the details once full monomorphization + /// codegen must figure out the details once full monomorphization /// is known. For example, this could be used to cast from a /// `&[i32;N]` to a `&[i32]`, or a `Box` to a `Box` /// (presuming `T: Trait`). diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index d01059a3e01..9de9347d0ce 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -184,11 +184,11 @@ impl<'a, 'tcx> HashStable> for CodegenUnit<'tcx> { name.hash_stable(hcx, hasher); - let mut items: Vec<(Fingerprint, _)> = items.iter().map(|(trans_item, &attrs)| { + let mut items: Vec<(Fingerprint, _)> = items.iter().map(|(mono_item, &attrs)| { let mut hasher = StableHasher::new(); - trans_item.hash_stable(hcx, &mut hasher); - let trans_item_fingerprint = hasher.finish(); - (trans_item_fingerprint, attrs) + mono_item.hash_stable(hcx, &mut hasher); + let mono_item_fingerprint = hasher.finish(); + (mono_item_fingerprint, attrs) }).collect(); items.sort_unstable_by_key(|i| i.0); @@ -238,4 +238,3 @@ impl Stats { self.fn_stats.extend(stats.fn_stats); } } - diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 489197e0381..2344cd11f66 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -270,7 +270,7 @@ impl OutputTypes { } // True if any of the output types require codegen or linking. - pub fn should_trans(&self) -> bool { + pub fn should_codegen(&self) -> bool { self.0.keys().any(|k| match *k { OutputType::Bitcode | OutputType::Assembly @@ -1135,14 +1135,14 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "count where LLVM instrs originate"), time_llvm_passes: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true, "The output of `-Z time-llvm-passes` will only reflect timings of \ - re-translated modules when used with incremental compilation" )], + re-codegened modules when used with incremental compilation" )], "measure time of each LLVM pass"), input_stats: bool = (false, parse_bool, [UNTRACKED], "gather statistics about the input"), - trans_stats: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true, - "The output of `-Z trans-stats` might not be accurate when incremental \ + codegen_stats: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true, + "The output of `-Z codegen-stats` might not be accurate when incremental \ compilation is enabled")], - "gather trans statistics"), + "gather codegen statistics"), asm_comments: bool = (false, parse_bool, [TRACKED], "generate comments into the assembly (may change behavior)"), no_verify: bool = (false, parse_bool, [TRACKED], @@ -1183,8 +1183,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, Use with RUST_REGION_GRAPH=help for more info"), parse_only: bool = (false, parse_bool, [UNTRACKED], "parse only; do not compile, assemble, or link"), - no_trans: bool = (false, parse_bool, [TRACKED], - "run all passes except translation; no output"), + no_codegen: bool = (false, parse_bool, [TRACKED], + "run all passes except codegen; no output"), treat_err_as_bug: bool = (false, parse_bool, [TRACKED], "treat all errors that occur as bugs"), external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED], @@ -1235,8 +1235,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "show spans for compiler debugging (expr|pat|ty)"), print_type_sizes: bool = (false, parse_bool, [UNTRACKED], "print layout information for each type encountered"), - print_trans_items: Option = (None, parse_opt_string, [UNTRACKED], - "print the result of the translation item collection pass"), + print_mono_items: Option = (None, parse_opt_string, [UNTRACKED], + "print the result of the monomorphization collection pass"), mir_opt_level: usize = (1, parse_uint, [TRACKED], "set the MIR optimization level (0-3, default: 1)"), mutable_noalias: bool = (false, parse_bool, [TRACKED], @@ -1244,7 +1244,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, arg_align_attributes: bool = (false, parse_bool, [TRACKED], "emit align metadata for reference arguments"), dump_mir: Option = (None, parse_opt_string, [UNTRACKED], - "dump MIR state at various points in translation"), + "dump MIR state at various points in transforms"), dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED], "the directory the MIR is dumped into"), dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED], @@ -1296,8 +1296,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "dump facts from NLL analysis into side files"), disable_nll_user_type_assert: bool = (false, parse_bool, [UNTRACKED], "disable user provided type assertion in NLL"), - trans_time_graph: bool = (false, parse_bool, [UNTRACKED], - "generate a graphical HTML report of time spent in trans and LLVM"), + codegen_time_graph: bool = (false, parse_bool, [UNTRACKED], + "generate a graphical HTML report of time spent in codegen and LLVM"), thinlto: Option = (None, parse_opt_bool, [TRACKED], "enable ThinLTO when possible"), inline_in_all_cgus: Option = (None, parse_opt_bool, [TRACKED], @@ -1309,7 +1309,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, the max/min integer respectively, and NaN is mapped to 0"), lower_128bit_ops: Option = (None, parse_opt_bool, [TRACKED], "rewrite operators on i128 and u128 into lang item calls (typically provided \ - by compiler-builtins) so translation doesn't need to support them, + by compiler-builtins) so codegen doesn't need to support them, overriding the default for the current target"), human_readable_cgu_names: bool = (false, parse_bool, [TRACKED], "generate human-readable, predictable names for codegen units"), @@ -3047,7 +3047,7 @@ mod tests { assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.input_stats = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); - opts.debugging_opts.trans_stats = true; + opts.debugging_opts.codegen_stats = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.borrowck_stats = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); @@ -3093,7 +3093,7 @@ mod tests { assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.keep_ast = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); - opts.debugging_opts.print_trans_items = Some(String::from("abc")); + opts.debugging_opts.print_mono_items = Some(String::from("abc")); assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.dump_mir = Some(String::from("abc")); assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); @@ -3120,7 +3120,7 @@ mod tests { assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); - opts.debugging_opts.no_trans = true; + opts.debugging_opts.no_codegen = true; assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index bbf873290a9..6c8d4f5669e 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -98,7 +98,7 @@ pub struct Session { /// arguments passed to the compiler. Its value together with the crate-name /// forms a unique global identifier for the crate. It is used to allow /// multiple crates with the same name to coexist. See the - /// trans::back::symbol_names module for more information. + /// rustc_codegen_llvm::back::symbol_names module for more information. pub crate_disambiguator: Once, features: Once, @@ -504,8 +504,8 @@ impl Session { pub fn time_llvm_passes(&self) -> bool { self.opts.debugging_opts.time_llvm_passes } - pub fn trans_stats(&self) -> bool { - self.opts.debugging_opts.trans_stats + pub fn codegen_stats(&self) -> bool { + self.opts.debugging_opts.codegen_stats } pub fn meta_stats(&self) -> bool { self.opts.debugging_opts.meta_stats @@ -894,11 +894,11 @@ impl Session { // Why is 16 codegen units the default all the time? // // The main reason for enabling multiple codegen units by default is to - // leverage the ability for the trans backend to do translation and - // codegen in parallel. This allows us, especially for large crates, to + // leverage the ability for the codegen backend to do codegen and + // optimization in parallel. This allows us, especially for large crates, to // make good use of all available resources on the machine once we've // hit that stage of compilation. Large crates especially then often - // take a long time in trans/codegen and this helps us amortize that + // take a long time in codegen/optimization and this helps us amortize that // cost. // // Note that a high number here doesn't mean that we'll be spawning a diff --git a/src/librustc/traits/codegen/mod.rs b/src/librustc/traits/codegen/mod.rs new file mode 100644 index 00000000000..cf404202ac1 --- /dev/null +++ b/src/librustc/traits/codegen/mod.rs @@ -0,0 +1,184 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This file contains various trait resolution methods used by codegen. +// They all assume regions can be erased and monomorphic types. It +// seems likely that they should eventually be merged into more +// general routines. + +use dep_graph::{DepKind, DepTrackingMapConfig}; +use std::marker::PhantomData; +use syntax_pos::DUMMY_SP; +use infer::InferCtxt; +use syntax_pos::Span; +use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, + TraitEngine, Vtable}; +use ty::{self, Ty, TyCtxt}; +use ty::subst::{Subst, Substs}; +use ty::fold::TypeFoldable; + +/// Attempts to resolve an obligation to a vtable.. The result is +/// a shallow vtable resolution -- meaning that we do not +/// (necessarily) resolve all nested obligations on the impl. Note +/// that type check should guarantee to us that all nested +/// obligations *could be* resolved if we wanted to. +/// Assumes that this is run after the entire crate has been successfully type-checked. +pub fn codegen_fulfill_obligation<'a, 'tcx>(ty: TyCtxt<'a, 'tcx, 'tcx>, + (param_env, trait_ref): + (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) + -> Vtable<'tcx, ()> +{ + // Remove any references to regions; this helps improve caching. + let trait_ref = ty.erase_regions(&trait_ref); + + debug!("codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})", + (param_env, trait_ref), trait_ref.def_id()); + + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + ty.infer_ctxt().enter(|infcx| { + let mut selcx = SelectionContext::new(&infcx); + + let obligation_cause = ObligationCause::dummy(); + let obligation = Obligation::new(obligation_cause, + param_env, + trait_ref.to_poly_trait_predicate()); + + let selection = match selcx.select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => { + // Ambiguity can happen when monomorphizing during trans + // expands to some humongo type that never occurred + // statically -- this humongo type can then overflow, + // leading to an ambiguous result. So report this as an + // overflow bug, since I believe this is the only case + // where ambiguity can result. + bug!("Encountered ambiguity selecting `{:?}` during codegen, \ + presuming due to overflow", + trait_ref) + } + Err(e) => { + bug!("Encountered error `{:?}` selecting `{:?}` during codegen", + e, trait_ref) + } + }; + + debug!("fulfill_obligation: selection={:?}", selection); + + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + let mut fulfill_cx = FulfillmentContext::new(); + let vtable = selection.map(|predicate| { + debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); + fulfill_cx.register_predicate_obligation(&infcx, predicate); + }); + let vtable = infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &vtable); + + info!("Cache miss: {:?} => {:?}", trait_ref, vtable); + vtable + }) +} + +impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { + /// Monomorphizes a type from the AST by first applying the + /// in-scope substitutions and then normalizing any associated + /// types. + pub fn subst_and_normalize_erasing_regions( + self, + param_substs: &Substs<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: &T + ) -> T + where + T: TypeFoldable<'tcx>, + { + debug!( + "subst_and_normalize_erasing_regions(\ + param_substs={:?}, \ + value={:?}, \ + param_env={:?})", + param_substs, + value, + param_env, + ); + let substituted = value.subst(self, param_substs); + self.normalize_erasing_regions(param_env, substituted) + } +} + +// Implement DepTrackingMapConfig for `trait_cache` +pub struct TraitSelectionCache<'tcx> { + data: PhantomData<&'tcx ()> +} + +impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { + type Key = (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>); + type Value = Vtable<'tcx, ()>; + fn to_dep_kind() -> DepKind { + DepKind::TraitSelect + } +} + +// # Global Cache + +pub struct ProjectionCache<'gcx> { + data: PhantomData<&'gcx ()> +} + +impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { + type Key = Ty<'gcx>; + type Value = Ty<'gcx>; + fn to_dep_kind() -> DepKind { + DepKind::TraitSelect + } +} + +impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { + /// Finishes processes any obligations that remain in the + /// fulfillment context, and then returns the result with all type + /// variables removed and regions erased. Because this is intended + /// for use after type-check has completed, if any errors occur, + /// it will panic. It is used during normalization and other cases + /// where processing the obligations in `fulfill_cx` may cause + /// type inference variables that appear in `result` to be + /// unified, and hence we need to process those obligations to get + /// the complete picture of the type. + fn drain_fulfillment_cx_or_panic(&self, + span: Span, + fulfill_cx: &mut FulfillmentContext<'tcx>, + result: &T) + -> T::Lifted + where T: TypeFoldable<'tcx> + ty::Lift<'gcx> + { + debug!("drain_fulfillment_cx_or_panic()"); + + // In principle, we only need to do this so long as `result` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + match fulfill_cx.select_all_or_error(self) { + Ok(()) => { } + Err(errors) => { + span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking", + errors); + } + } + + let result = self.resolve_type_vars_if_possible(result); + let result = self.tcx.erase_regions(&result); + + match self.tcx.lift_to_global(&result) { + Some(result) => result, + None => { + span_bug!(span, "Uninferred types/regions in `{:?}`", result); + } + } + } +} diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index f4f0c47899d..b5115eab7dc 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -64,7 +64,7 @@ mod on_unimplemented; mod select; mod specialize; mod structural_impls; -pub mod trans; +pub mod codegen; mod util; pub mod query; @@ -473,8 +473,8 @@ pub enum Vtable<'tcx, N> { /// /// The type parameter `N` indicates the type used for "nested /// obligations" that are required by the impl. During type check, this -/// is `Obligation`, as one might expect. During trans, however, this -/// is `()`, because trans only requires a shallow resolution of an +/// is `Obligation`, as one might expect. During codegen, however, this +/// is `()`, because codegen only requires a shallow resolution of an /// impl, and nested obligations are satisfied later. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub struct VtableImplData<'tcx, N> { @@ -856,7 +856,7 @@ fn vtable_methods<'a, 'tcx>( // It's possible that the method relies on where clauses that // do not hold for this particular set of type parameters. // Note that this method could then never be called, so we - // do not want to try and trans it, in that case (see #23435). + // do not want to try and codegen it, in that case (see #23435). let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); if !normalize_and_test_predicates(tcx, predicates.predicates) { debug!("vtable_methods: predicates do not hold"); @@ -992,7 +992,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { is_object_safe: object_safety::is_object_safe_provider, specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, - trans_fulfill_obligation: trans::trans_fulfill_obligation, + codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, vtable_methods, substitute_normalize_and_test_predicates, ..*providers diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index bfa32f8e7fa..270e06a872b 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -65,7 +65,7 @@ pub enum Reveal { /// } UserFacing, - /// At trans time, all monomorphic projections will succeed. + /// At codegen time, all monomorphic projections will succeed. /// Also, `impl Trait` is normalized to the concrete type, /// which has to be already collected by type-checking. /// @@ -346,7 +346,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, let ty = ty.super_fold_with(self); match ty.sty { ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => { // (*) - // Only normalize `impl Trait` after type-checking, usually in trans. + // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal { Reveal::UserFacing => ty, @@ -1054,7 +1054,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( super::VtableImpl(impl_data) => { // We have to be careful when projecting out of an // impl because of specialization. If we are not in - // trans (i.e., projection mode is not "any"), and the + // codegen (i.e., projection mode is not "any"), and the // impl's type is declared as default, then we disable // projection (even if the trait ref is fully // monomorphic). In the case where trait ref is not diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index f074e061653..1e9e9c056c9 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -104,7 +104,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx match ty.sty { ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => { // (*) - // Only normalize `impl Trait` after type-checking, usually in trans. + // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal { Reveal::UserFacing => ty, diff --git a/src/librustc/traits/query/normalize_erasing_regions.rs b/src/librustc/traits/query/normalize_erasing_regions.rs index a9734e9c298..1cb96a3e33f 100644 --- a/src/librustc/traits/query/normalize_erasing_regions.rs +++ b/src/librustc/traits/query/normalize_erasing_regions.rs @@ -57,7 +57,7 @@ impl<'cx, 'tcx> TyCtxt<'cx, 'tcx, 'tcx> { /// /// NB. Currently, higher-ranked type bounds inhibit /// normalization. Therefore, each time we erase them in - /// translation, we need to normalize the contents. + /// codegen, we need to normalize the contents. pub fn normalize_erasing_late_bound_regions( self, param_env: ty::ParamEnv<'tcx>, diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index b9593047af4..2e2f7a2ad31 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -275,7 +275,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> { } } -// For trans only. +// For codegen only. impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { type Lifted = traits::Vtable<'tcx, ()>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs deleted file mode 100644 index 31e851126d7..00000000000 --- a/src/librustc/traits/trans/mod.rs +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// This file contains various trait resolution methods used by trans. -// They all assume regions can be erased and monomorphic types. It -// seems likely that they should eventually be merged into more -// general routines. - -use dep_graph::{DepKind, DepTrackingMapConfig}; -use std::marker::PhantomData; -use syntax_pos::DUMMY_SP; -use infer::InferCtxt; -use syntax_pos::Span; -use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, - TraitEngine, Vtable}; -use ty::{self, Ty, TyCtxt}; -use ty::subst::{Subst, Substs}; -use ty::fold::TypeFoldable; - -/// Attempts to resolve an obligation to a vtable.. The result is -/// a shallow vtable resolution -- meaning that we do not -/// (necessarily) resolve all nested obligations on the impl. Note -/// that type check should guarantee to us that all nested -/// obligations *could be* resolved if we wanted to. -/// Assumes that this is run after the entire crate has been successfully type-checked. -pub fn trans_fulfill_obligation<'a, 'tcx>(ty: TyCtxt<'a, 'tcx, 'tcx>, - (param_env, trait_ref): - (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) - -> Vtable<'tcx, ()> -{ - // Remove any references to regions; this helps improve caching. - let trait_ref = ty.erase_regions(&trait_ref); - - debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", - (param_env, trait_ref), trait_ref.def_id()); - - // Do the initial selection for the obligation. This yields the - // shallow result we are looking for -- that is, what specific impl. - ty.infer_ctxt().enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - - let obligation_cause = ObligationCause::dummy(); - let obligation = Obligation::new(obligation_cause, - param_env, - trait_ref.to_poly_trait_predicate()); - - let selection = match selcx.select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => { - // Ambiguity can happen when monomorphizing during trans - // expands to some humongo type that never occurred - // statically -- this humongo type can then overflow, - // leading to an ambiguous result. So report this as an - // overflow bug, since I believe this is the only case - // where ambiguity can result. - bug!("Encountered ambiguity selecting `{:?}` during trans, \ - presuming due to overflow", - trait_ref) - } - Err(e) => { - bug!("Encountered error `{:?}` selecting `{:?}` during trans", - e, trait_ref) - } - }; - - debug!("fulfill_obligation: selection={:?}", selection); - - // Currently, we use a fulfillment context to completely resolve - // all nested obligations. This is because they can inform the - // inference of the impl's type parameters. - let mut fulfill_cx = FulfillmentContext::new(); - let vtable = selection.map(|predicate| { - debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); - fulfill_cx.register_predicate_obligation(&infcx, predicate); - }); - let vtable = infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &vtable); - - info!("Cache miss: {:?} => {:?}", trait_ref, vtable); - vtable - }) -} - -impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { - /// Monomorphizes a type from the AST by first applying the - /// in-scope substitutions and then normalizing any associated - /// types. - pub fn subst_and_normalize_erasing_regions( - self, - param_substs: &Substs<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: &T - ) -> T - where - T: TypeFoldable<'tcx>, - { - debug!( - "subst_and_normalize_erasing_regions(\ - param_substs={:?}, \ - value={:?}, \ - param_env={:?})", - param_substs, - value, - param_env, - ); - let substituted = value.subst(self, param_substs); - self.normalize_erasing_regions(param_env, substituted) - } -} - -// Implement DepTrackingMapConfig for `trait_cache` -pub struct TraitSelectionCache<'tcx> { - data: PhantomData<&'tcx ()> -} - -impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { - type Key = (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>); - type Value = Vtable<'tcx, ()>; - fn to_dep_kind() -> DepKind { - DepKind::TraitSelect - } -} - -// # Global Cache - -pub struct ProjectionCache<'gcx> { - data: PhantomData<&'gcx ()> -} - -impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { - type Key = Ty<'gcx>; - type Value = Ty<'gcx>; - fn to_dep_kind() -> DepKind { - DepKind::TraitSelect - } -} - -impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - /// Finishes processes any obligations that remain in the - /// fulfillment context, and then returns the result with all type - /// variables removed and regions erased. Because this is intended - /// for use after type-check has completed, if any errors occur, - /// it will panic. It is used during normalization and other cases - /// where processing the obligations in `fulfill_cx` may cause - /// type inference variables that appear in `result` to be - /// unified, and hence we need to process those obligations to get - /// the complete picture of the type. - fn drain_fulfillment_cx_or_panic(&self, - span: Span, - fulfill_cx: &mut FulfillmentContext<'tcx>, - result: &T) - -> T::Lifted - where T: TypeFoldable<'tcx> + ty::Lift<'gcx> - { - debug!("drain_fulfillment_cx_or_panic()"); - - // In principle, we only need to do this so long as `result` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - match fulfill_cx.select_all_or_error(self) { - Ok(()) => { } - Err(errors) => { - span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking", - errors); - } - } - - let result = self.resolve_type_vars_if_possible(result); - let result = self.tcx.erase_regions(&result); - - match self.tcx.lift_to_global(&result) { - Some(result) => result, - None => { - span_bug!(span, "Uninferred types/regions in `{:?}`", result); - } - } - } -} diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index a0c31e8b509..3263da8fda3 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -91,8 +91,8 @@ pub enum Adjust<'tcx> { /// pointers. We don't store the details of how the transform is /// done (in fact, we don't know that, because it might depend on /// the precise type parameters). We just store the target - /// type. Trans figures out what has to be done at monomorphization - /// time based on the precise source/target type at hand. + /// type. Codegen backends and miri figure out what has to be done + /// based on the precise source/target type at hand. Unsize, } diff --git a/src/librustc/ty/cast.rs b/src/librustc/ty/cast.rs index 908335424e7..7593d4ed24e 100644 --- a/src/librustc/ty/cast.rs +++ b/src/librustc/ty/cast.rs @@ -9,7 +9,7 @@ // except according to those terms. // Helpers for handling cast expressions, used in both -// typeck and trans. +// typeck and codegen. use ty::{self, Ty}; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 3c345fcd9ee..ee55b8dd767 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -401,7 +401,7 @@ pub struct TypeckTables<'tcx> { /// For each fn, records the "liberated" types of its arguments /// and return type. Liberated means that all bound regions /// (including late-bound regions) are replaced with free - /// equivalents. This table is not used in trans (since regions + /// equivalents. This table is not used in codegen (since regions /// are erased there) and hence is not serialized to metadata. liberated_fn_sigs: ItemLocalMap>, @@ -921,7 +921,7 @@ pub struct GlobalCtxt<'tcx> { /// A general purpose channel to throw data out the back towards LLVM worker /// threads. /// - /// This is intended to only get used during the trans phase of the compiler + /// This is intended to only get used during the codegen phase of the compiler /// when satisfying the query for a particular codegen unit. Internally in /// the query it'll send data along this channel to get processed later. pub tx_to_llvm_workers: Lock>>, diff --git a/src/librustc/ty/erase_regions.rs b/src/librustc/ty/erase_regions.rs index 4f8fca67949..f483b4c174a 100644 --- a/src/librustc/ty/erase_regions.rs +++ b/src/librustc/ty/erase_regions.rs @@ -68,7 +68,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionEraserVisitor<'a, 'gcx, 't // // Note that we *CAN* replace early-bound regions -- the // type system never "sees" those, they get substituted - // away. In trans, they will always be erased to 'erased + // away. In codegen, they will always be erased to 'erased // whenever a substitution occurs. match *r { ty::ReLateBound(..) => r, @@ -76,4 +76,3 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionEraserVisitor<'a, 'gcx, 't } } } - diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 250f33d9dba..8aca7177d55 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -424,7 +424,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { collector.regions } - /// Replace any late-bound regions bound in `value` with `'erased`. Useful in trans but also + /// Replace any late-bound regions bound in `value` with `'erased`. Useful in codegen but also /// method lookup and a few other places where precise region relationships are not required. pub fn erase_late_bound_regions(self, value: &Binder) -> T where T : TypeFoldable<'tcx> diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index e7b71ca2b22..e97f782fccf 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -104,13 +104,13 @@ impl<'tcx> InstanceDef<'tcx> { return true } if let ty::InstanceDef::DropGlue(..) = *self { - // Drop glue wants to be instantiated at every translation + // Drop glue wants to be instantiated at every codegen // unit, but without an #[inline] hint. We should make this // available to normal end-users. return true } - let trans_fn_attrs = tcx.trans_fn_attrs(self.def_id()); - trans_fn_attrs.requests_inline() || tcx.is_const_fn(self.def_id()) + let codegen_fn_attrs = tcx.codegen_fn_attrs(self.def_id()); + codegen_fn_attrs.requests_inline() || tcx.is_const_fn(self.def_id()) } } @@ -145,7 +145,7 @@ impl<'a, 'b, 'tcx> Instance<'tcx> { pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> Instance<'tcx> { assert!(!substs.has_escaping_regions(), - "substs of instance {:?} not normalized for trans: {:?}", + "substs of instance {:?} not normalized for codegen: {:?}", def_id, substs); Instance { def: InstanceDef::Item(def_id), substs: substs } } @@ -175,7 +175,7 @@ impl<'a, 'b, 'tcx> Instance<'tcx> { /// `RevealMode` in the parameter environment.) /// /// Presuming that coherence and type-check have succeeded, if this method is invoked - /// in a monomorphic context (i.e., like during trans), then it is guaranteed to return + /// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return /// `Some`. pub fn resolve(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -259,7 +259,7 @@ fn resolve_associated_item<'a, 'tcx>( def_id, trait_id, rcvr_substs); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = tcx.trans_fulfill_obligation((param_env, ty::Binder::bind(trait_ref))); + let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref))); // Now that we know which impl is being used, we can dispatch to // the actual function: @@ -321,7 +321,7 @@ fn needs_fn_once_adapter_shim<'a, 'tcx>(actual_closure_kind: ty::ClosureKind, } (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { // The closure fn `llfn` is a `fn(&self, ...)`. We want a - // `fn(&mut self, ...)`. In fact, at trans time, these are + // `fn(&mut self, ...)`. In fact, at codegen time, these are // basically the same thing, so we can just return llfn. Ok(false) } @@ -334,7 +334,7 @@ fn needs_fn_once_adapter_shim<'a, 'tcx>(actual_closure_kind: ty::ClosureKind, // fn call_once(self, ...) { call_mut(&self, ...) } // fn call_once(mut self, ...) { call_mut(&mut self, ...) } // - // These are both the same at trans time. + // These are both the same at codegen time. Ok(true) } (ty::ClosureKind::FnMut, _) | diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index bbfc6d883e9..dbc32f4dbdd 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -949,14 +949,14 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // because this discriminant will be loaded, and then stored into variable of // type calculated by typeck. Consider such case (a bug): typeck decided on // byte-sized discriminant, but layout thinks we need a 16-bit to store all - // discriminant values. That would be a bug, because then, in trans, in order + // discriminant values. That would be a bug, because then, in codegen, in order // to store this 16-bit discriminant into 8-bit sized temporary some of the // space necessary to represent would have to be discarded (or layout is wrong // on thinking it needs 16 bits) bug!("layout decided on a larger discriminant type ({:?}) than typeck ({:?})", min_ity, typeck_ity); // However, it is fine to make discr type however large (as an optimisation) - // after this point – we’ll just truncate the value we load in trans. + // after this point – we’ll just truncate the value we load in codegen. } // Check to see if we should use a different type for the @@ -1121,7 +1121,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // If we are running with `-Zprint-type-sizes`, record layouts for // dumping later. Ignore layouts that are done with non-empty // environments or non-monomorphic layouts, as the user only wants - // to see the stuff resulting from the final trans session. + // to see the stuff resulting from the final codegen session. if !self.tcx.sess.opts.debugging_opts.print_type_sizes || layout.ty.has_param_types() || diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index ad48519e136..19c97a918bb 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -349,7 +349,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::is_mir_available<'tcx> { } } -impl<'tcx> QueryDescription<'tcx> for queries::trans_fulfill_obligation<'tcx> { +impl<'tcx> QueryDescription<'tcx> for queries::codegen_fulfill_obligation<'tcx> { fn describe(tcx: TyCtxt, key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> String { format!("checking if `{}` fulfills its obligations", tcx.item_path_str(key.1.def_id())) } @@ -637,9 +637,9 @@ impl<'tcx> QueryDescription<'tcx> for queries::exported_symbols<'tcx> { } } -impl<'tcx> QueryDescription<'tcx> for queries::collect_and_partition_translation_items<'tcx> { +impl<'tcx> QueryDescription<'tcx> for queries::collect_and_partition_mono_items<'tcx> { fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("collect_and_partition_translation_items") + format!("collect_and_partition_mono_items") } } @@ -795,5 +795,5 @@ impl_disk_cacheable_query!(def_symbol_name, |_| true); impl_disk_cacheable_query!(type_of, |def_id| def_id.is_local()); impl_disk_cacheable_query!(predicates_of, |def_id| def_id.is_local()); impl_disk_cacheable_query!(used_trait_imports, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(trans_fn_attrs, |_| true); +impl_disk_cacheable_query!(codegen_fn_attrs, |_| true); impl_disk_cacheable_query!(specialization_graph_of, |_| true); diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 6e419627dd8..6556e47720c 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -11,7 +11,7 @@ use dep_graph::{DepConstructor, DepNode}; use hir::def_id::{CrateNum, DefId, DefIndex}; use hir::def::{Def, Export}; -use hir::{self, TraitCandidate, ItemLocalId, TransFnAttrs}; +use hir::{self, TraitCandidate, ItemLocalId, CodegenFnAttrs}; use hir::svh::Svh; use infer::canonical::{self, Canonical}; use lint; @@ -181,7 +181,7 @@ define_maps! { <'tcx> [] fn mir_validated: MirValidated(DefId) -> &'tcx Steal>, /// MIR after our optimization passes have run. This is MIR that is ready - /// for trans. This is also the only query that can fetch non-local MIR, at present. + /// for codegen. This is also the only query that can fetch non-local MIR, at present. [] fn optimized_mir: MirOptimized(DefId) -> &'tcx mir::Mir<'tcx>, /// The result of unsafety-checking this def-id. @@ -255,7 +255,7 @@ define_maps! { <'tcx> [] fn lookup_stability: LookupStability(DefId) -> Option<&'tcx attr::Stability>, [] fn lookup_deprecation_entry: LookupDeprecationEntry(DefId) -> Option, [] fn item_attrs: ItemAttrs(DefId) -> Lrc<[ast::Attribute]>, - [] fn trans_fn_attrs: trans_fn_attrs(DefId) -> TransFnAttrs, + [] fn codegen_fn_attrs: codegen_fn_attrs(DefId) -> CodegenFnAttrs, [] fn fn_arg_names: FnArgNames(DefId) -> Vec, /// Gets the rendered value of the specified constant or associated constant. /// Used by rustdoc. @@ -268,7 +268,7 @@ define_maps! { <'tcx> [] fn vtable_methods: vtable_methods_node(ty::PolyTraitRef<'tcx>) -> Lrc)>>>, - [] fn trans_fulfill_obligation: fulfill_obligation_dep_node( + [] fn codegen_fulfill_obligation: fulfill_obligation_dep_node( (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Vtable<'tcx, ()>, [] fn trait_impls_of: TraitImpls(DefId) -> Lrc, [] fn specialization_graph_of: SpecializationGraph(DefId) -> Lrc, @@ -402,10 +402,10 @@ define_maps! { <'tcx> [] fn exported_symbols: ExportedSymbols(CrateNum) -> Arc, SymbolExportLevel)>>, - [] fn collect_and_partition_translation_items: - collect_and_partition_translation_items_node(CrateNum) + [] fn collect_and_partition_mono_items: + collect_and_partition_mono_items_node(CrateNum) -> (Arc, Arc>>>), - [] fn is_translated_item: IsTranslatedItem(DefId) -> bool, + [] fn is_codegened_item: IsCodegenedItem(DefId) -> bool, [] fn codegen_unit: CodegenUnit(InternedString) -> Arc>, [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats, [] fn output_filenames: output_filenames_node(CrateNum) @@ -475,8 +475,8 @@ fn features_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { DepConstructor::Features } -fn trans_fn_attrs<'tcx>(id: DefId) -> DepConstructor<'tcx> { - DepConstructor::TransFnAttrs { 0: id } +fn codegen_fn_attrs<'tcx>(id: DefId) -> DepConstructor<'tcx> { + DepConstructor::CodegenFnAttrs { 0: id } } fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> { @@ -609,8 +609,8 @@ fn all_traits_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { DepConstructor::AllTraits } -fn collect_and_partition_translation_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::CollectAndPartitionTranslationItems +fn collect_and_partition_mono_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::CollectAndPartitionMonoItems } fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index cea2a03fd53..9ca90a06c4e 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -224,7 +224,7 @@ impl<'sess> OnDiskCache<'sess> { encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; @@ -234,7 +234,7 @@ impl<'sess> OnDiskCache<'sess> { encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; // const eval is special, it only encodes successfully evaluated constants diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 65dcb7311d3..065b7939ac3 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -871,7 +871,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, // Since we cannot reconstruct the query key of a DepNode::CodegenUnit, we // would always end up having to evaluate the first caller of the // `codegen_unit` query that *is* reconstructible. This might very well be - // the `compile_codegen_unit` query, thus re-translating the whole CGU just + // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just // to re-trigger calling the `codegen_unit` query with the right key. At // that point we would already have re-done all the work we are trying to // avoid doing in the first place. @@ -1046,7 +1046,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, } DepKind::IsMirAvailable => { force!(is_mir_available, def_id!()); } DepKind::ItemAttrs => { force!(item_attrs, def_id!()); } - DepKind::TransFnAttrs => { force!(trans_fn_attrs, def_id!()); } + DepKind::CodegenFnAttrs => { force!(codegen_fn_attrs, def_id!()); } DepKind::FnArgNames => { force!(fn_arg_names, def_id!()); } DepKind::RenderedConst => { force!(rendered_const, def_id!()); } DepKind::DylibDepFormats => { force!(dylib_dependency_formats, krate!()); } @@ -1121,10 +1121,10 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::AllTraits => { force!(all_traits, LOCAL_CRATE); } DepKind::AllCrateNums => { force!(all_crate_nums, LOCAL_CRATE); } DepKind::ExportedSymbols => { force!(exported_symbols, krate!()); } - DepKind::CollectAndPartitionTranslationItems => { - force!(collect_and_partition_translation_items, LOCAL_CRATE); + DepKind::CollectAndPartitionMonoItems => { + force!(collect_and_partition_mono_items, LOCAL_CRATE); } - DepKind::IsTranslatedItem => { force!(is_translated_item, def_id!()); } + DepKind::IsCodegenedItem => { force!(is_codegened_item, def_id!()); } DepKind::OutputFilenames => { force!(output_filenames, LOCAL_CRATE); } DepKind::TargetFeaturesWhitelist => { force!(target_features_whitelist, LOCAL_CRATE); } @@ -1207,6 +1207,6 @@ impl_load_from_cache!( GenericsOfItem => generics_of, PredicatesOfItem => predicates_of, UsedTraitImports => used_trait_imports, - TransFnAttrs => trans_fn_attrs, + CodegenFnAttrs => codegen_fn_attrs, SpecializationGraph => specialization_graph_of, ); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index eb638d7c9a1..ce7feae0719 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -118,7 +118,7 @@ mod sty; // Data types /// The complete set of all analyses described in this module. This is -/// produced by the driver and fed to trans and later passes. +/// produced by the driver and fed to codegen and later passes. /// /// NB: These contents are being migrated into queries using the /// *on-demand* infrastructure. @@ -1426,7 +1426,7 @@ pub struct ParamEnv<'tcx> { /// into Obligations, and elaborated and normalized. pub caller_bounds: &'tcx Slice>, - /// Typically, this is `Reveal::UserFacing`, but during trans we + /// Typically, this is `Reveal::UserFacing`, but during codegen we /// want `Reveal::All` -- note that this is always paired with an /// empty environment. To get that, use `ParamEnv::reveal()`. pub reveal: traits::Reveal, @@ -1444,7 +1444,7 @@ impl<'tcx> ParamEnv<'tcx> { /// Construct a trait environment with no where clauses in scope /// where the values of all `impl Trait` and other hidden types /// are revealed. This is suitable for monomorphized, post-typeck - /// environments like trans or doing optimizations. + /// environments like codegen or doing optimizations. /// /// NB. If you want to have predicates in scope, use `ParamEnv::new`, /// or invoke `param_env.with_reveal_all()`. @@ -1462,7 +1462,7 @@ impl<'tcx> ParamEnv<'tcx> { /// Returns a new parameter environment with the same clauses, but /// which "reveals" the true results of projections in all cases /// (even for associated types that are specializable). This is - /// the desired behavior during trans and certain other special + /// the desired behavior during codegen and certain other special /// contexts; normally though we want to use `Reveal::UserFacing`, /// which is the default. pub fn with_reveal_all(self) -> Self { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 5c0217fc3f5..4493c668593 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -243,7 +243,7 @@ pub enum TypeVariants<'tcx> { /// out later. /// /// All right, you say, but why include the type parameters from the -/// original function then? The answer is that trans may need them +/// original function then? The answer is that codegen may need them /// when monomorphizing, and they may not appear in the upvars. A /// closure could capture no variables but still make use of some /// in-scope type parameter with a bound (e.g., if our example above @@ -273,7 +273,7 @@ pub struct ClosureSubsts<'tcx> { /// Lifetime and type parameters from the enclosing function, /// concatenated with the types of the upvars. /// - /// These are separated out because trans wants to pass them around + /// These are separated out because codegen wants to pass them around /// when monomorphizing. pub substs: &'tcx Substs<'tcx>, } @@ -1093,7 +1093,7 @@ pub enum RegionKind { /// variable with no constraints. ReEmpty, - /// Erased region, used by trait selection, in MIR and during trans. + /// Erased region, used by trait selection, in MIR and during codegen. ReErased, /// These are regions bound in the "defining type" for a diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index eaae874635f..c66dd79cbf5 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1135,7 +1135,7 @@ define_print! { })? } else { // cross-crate closure types should only be - // visible in trans bug reports, I imagine. + // visible in codegen bug reports, I imagine. write!(f, "@{:?}", did)?; let mut sep = " "; for (index, upvar_ty) in upvar_tys.enumerate() { @@ -1175,7 +1175,7 @@ define_print! { })? } else { // cross-crate closure types should only be - // visible in trans bug reports, I imagine. + // visible in codegen bug reports, I imagine. write!(f, "@{:?}", did)?; let mut sep = " "; for (index, upvar_ty) in upvar_tys.enumerate() { diff --git a/src/librustc_borrowck/borrowck/README.md b/src/librustc_borrowck/borrowck/README.md index 29f03c06ab7..6fc0ed47b80 100644 --- a/src/librustc_borrowck/borrowck/README.md +++ b/src/librustc_borrowck/borrowck/README.md @@ -1126,7 +1126,7 @@ fn foo(a: [D; 10], b: [D; 10], i: i32, t: bool) -> D { } ``` -There are a number of ways that the trans backend could choose to +There are a number of ways that the codegen backend could choose to compile this (e.g. a `[bool; 10]` array for each such moved array; or an `Option` for each moved array). From the viewpoint of the borrow-checker, the important thing is to record what kind of fragment diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml new file mode 100644 index 00000000000..7cf0a1c1bec --- /dev/null +++ b/src/librustc_codegen_llvm/Cargo.toml @@ -0,0 +1,49 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_codegen_llvm" +version = "0.0.0" + +[lib] +name = "rustc_codegen_llvm" +path = "lib.rs" +crate-type = ["dylib"] +test = false + +[dependencies] +bitflags = "1.0.1" +cc = "1.0.1" +flate2 = "1.0" +jobserver = "0.1.5" +libc = "0.2" +log = "0.4" +num_cpus = "1.0" +rustc = { path = "../librustc" } +rustc-demangle = "0.1.4" +rustc_allocator = { path = "../librustc_allocator" } +rustc_apfloat = { path = "../librustc_apfloat" } +rustc_target = { path = "../librustc_target" } +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_errors = { path = "../librustc_errors" } +rustc_incremental = { path = "../librustc_incremental" } +rustc_llvm = { path = "../librustc_llvm" } +rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } +rustc_codegen_utils = { path = "../librustc_codegen_utils" } +rustc_mir = { path = "../librustc_mir" } +serialize = { path = "../libserialize" } +syntax = { path = "../libsyntax" } +syntax_pos = { path = "../libsyntax_pos" } +tempdir = "0.3" + +# not actually used but needed to make sure we enable the same feature set as +# winapi used in librustc +env_logger = { version = "0.5", default-features = false } + +[features] +# Used to communicate the feature to `rustc_target` in the same manner that the +# `rustc` driver script communicate this. +jemalloc = ["rustc_target/jemalloc"] + +# This is used to convince Cargo to separately cache builds of `rustc_codegen_llvm` +# when this option is enabled or not. That way we can build two, cache two +# artifacts, and have nice speedy rebuilds. +emscripten = ["rustc_llvm/emscripten"] diff --git a/src/librustc_codegen_llvm/README.md b/src/librustc_codegen_llvm/README.md new file mode 100644 index 00000000000..8d1c9a52b24 --- /dev/null +++ b/src/librustc_codegen_llvm/README.md @@ -0,0 +1,7 @@ +The `codegen` crate contains the code to convert from MIR into LLVM IR, +and then from LLVM IR into machine code. In general it contains code +that runs towards the end of the compilation process. + +For more information about how codegen works, see the [rustc guide]. + +[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/codegen.html diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs new file mode 100644 index 00000000000..25c598c532c --- /dev/null +++ b/src/librustc_codegen_llvm/abi.rs @@ -0,0 +1,696 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use llvm::{self, ValueRef, AttributePlace}; +use base; +use builder::{Builder, MemFlags}; +use common::{ty_fn_sig, C_usize}; +use context::CodegenCx; +use mir::place::PlaceRef; +use mir::operand::OperandValue; +use type_::Type; +use type_of::{LayoutLlvmExt, PointerKind}; + +use rustc_target::abi::{LayoutOf, Size, TyLayout}; +use rustc::ty::{self, Ty}; +use rustc::ty::layout; + +use libc::c_uint; + +pub use rustc_target::spec::abi::Abi; +pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; +pub use rustc_target::abi::call::*; + +macro_rules! for_each_kind { + ($flags: ident, $f: ident, $($kind: ident),+) => ({ + $(if $flags.contains(ArgAttribute::$kind) { $f(llvm::Attribute::$kind) })+ + }) +} + +trait ArgAttributeExt { + fn for_each_kind(&self, f: F) where F: FnMut(llvm::Attribute); +} + +impl ArgAttributeExt for ArgAttribute { + fn for_each_kind(&self, mut f: F) where F: FnMut(llvm::Attribute) { + for_each_kind!(self, f, + ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg) + } +} + +pub trait ArgAttributesExt { + fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef); + fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef); +} + +impl ArgAttributesExt for ArgAttributes { + fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { + let mut regular = self.regular; + unsafe { + let deref = self.pointee_size.bytes(); + if deref != 0 { + if regular.contains(ArgAttribute::NonNull) { + llvm::LLVMRustAddDereferenceableAttr(llfn, + idx.as_uint(), + deref); + } else { + llvm::LLVMRustAddDereferenceableOrNullAttr(llfn, + idx.as_uint(), + deref); + } + regular -= ArgAttribute::NonNull; + } + if let Some(align) = self.pointee_align { + llvm::LLVMRustAddAlignmentAttr(llfn, + idx.as_uint(), + align.abi() as u32); + } + regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn)); + } + } + + fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) { + let mut regular = self.regular; + unsafe { + let deref = self.pointee_size.bytes(); + if deref != 0 { + if regular.contains(ArgAttribute::NonNull) { + llvm::LLVMRustAddDereferenceableCallSiteAttr(callsite, + idx.as_uint(), + deref); + } else { + llvm::LLVMRustAddDereferenceableOrNullCallSiteAttr(callsite, + idx.as_uint(), + deref); + } + regular -= ArgAttribute::NonNull; + } + if let Some(align) = self.pointee_align { + llvm::LLVMRustAddAlignmentCallSiteAttr(callsite, + idx.as_uint(), + align.abi() as u32); + } + regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite)); + } + } +} + +pub trait LlvmType { + fn llvm_type(&self, cx: &CodegenCx) -> Type; +} + +impl LlvmType for Reg { + fn llvm_type(&self, cx: &CodegenCx) -> Type { + match self.kind { + RegKind::Integer => Type::ix(cx, self.size.bits()), + RegKind::Float => { + match self.size.bits() { + 32 => Type::f32(cx), + 64 => Type::f64(cx), + _ => bug!("unsupported float: {:?}", self) + } + } + RegKind::Vector => { + Type::vector(&Type::i8(cx), self.size.bytes()) + } + } + } +} + +impl LlvmType for CastTarget { + fn llvm_type(&self, cx: &CodegenCx) -> Type { + let rest_ll_unit = self.rest.unit.llvm_type(cx); + let rest_count = self.rest.total.bytes() / self.rest.unit.size.bytes(); + let rem_bytes = self.rest.total.bytes() % self.rest.unit.size.bytes(); + + if self.prefix.iter().all(|x| x.is_none()) { + // Simplify to a single unit when there is no prefix and size <= unit size + if self.rest.total <= self.rest.unit.size { + return rest_ll_unit; + } + + // Simplify to array when all chunks are the same size and type + if rem_bytes == 0 { + return Type::array(&rest_ll_unit, rest_count); + } + } + + // Create list of fields in the main structure + let mut args: Vec<_> = + self.prefix.iter().flat_map(|option_kind| option_kind.map( + |kind| Reg { kind: kind, size: self.prefix_chunk }.llvm_type(cx))) + .chain((0..rest_count).map(|_| rest_ll_unit)) + .collect(); + + // Append final integer + if rem_bytes != 0 { + // Only integers can be really split further. + assert_eq!(self.rest.unit.kind, RegKind::Integer); + args.push(Type::ix(cx, rem_bytes * 8)); + } + + Type::struct_(cx, &args, false) + } +} + +pub trait ArgTypeExt<'a, 'tcx> { + fn memory_ty(&self, cx: &CodegenCx<'a, 'tcx>) -> Type; + fn store(&self, bx: &Builder<'a, 'tcx>, val: ValueRef, dst: PlaceRef<'tcx>); + fn store_fn_arg(&self, bx: &Builder<'a, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx>); +} + +impl<'a, 'tcx> ArgTypeExt<'a, 'tcx> for ArgType<'tcx, Ty<'tcx>> { + /// Get the LLVM type for a place of the original Rust type of + /// this argument/return, i.e. the result of `type_of::type_of`. + fn memory_ty(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { + self.layout.llvm_type(cx) + } + + /// Store a direct/indirect value described by this ArgType into a + /// place for the original Rust type of this argument/return. + /// Can be used for both storing formal arguments into Rust variables + /// or results of call/invoke instructions into their destinations. + fn store(&self, bx: &Builder<'a, 'tcx>, val: ValueRef, dst: PlaceRef<'tcx>) { + if self.is_ignore() { + return; + } + let cx = bx.cx; + if self.is_indirect() { + OperandValue::Ref(val, self.layout.align).store(bx, dst) + } else if let PassMode::Cast(cast) = self.mode { + // FIXME(eddyb): Figure out when the simpler Store is safe, clang + // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. + let can_store_through_cast_ptr = false; + if can_store_through_cast_ptr { + let cast_dst = bx.pointercast(dst.llval, cast.llvm_type(cx).ptr_to()); + bx.store(val, cast_dst, self.layout.align); + } else { + // The actual return type is a struct, but the ABI + // adaptation code has cast it into some scalar type. The + // code that follows is the only reliable way I have + // found to do a transform like i64 -> {i32,i32}. + // Basically we dump the data onto the stack then memcpy it. + // + // Other approaches I tried: + // - Casting rust ret pointer to the foreign type and using Store + // is (a) unsafe if size of foreign type > size of rust type and + // (b) runs afoul of strict aliasing rules, yielding invalid + // assembly under -O (specifically, the store gets removed). + // - Truncating foreign type to correct integral type and then + // bitcasting to the struct type yields invalid cast errors. + + // We instead thus allocate some scratch space... + let scratch_size = cast.size(cx); + let scratch_align = cast.align(cx); + let llscratch = bx.alloca(cast.llvm_type(cx), "abi_cast", scratch_align); + bx.lifetime_start(llscratch, scratch_size); + + // ...where we first store the value... + bx.store(val, llscratch, scratch_align); + + // ...and then memcpy it to the intended destination. + base::call_memcpy(bx, + bx.pointercast(dst.llval, Type::i8p(cx)), + bx.pointercast(llscratch, Type::i8p(cx)), + C_usize(cx, self.layout.size.bytes()), + self.layout.align.min(scratch_align), + MemFlags::empty()); + + bx.lifetime_end(llscratch, scratch_size); + } + } else { + OperandValue::Immediate(val).store(bx, dst); + } + } + + fn store_fn_arg(&self, bx: &Builder<'a, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx>) { + let mut next = || { + let val = llvm::get_param(bx.llfn(), *idx as c_uint); + *idx += 1; + val + }; + match self.mode { + PassMode::Ignore => {}, + PassMode::Pair(..) => { + OperandValue::Pair(next(), next()).store(bx, dst); + } + PassMode::Direct(_) | PassMode::Indirect(_) | PassMode::Cast(_) => { + self.store(bx, next(), dst); + } + } + } +} + +pub trait FnTypeExt<'a, 'tcx> { + fn of_instance(cx: &CodegenCx<'a, 'tcx>, instance: &ty::Instance<'tcx>) + -> Self; + fn new(cx: &CodegenCx<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> Self; + fn new_vtable(cx: &CodegenCx<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> Self; + fn unadjusted(cx: &CodegenCx<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> Self; + fn adjust_for_abi(&mut self, + cx: &CodegenCx<'a, 'tcx>, + abi: Abi); + fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type; + fn llvm_cconv(&self) -> llvm::CallConv; + fn apply_attrs_llfn(&self, llfn: ValueRef); + fn apply_attrs_callsite(&self, bx: &Builder<'a, 'tcx>, callsite: ValueRef); +} + +impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { + fn of_instance(cx: &CodegenCx<'a, 'tcx>, instance: &ty::Instance<'tcx>) + -> Self { + let fn_ty = instance.ty(cx.tcx); + let sig = ty_fn_sig(cx, fn_ty); + let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + FnType::new(cx, sig, &[]) + } + + fn new(cx: &CodegenCx<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> Self { + let mut fn_ty = FnType::unadjusted(cx, sig, extra_args); + fn_ty.adjust_for_abi(cx, sig.abi); + fn_ty + } + + fn new_vtable(cx: &CodegenCx<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> Self { + let mut fn_ty = FnType::unadjusted(cx, sig, extra_args); + // Don't pass the vtable, it's not an argument of the virtual fn. + { + let self_arg = &mut fn_ty.args[0]; + match self_arg.mode { + PassMode::Pair(data_ptr, _) => { + self_arg.mode = PassMode::Direct(data_ptr); + } + _ => bug!("FnType::new_vtable: non-pair self {:?}", self_arg) + } + + let pointee = self_arg.layout.ty.builtin_deref(true) + .unwrap_or_else(|| { + bug!("FnType::new_vtable: non-pointer self {:?}", self_arg) + }).ty; + let fat_ptr_ty = cx.tcx.mk_mut_ptr(pointee); + self_arg.layout = cx.layout_of(fat_ptr_ty).field(cx, 0); + } + fn_ty.adjust_for_abi(cx, sig.abi); + fn_ty + } + + fn unadjusted(cx: &CodegenCx<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> Self { + debug!("FnType::unadjusted({:?}, {:?})", sig, extra_args); + + use self::Abi::*; + let conv = match cx.sess().target.target.adjust_abi(sig.abi) { + RustIntrinsic | PlatformIntrinsic | + Rust | RustCall => Conv::C, + + // It's the ABI's job to select this, not us. + System => bug!("system abi should be selected elsewhere"), + + Stdcall => Conv::X86Stdcall, + Fastcall => Conv::X86Fastcall, + Vectorcall => Conv::X86VectorCall, + Thiscall => Conv::X86ThisCall, + C => Conv::C, + Unadjusted => Conv::C, + Win64 => Conv::X86_64Win64, + SysV64 => Conv::X86_64SysV, + Aapcs => Conv::ArmAapcs, + PtxKernel => Conv::PtxKernel, + Msp430Interrupt => Conv::Msp430Intr, + X86Interrupt => Conv::X86Intr, + + // These API constants ought to be more specific... + Cdecl => Conv::C, + }; + + let mut inputs = sig.inputs(); + let extra_args = if sig.abi == RustCall { + assert!(!sig.variadic && extra_args.is_empty()); + + match sig.inputs().last().unwrap().sty { + ty::TyTuple(ref tupled_arguments) => { + inputs = &sig.inputs()[0..sig.inputs().len() - 1]; + tupled_arguments + } + _ => { + bug!("argument to function with \"rust-call\" ABI \ + is not a tuple"); + } + } + } else { + assert!(sig.variadic || extra_args.is_empty()); + extra_args + }; + + let target = &cx.sess().target.target; + let win_x64_gnu = target.target_os == "windows" + && target.arch == "x86_64" + && target.target_env == "gnu"; + let linux_s390x = target.target_os == "linux" + && target.arch == "s390x" + && target.target_env == "gnu"; + let rust_abi = match sig.abi { + RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true, + _ => false + }; + + // Handle safe Rust thin and fat pointers. + let adjust_for_rust_scalar = |attrs: &mut ArgAttributes, + scalar: &layout::Scalar, + layout: TyLayout<'tcx, Ty<'tcx>>, + offset: Size, + is_return: bool| { + // Booleans are always an i1 that needs to be zero-extended. + if scalar.is_bool() { + attrs.set(ArgAttribute::ZExt); + return; + } + + // Only pointer types handled below. + if scalar.value != layout::Pointer { + return; + } + + if scalar.valid_range.start() < scalar.valid_range.end() { + if *scalar.valid_range.start() > 0 { + attrs.set(ArgAttribute::NonNull); + } + } + + if let Some(pointee) = layout.pointee_info_at(cx, offset) { + if let Some(kind) = pointee.safe { + attrs.pointee_size = pointee.size; + attrs.pointee_align = Some(pointee.align); + + // HACK(eddyb) LLVM inserts `llvm.assume` calls when inlining functions + // with align attributes, and those calls later block optimizations. + if !is_return && !cx.tcx.sess.opts.debugging_opts.arg_align_attributes { + attrs.pointee_align = None; + } + + // `Box` pointer parameters never alias because ownership is transferred + // `&mut` pointer parameters never alias other parameters, + // or mutable global data + // + // `&T` where `T` contains no `UnsafeCell` is immutable, + // and can be marked as both `readonly` and `noalias`, as + // LLVM's definition of `noalias` is based solely on memory + // dependencies rather than pointer equality + let no_alias = match kind { + PointerKind::Shared => false, + PointerKind::UniqueOwned => true, + PointerKind::Frozen | + PointerKind::UniqueBorrowed => !is_return + }; + if no_alias { + attrs.set(ArgAttribute::NoAlias); + } + + if kind == PointerKind::Frozen && !is_return { + attrs.set(ArgAttribute::ReadOnly); + } + } + } + }; + + let arg_of = |ty: Ty<'tcx>, is_return: bool| { + let mut arg = ArgType::new(cx.layout_of(ty)); + if arg.layout.is_zst() { + // For some forsaken reason, x86_64-pc-windows-gnu + // doesn't ignore zero-sized struct arguments. + // The same is true for s390x-unknown-linux-gnu. + if is_return || rust_abi || (!win_x64_gnu && !linux_s390x) { + arg.mode = PassMode::Ignore; + } + } + + // FIXME(eddyb) other ABIs don't have logic for scalar pairs. + if !is_return && rust_abi { + if let layout::Abi::ScalarPair(ref a, ref b) = arg.layout.abi { + let mut a_attrs = ArgAttributes::new(); + let mut b_attrs = ArgAttributes::new(); + adjust_for_rust_scalar(&mut a_attrs, + a, + arg.layout, + Size::from_bytes(0), + false); + adjust_for_rust_scalar(&mut b_attrs, + b, + arg.layout, + a.value.size(cx).abi_align(b.value.align(cx)), + false); + arg.mode = PassMode::Pair(a_attrs, b_attrs); + return arg; + } + } + + if let layout::Abi::Scalar(ref scalar) = arg.layout.abi { + if let PassMode::Direct(ref mut attrs) = arg.mode { + adjust_for_rust_scalar(attrs, + scalar, + arg.layout, + Size::from_bytes(0), + is_return); + } + } + + arg + }; + + FnType { + ret: arg_of(sig.output(), true), + args: inputs.iter().chain(extra_args.iter()).map(|ty| { + arg_of(ty, false) + }).collect(), + variadic: sig.variadic, + conv, + } + } + + fn adjust_for_abi(&mut self, + cx: &CodegenCx<'a, 'tcx>, + abi: Abi) { + if abi == Abi::Unadjusted { return } + + if abi == Abi::Rust || abi == Abi::RustCall || + abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { + let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| { + if arg.is_ignore() { return; } + + match arg.layout.abi { + layout::Abi::Aggregate { .. } => {} + + // This is a fun case! The gist of what this is doing is + // that we want callers and callees to always agree on the + // ABI of how they pass SIMD arguments. If we were to *not* + // make these arguments indirect then they'd be immediates + // in LLVM, which means that they'd used whatever the + // appropriate ABI is for the callee and the caller. That + // means, for example, if the caller doesn't have AVX + // enabled but the callee does, then passing an AVX argument + // across this boundary would cause corrupt data to show up. + // + // This problem is fixed by unconditionally passing SIMD + // arguments through memory between callers and callees + // which should get them all to agree on ABI regardless of + // target feature sets. Some more information about this + // issue can be found in #44367. + // + // Note that the platform intrinsic ABI is exempt here as + // that's how we connect up to LLVM and it's unstable + // anyway, we control all calls to it in libstd. + layout::Abi::Vector { .. } if abi != Abi::PlatformIntrinsic => { + arg.make_indirect(); + return + } + + _ => return + } + + let size = arg.layout.size; + if size > layout::Pointer.size(cx) { + arg.make_indirect(); + } else { + // We want to pass small aggregates as immediates, but using + // a LLVM aggregate type for this leads to bad optimizations, + // so we pick an appropriately sized integer type instead. + arg.cast_to(Reg { + kind: RegKind::Integer, + size + }); + } + }; + fixup(&mut self.ret); + for arg in &mut self.args { + fixup(arg); + } + if let PassMode::Indirect(ref mut attrs) = self.ret.mode { + attrs.set(ArgAttribute::StructRet); + } + return; + } + + if let Err(msg) = self.adjust_for_cabi(cx, abi) { + cx.sess().fatal(&msg); + } + } + + fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { + let mut llargument_tys = Vec::new(); + + let llreturn_ty = match self.ret.mode { + PassMode::Ignore => Type::void(cx), + PassMode::Direct(_) | PassMode::Pair(..) => { + self.ret.layout.immediate_llvm_type(cx) + } + PassMode::Cast(cast) => cast.llvm_type(cx), + PassMode::Indirect(_) => { + llargument_tys.push(self.ret.memory_ty(cx).ptr_to()); + Type::void(cx) + } + }; + + for arg in &self.args { + // add padding + if let Some(ty) = arg.pad { + llargument_tys.push(ty.llvm_type(cx)); + } + + let llarg_ty = match arg.mode { + PassMode::Ignore => continue, + PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx), + PassMode::Pair(..) => { + llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0)); + llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1)); + continue; + } + PassMode::Cast(cast) => cast.llvm_type(cx), + PassMode::Indirect(_) => arg.memory_ty(cx).ptr_to(), + }; + llargument_tys.push(llarg_ty); + } + + if self.variadic { + Type::variadic_func(&llargument_tys, &llreturn_ty) + } else { + Type::func(&llargument_tys, &llreturn_ty) + } + } + + fn llvm_cconv(&self) -> llvm::CallConv { + match self.conv { + Conv::C => llvm::CCallConv, + Conv::ArmAapcs => llvm::ArmAapcsCallConv, + Conv::Msp430Intr => llvm::Msp430Intr, + Conv::PtxKernel => llvm::PtxKernel, + Conv::X86Fastcall => llvm::X86FastcallCallConv, + Conv::X86Intr => llvm::X86_Intr, + Conv::X86Stdcall => llvm::X86StdcallCallConv, + Conv::X86ThisCall => llvm::X86_ThisCall, + Conv::X86VectorCall => llvm::X86_VectorCall, + Conv::X86_64SysV => llvm::X86_64_SysV, + Conv::X86_64Win64 => llvm::X86_64_Win64, + } + } + + fn apply_attrs_llfn(&self, llfn: ValueRef) { + let mut i = 0; + let mut apply = |attrs: &ArgAttributes| { + attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn); + i += 1; + }; + match self.ret.mode { + PassMode::Direct(ref attrs) => { + attrs.apply_llfn(llvm::AttributePlace::ReturnValue, llfn); + } + PassMode::Indirect(ref attrs) => apply(attrs), + _ => {} + } + for arg in &self.args { + if arg.pad.is_some() { + apply(&ArgAttributes::new()); + } + match arg.mode { + PassMode::Ignore => {} + PassMode::Direct(ref attrs) | + PassMode::Indirect(ref attrs) => apply(attrs), + PassMode::Pair(ref a, ref b) => { + apply(a); + apply(b); + } + PassMode::Cast(_) => apply(&ArgAttributes::new()), + } + } + } + + fn apply_attrs_callsite(&self, bx: &Builder<'a, 'tcx>, callsite: ValueRef) { + let mut i = 0; + let mut apply = |attrs: &ArgAttributes| { + attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite); + i += 1; + }; + match self.ret.mode { + PassMode::Direct(ref attrs) => { + attrs.apply_callsite(llvm::AttributePlace::ReturnValue, callsite); + } + PassMode::Indirect(ref attrs) => apply(attrs), + _ => {} + } + if let layout::Abi::Scalar(ref scalar) = self.ret.layout.abi { + // If the value is a boolean, the range is 0..2 and that ultimately + // become 0..0 when the type becomes i1, which would be rejected + // by the LLVM verifier. + match scalar.value { + layout::Int(..) if !scalar.is_bool() => { + let range = scalar.valid_range_exclusive(bx.cx); + if range.start != range.end { + // FIXME(nox): This causes very weird type errors about + // SHL operators in constants in stage 2 with LLVM 3.9. + if unsafe { llvm::LLVMRustVersionMajor() >= 4 } { + bx.range_metadata(callsite, range); + } + } + } + _ => {} + } + } + for arg in &self.args { + if arg.pad.is_some() { + apply(&ArgAttributes::new()); + } + match arg.mode { + PassMode::Ignore => {} + PassMode::Direct(ref attrs) | + PassMode::Indirect(ref attrs) => apply(attrs), + PassMode::Pair(ref a, ref b) => { + apply(a); + apply(b); + } + PassMode::Cast(_) => apply(&ArgAttributes::new()), + } + } + + let cconv = self.llvm_cconv(); + if cconv != llvm::CCallConv { + llvm::SetInstructionCallConv(callsite, cconv); + } + } +} diff --git a/src/librustc_codegen_llvm/allocator.rs b/src/librustc_codegen_llvm/allocator.rs new file mode 100644 index 00000000000..eeb02e948f1 --- /dev/null +++ b/src/librustc_codegen_llvm/allocator.rs @@ -0,0 +1,103 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ffi::CString; +use std::ptr; + +use attributes; +use libc::c_uint; +use rustc::middle::allocator::AllocatorKind; +use rustc::ty::TyCtxt; +use rustc_allocator::{ALLOCATOR_METHODS, AllocatorTy}; + +use ModuleLlvm; +use llvm::{self, False, True}; + +pub(crate) unsafe fn codegen(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) { + let llcx = mods.llcx; + let llmod = mods.llmod; + let usize = match &tcx.sess.target.target.target_pointer_width[..] { + "16" => llvm::LLVMInt16TypeInContext(llcx), + "32" => llvm::LLVMInt32TypeInContext(llcx), + "64" => llvm::LLVMInt64TypeInContext(llcx), + tws => bug!("Unsupported target word size for int: {}", tws), + }; + let i8 = llvm::LLVMInt8TypeInContext(llcx); + let i8p = llvm::LLVMPointerType(i8, 0); + let void = llvm::LLVMVoidTypeInContext(llcx); + + for method in ALLOCATOR_METHODS { + let mut args = Vec::new(); + for ty in method.inputs.iter() { + match *ty { + AllocatorTy::Layout => { + args.push(usize); // size + args.push(usize); // align + } + AllocatorTy::Ptr => args.push(i8p), + AllocatorTy::Usize => args.push(usize), + + AllocatorTy::ResultPtr | + AllocatorTy::Unit => panic!("invalid allocator arg"), + } + } + let output = match method.output { + AllocatorTy::ResultPtr => Some(i8p), + AllocatorTy::Unit => None, + + AllocatorTy::Layout | + AllocatorTy::Usize | + AllocatorTy::Ptr => panic!("invalid allocator output"), + }; + let ty = llvm::LLVMFunctionType(output.unwrap_or(void), + args.as_ptr(), + args.len() as c_uint, + False); + let name = CString::new(format!("__rust_{}", method.name)).unwrap(); + let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, + name.as_ptr(), + ty); + + if tcx.sess.target.target.options.default_hidden_visibility { + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + } + if tcx.sess.target.target.options.requires_uwtable { + attributes::emit_uwtable(llfn, true); + } + + let callee = CString::new(kind.fn_name(method.name)).unwrap(); + let callee = llvm::LLVMRustGetOrInsertFunction(llmod, + callee.as_ptr(), + ty); + + let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, + llfn, + "entry\0".as_ptr() as *const _); + + let llbuilder = llvm::LLVMCreateBuilderInContext(llcx); + llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb); + let args = args.iter().enumerate().map(|(i, _)| { + llvm::LLVMGetParam(llfn, i as c_uint) + }).collect::>(); + let ret = llvm::LLVMRustBuildCall(llbuilder, + callee, + args.as_ptr(), + args.len() as c_uint, + ptr::null_mut(), + "\0".as_ptr() as *const _); + llvm::LLVMSetTailCall(ret, True); + if output.is_some() { + llvm::LLVMBuildRet(llbuilder, ret); + } else { + llvm::LLVMBuildRetVoid(llbuilder); + } + llvm::LLVMDisposeBuilder(llbuilder); + } +} diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs new file mode 100644 index 00000000000..82f068106ff --- /dev/null +++ b/src/librustc_codegen_llvm/asm.rs @@ -0,0 +1,127 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use llvm::{self, ValueRef}; +use common::*; +use type_::Type; +use type_of::LayoutLlvmExt; +use builder::Builder; + +use rustc::hir; + +use mir::place::PlaceRef; +use mir::operand::OperandValue; + +use std::ffi::CString; +use syntax::ast::AsmDialect; +use libc::{c_uint, c_char}; + +// Take an inline assembly expression and splat it out via LLVM +pub fn codegen_inline_asm<'a, 'tcx>( + bx: &Builder<'a, 'tcx>, + ia: &hir::InlineAsm, + outputs: Vec>, + mut inputs: Vec +) { + let mut ext_constraints = vec![]; + let mut output_types = vec![]; + + // Prepare the output operands + let mut indirect_outputs = vec![]; + for (i, (out, place)) in ia.outputs.iter().zip(&outputs).enumerate() { + if out.is_rw { + inputs.push(place.load(bx).immediate()); + ext_constraints.push(i.to_string()); + } + if out.is_indirect { + indirect_outputs.push(place.load(bx).immediate()); + } else { + output_types.push(place.layout.llvm_type(bx.cx)); + } + } + if !indirect_outputs.is_empty() { + indirect_outputs.extend_from_slice(&inputs); + inputs = indirect_outputs; + } + + let clobbers = ia.clobbers.iter() + .map(|s| format!("~{{{}}}", &s)); + + // Default per-arch clobbers + // Basically what clang does + let arch_clobbers = match &bx.sess().target.target.arch[..] { + "x86" | "x86_64" => vec!["~{dirflag}", "~{fpsr}", "~{flags}"], + "mips" | "mips64" => vec!["~{$1}"], + _ => Vec::new() + }; + + let all_constraints = + ia.outputs.iter().map(|out| out.constraint.to_string()) + .chain(ia.inputs.iter().map(|s| s.to_string())) + .chain(ext_constraints) + .chain(clobbers) + .chain(arch_clobbers.iter().map(|s| s.to_string())) + .collect::>().join(","); + + debug!("Asm Constraints: {}", &all_constraints); + + // Depending on how many outputs we have, the return type is different + let num_outputs = output_types.len(); + let output_type = match num_outputs { + 0 => Type::void(bx.cx), + 1 => output_types[0], + _ => Type::struct_(bx.cx, &output_types, false) + }; + + let dialect = match ia.dialect { + AsmDialect::Att => llvm::AsmDialect::Att, + AsmDialect::Intel => llvm::AsmDialect::Intel, + }; + + let asm = CString::new(ia.asm.as_str().as_bytes()).unwrap(); + let constraint_cstr = CString::new(all_constraints).unwrap(); + let r = bx.inline_asm_call( + asm.as_ptr(), + constraint_cstr.as_ptr(), + &inputs, + output_type, + ia.volatile, + ia.alignstack, + dialect + ); + + // Again, based on how many outputs we have + let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect); + for (i, (_, &place)) in outputs.enumerate() { + let v = if num_outputs == 1 { r } else { bx.extract_value(r, i as u64) }; + OperandValue::Immediate(v).store(bx, place); + } + + // Store mark in a metadata node so we can map LLVM errors + // back to source locations. See #17552. + unsafe { + let key = "srcloc"; + let kind = llvm::LLVMGetMDKindIDInContext(bx.cx.llcx, + key.as_ptr() as *const c_char, key.len() as c_uint); + + let val: llvm::ValueRef = C_i32(bx.cx, ia.ctxt.outer().as_u32() as i32); + + llvm::LLVMSetMetadata(r, kind, + llvm::LLVMMDNodeInContext(bx.cx.llcx, &val, 1)); + } +} + +pub fn codegen_global_asm<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + ga: &hir::GlobalAsm) { + let asm = CString::new(ga.asm.as_str().as_bytes()).unwrap(); + unsafe { + llvm::LLVMRustAppendModuleInlineAsm(cx.llmod, asm.as_ptr()); + } +} diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs new file mode 100644 index 00000000000..b64e102ba78 --- /dev/null +++ b/src/librustc_codegen_llvm/attributes.rs @@ -0,0 +1,259 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! Set and unset common attributes on LLVM values. + +use std::ffi::{CStr, CString}; + +use rustc::hir::{self, CodegenFnAttrFlags}; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::session::Session; +use rustc::session::config::Sanitizer; +use rustc::ty::TyCtxt; +use rustc::ty::maps::Providers; +use rustc_data_structures::sync::Lrc; +use rustc_data_structures::fx::FxHashMap; + +use llvm::{self, Attribute, ValueRef}; +use llvm::AttributePlace::Function; +use llvm_util; +pub use syntax::attr::{self, InlineAttr}; +use context::CodegenCx; + +/// Mark LLVM function to use provided inline heuristic. +#[inline] +pub fn inline(val: ValueRef, inline: InlineAttr) { + use self::InlineAttr::*; + match inline { + Hint => Attribute::InlineHint.apply_llfn(Function, val), + Always => Attribute::AlwaysInline.apply_llfn(Function, val), + Never => Attribute::NoInline.apply_llfn(Function, val), + None => { + Attribute::InlineHint.unapply_llfn(Function, val); + Attribute::AlwaysInline.unapply_llfn(Function, val); + Attribute::NoInline.unapply_llfn(Function, val); + }, + }; +} + +/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function. +#[inline] +pub fn emit_uwtable(val: ValueRef, emit: bool) { + Attribute::UWTable.toggle_llfn(Function, val, emit); +} + +/// Tell LLVM whether the function can or cannot unwind. +#[inline] +pub fn unwind(val: ValueRef, can_unwind: bool) { + Attribute::NoUnwind.toggle_llfn(Function, val, !can_unwind); +} + +/// Tell LLVM whether it should optimize function for size. +#[inline] +#[allow(dead_code)] // possibly useful function +pub fn set_optimize_for_size(val: ValueRef, optimize: bool) { + Attribute::OptimizeForSize.toggle_llfn(Function, val, optimize); +} + +/// Tell LLVM if this function should be 'naked', i.e. skip the epilogue and prologue. +#[inline] +pub fn naked(val: ValueRef, is_naked: bool) { + Attribute::Naked.toggle_llfn(Function, val, is_naked); +} + +pub fn set_frame_pointer_elimination(cx: &CodegenCx, llfn: ValueRef) { + if cx.sess().must_not_eliminate_frame_pointers() { + llvm::AddFunctionAttrStringValue( + llfn, llvm::AttributePlace::Function, + cstr("no-frame-pointer-elim\0"), cstr("true\0")); + } +} + +pub fn set_probestack(cx: &CodegenCx, llfn: ValueRef) { + // Only use stack probes if the target specification indicates that we + // should be using stack probes + if !cx.sess().target.target.options.stack_probes { + return + } + + // Currently stack probes seem somewhat incompatible with the address + // sanitizer. With asan we're already protected from stack overflow anyway + // so we don't really need stack probes regardless. + match cx.sess().opts.debugging_opts.sanitizer { + Some(Sanitizer::Address) => return, + _ => {} + } + + // probestack doesn't play nice either with pgo-gen. + if cx.sess().opts.debugging_opts.pgo_gen.is_some() { + return; + } + + // Flag our internal `__rust_probestack` function as the stack probe symbol. + // This is defined in the `compiler-builtins` crate for each architecture. + llvm::AddFunctionAttrStringValue( + llfn, llvm::AttributePlace::Function, + cstr("probe-stack\0"), cstr("__rust_probestack\0")); +} + +pub fn llvm_target_features(sess: &Session) -> impl Iterator { + const RUSTC_SPECIFIC_FEATURES: &[&str] = &[ + "crt-static", + ]; + + let cmdline = sess.opts.cg.target_feature.split(',') + .filter(|f| !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s))); + sess.target.target.options.features.split(',') + .chain(cmdline) + .filter(|l| !l.is_empty()) +} + +/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute]) +/// attributes. +pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) { + let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(id); + + inline(llfn, codegen_fn_attrs.inline); + + set_frame_pointer_elimination(cx, llfn); + set_probestack(cx, llfn); + + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) { + Attribute::Cold.apply_llfn(Function, llfn); + } + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { + naked(llfn, true); + } + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) { + Attribute::NoAlias.apply_llfn( + llvm::AttributePlace::ReturnValue, llfn); + } + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::UNWIND) { + unwind(llfn, true); + } + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) { + unwind(llfn, false); + } + + let features = llvm_target_features(cx.tcx.sess) + .map(|s| s.to_string()) + .chain( + codegen_fn_attrs.target_features + .iter() + .map(|f| { + let feature = &*f.as_str(); + format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature)) + }) + ) + .collect::>() + .join(","); + + if !features.is_empty() { + let val = CString::new(features).unwrap(); + llvm::AddFunctionAttrStringValue( + llfn, llvm::AttributePlace::Function, + cstr("target-features\0"), &val); + } + + // Note that currently the `wasm-import-module` doesn't do anything, but + // eventually LLVM 7 should read this and ferry the appropriate import + // module to the output file. + if cx.tcx.sess.target.target.arch == "wasm32" { + if let Some(module) = wasm_import_module(cx.tcx, id) { + llvm::AddFunctionAttrStringValue( + llfn, + llvm::AttributePlace::Function, + cstr("wasm-import-module\0"), + &module, + ); + } + } +} + +fn cstr(s: &'static str) -> &CStr { + CStr::from_bytes_with_nul(s.as_bytes()).expect("null-terminated string") +} + +pub fn provide(providers: &mut Providers) { + providers.target_features_whitelist = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + if tcx.sess.opts.actually_rustdoc { + // rustdoc needs to be able to document functions that use all the features, so + // whitelist them all + Lrc::new(llvm_util::all_known_features() + .map(|(a, b)| (a.to_string(), b.map(|s| s.to_string()))) + .collect()) + } else { + Lrc::new(llvm_util::target_feature_whitelist(tcx.sess) + .iter() + .map(|&(a, b)| (a.to_string(), b.map(|s| s.to_string()))) + .collect()) + } + }; + + providers.wasm_custom_sections = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + let mut finder = WasmSectionFinder { tcx, list: Vec::new() }; + tcx.hir.krate().visit_all_item_likes(&mut finder); + Lrc::new(finder.list) + }; + + provide_extern(providers); +} + +struct WasmSectionFinder<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + list: Vec, +} + +impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for WasmSectionFinder<'a, 'tcx> { + fn visit_item(&mut self, i: &'tcx hir::Item) { + match i.node { + hir::ItemConst(..) => {} + _ => return, + } + if i.attrs.iter().any(|i| i.check_name("wasm_custom_section")) { + self.list.push(self.tcx.hir.local_def_id(i.id)); + } + } + + fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) {} + + fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {} +} + +pub fn provide_extern(providers: &mut Providers) { + providers.wasm_import_module_map = |tcx, cnum| { + let mut ret = FxHashMap(); + for lib in tcx.foreign_modules(cnum).iter() { + let attrs = tcx.get_attrs(lib.def_id); + let mut module = None; + for attr in attrs.iter().filter(|a| a.check_name("wasm_import_module")) { + module = attr.value_str(); + } + let module = match module { + Some(s) => s, + None => continue, + }; + for id in lib.foreign_items.iter() { + assert_eq!(id.krate, cnum); + ret.insert(*id, module.to_string()); + } + } + + Lrc::new(ret) + } +} + +fn wasm_import_module(tcx: TyCtxt, id: DefId) -> Option { + tcx.wasm_import_module_map(id.krate) + .get(&id) + .map(|s| CString::new(&s[..]).unwrap()) +} diff --git a/src/librustc_codegen_llvm/back/archive.rs b/src/librustc_codegen_llvm/back/archive.rs new file mode 100644 index 00000000000..609629bffb9 --- /dev/null +++ b/src/librustc_codegen_llvm/back/archive.rs @@ -0,0 +1,325 @@ +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A helper class for dealing with static archives + +use std::ffi::{CString, CStr}; +use std::io; +use std::mem; +use std::path::{Path, PathBuf}; +use std::ptr; +use std::str; + +use back::bytecode::RLIB_BYTECODE_EXTENSION; +use libc; +use llvm::archive_ro::{ArchiveRO, Child}; +use llvm::{self, ArchiveKind}; +use metadata::METADATA_FILENAME; +use rustc::session::Session; + +pub struct ArchiveConfig<'a> { + pub sess: &'a Session, + pub dst: PathBuf, + pub src: Option, + pub lib_search_paths: Vec, +} + +/// Helper for adding many files to an archive. +#[must_use = "must call build() to finish building the archive"] +pub struct ArchiveBuilder<'a> { + config: ArchiveConfig<'a>, + removals: Vec, + additions: Vec, + should_update_symbols: bool, + src_archive: Option>, +} + +enum Addition { + File { + path: PathBuf, + name_in_archive: String, + }, + Archive { + archive: ArchiveRO, + skip: Box bool>, + }, +} + +pub fn find_library(name: &str, search_paths: &[PathBuf], sess: &Session) + -> PathBuf { + // On Windows, static libraries sometimes show up as libfoo.a and other + // times show up as foo.lib + let oslibname = format!("{}{}{}", + sess.target.target.options.staticlib_prefix, + name, + sess.target.target.options.staticlib_suffix); + let unixlibname = format!("lib{}.a", name); + + for path in search_paths { + debug!("looking for {} inside {:?}", name, path); + let test = path.join(&oslibname); + if test.exists() { return test } + if oslibname != unixlibname { + let test = path.join(&unixlibname); + if test.exists() { return test } + } + } + sess.fatal(&format!("could not find native static library `{}`, \ + perhaps an -L flag is missing?", name)); +} + +fn is_relevant_child(c: &Child) -> bool { + match c.name() { + Some(name) => !name.contains("SYMDEF"), + None => false, + } +} + +impl<'a> ArchiveBuilder<'a> { + /// Create a new static archive, ready for modifying the archive specified + /// by `config`. + pub fn new(config: ArchiveConfig<'a>) -> ArchiveBuilder<'a> { + ArchiveBuilder { + config, + removals: Vec::new(), + additions: Vec::new(), + should_update_symbols: false, + src_archive: None, + } + } + + /// Removes a file from this archive + pub fn remove_file(&mut self, file: &str) { + self.removals.push(file.to_string()); + } + + /// Lists all files in an archive + pub fn src_files(&mut self) -> Vec { + if self.src_archive().is_none() { + return Vec::new() + } + let archive = self.src_archive.as_ref().unwrap().as_ref().unwrap(); + let ret = archive.iter() + .filter_map(|child| child.ok()) + .filter(is_relevant_child) + .filter_map(|child| child.name()) + .filter(|name| !self.removals.iter().any(|x| x == name)) + .map(|name| name.to_string()) + .collect(); + return ret; + } + + fn src_archive(&mut self) -> Option<&ArchiveRO> { + if let Some(ref a) = self.src_archive { + return a.as_ref() + } + let src = self.config.src.as_ref()?; + self.src_archive = Some(ArchiveRO::open(src).ok()); + self.src_archive.as_ref().unwrap().as_ref() + } + + /// Adds all of the contents of a native library to this archive. This will + /// search in the relevant locations for a library named `name`. + pub fn add_native_library(&mut self, name: &str) { + let location = find_library(name, &self.config.lib_search_paths, + self.config.sess); + self.add_archive(&location, |_| false).unwrap_or_else(|e| { + self.config.sess.fatal(&format!("failed to add native library {}: {}", + location.to_string_lossy(), e)); + }); + } + + /// Adds all of the contents of the rlib at the specified path to this + /// archive. + /// + /// This ignores adding the bytecode from the rlib, and if LTO is enabled + /// then the object file also isn't added. + pub fn add_rlib(&mut self, + rlib: &Path, + name: &str, + lto: bool, + skip_objects: bool) -> io::Result<()> { + // Ignoring obj file starting with the crate name + // as simple comparison is not enough - there + // might be also an extra name suffix + let obj_start = format!("{}", name); + + self.add_archive(rlib, move |fname: &str| { + // Ignore bytecode/metadata files, no matter the name. + if fname.ends_with(RLIB_BYTECODE_EXTENSION) || fname == METADATA_FILENAME { + return true + } + + // Don't include Rust objects if LTO is enabled + if lto && fname.starts_with(&obj_start) && fname.ends_with(".o") { + return true + } + + // Otherwise if this is *not* a rust object and we're skipping + // objects then skip this file + if skip_objects && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) { + return true + } + + // ok, don't skip this + return false + }) + } + + fn add_archive(&mut self, archive: &Path, skip: F) + -> io::Result<()> + where F: FnMut(&str) -> bool + 'static + { + let archive = match ArchiveRO::open(archive) { + Ok(ar) => ar, + Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)), + }; + self.additions.push(Addition::Archive { + archive, + skip: Box::new(skip), + }); + Ok(()) + } + + /// Adds an arbitrary file to this archive + pub fn add_file(&mut self, file: &Path) { + let name = file.file_name().unwrap().to_str().unwrap(); + self.additions.push(Addition::File { + path: file.to_path_buf(), + name_in_archive: name.to_string(), + }); + } + + /// Indicate that the next call to `build` should update all symbols in + /// the archive (equivalent to running 'ar s' over it). + pub fn update_symbols(&mut self) { + self.should_update_symbols = true; + } + + /// Combine the provided files, rlibs, and native libraries into a single + /// `Archive`. + pub fn build(&mut self) { + let kind = match self.llvm_archive_kind() { + Ok(kind) => kind, + Err(kind) => { + self.config.sess.fatal(&format!("Don't know how to build archive of type: {}", + kind)); + } + }; + + if let Err(e) = self.build_with_llvm(kind) { + self.config.sess.fatal(&format!("failed to build archive: {}", e)); + } + + } + + fn llvm_archive_kind(&self) -> Result { + let kind = &*self.config.sess.target.target.options.archive_format; + kind.parse().map_err(|_| kind) + } + + fn build_with_llvm(&mut self, kind: ArchiveKind) -> io::Result<()> { + let mut archives = Vec::new(); + let mut strings = Vec::new(); + let mut members = Vec::new(); + let removals = mem::replace(&mut self.removals, Vec::new()); + + unsafe { + if let Some(archive) = self.src_archive() { + for child in archive.iter() { + let child = child.map_err(string_to_io_error)?; + let child_name = match child.name() { + Some(s) => s, + None => continue, + }; + if removals.iter().any(|r| r == child_name) { + continue + } + + let name = CString::new(child_name)?; + members.push(llvm::LLVMRustArchiveMemberNew(ptr::null(), + name.as_ptr(), + child.raw())); + strings.push(name); + } + } + for addition in mem::replace(&mut self.additions, Vec::new()) { + match addition { + Addition::File { path, name_in_archive } => { + let path = CString::new(path.to_str().unwrap())?; + let name = CString::new(name_in_archive)?; + members.push(llvm::LLVMRustArchiveMemberNew(path.as_ptr(), + name.as_ptr(), + ptr::null_mut())); + strings.push(path); + strings.push(name); + } + Addition::Archive { archive, mut skip } => { + for child in archive.iter() { + let child = child.map_err(string_to_io_error)?; + if !is_relevant_child(&child) { + continue + } + let child_name = child.name().unwrap(); + if skip(child_name) { + continue + } + + // It appears that LLVM's archive writer is a little + // buggy if the name we pass down isn't just the + // filename component, so chop that off here and + // pass it in. + // + // See LLVM bug 25877 for more info. + let child_name = Path::new(child_name) + .file_name().unwrap() + .to_str().unwrap(); + let name = CString::new(child_name)?; + let m = llvm::LLVMRustArchiveMemberNew(ptr::null(), + name.as_ptr(), + child.raw()); + members.push(m); + strings.push(name); + } + archives.push(archive); + } + } + } + + let dst = self.config.dst.to_str().unwrap().as_bytes(); + let dst = CString::new(dst)?; + let r = llvm::LLVMRustWriteArchive(dst.as_ptr(), + members.len() as libc::size_t, + members.as_ptr(), + self.should_update_symbols, + kind); + let ret = if r.into_result().is_err() { + let err = llvm::LLVMRustGetLastError(); + let msg = if err.is_null() { + "failed to write archive".to_string() + } else { + String::from_utf8_lossy(CStr::from_ptr(err).to_bytes()) + .into_owned() + }; + Err(io::Error::new(io::ErrorKind::Other, msg)) + } else { + Ok(()) + }; + for member in members { + llvm::LLVMRustArchiveMemberFree(member); + } + return ret + } + } +} + +fn string_to_io_error(s: String) -> io::Error { + io::Error::new(io::ErrorKind::Other, format!("bad archive: {}", s)) +} diff --git a/src/librustc_codegen_llvm/back/bytecode.rs b/src/librustc_codegen_llvm/back/bytecode.rs new file mode 100644 index 00000000000..212d1aaf055 --- /dev/null +++ b/src/librustc_codegen_llvm/back/bytecode.rs @@ -0,0 +1,160 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Management of the encoding of LLVM bytecode into rlibs +//! +//! This module contains the management of encoding LLVM bytecode into rlibs, +//! primarily for the usage in LTO situations. Currently the compiler will +//! unconditionally encode LLVM-IR into rlibs regardless of what's happening +//! elsewhere, so we currently compress the bytecode via deflate to avoid taking +//! up too much space on disk. +//! +//! After compressing the bytecode we then have the rest of the format to +//! basically deal with various bugs in various archive implementations. The +//! format currently is: +//! +//! RLIB LLVM-BYTECODE OBJECT LAYOUT +//! Version 2 +//! Bytes Data +//! 0..10 "RUST_OBJECT" encoded in ASCII +//! 11..14 format version as little-endian u32 +//! 15..19 the length of the module identifier string +//! 20..n the module identifier string +//! n..n+8 size in bytes of deflate compressed LLVM bitcode as +//! little-endian u64 +//! n+9.. compressed LLVM bitcode +//! ? maybe a byte to make this whole thing even length + +use std::io::{Read, Write}; +use std::ptr; +use std::str; + +use flate2::Compression; +use flate2::read::DeflateDecoder; +use flate2::write::DeflateEncoder; + +// This is the "magic number" expected at the beginning of a LLVM bytecode +// object in an rlib. +pub const RLIB_BYTECODE_OBJECT_MAGIC: &'static [u8] = b"RUST_OBJECT"; + +// The version number this compiler will write to bytecode objects in rlibs +pub const RLIB_BYTECODE_OBJECT_VERSION: u8 = 2; + +pub const RLIB_BYTECODE_EXTENSION: &str = "bc.z"; + +pub fn encode(identifier: &str, bytecode: &[u8]) -> Vec { + let mut encoded = Vec::new(); + + // Start off with the magic string + encoded.extend_from_slice(RLIB_BYTECODE_OBJECT_MAGIC); + + // Next up is the version + encoded.extend_from_slice(&[RLIB_BYTECODE_OBJECT_VERSION, 0, 0, 0]); + + // Next is the LLVM module identifier length + contents + let identifier_len = identifier.len(); + encoded.extend_from_slice(&[ + (identifier_len >> 0) as u8, + (identifier_len >> 8) as u8, + (identifier_len >> 16) as u8, + (identifier_len >> 24) as u8, + ]); + encoded.extend_from_slice(identifier.as_bytes()); + + // Next is the LLVM module deflate compressed, prefixed with its length. We + // don't know its length yet, so fill in 0s + let deflated_size_pos = encoded.len(); + encoded.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]); + + let before = encoded.len(); + DeflateEncoder::new(&mut encoded, Compression::fast()) + .write_all(bytecode) + .unwrap(); + let after = encoded.len(); + + // Fill in the length we reserved space for before + let bytecode_len = (after - before) as u64; + encoded[deflated_size_pos + 0] = (bytecode_len >> 0) as u8; + encoded[deflated_size_pos + 1] = (bytecode_len >> 8) as u8; + encoded[deflated_size_pos + 2] = (bytecode_len >> 16) as u8; + encoded[deflated_size_pos + 3] = (bytecode_len >> 24) as u8; + encoded[deflated_size_pos + 4] = (bytecode_len >> 32) as u8; + encoded[deflated_size_pos + 5] = (bytecode_len >> 40) as u8; + encoded[deflated_size_pos + 6] = (bytecode_len >> 48) as u8; + encoded[deflated_size_pos + 7] = (bytecode_len >> 56) as u8; + + // If the number of bytes written to the object so far is odd, add a + // padding byte to make it even. This works around a crash bug in LLDB + // (see issue #15950) + if encoded.len() % 2 == 1 { + encoded.push(0); + } + + return encoded +} + +pub struct DecodedBytecode<'a> { + identifier: &'a str, + encoded_bytecode: &'a [u8], +} + +impl<'a> DecodedBytecode<'a> { + pub fn new(data: &'a [u8]) -> Result, String> { + if !data.starts_with(RLIB_BYTECODE_OBJECT_MAGIC) { + return Err(format!("magic bytecode prefix not found")) + } + let data = &data[RLIB_BYTECODE_OBJECT_MAGIC.len()..]; + if !data.starts_with(&[RLIB_BYTECODE_OBJECT_VERSION, 0, 0, 0]) { + return Err(format!("wrong version prefix found in bytecode")) + } + let data = &data[4..]; + if data.len() < 4 { + return Err(format!("bytecode corrupted")) + } + let identifier_len = unsafe { + u32::from_le(ptr::read_unaligned(data.as_ptr() as *const u32)) as usize + }; + let data = &data[4..]; + if data.len() < identifier_len { + return Err(format!("bytecode corrupted")) + } + let identifier = match str::from_utf8(&data[..identifier_len]) { + Ok(s) => s, + Err(_) => return Err(format!("bytecode corrupted")) + }; + let data = &data[identifier_len..]; + if data.len() < 8 { + return Err(format!("bytecode corrupted")) + } + let bytecode_len = unsafe { + u64::from_le(ptr::read_unaligned(data.as_ptr() as *const u64)) as usize + }; + let data = &data[8..]; + if data.len() < bytecode_len { + return Err(format!("bytecode corrupted")) + } + let encoded_bytecode = &data[..bytecode_len]; + + Ok(DecodedBytecode { + identifier, + encoded_bytecode, + }) + } + + pub fn bytecode(&self) -> Vec { + let mut data = Vec::new(); + DeflateDecoder::new(self.encoded_bytecode).read_to_end(&mut data).unwrap(); + return data + } + + pub fn identifier(&self) -> &'a str { + self.identifier + } +} diff --git a/src/librustc_codegen_llvm/back/command.rs b/src/librustc_codegen_llvm/back/command.rs new file mode 100644 index 00000000000..9ebbdd7c3c9 --- /dev/null +++ b/src/librustc_codegen_llvm/back/command.rs @@ -0,0 +1,175 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A thin wrapper around `Command` in the standard library which allows us to +//! read the arguments that are built up. + +use std::ffi::{OsStr, OsString}; +use std::fmt; +use std::io; +use std::mem; +use std::process::{self, Output}; + +use rustc_target::spec::LldFlavor; + +#[derive(Clone)] +pub struct Command { + program: Program, + args: Vec, + env: Vec<(OsString, OsString)>, +} + +#[derive(Clone)] +enum Program { + Normal(OsString), + CmdBatScript(OsString), + Lld(OsString, LldFlavor) +} + +impl Command { + pub fn new>(program: P) -> Command { + Command::_new(Program::Normal(program.as_ref().to_owned())) + } + + pub fn bat_script>(program: P) -> Command { + Command::_new(Program::CmdBatScript(program.as_ref().to_owned())) + } + + pub fn lld>(program: P, flavor: LldFlavor) -> Command { + Command::_new(Program::Lld(program.as_ref().to_owned(), flavor)) + } + + fn _new(program: Program) -> Command { + Command { + program, + args: Vec::new(), + env: Vec::new(), + } + } + + pub fn arg>(&mut self, arg: P) -> &mut Command { + self._arg(arg.as_ref()); + self + } + + pub fn args(&mut self, args: I) -> &mut Command + where I: IntoIterator, + I::Item: AsRef, + { + for arg in args { + self._arg(arg.as_ref()); + } + self + } + + fn _arg(&mut self, arg: &OsStr) { + self.args.push(arg.to_owned()); + } + + pub fn env(&mut self, key: K, value: V) -> &mut Command + where K: AsRef, + V: AsRef + { + self._env(key.as_ref(), value.as_ref()); + self + } + + fn _env(&mut self, key: &OsStr, value: &OsStr) { + self.env.push((key.to_owned(), value.to_owned())); + } + + pub fn output(&mut self) -> io::Result { + self.command().output() + } + + pub fn command(&self) -> process::Command { + let mut ret = match self.program { + Program::Normal(ref p) => process::Command::new(p), + Program::CmdBatScript(ref p) => { + let mut c = process::Command::new("cmd"); + c.arg("/c").arg(p); + c + } + Program::Lld(ref p, flavor) => { + let mut c = process::Command::new(p); + c.arg("-flavor").arg(match flavor { + LldFlavor::Wasm => "wasm", + LldFlavor::Ld => "gnu", + LldFlavor::Link => "link", + LldFlavor::Ld64 => "darwin", + }); + c + } + }; + ret.args(&self.args); + ret.envs(self.env.clone()); + return ret + } + + // extensions + + pub fn get_args(&self) -> &[OsString] { + &self.args + } + + pub fn take_args(&mut self) -> Vec { + mem::replace(&mut self.args, Vec::new()) + } + + /// Returns a `true` if we're pretty sure that this'll blow OS spawn limits, + /// or `false` if we should attempt to spawn and see what the OS says. + pub fn very_likely_to_exceed_some_spawn_limit(&self) -> bool { + // We mostly only care about Windows in this method, on Unix the limits + // can be gargantuan anyway so we're pretty unlikely to hit them + if cfg!(unix) { + return false + } + + // Right now LLD doesn't support the `@` syntax of passing an argument + // through files, so regardless of the platform we try to go to the OS + // on this one. + if let Program::Lld(..) = self.program { + return false + } + + // Ok so on Windows to spawn a process is 32,768 characters in its + // command line [1]. Unfortunately we don't actually have access to that + // as it's calculated just before spawning. Instead we perform a + // poor-man's guess as to how long our command line will be. We're + // assuming here that we don't have to escape every character... + // + // Turns out though that `cmd.exe` has even smaller limits, 8192 + // characters [2]. Linkers can often be batch scripts (for example + // Emscripten, Gecko's current build system) which means that we're + // running through batch scripts. These linkers often just forward + // arguments elsewhere (and maybe tack on more), so if we blow 8192 + // bytes we'll typically cause them to blow as well. + // + // Basically as a result just perform an inflated estimate of what our + // command line will look like and test if it's > 8192 (we actually + // test against 6k to artificially inflate our estimate). If all else + // fails we'll fall back to the normal unix logic of testing the OS + // error code if we fail to spawn and automatically re-spawning the + // linker with smaller arguments. + // + // [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx + // [2]: https://blogs.msdn.microsoft.com/oldnewthing/20031210-00/?p=41553 + + let estimated_command_line_len = + self.args.iter().map(|a| a.len()).sum::(); + estimated_command_line_len > 1024 * 6 + } +} + +impl fmt::Debug for Command { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.command().fmt(f) + } +} diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs new file mode 100644 index 00000000000..dbfd430a3e2 --- /dev/null +++ b/src/librustc_codegen_llvm/back/link.rs @@ -0,0 +1,1630 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use back::wasm; +use cc::windows_registry; +use super::archive::{ArchiveBuilder, ArchiveConfig}; +use super::bytecode::RLIB_BYTECODE_EXTENSION; +use super::linker::Linker; +use super::command::Command; +use super::rpath::RPathConfig; +use super::rpath; +use metadata::METADATA_FILENAME; +use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType, PrintRequest}; +use rustc::session::config::{RUST_CGU_EXT, Lto}; +use rustc::session::filesearch; +use rustc::session::search_paths::PathKind; +use rustc::session::Session; +use rustc::middle::cstore::{NativeLibrary, LibSource, NativeLibraryKind}; +use rustc::middle::dependency_format::Linkage; +use {CodegenResults, CrateInfo}; +use rustc::util::common::time; +use rustc::util::fs::fix_windows_verbatim_for_gcc; +use rustc::hir::def_id::CrateNum; +use tempdir::TempDir; +use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor, TargetTriple}; +use rustc_data_structures::fx::FxHashSet; +use context::get_reloc_model; +use llvm; + +use std::ascii; +use std::char; +use std::env; +use std::fmt; +use std::fs; +use std::io; +use std::path::{Path, PathBuf}; +use std::process::{Output, Stdio}; +use std::str; +use syntax::attr; + +/// The LLVM module name containing crate-metadata. This includes a `.` on +/// purpose, so it cannot clash with the name of a user-defined module. +pub const METADATA_MODULE_NAME: &'static str = "crate.metadata"; + +// same as for metadata above, but for allocator shim +pub const ALLOCATOR_MODULE_NAME: &'static str = "crate.allocator"; + +pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default_output_for_target, + invalid_output_for_target, build_link_meta, out_filename, + check_file_is_writeable}; + +// The third parameter is for env vars, used on windows to set up the +// path for MSVC to find its DLLs, and gcc to find its bundled +// toolchain +pub fn get_linker(sess: &Session) -> (PathBuf, Command) { + // If our linker looks like a batch script on Windows then to execute this + // we'll need to spawn `cmd` explicitly. This is primarily done to handle + // emscripten where the linker is `emcc.bat` and needs to be spawned as + // `cmd /c emcc.bat ...`. + // + // This worked historically but is needed manually since #42436 (regression + // was tagged as #42791) and some more info can be found on #44443 for + // emscripten itself. + let cmd = |linker: &Path| { + if let Some(linker) = linker.to_str() { + if cfg!(windows) && linker.ends_with(".bat") { + return Command::bat_script(linker) + } + } + match sess.linker_flavor() { + LinkerFlavor::Lld(f) => Command::lld(linker, f), + _ => Command::new(linker), + + } + }; + + let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe"); + + let linker_path = sess.opts.cg.linker.as_ref().map(|s| &**s) + .or(sess.target.target.options.linker.as_ref().map(|s| s.as_ref())) + .unwrap_or(match sess.linker_flavor() { + LinkerFlavor::Msvc => { + msvc_tool.as_ref().map(|t| t.path()).unwrap_or("link.exe".as_ref()) + } + LinkerFlavor::Em if cfg!(windows) => "emcc.bat".as_ref(), + LinkerFlavor::Em => "emcc".as_ref(), + LinkerFlavor::Gcc => "cc".as_ref(), + LinkerFlavor::Ld => "ld".as_ref(), + LinkerFlavor::Lld(_) => "lld".as_ref(), + }); + + let mut cmd = cmd(linker_path); + + // The compiler's sysroot often has some bundled tools, so add it to the + // PATH for the child. + let mut new_path = sess.host_filesearch(PathKind::All) + .get_tools_search_paths(); + let mut msvc_changed_path = false; + if sess.target.target.options.is_like_msvc { + if let Some(ref tool) = msvc_tool { + cmd.args(tool.args()); + for &(ref k, ref v) in tool.env() { + if k == "PATH" { + new_path.extend(env::split_paths(v)); + msvc_changed_path = true; + } else { + cmd.env(k, v); + } + } + } + } + + if !msvc_changed_path { + if let Some(path) = env::var_os("PATH") { + new_path.extend(env::split_paths(&path)); + } + } + cmd.env("PATH", env::join_paths(new_path).unwrap()); + + (linker_path.to_path_buf(), cmd) +} + +pub fn remove(sess: &Session, path: &Path) { + match fs::remove_file(path) { + Ok(..) => {} + Err(e) => { + sess.err(&format!("failed to remove {}: {}", + path.display(), + e)); + } + } +} + +/// Perform the linkage portion of the compilation phase. This will generate all +/// of the requested outputs for this compilation session. +pub(crate) fn link_binary(sess: &Session, + codegen_results: &CodegenResults, + outputs: &OutputFilenames, + crate_name: &str) -> Vec { + let mut out_filenames = Vec::new(); + for &crate_type in sess.crate_types.borrow().iter() { + // Ignore executable crates if we have -Z no-codegen, as they will error. + let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); + if (sess.opts.debugging_opts.no_codegen || !sess.opts.output_types.should_codegen()) && + !output_metadata && + crate_type == config::CrateTypeExecutable { + continue; + } + + if invalid_output_for_target(sess, crate_type) { + bug!("invalid output type `{:?}` for target os `{}`", + crate_type, sess.opts.target_triple); + } + let mut out_files = link_binary_output(sess, + codegen_results, + crate_type, + outputs, + crate_name); + out_filenames.append(&mut out_files); + } + + // Remove the temporary object file and metadata if we aren't saving temps + if !sess.opts.cg.save_temps { + if sess.opts.output_types.should_codegen() && + !preserve_objects_for_their_debuginfo(sess) + { + for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { + remove(sess, obj); + } + } + for obj in codegen_results.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) { + remove(sess, obj); + } + if let Some(ref obj) = codegen_results.metadata_module.object { + remove(sess, obj); + } + if let Some(ref allocator) = codegen_results.allocator_module { + if let Some(ref obj) = allocator.object { + remove(sess, obj); + } + if let Some(ref bc) = allocator.bytecode_compressed { + remove(sess, bc); + } + } + } + + out_filenames +} + +/// Returns a boolean indicating whether we should preserve the object files on +/// the filesystem for their debug information. This is often useful with +/// split-dwarf like schemes. +fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool { + // If the objects don't have debuginfo there's nothing to preserve. + if sess.opts.debuginfo == NoDebugInfo { + return false + } + + // If we're only producing artifacts that are archives, no need to preserve + // the objects as they're losslessly contained inside the archives. + let output_linked = sess.crate_types.borrow() + .iter() + .any(|x| *x != config::CrateTypeRlib && *x != config::CrateTypeStaticlib); + if !output_linked { + return false + } + + // If we're on OSX then the equivalent of split dwarf is turned on by + // default. The final executable won't actually have any debug information + // except it'll have pointers to elsewhere. Historically we've always run + // `dsymutil` to "link all the dwarf together" but this is actually sort of + // a bummer for incremental compilation! (the whole point of split dwarf is + // that you don't do this sort of dwarf link). + // + // Basically as a result this just means that if we're on OSX and we're + // *not* running dsymutil then the object files are the only source of truth + // for debug information, so we must preserve them. + if sess.target.target.options.is_like_osx { + match sess.opts.debugging_opts.run_dsymutil { + // dsymutil is not being run, preserve objects + Some(false) => return true, + + // dsymutil is being run, no need to preserve the objects + Some(true) => return false, + + // The default historical behavior was to always run dsymutil, so + // we're preserving that temporarily, but we're likely to switch the + // default soon. + None => return false, + } + } + + false +} + +fn filename_for_metadata(sess: &Session, crate_name: &str, outputs: &OutputFilenames) -> PathBuf { + let out_filename = outputs.single_output_file.clone() + .unwrap_or(outputs + .out_directory + .join(&format!("lib{}{}.rmeta", crate_name, sess.opts.cg.extra_filename))); + check_file_is_writeable(&out_filename, sess); + out_filename +} + +pub(crate) fn each_linked_rlib(sess: &Session, + info: &CrateInfo, + f: &mut FnMut(CrateNum, &Path)) -> Result<(), String> { + let crates = info.used_crates_static.iter(); + let fmts = sess.dependency_formats.borrow(); + let fmts = fmts.get(&config::CrateTypeExecutable) + .or_else(|| fmts.get(&config::CrateTypeStaticlib)) + .or_else(|| fmts.get(&config::CrateTypeCdylib)) + .or_else(|| fmts.get(&config::CrateTypeProcMacro)); + let fmts = match fmts { + Some(f) => f, + None => return Err(format!("could not find formats for rlibs")) + }; + for &(cnum, ref path) in crates { + match fmts.get(cnum.as_usize() - 1) { + Some(&Linkage::NotLinked) | + Some(&Linkage::IncludedFromDylib) => continue, + Some(_) => {} + None => return Err(format!("could not find formats for rlibs")) + } + let name = &info.crate_name[&cnum]; + let path = match *path { + LibSource::Some(ref p) => p, + LibSource::MetadataOnly => { + return Err(format!("could not find rlib for: `{}`, found rmeta (metadata) file", + name)) + } + LibSource::None => { + return Err(format!("could not find rlib for: `{}`", name)) + } + }; + f(cnum, &path); + } + Ok(()) +} + +/// Returns a boolean indicating whether the specified crate should be ignored +/// during LTO. +/// +/// Crates ignored during LTO are not lumped together in the "massive object +/// file" that we create and are linked in their normal rlib states. See +/// comments below for what crates do not participate in LTO. +/// +/// It's unusual for a crate to not participate in LTO. Typically only +/// compiler-specific and unstable crates have a reason to not participate in +/// LTO. +pub(crate) fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool { + // If our target enables builtin function lowering in LLVM then the + // crates providing these functions don't participate in LTO (e.g. + // no_builtins or compiler builtins crates). + !sess.target.target.options.no_builtins && + (info.is_no_builtins.contains(&cnum) || info.compiler_builtins == Some(cnum)) +} + +fn link_binary_output(sess: &Session, + codegen_results: &CodegenResults, + crate_type: config::CrateType, + outputs: &OutputFilenames, + crate_name: &str) -> Vec { + for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { + check_file_is_writeable(obj, sess); + } + + let mut out_filenames = vec![]; + + if outputs.outputs.contains_key(&OutputType::Metadata) { + let out_filename = filename_for_metadata(sess, crate_name, outputs); + // To avoid races with another rustc process scanning the output directory, + // we need to write the file somewhere else and atomically move it to its + // final destination, with a `fs::rename` call. In order for the rename to + // always succeed, the temporary file needs to be on the same filesystem, + // which is why we create it inside the output directory specifically. + let metadata_tmpdir = match TempDir::new_in(out_filename.parent().unwrap(), "rmeta") { + Ok(tmpdir) => tmpdir, + Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)), + }; + let metadata = emit_metadata(sess, codegen_results, &metadata_tmpdir); + if let Err(e) = fs::rename(metadata, &out_filename) { + sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); + } + out_filenames.push(out_filename); + } + + let tmpdir = match TempDir::new("rustc") { + Ok(tmpdir) => tmpdir, + Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)), + }; + + if outputs.outputs.should_codegen() { + let out_filename = out_filename(sess, crate_type, outputs, crate_name); + match crate_type { + config::CrateTypeRlib => { + link_rlib(sess, + codegen_results, + RlibFlavor::Normal, + &out_filename, + &tmpdir).build(); + } + config::CrateTypeStaticlib => { + link_staticlib(sess, codegen_results, &out_filename, &tmpdir); + } + _ => { + link_natively(sess, crate_type, &out_filename, codegen_results, tmpdir.path()); + } + } + out_filenames.push(out_filename); + } + + if sess.opts.cg.save_temps { + let _ = tmpdir.into_path(); + } + + out_filenames +} + +fn archive_search_paths(sess: &Session) -> Vec { + let mut search = Vec::new(); + sess.target_filesearch(PathKind::Native).for_each_lib_search_path(|path, _| { + search.push(path.to_path_buf()); + }); + return search; +} + +fn archive_config<'a>(sess: &'a Session, + output: &Path, + input: Option<&Path>) -> ArchiveConfig<'a> { + ArchiveConfig { + sess, + dst: output.to_path_buf(), + src: input.map(|p| p.to_path_buf()), + lib_search_paths: archive_search_paths(sess), + } +} + +/// We use a temp directory here to avoid races between concurrent rustc processes, +/// such as builds in the same directory using the same filename for metadata while +/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a +/// directory being searched for `extern crate` (observing an incomplete file). +/// The returned path is the temporary file containing the complete metadata. +fn emit_metadata<'a>(sess: &'a Session, codegen_results: &CodegenResults, tmpdir: &TempDir) + -> PathBuf { + let out_filename = tmpdir.path().join(METADATA_FILENAME); + let result = fs::write(&out_filename, &codegen_results.metadata.raw_data); + + if let Err(e) = result { + sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); + } + + out_filename +} + +enum RlibFlavor { + Normal, + StaticlibBase, +} + +// Create an 'rlib' +// +// An rlib in its current incarnation is essentially a renamed .a file. The +// rlib primarily contains the object file of the crate, but it also contains +// all of the object files from native libraries. This is done by unzipping +// native libraries and inserting all of the contents into this archive. +fn link_rlib<'a>(sess: &'a Session, + codegen_results: &CodegenResults, + flavor: RlibFlavor, + out_filename: &Path, + tmpdir: &TempDir) -> ArchiveBuilder<'a> { + info!("preparing rlib to {:?}", out_filename); + let mut ab = ArchiveBuilder::new(archive_config(sess, out_filename, None)); + + for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { + ab.add_file(obj); + } + + // Note that in this loop we are ignoring the value of `lib.cfg`. That is, + // we may not be configured to actually include a static library if we're + // adding it here. That's because later when we consume this rlib we'll + // decide whether we actually needed the static library or not. + // + // To do this "correctly" we'd need to keep track of which libraries added + // which object files to the archive. We don't do that here, however. The + // #[link(cfg(..))] feature is unstable, though, and only intended to get + // liblibc working. In that sense the check below just indicates that if + // there are any libraries we want to omit object files for at link time we + // just exclude all custom object files. + // + // Eventually if we want to stabilize or flesh out the #[link(cfg(..))] + // feature then we'll need to figure out how to record what objects were + // loaded from the libraries found here and then encode that into the + // metadata of the rlib we're generating somehow. + for lib in codegen_results.crate_info.used_libraries.iter() { + match lib.kind { + NativeLibraryKind::NativeStatic => {} + NativeLibraryKind::NativeStaticNobundle | + NativeLibraryKind::NativeFramework | + NativeLibraryKind::NativeUnknown => continue, + } + ab.add_native_library(&lib.name.as_str()); + } + + // After adding all files to the archive, we need to update the + // symbol table of the archive. + ab.update_symbols(); + + // Note that it is important that we add all of our non-object "magical + // files" *after* all of the object files in the archive. The reason for + // this is as follows: + // + // * When performing LTO, this archive will be modified to remove + // objects from above. The reason for this is described below. + // + // * When the system linker looks at an archive, it will attempt to + // determine the architecture of the archive in order to see whether its + // linkable. + // + // The algorithm for this detection is: iterate over the files in the + // archive. Skip magical SYMDEF names. Interpret the first file as an + // object file. Read architecture from the object file. + // + // * As one can probably see, if "metadata" and "foo.bc" were placed + // before all of the objects, then the architecture of this archive would + // not be correctly inferred once 'foo.o' is removed. + // + // Basically, all this means is that this code should not move above the + // code above. + match flavor { + RlibFlavor::Normal => { + // Instead of putting the metadata in an object file section, rlibs + // contain the metadata in a separate file. + ab.add_file(&emit_metadata(sess, codegen_results, tmpdir)); + + // For LTO purposes, the bytecode of this library is also inserted + // into the archive. + for bytecode in codegen_results + .modules + .iter() + .filter_map(|m| m.bytecode_compressed.as_ref()) + { + ab.add_file(bytecode); + } + + // After adding all files to the archive, we need to update the + // symbol table of the archive. This currently dies on macOS (see + // #11162), and isn't necessary there anyway + if !sess.target.target.options.is_like_osx { + ab.update_symbols(); + } + } + + RlibFlavor::StaticlibBase => { + let obj = codegen_results.allocator_module + .as_ref() + .and_then(|m| m.object.as_ref()); + if let Some(obj) = obj { + ab.add_file(obj); + } + } + } + + ab +} + +// Create a static archive +// +// This is essentially the same thing as an rlib, but it also involves adding +// all of the upstream crates' objects into the archive. This will slurp in +// all of the native libraries of upstream dependencies as well. +// +// Additionally, there's no way for us to link dynamic libraries, so we warn +// about all dynamic library dependencies that they're not linked in. +// +// There's no need to include metadata in a static archive, so ensure to not +// link in the metadata object file (and also don't prepare the archive with a +// metadata file). +fn link_staticlib(sess: &Session, + codegen_results: &CodegenResults, + out_filename: &Path, + tempdir: &TempDir) { + let mut ab = link_rlib(sess, + codegen_results, + RlibFlavor::StaticlibBase, + out_filename, + tempdir); + let mut all_native_libs = vec![]; + + let res = each_linked_rlib(sess, &codegen_results.crate_info, &mut |cnum, path| { + let name = &codegen_results.crate_info.crate_name[&cnum]; + let native_libs = &codegen_results.crate_info.native_libraries[&cnum]; + + // Here when we include the rlib into our staticlib we need to make a + // decision whether to include the extra object files along the way. + // These extra object files come from statically included native + // libraries, but they may be cfg'd away with #[link(cfg(..))]. + // + // This unstable feature, though, only needs liblibc to work. The only + // use case there is where musl is statically included in liblibc.rlib, + // so if we don't want the included version we just need to skip it. As + // a result the logic here is that if *any* linked library is cfg'd away + // we just skip all object files. + // + // Clearly this is not sufficient for a general purpose feature, and + // we'd want to read from the library's metadata to determine which + // object files come from where and selectively skip them. + let skip_object_files = native_libs.iter().any(|lib| { + lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) + }); + ab.add_rlib(path, + &name.as_str(), + is_full_lto_enabled(sess) && + !ignored_for_lto(sess, &codegen_results.crate_info, cnum), + skip_object_files).unwrap(); + + all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned()); + }); + if let Err(e) = res { + sess.fatal(&e); + } + + ab.update_symbols(); + ab.build(); + + if !all_native_libs.is_empty() { + if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) { + print_native_static_libs(sess, &all_native_libs); + } + } +} + +fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) { + let lib_args: Vec<_> = all_native_libs.iter() + .filter(|l| relevant_lib(sess, l)) + .filter_map(|lib| match lib.kind { + NativeLibraryKind::NativeStaticNobundle | + NativeLibraryKind::NativeUnknown => { + if sess.target.target.options.is_like_msvc { + Some(format!("{}.lib", lib.name)) + } else { + Some(format!("-l{}", lib.name)) + } + }, + NativeLibraryKind::NativeFramework => { + // ld-only syntax, since there are no frameworks in MSVC + Some(format!("-framework {}", lib.name)) + }, + // These are included, no need to print them + NativeLibraryKind::NativeStatic => None, + }) + .collect(); + if !lib_args.is_empty() { + sess.note_without_error("Link against the following native artifacts when linking \ + against this static library. The order and any duplication \ + can be significant on some platforms."); + // Prefix for greppability + sess.note_without_error(&format!("native-static-libs: {}", &lib_args.join(" "))); + } +} + +// Create a dynamic library or executable +// +// This will invoke the system linker/cc to create the resulting file. This +// links to all upstream files as well. +fn link_natively(sess: &Session, + crate_type: config::CrateType, + out_filename: &Path, + codegen_results: &CodegenResults, + tmpdir: &Path) { + info!("preparing {:?} to {:?}", crate_type, out_filename); + let flavor = sess.linker_flavor(); + + // The invocations of cc share some flags across platforms + let (pname, mut cmd) = get_linker(sess); + + let root = sess.target_filesearch(PathKind::Native).get_lib_path(); + if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) { + cmd.args(args); + } + if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) { + if sess.crt_static() { + cmd.args(args); + } + } + if let Some(ref args) = sess.opts.debugging_opts.pre_link_args { + cmd.args(args); + } + cmd.args(&sess.opts.debugging_opts.pre_link_arg); + + let pre_link_objects = if crate_type == config::CrateTypeExecutable { + &sess.target.target.options.pre_link_objects_exe + } else { + &sess.target.target.options.pre_link_objects_dll + }; + for obj in pre_link_objects { + cmd.arg(root.join(obj)); + } + + if crate_type == config::CrateTypeExecutable && sess.crt_static() { + for obj in &sess.target.target.options.pre_link_objects_exe_crt { + cmd.arg(root.join(obj)); + } + + for obj in &sess.target.target.options.pre_link_objects_exe_crt_sys { + if flavor == LinkerFlavor::Gcc { + cmd.arg(format!("-l:{}", obj)); + } + } + } + + if sess.target.target.options.is_like_emscripten { + cmd.arg("-s"); + cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort { + "DISABLE_EXCEPTION_CATCHING=1" + } else { + "DISABLE_EXCEPTION_CATCHING=0" + }); + } + + { + let mut linker = codegen_results.linker_info.to_linker(cmd, &sess); + link_args(&mut *linker, sess, crate_type, tmpdir, + out_filename, codegen_results); + cmd = linker.finalize(); + } + if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { + cmd.args(args); + } + for obj in &sess.target.target.options.post_link_objects { + cmd.arg(root.join(obj)); + } + if sess.crt_static() { + for obj in &sess.target.target.options.post_link_objects_crt_sys { + if flavor == LinkerFlavor::Gcc { + cmd.arg(format!("-l:{}", obj)); + } + } + for obj in &sess.target.target.options.post_link_objects_crt { + cmd.arg(root.join(obj)); + } + } + if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) { + cmd.args(args); + } + for &(ref k, ref v) in &sess.target.target.options.link_env { + cmd.env(k, v); + } + + if sess.opts.debugging_opts.print_link_args { + println!("{:?}", &cmd); + } + + // May have not found libraries in the right formats. + sess.abort_if_errors(); + + // Invoke the system linker + // + // Note that there's a terribly awful hack that really shouldn't be present + // in any compiler. Here an environment variable is supported to + // automatically retry the linker invocation if the linker looks like it + // segfaulted. + // + // Gee that seems odd, normally segfaults are things we want to know about! + // Unfortunately though in rust-lang/rust#38878 we're experiencing the + // linker segfaulting on Travis quite a bit which is causing quite a bit of + // pain to land PRs when they spuriously fail due to a segfault. + // + // The issue #38878 has some more debugging information on it as well, but + // this unfortunately looks like it's just a race condition in macOS's linker + // with some thread pool working in the background. It seems that no one + // currently knows a fix for this so in the meantime we're left with this... + info!("{:?}", &cmd); + let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok(); + let mut prog; + let mut i = 0; + loop { + i += 1; + prog = time(sess, "running linker", || { + exec_linker(sess, &mut cmd, out_filename, tmpdir) + }); + let output = match prog { + Ok(ref output) => output, + Err(_) => break, + }; + if output.status.success() { + break + } + let mut out = output.stderr.clone(); + out.extend(&output.stdout); + let out = String::from_utf8_lossy(&out); + + // Check to see if the link failed with "unrecognized command line option: + // '-no-pie'" for gcc or "unknown argument: '-no-pie'" for clang. If so, + // reperform the link step without the -no-pie option. This is safe because + // if the linker doesn't support -no-pie then it should not default to + // linking executables as pie. Different versions of gcc seem to use + // different quotes in the error message so don't check for them. + if sess.target.target.options.linker_is_gnu && + sess.linker_flavor() != LinkerFlavor::Ld && + (out.contains("unrecognized command line option") || + out.contains("unknown argument")) && + out.contains("-no-pie") && + cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie") { + info!("linker output: {:?}", out); + warn!("Linker does not support -no-pie command line option. Retrying without."); + for arg in cmd.take_args() { + if arg.to_string_lossy() != "-no-pie" { + cmd.arg(arg); + } + } + info!("{:?}", &cmd); + continue; + } + if !retry_on_segfault || i > 3 { + break + } + let msg_segv = "clang: error: unable to execute command: Segmentation fault: 11"; + let msg_bus = "clang: error: unable to execute command: Bus error: 10"; + if !(out.contains(msg_segv) || out.contains(msg_bus)) { + break + } + + warn!( + "looks like the linker segfaulted when we tried to call it, \ + automatically retrying again. cmd = {:?}, out = {}.", + cmd, + out, + ); + } + + match prog { + Ok(prog) => { + fn escape_string(s: &[u8]) -> String { + str::from_utf8(s).map(|s| s.to_owned()) + .unwrap_or_else(|_| { + let mut x = "Non-UTF-8 output: ".to_string(); + x.extend(s.iter() + .flat_map(|&b| ascii::escape_default(b)) + .map(|b| char::from_u32(b as u32).unwrap())); + x + }) + } + if !prog.status.success() { + let mut output = prog.stderr.clone(); + output.extend_from_slice(&prog.stdout); + sess.struct_err(&format!("linking with `{}` failed: {}", + pname.display(), + prog.status)) + .note(&format!("{:?}", &cmd)) + .note(&escape_string(&output)) + .emit(); + sess.abort_if_errors(); + } + info!("linker stderr:\n{}", escape_string(&prog.stderr)); + info!("linker stdout:\n{}", escape_string(&prog.stdout)); + }, + Err(e) => { + let linker_not_found = e.kind() == io::ErrorKind::NotFound; + + let mut linker_error = { + if linker_not_found { + sess.struct_err(&format!("linker `{}` not found", pname.display())) + } else { + sess.struct_err(&format!("could not exec the linker `{}`", pname.display())) + } + }; + + linker_error.note(&format!("{}", e)); + + if !linker_not_found { + linker_error.note(&format!("{:?}", &cmd)); + } + + linker_error.emit(); + + if sess.target.target.options.is_like_msvc && linker_not_found { + sess.note_without_error("the msvc targets depend on the msvc linker \ + but `link.exe` was not found"); + sess.note_without_error("please ensure that VS 2013 or VS 2015 was installed \ + with the Visual C++ option"); + } + sess.abort_if_errors(); + } + } + + + // On macOS, debuggers need this utility to get run to do some munging of + // the symbols. Note, though, that if the object files are being preserved + // for their debug information there's no need for us to run dsymutil. + if sess.target.target.options.is_like_osx && + sess.opts.debuginfo != NoDebugInfo && + !preserve_objects_for_their_debuginfo(sess) + { + match Command::new("dsymutil").arg(out_filename).output() { + Ok(..) => {} + Err(e) => sess.fatal(&format!("failed to run dsymutil: {}", e)), + } + } + + if sess.opts.target_triple == TargetTriple::from_triple("wasm32-unknown-unknown") { + wasm::rewrite_imports(&out_filename, &codegen_results.crate_info.wasm_imports); + wasm::add_custom_sections(&out_filename, + &codegen_results.crate_info.wasm_custom_sections); + } +} + +fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: &Path) + -> io::Result +{ + // When attempting to spawn the linker we run a risk of blowing out the + // size limits for spawning a new process with respect to the arguments + // we pass on the command line. + // + // Here we attempt to handle errors from the OS saying "your list of + // arguments is too big" by reinvoking the linker again with an `@`-file + // that contains all the arguments. The theory is that this is then + // accepted on all linkers and the linker will read all its options out of + // there instead of looking at the command line. + if !cmd.very_likely_to_exceed_some_spawn_limit() { + match cmd.command().stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() { + Ok(child) => { + let output = child.wait_with_output(); + flush_linked_file(&output, out_filename)?; + return output; + } + Err(ref e) if command_line_too_big(e) => { + info!("command line to linker was too big: {}", e); + } + Err(e) => return Err(e) + } + } + + info!("falling back to passing arguments to linker via an @-file"); + let mut cmd2 = cmd.clone(); + let mut args = String::new(); + for arg in cmd2.take_args() { + args.push_str(&Escape { + arg: arg.to_str().unwrap(), + is_like_msvc: sess.target.target.options.is_like_msvc, + }.to_string()); + args.push_str("\n"); + } + let file = tmpdir.join("linker-arguments"); + let bytes = if sess.target.target.options.is_like_msvc { + let mut out = vec![]; + // start the stream with a UTF-16 BOM + for c in vec![0xFEFF].into_iter().chain(args.encode_utf16()) { + // encode in little endian + out.push(c as u8); + out.push((c >> 8) as u8); + } + out + } else { + args.into_bytes() + }; + fs::write(&file, &bytes)?; + cmd2.arg(format!("@{}", file.display())); + info!("invoking linker {:?}", cmd2); + let output = cmd2.output(); + flush_linked_file(&output, out_filename)?; + return output; + + #[cfg(unix)] + fn flush_linked_file(_: &io::Result, _: &Path) -> io::Result<()> { + Ok(()) + } + + #[cfg(windows)] + fn flush_linked_file(command_output: &io::Result, out_filename: &Path) + -> io::Result<()> + { + // On Windows, under high I/O load, output buffers are sometimes not flushed, + // even long after process exit, causing nasty, non-reproducible output bugs. + // + // File::sync_all() calls FlushFileBuffers() down the line, which solves the problem. + // + // А full writeup of the original Chrome bug can be found at + // randomascii.wordpress.com/2018/02/25/compiler-bug-linker-bug-windows-kernel-bug/amp + + if let &Ok(ref out) = command_output { + if out.status.success() { + if let Ok(of) = fs::OpenOptions::new().write(true).open(out_filename) { + of.sync_all()?; + } + } + } + + Ok(()) + } + + #[cfg(unix)] + fn command_line_too_big(err: &io::Error) -> bool { + err.raw_os_error() == Some(::libc::E2BIG) + } + + #[cfg(windows)] + fn command_line_too_big(err: &io::Error) -> bool { + const ERROR_FILENAME_EXCED_RANGE: i32 = 206; + err.raw_os_error() == Some(ERROR_FILENAME_EXCED_RANGE) + } + + struct Escape<'a> { + arg: &'a str, + is_like_msvc: bool, + } + + impl<'a> fmt::Display for Escape<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_like_msvc { + // This is "documented" at + // https://msdn.microsoft.com/en-us/library/4xdcbak7.aspx + // + // Unfortunately there's not a great specification of the + // syntax I could find online (at least) but some local + // testing showed that this seemed sufficient-ish to catch + // at least a few edge cases. + write!(f, "\"")?; + for c in self.arg.chars() { + match c { + '"' => write!(f, "\\{}", c)?, + c => write!(f, "{}", c)?, + } + } + write!(f, "\"")?; + } else { + // This is documented at https://linux.die.net/man/1/ld, namely: + // + // > Options in file are separated by whitespace. A whitespace + // > character may be included in an option by surrounding the + // > entire option in either single or double quotes. Any + // > character (including a backslash) may be included by + // > prefixing the character to be included with a backslash. + // + // We put an argument on each line, so all we need to do is + // ensure the line is interpreted as one whole argument. + for c in self.arg.chars() { + match c { + '\\' | + ' ' => write!(f, "\\{}", c)?, + c => write!(f, "{}", c)?, + } + } + } + Ok(()) + } + } +} + +fn link_args(cmd: &mut Linker, + sess: &Session, + crate_type: config::CrateType, + tmpdir: &Path, + out_filename: &Path, + codegen_results: &CodegenResults) { + + // Linker plugins should be specified early in the list of arguments + cmd.cross_lang_lto(); + + // The default library location, we need this to find the runtime. + // The location of crates will be determined as needed. + let lib_path = sess.target_filesearch(PathKind::All).get_lib_path(); + + // target descriptor + let t = &sess.target.target; + + cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); + for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { + cmd.add_object(obj); + } + cmd.output_filename(out_filename); + + if crate_type == config::CrateTypeExecutable && + sess.target.target.options.is_like_windows { + if let Some(ref s) = codegen_results.windows_subsystem { + cmd.subsystem(s); + } + } + + // If we're building a dynamic library then some platforms need to make sure + // that all symbols are exported correctly from the dynamic library. + if crate_type != config::CrateTypeExecutable || + sess.target.target.options.is_like_emscripten { + cmd.export_symbols(tmpdir, crate_type); + } + + // When linking a dynamic library, we put the metadata into a section of the + // executable. This metadata is in a separate object file from the main + // object file, so we link that in here. + if crate_type == config::CrateTypeDylib || + crate_type == config::CrateTypeProcMacro { + if let Some(obj) = codegen_results.metadata_module.object.as_ref() { + cmd.add_object(obj); + } + } + + let obj = codegen_results.allocator_module + .as_ref() + .and_then(|m| m.object.as_ref()); + if let Some(obj) = obj { + cmd.add_object(obj); + } + + // Try to strip as much out of the generated object by removing unused + // sections if possible. See more comments in linker.rs + if !sess.opts.cg.link_dead_code { + let keep_metadata = crate_type == config::CrateTypeDylib; + cmd.gc_sections(keep_metadata); + } + + let used_link_args = &codegen_results.crate_info.link_args; + + if crate_type == config::CrateTypeExecutable { + let mut position_independent_executable = false; + + if t.options.position_independent_executables { + let empty_vec = Vec::new(); + let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec); + let more_args = &sess.opts.cg.link_arg; + let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter()); + + if get_reloc_model(sess) == llvm::RelocMode::PIC + && !sess.crt_static() && !args.any(|x| *x == "-static") { + position_independent_executable = true; + } + } + + if position_independent_executable { + cmd.position_independent_executable(); + } else { + // recent versions of gcc can be configured to generate position + // independent executables by default. We have to pass -no-pie to + // explicitly turn that off. Not applicable to ld. + if sess.target.target.options.linker_is_gnu + && sess.linker_flavor() != LinkerFlavor::Ld { + cmd.no_position_independent_executable(); + } + } + } + + let relro_level = match sess.opts.debugging_opts.relro_level { + Some(level) => level, + None => t.options.relro_level, + }; + match relro_level { + RelroLevel::Full => { + cmd.full_relro(); + }, + RelroLevel::Partial => { + cmd.partial_relro(); + }, + RelroLevel::Off => { + cmd.no_relro(); + }, + RelroLevel::None => { + }, + } + + // Pass optimization flags down to the linker. + cmd.optimize(); + + // Pass debuginfo flags down to the linker. + cmd.debuginfo(); + + // We want to prevent the compiler from accidentally leaking in any system + // libraries, so we explicitly ask gcc to not link to any libraries by + // default. Note that this does not happen for windows because windows pulls + // in some large number of libraries and I couldn't quite figure out which + // subset we wanted. + if t.options.no_default_libraries { + cmd.no_default_libraries(); + } + + // Take careful note of the ordering of the arguments we pass to the linker + // here. Linkers will assume that things on the left depend on things to the + // right. Things on the right cannot depend on things on the left. This is + // all formally implemented in terms of resolving symbols (libs on the right + // resolve unknown symbols of libs on the left, but not vice versa). + // + // For this reason, we have organized the arguments we pass to the linker as + // such: + // + // 1. The local object that LLVM just generated + // 2. Local native libraries + // 3. Upstream rust libraries + // 4. Upstream native libraries + // + // The rationale behind this ordering is that those items lower down in the + // list can't depend on items higher up in the list. For example nothing can + // depend on what we just generated (e.g. that'd be a circular dependency). + // Upstream rust libraries are not allowed to depend on our local native + // libraries as that would violate the structure of the DAG, in that + // scenario they are required to link to them as well in a shared fashion. + // + // Note that upstream rust libraries may contain native dependencies as + // well, but they also can't depend on what we just started to add to the + // link line. And finally upstream native libraries can't depend on anything + // in this DAG so far because they're only dylibs and dylibs can only depend + // on other dylibs (e.g. other native deps). + add_local_native_libraries(cmd, sess, codegen_results); + add_upstream_rust_crates(cmd, sess, codegen_results, crate_type, tmpdir); + add_upstream_native_libraries(cmd, sess, codegen_results, crate_type); + + // Tell the linker what we're doing. + if crate_type != config::CrateTypeExecutable { + cmd.build_dylib(out_filename); + } + if crate_type == config::CrateTypeExecutable && sess.crt_static() { + cmd.build_static_executable(); + } + + if sess.opts.debugging_opts.pgo_gen.is_some() { + cmd.pgo_gen(); + } + + // FIXME (#2397): At some point we want to rpath our guesses as to + // where extern libraries might live, based on the + // addl_lib_search_paths + if sess.opts.cg.rpath { + let sysroot = sess.sysroot(); + let target_triple = sess.opts.target_triple.triple(); + let mut get_install_prefix_lib_path = || { + let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX"); + let tlib = filesearch::relative_target_lib_path(sysroot, target_triple); + let mut path = PathBuf::from(install_prefix); + path.push(&tlib); + + path + }; + let mut rpath_config = RPathConfig { + used_crates: &codegen_results.crate_info.used_crates_dynamic, + out_filename: out_filename.to_path_buf(), + has_rpath: sess.target.target.options.has_rpath, + is_like_osx: sess.target.target.options.is_like_osx, + linker_is_gnu: sess.target.target.options.linker_is_gnu, + get_install_prefix_lib_path: &mut get_install_prefix_lib_path, + }; + cmd.args(&rpath::get_rpath_flags(&mut rpath_config)); + } + + // Finally add all the linker arguments provided on the command line along + // with any #[link_args] attributes found inside the crate + if let Some(ref args) = sess.opts.cg.link_args { + cmd.args(args); + } + cmd.args(&sess.opts.cg.link_arg); + cmd.args(&used_link_args); +} + +// # Native library linking +// +// User-supplied library search paths (-L on the command line). These are +// the same paths used to find Rust crates, so some of them may have been +// added already by the previous crate linking code. This only allows them +// to be found at compile time so it is still entirely up to outside +// forces to make sure that library can be found at runtime. +// +// Also note that the native libraries linked here are only the ones located +// in the current crate. Upstream crates with native library dependencies +// may have their native library pulled in above. +fn add_local_native_libraries(cmd: &mut Linker, + sess: &Session, + codegen_results: &CodegenResults) { + sess.target_filesearch(PathKind::All).for_each_lib_search_path(|path, k| { + match k { + PathKind::Framework => { cmd.framework_path(path); } + _ => { cmd.include_path(&fix_windows_verbatim_for_gcc(path)); } + } + }); + + let relevant_libs = codegen_results.crate_info.used_libraries.iter().filter(|l| { + relevant_lib(sess, l) + }); + + let search_path = archive_search_paths(sess); + for lib in relevant_libs { + match lib.kind { + NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()), + NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()), + NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&lib.name.as_str()), + NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&lib.name.as_str(), + &search_path) + } + } +} + +// # Rust Crate linking +// +// Rust crates are not considered at all when creating an rlib output. All +// dependencies will be linked when producing the final output (instead of +// the intermediate rlib version) +fn add_upstream_rust_crates(cmd: &mut Linker, + sess: &Session, + codegen_results: &CodegenResults, + crate_type: config::CrateType, + tmpdir: &Path) { + // All of the heavy lifting has previously been accomplished by the + // dependency_format module of the compiler. This is just crawling the + // output of that module, adding crates as necessary. + // + // Linking to a rlib involves just passing it to the linker (the linker + // will slurp up the object files inside), and linking to a dynamic library + // involves just passing the right -l flag. + + let formats = sess.dependency_formats.borrow(); + let data = formats.get(&crate_type).unwrap(); + + // Invoke get_used_crates to ensure that we get a topological sorting of + // crates. + let deps = &codegen_results.crate_info.used_crates_dynamic; + + // There's a few internal crates in the standard library (aka libcore and + // libstd) which actually have a circular dependence upon one another. This + // currently arises through "weak lang items" where libcore requires things + // like `rust_begin_unwind` but libstd ends up defining it. To get this + // circular dependence to work correctly in all situations we'll need to be + // sure to correctly apply the `--start-group` and `--end-group` options to + // GNU linkers, otherwise if we don't use any other symbol from the standard + // library it'll get discarded and the whole application won't link. + // + // In this loop we're calculating the `group_end`, after which crate to + // pass `--end-group` and `group_start`, before which crate to pass + // `--start-group`. We currently do this by passing `--end-group` after + // the first crate (when iterating backwards) that requires a lang item + // defined somewhere else. Once that's set then when we've defined all the + // necessary lang items we'll pass `--start-group`. + // + // Note that this isn't amazing logic for now but it should do the trick + // for the current implementation of the standard library. + let mut group_end = None; + let mut group_start = None; + let mut end_with = FxHashSet(); + let info = &codegen_results.crate_info; + for &(cnum, _) in deps.iter().rev() { + if let Some(missing) = info.missing_lang_items.get(&cnum) { + end_with.extend(missing.iter().cloned()); + if end_with.len() > 0 && group_end.is_none() { + group_end = Some(cnum); + } + } + end_with.retain(|item| info.lang_item_to_crate.get(item) != Some(&cnum)); + if end_with.len() == 0 && group_end.is_some() { + group_start = Some(cnum); + break + } + } + + // If we didn't end up filling in all lang items from upstream crates then + // we'll be filling it in with our crate. This probably means we're the + // standard library itself, so skip this for now. + if group_end.is_some() && group_start.is_none() { + group_end = None; + } + + let mut compiler_builtins = None; + + for &(cnum, _) in deps.iter() { + if group_start == Some(cnum) { + cmd.group_start(); + } + + // We may not pass all crates through to the linker. Some crates may + // appear statically in an existing dylib, meaning we'll pick up all the + // symbols from the dylib. + let src = &codegen_results.crate_info.used_crate_source[&cnum]; + match data[cnum.as_usize() - 1] { + _ if codegen_results.crate_info.profiler_runtime == Some(cnum) => { + add_static_crate(cmd, sess, codegen_results, tmpdir, crate_type, cnum); + } + _ if codegen_results.crate_info.sanitizer_runtime == Some(cnum) => { + link_sanitizer_runtime(cmd, sess, codegen_results, tmpdir, cnum); + } + // compiler-builtins are always placed last to ensure that they're + // linked correctly. + _ if codegen_results.crate_info.compiler_builtins == Some(cnum) => { + assert!(compiler_builtins.is_none()); + compiler_builtins = Some(cnum); + } + Linkage::NotLinked | + Linkage::IncludedFromDylib => {} + Linkage::Static => { + add_static_crate(cmd, sess, codegen_results, tmpdir, crate_type, cnum); + } + Linkage::Dynamic => { + add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0) + } + } + + if group_end == Some(cnum) { + cmd.group_end(); + } + } + + // compiler-builtins are always placed last to ensure that they're + // linked correctly. + // We must always link the `compiler_builtins` crate statically. Even if it + // was already "included" in a dylib (e.g. `libstd` when `-C prefer-dynamic` + // is used) + if let Some(cnum) = compiler_builtins { + add_static_crate(cmd, sess, codegen_results, tmpdir, crate_type, cnum); + } + + // Converts a library file-stem into a cc -l argument + fn unlib<'a>(config: &config::Config, stem: &'a str) -> &'a str { + if stem.starts_with("lib") && !config.target.options.is_like_windows { + &stem[3..] + } else { + stem + } + } + + // We must link the sanitizer runtime using -Wl,--whole-archive but since + // it's packed in a .rlib, it contains stuff that are not objects that will + // make the linker error. So we must remove those bits from the .rlib before + // linking it. + fn link_sanitizer_runtime(cmd: &mut Linker, + sess: &Session, + codegen_results: &CodegenResults, + tmpdir: &Path, + cnum: CrateNum) { + let src = &codegen_results.crate_info.used_crate_source[&cnum]; + let cratepath = &src.rlib.as_ref().unwrap().0; + + if sess.target.target.options.is_like_osx { + // On Apple platforms, the sanitizer is always built as a dylib, and + // LLVM will link to `@rpath/*.dylib`, so we need to specify an + // rpath to the library as well (the rpath should be absolute, see + // PR #41352 for details). + // + // FIXME: Remove this logic into librustc_*san once Cargo supports it + let rpath = cratepath.parent().unwrap(); + let rpath = rpath.to_str().expect("non-utf8 component in path"); + cmd.args(&["-Wl,-rpath".into(), "-Xlinker".into(), rpath.into()]); + } + + let dst = tmpdir.join(cratepath.file_name().unwrap()); + let cfg = archive_config(sess, &dst, Some(cratepath)); + let mut archive = ArchiveBuilder::new(cfg); + archive.update_symbols(); + + for f in archive.src_files() { + if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME { + archive.remove_file(&f); + continue + } + } + + archive.build(); + + cmd.link_whole_rlib(&dst); + } + + // Adds the static "rlib" versions of all crates to the command line. + // There's a bit of magic which happens here specifically related to LTO and + // dynamic libraries. Specifically: + // + // * For LTO, we remove upstream object files. + // * For dylibs we remove metadata and bytecode from upstream rlibs + // + // When performing LTO, almost(*) all of the bytecode from the upstream + // libraries has already been included in our object file output. As a + // result we need to remove the object files in the upstream libraries so + // the linker doesn't try to include them twice (or whine about duplicate + // symbols). We must continue to include the rest of the rlib, however, as + // it may contain static native libraries which must be linked in. + // + // (*) Crates marked with `#![no_builtins]` don't participate in LTO and + // their bytecode wasn't included. The object files in those libraries must + // still be passed to the linker. + // + // When making a dynamic library, linkers by default don't include any + // object files in an archive if they're not necessary to resolve the link. + // We basically want to convert the archive (rlib) to a dylib, though, so we + // *do* want everything included in the output, regardless of whether the + // linker thinks it's needed or not. As a result we must use the + // --whole-archive option (or the platform equivalent). When using this + // option the linker will fail if there are non-objects in the archive (such + // as our own metadata and/or bytecode). All in all, for rlibs to be + // entirely included in dylibs, we need to remove all non-object files. + // + // Note, however, that if we're not doing LTO or we're not producing a dylib + // (aka we're making an executable), we can just pass the rlib blindly to + // the linker (fast) because it's fine if it's not actually included as + // we're at the end of the dependency chain. + fn add_static_crate(cmd: &mut Linker, + sess: &Session, + codegen_results: &CodegenResults, + tmpdir: &Path, + crate_type: config::CrateType, + cnum: CrateNum) { + let src = &codegen_results.crate_info.used_crate_source[&cnum]; + let cratepath = &src.rlib.as_ref().unwrap().0; + + // See the comment above in `link_staticlib` and `link_rlib` for why if + // there's a static library that's not relevant we skip all object + // files. + let native_libs = &codegen_results.crate_info.native_libraries[&cnum]; + let skip_native = native_libs.iter().any(|lib| { + lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) + }); + + if (!is_full_lto_enabled(sess) || + ignored_for_lto(sess, &codegen_results.crate_info, cnum)) && + crate_type != config::CrateTypeDylib && + !skip_native { + cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); + return + } + + let dst = tmpdir.join(cratepath.file_name().unwrap()); + let name = cratepath.file_name().unwrap().to_str().unwrap(); + let name = &name[3..name.len() - 5]; // chop off lib/.rlib + + time(sess, &format!("altering {}.rlib", name), || { + let cfg = archive_config(sess, &dst, Some(cratepath)); + let mut archive = ArchiveBuilder::new(cfg); + archive.update_symbols(); + + let mut any_objects = false; + for f in archive.src_files() { + if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME { + archive.remove_file(&f); + continue + } + + let canonical = f.replace("-", "_"); + let canonical_name = name.replace("-", "_"); + + // Look for `.rcgu.o` at the end of the filename to conclude + // that this is a Rust-related object file. + fn looks_like_rust(s: &str) -> bool { + let path = Path::new(s); + let ext = path.extension().and_then(|s| s.to_str()); + if ext != Some(OutputType::Object.extension()) { + return false + } + let ext2 = path.file_stem() + .and_then(|s| Path::new(s).extension()) + .and_then(|s| s.to_str()); + ext2 == Some(RUST_CGU_EXT) + } + + let is_rust_object = + canonical.starts_with(&canonical_name) && + looks_like_rust(&f); + + // If we've been requested to skip all native object files + // (those not generated by the rust compiler) then we can skip + // this file. See above for why we may want to do this. + let skip_because_cfg_say_so = skip_native && !is_rust_object; + + // If we're performing LTO and this is a rust-generated object + // file, then we don't need the object file as it's part of the + // LTO module. Note that `#![no_builtins]` is excluded from LTO, + // though, so we let that object file slide. + let skip_because_lto = is_full_lto_enabled(sess) && + is_rust_object && + (sess.target.target.options.no_builtins || + !codegen_results.crate_info.is_no_builtins.contains(&cnum)); + + if skip_because_cfg_say_so || skip_because_lto { + archive.remove_file(&f); + } else { + any_objects = true; + } + } + + if !any_objects { + return + } + archive.build(); + + // If we're creating a dylib, then we need to include the + // whole of each object in our archive into that artifact. This is + // because a `dylib` can be reused as an intermediate artifact. + // + // Note, though, that we don't want to include the whole of a + // compiler-builtins crate (e.g. compiler-rt) because it'll get + // repeatedly linked anyway. + if crate_type == config::CrateTypeDylib && + codegen_results.crate_info.compiler_builtins != Some(cnum) { + cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst)); + } else { + cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst)); + } + }); + } + + // Same thing as above, but for dynamic crates instead of static crates. + fn add_dynamic_crate(cmd: &mut Linker, sess: &Session, cratepath: &Path) { + // If we're performing LTO, then it should have been previously required + // that all upstream rust dependencies were available in an rlib format. + assert!(!is_full_lto_enabled(sess)); + + // Just need to tell the linker about where the library lives and + // what its name is + let parent = cratepath.parent(); + if let Some(dir) = parent { + cmd.include_path(&fix_windows_verbatim_for_gcc(dir)); + } + let filestem = cratepath.file_stem().unwrap().to_str().unwrap(); + cmd.link_rust_dylib(&unlib(&sess.target, filestem), + parent.unwrap_or(Path::new(""))); + } +} + +// Link in all of our upstream crates' native dependencies. Remember that +// all of these upstream native dependencies are all non-static +// dependencies. We've got two cases then: +// +// 1. The upstream crate is an rlib. In this case we *must* link in the +// native dependency because the rlib is just an archive. +// +// 2. The upstream crate is a dylib. In order to use the dylib, we have to +// have the dependency present on the system somewhere. Thus, we don't +// gain a whole lot from not linking in the dynamic dependency to this +// crate as well. +// +// The use case for this is a little subtle. In theory the native +// dependencies of a crate are purely an implementation detail of the crate +// itself, but the problem arises with generic and inlined functions. If a +// generic function calls a native function, then the generic function must +// be instantiated in the target crate, meaning that the native symbol must +// also be resolved in the target crate. +fn add_upstream_native_libraries(cmd: &mut Linker, + sess: &Session, + codegen_results: &CodegenResults, + crate_type: config::CrateType) { + // Be sure to use a topological sorting of crates because there may be + // interdependencies between native libraries. When passing -nodefaultlibs, + // for example, almost all native libraries depend on libc, so we have to + // make sure that's all the way at the right (liblibc is near the base of + // the dependency chain). + // + // This passes RequireStatic, but the actual requirement doesn't matter, + // we're just getting an ordering of crate numbers, we're not worried about + // the paths. + let formats = sess.dependency_formats.borrow(); + let data = formats.get(&crate_type).unwrap(); + + let crates = &codegen_results.crate_info.used_crates_static; + for &(cnum, _) in crates { + for lib in codegen_results.crate_info.native_libraries[&cnum].iter() { + if !relevant_lib(sess, &lib) { + continue + } + match lib.kind { + NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()), + NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()), + NativeLibraryKind::NativeStaticNobundle => { + // Link "static-nobundle" native libs only if the crate they originate from + // is being linked statically to the current crate. If it's linked dynamically + // or is an rlib already included via some other dylib crate, the symbols from + // native libs will have already been included in that dylib. + if data[cnum.as_usize() - 1] == Linkage::Static { + cmd.link_staticlib(&lib.name.as_str()) + } + }, + // ignore statically included native libraries here as we've + // already included them when we included the rust library + // previously + NativeLibraryKind::NativeStatic => {} + } + } + } +} + +fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { + match lib.cfg { + Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None), + None => true, + } +} + +fn is_full_lto_enabled(sess: &Session) -> bool { + match sess.lto() { + Lto::Yes | + Lto::Thin | + Lto::Fat => true, + Lto::No | + Lto::ThinLocal => false, + } +} diff --git a/src/librustc_codegen_llvm/back/linker.rs b/src/librustc_codegen_llvm/back/linker.rs new file mode 100644 index 00000000000..dd1983bdc17 --- /dev/null +++ b/src/librustc_codegen_llvm/back/linker.rs @@ -0,0 +1,1037 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::HashMap; +use std::ffi::{OsStr, OsString}; +use std::fs::{self, File}; +use std::io::prelude::*; +use std::io::{self, BufWriter}; +use std::path::{Path, PathBuf}; + +use back::archive; +use back::command::Command; +use back::symbol_export; +use rustc::hir::def_id::{LOCAL_CRATE, CrateNum}; +use rustc::middle::dependency_format::Linkage; +use rustc::session::Session; +use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel, + CrossLangLto}; +use rustc::ty::TyCtxt; +use rustc_target::spec::{LinkerFlavor, LldFlavor}; +use serialize::{json, Encoder}; + +/// For all the linkers we support, and information they might +/// need out of the shared crate context before we get rid of it. +pub struct LinkerInfo { + exports: HashMap>, +} + +impl LinkerInfo { + pub fn new(tcx: TyCtxt) -> LinkerInfo { + LinkerInfo { + exports: tcx.sess.crate_types.borrow().iter().map(|&c| { + (c, exported_symbols(tcx, c)) + }).collect(), + } + } + + pub fn to_linker<'a>(&'a self, + cmd: Command, + sess: &'a Session) -> Box { + match sess.linker_flavor() { + LinkerFlavor::Lld(LldFlavor::Link) | + LinkerFlavor::Msvc => { + Box::new(MsvcLinker { + cmd, + sess, + info: self + }) as Box + } + LinkerFlavor::Em => { + Box::new(EmLinker { + cmd, + sess, + info: self + }) as Box + } + LinkerFlavor::Gcc => { + Box::new(GccLinker { + cmd, + sess, + info: self, + hinted_static: false, + is_ld: false, + }) as Box + } + + LinkerFlavor::Lld(LldFlavor::Ld) | + LinkerFlavor::Lld(LldFlavor::Ld64) | + LinkerFlavor::Ld => { + Box::new(GccLinker { + cmd, + sess, + info: self, + hinted_static: false, + is_ld: true, + }) as Box + } + + LinkerFlavor::Lld(LldFlavor::Wasm) => { + Box::new(WasmLd { + cmd, + }) as Box + } + } + } +} + +/// Linker abstraction used by back::link to build up the command to invoke a +/// linker. +/// +/// This trait is the total list of requirements needed by `back::link` and +/// represents the meaning of each option being passed down. This trait is then +/// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an +/// MSVC linker (e.g. `link.exe`) is being used. +pub trait Linker { + fn link_dylib(&mut self, lib: &str); + fn link_rust_dylib(&mut self, lib: &str, path: &Path); + fn link_framework(&mut self, framework: &str); + fn link_staticlib(&mut self, lib: &str); + fn link_rlib(&mut self, lib: &Path); + fn link_whole_rlib(&mut self, lib: &Path); + fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]); + fn include_path(&mut self, path: &Path); + fn framework_path(&mut self, path: &Path); + fn output_filename(&mut self, path: &Path); + fn add_object(&mut self, path: &Path); + fn gc_sections(&mut self, keep_metadata: bool); + fn position_independent_executable(&mut self); + fn no_position_independent_executable(&mut self); + fn full_relro(&mut self); + fn partial_relro(&mut self); + fn no_relro(&mut self); + fn optimize(&mut self); + fn pgo_gen(&mut self); + fn debuginfo(&mut self); + fn no_default_libraries(&mut self); + fn build_dylib(&mut self, out_filename: &Path); + fn build_static_executable(&mut self); + fn args(&mut self, args: &[String]); + fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType); + fn subsystem(&mut self, subsystem: &str); + fn group_start(&mut self); + fn group_end(&mut self); + fn cross_lang_lto(&mut self); + // Should have been finalize(self), but we don't support self-by-value on trait objects (yet?). + fn finalize(&mut self) -> Command; +} + +pub struct GccLinker<'a> { + cmd: Command, + sess: &'a Session, + info: &'a LinkerInfo, + hinted_static: bool, // Keeps track of the current hinting mode. + // Link as ld + is_ld: bool, +} + +impl<'a> GccLinker<'a> { + /// Argument that must be passed *directly* to the linker + /// + /// These arguments need to be prepended with '-Wl,' when a gcc-style linker is used + fn linker_arg(&mut self, arg: S) -> &mut Self + where S: AsRef + { + if !self.is_ld { + let mut os = OsString::from("-Wl,"); + os.push(arg.as_ref()); + self.cmd.arg(os); + } else { + self.cmd.arg(arg); + } + self + } + + fn takes_hints(&self) -> bool { + !self.sess.target.target.options.is_like_osx + } + + // Some platforms take hints about whether a library is static or dynamic. + // For those that support this, we ensure we pass the option if the library + // was flagged "static" (most defaults are dynamic) to ensure that if + // libfoo.a and libfoo.so both exist that the right one is chosen. + fn hint_static(&mut self) { + if !self.takes_hints() { return } + if !self.hinted_static { + self.linker_arg("-Bstatic"); + self.hinted_static = true; + } + } + + fn hint_dynamic(&mut self) { + if !self.takes_hints() { return } + if self.hinted_static { + self.linker_arg("-Bdynamic"); + self.hinted_static = false; + } + } +} + +impl<'a> Linker for GccLinker<'a> { + fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg("-l").arg(lib); } + fn link_staticlib(&mut self, lib: &str) { self.hint_static(); self.cmd.arg("-l").arg(lib); } + fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); } + fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); } + fn framework_path(&mut self, path: &Path) { self.cmd.arg("-F").arg(path); } + fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); } + fn add_object(&mut self, path: &Path) { self.cmd.arg(path); } + fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); } + fn no_position_independent_executable(&mut self) { self.cmd.arg("-no-pie"); } + fn full_relro(&mut self) { self.linker_arg("-z,relro,-z,now"); } + fn partial_relro(&mut self) { self.linker_arg("-z,relro"); } + fn no_relro(&mut self) { self.linker_arg("-z,norelro"); } + fn build_static_executable(&mut self) { self.cmd.arg("-static"); } + fn args(&mut self, args: &[String]) { self.cmd.args(args); } + + fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { + self.hint_dynamic(); + self.cmd.arg("-l").arg(lib); + } + + fn link_framework(&mut self, framework: &str) { + self.hint_dynamic(); + self.cmd.arg("-framework").arg(framework); + } + + // Here we explicitly ask that the entire archive is included into the + // result artifact. For more details see #15460, but the gist is that + // the linker will strip away any unused objects in the archive if we + // don't otherwise explicitly reference them. This can occur for + // libraries which are just providing bindings, libraries with generic + // functions, etc. + fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]) { + self.hint_static(); + let target = &self.sess.target.target; + if !target.options.is_like_osx { + self.linker_arg("--whole-archive").cmd.arg("-l").arg(lib); + self.linker_arg("--no-whole-archive"); + } else { + // -force_load is the macOS equivalent of --whole-archive, but it + // involves passing the full path to the library to link. + let mut v = OsString::from("-force_load,"); + v.push(&archive::find_library(lib, search_path, &self.sess)); + self.linker_arg(&v); + } + } + + fn link_whole_rlib(&mut self, lib: &Path) { + self.hint_static(); + if self.sess.target.target.options.is_like_osx { + let mut v = OsString::from("-force_load,"); + v.push(lib); + self.linker_arg(&v); + } else { + self.linker_arg("--whole-archive").cmd.arg(lib); + self.linker_arg("--no-whole-archive"); + } + } + + fn gc_sections(&mut self, keep_metadata: bool) { + // The dead_strip option to the linker specifies that functions and data + // unreachable by the entry point will be removed. This is quite useful + // with Rust's compilation model of compiling libraries at a time into + // one object file. For example, this brings hello world from 1.7MB to + // 458K. + // + // Note that this is done for both executables and dynamic libraries. We + // won't get much benefit from dylibs because LLVM will have already + // stripped away as much as it could. This has not been seen to impact + // link times negatively. + // + // -dead_strip can't be part of the pre_link_args because it's also used + // for partial linking when using multiple codegen units (-r). So we + // insert it here. + if self.sess.target.target.options.is_like_osx { + self.linker_arg("-dead_strip"); + } else if self.sess.target.target.options.is_like_solaris { + self.linker_arg("-z"); + self.linker_arg("ignore"); + + // If we're building a dylib, we don't use --gc-sections because LLVM + // has already done the best it can do, and we also don't want to + // eliminate the metadata. If we're building an executable, however, + // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67% + // reduction. + } else if !keep_metadata { + self.linker_arg("--gc-sections"); + } + } + + fn optimize(&mut self) { + if !self.sess.target.target.options.linker_is_gnu { return } + + // GNU-style linkers support optimization with -O. GNU ld doesn't + // need a numeric argument, but other linkers do. + if self.sess.opts.optimize == config::OptLevel::Default || + self.sess.opts.optimize == config::OptLevel::Aggressive { + self.linker_arg("-O1"); + } + } + + fn pgo_gen(&mut self) { + if !self.sess.target.target.options.linker_is_gnu { return } + + // If we're doing PGO generation stuff and on a GNU-like linker, use the + // "-u" flag to properly pull in the profiler runtime bits. + // + // This is because LLVM otherwise won't add the needed initialization + // for us on Linux (though the extra flag should be harmless if it + // does). + // + // See https://reviews.llvm.org/D14033 and https://reviews.llvm.org/D14030. + // + // Though it may be worth to try to revert those changes upstream, since + // the overhead of the initialization should be minor. + self.cmd.arg("-u"); + self.cmd.arg("__llvm_profile_runtime"); + } + + fn debuginfo(&mut self) { + match self.sess.opts.debuginfo { + DebugInfoLevel::NoDebugInfo => { + // If we are building without debuginfo enabled and we were called with + // `-Zstrip-debuginfo-if-disabled=yes`, tell the linker to strip any debuginfo + // found when linking to get rid of symbols from libstd. + match self.sess.opts.debugging_opts.strip_debuginfo_if_disabled { + Some(true) => { self.linker_arg("-S"); }, + _ => {}, + } + }, + _ => {}, + }; + } + + fn no_default_libraries(&mut self) { + if !self.is_ld { + self.cmd.arg("-nodefaultlibs"); + } + } + + fn build_dylib(&mut self, out_filename: &Path) { + // On mac we need to tell the linker to let this library be rpathed + if self.sess.target.target.options.is_like_osx { + self.cmd.arg("-dynamiclib"); + self.linker_arg("-dylib"); + + // Note that the `osx_rpath_install_name` option here is a hack + // purely to support rustbuild right now, we should get a more + // principled solution at some point to force the compiler to pass + // the right `-Wl,-install_name` with an `@rpath` in it. + if self.sess.opts.cg.rpath || + self.sess.opts.debugging_opts.osx_rpath_install_name { + let mut v = OsString::from("-install_name,@rpath/"); + v.push(out_filename.file_name().unwrap()); + self.linker_arg(&v); + } + } else { + self.cmd.arg("-shared"); + } + } + + fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) { + // If we're compiling a dylib, then we let symbol visibility in object + // files to take care of whether they're exported or not. + // + // If we're compiling a cdylib, however, we manually create a list of + // exported symbols to ensure we don't expose any more. The object files + // have far more public symbols than we actually want to export, so we + // hide them all here. + if crate_type == CrateType::CrateTypeDylib || + crate_type == CrateType::CrateTypeProcMacro { + return + } + + let mut arg = OsString::new(); + let path = tmpdir.join("list"); + + debug!("EXPORTED SYMBOLS:"); + + if self.sess.target.target.options.is_like_osx { + // Write a plain, newline-separated list of symbols + let res = (|| -> io::Result<()> { + let mut f = BufWriter::new(File::create(&path)?); + for sym in self.info.exports[&crate_type].iter() { + debug!(" _{}", sym); + writeln!(f, "_{}", sym)?; + } + Ok(()) + })(); + if let Err(e) = res { + self.sess.fatal(&format!("failed to write lib.def file: {}", e)); + } + } else { + // Write an LD version script + let res = (|| -> io::Result<()> { + let mut f = BufWriter::new(File::create(&path)?); + writeln!(f, "{{\n global:")?; + for sym in self.info.exports[&crate_type].iter() { + debug!(" {};", sym); + writeln!(f, " {};", sym)?; + } + writeln!(f, "\n local:\n *;\n}};")?; + Ok(()) + })(); + if let Err(e) = res { + self.sess.fatal(&format!("failed to write version script: {}", e)); + } + } + + if self.sess.target.target.options.is_like_osx { + if !self.is_ld { + arg.push("-Wl,") + } + arg.push("-exported_symbols_list,"); + } else if self.sess.target.target.options.is_like_solaris { + if !self.is_ld { + arg.push("-Wl,") + } + arg.push("-M,"); + } else { + if !self.is_ld { + arg.push("-Wl,") + } + arg.push("--version-script="); + } + + arg.push(&path); + self.cmd.arg(arg); + } + + fn subsystem(&mut self, subsystem: &str) { + self.linker_arg(&format!("--subsystem,{}", subsystem)); + } + + fn finalize(&mut self) -> Command { + self.hint_dynamic(); // Reset to default before returning the composed command line. + let mut cmd = Command::new(""); + ::std::mem::swap(&mut cmd, &mut self.cmd); + cmd + } + + fn group_start(&mut self) { + if !self.sess.target.target.options.is_like_osx { + self.linker_arg("--start-group"); + } + } + + fn group_end(&mut self) { + if !self.sess.target.target.options.is_like_osx { + self.linker_arg("--end-group"); + } + } + + fn cross_lang_lto(&mut self) { + match self.sess.opts.debugging_opts.cross_lang_lto { + CrossLangLto::Disabled | + CrossLangLto::NoLink => { + // Nothing to do + } + CrossLangLto::LinkerPlugin(ref path) => { + self.linker_arg(&format!("-plugin={}", path.display())); + + let opt_level = match self.sess.opts.optimize { + config::OptLevel::No => "O0", + config::OptLevel::Less => "O1", + config::OptLevel::Default => "O2", + config::OptLevel::Aggressive => "O3", + config::OptLevel::Size => "Os", + config::OptLevel::SizeMin => "Oz", + }; + + self.linker_arg(&format!("-plugin-opt={}", opt_level)); + self.linker_arg(&format!("-plugin-opt=mcpu={}", self.sess.target_cpu())); + + match self.sess.opts.cg.lto { + config::Lto::Thin | + config::Lto::ThinLocal => { + self.linker_arg(&format!("-plugin-opt=thin")); + } + config::Lto::Fat | + config::Lto::Yes | + config::Lto::No => { + // default to regular LTO + } + } + } + } + } +} + +pub struct MsvcLinker<'a> { + cmd: Command, + sess: &'a Session, + info: &'a LinkerInfo +} + +impl<'a> Linker for MsvcLinker<'a> { + fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); } + fn add_object(&mut self, path: &Path) { self.cmd.arg(path); } + fn args(&mut self, args: &[String]) { self.cmd.args(args); } + + fn build_dylib(&mut self, out_filename: &Path) { + self.cmd.arg("/DLL"); + let mut arg: OsString = "/IMPLIB:".into(); + arg.push(out_filename.with_extension("dll.lib")); + self.cmd.arg(arg); + } + + fn build_static_executable(&mut self) { + // noop + } + + fn gc_sections(&mut self, _keep_metadata: bool) { + // MSVC's ICF (Identical COMDAT Folding) link optimization is + // slow for Rust and thus we disable it by default when not in + // optimization build. + if self.sess.opts.optimize != config::OptLevel::No { + self.cmd.arg("/OPT:REF,ICF"); + } else { + // It is necessary to specify NOICF here, because /OPT:REF + // implies ICF by default. + self.cmd.arg("/OPT:REF,NOICF"); + } + } + + fn link_dylib(&mut self, lib: &str) { + self.cmd.arg(&format!("{}.lib", lib)); + } + + fn link_rust_dylib(&mut self, lib: &str, path: &Path) { + // When producing a dll, the MSVC linker may not actually emit a + // `foo.lib` file if the dll doesn't actually export any symbols, so we + // check to see if the file is there and just omit linking to it if it's + // not present. + let name = format!("{}.dll.lib", lib); + if fs::metadata(&path.join(&name)).is_ok() { + self.cmd.arg(name); + } + } + + fn link_staticlib(&mut self, lib: &str) { + self.cmd.arg(&format!("{}.lib", lib)); + } + + fn position_independent_executable(&mut self) { + // noop + } + + fn no_position_independent_executable(&mut self) { + // noop + } + + fn full_relro(&mut self) { + // noop + } + + fn partial_relro(&mut self) { + // noop + } + + fn no_relro(&mut self) { + // noop + } + + fn no_default_libraries(&mut self) { + // Currently we don't pass the /NODEFAULTLIB flag to the linker on MSVC + // as there's been trouble in the past of linking the C++ standard + // library required by LLVM. This likely needs to happen one day, but + // in general Windows is also a more controlled environment than + // Unix, so it's not necessarily as critical that this be implemented. + // + // Note that there are also some licensing worries about statically + // linking some libraries which require a specific agreement, so it may + // not ever be possible for us to pass this flag. + } + + fn include_path(&mut self, path: &Path) { + let mut arg = OsString::from("/LIBPATH:"); + arg.push(path); + self.cmd.arg(&arg); + } + + fn output_filename(&mut self, path: &Path) { + let mut arg = OsString::from("/OUT:"); + arg.push(path); + self.cmd.arg(&arg); + } + + fn framework_path(&mut self, _path: &Path) { + bug!("frameworks are not supported on windows") + } + fn link_framework(&mut self, _framework: &str) { + bug!("frameworks are not supported on windows") + } + + fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) { + // not supported? + self.link_staticlib(lib); + } + fn link_whole_rlib(&mut self, path: &Path) { + // not supported? + self.link_rlib(path); + } + fn optimize(&mut self) { + // Needs more investigation of `/OPT` arguments + } + + fn pgo_gen(&mut self) { + // Nothing needed here. + } + + fn debuginfo(&mut self) { + // This will cause the Microsoft linker to generate a PDB file + // from the CodeView line tables in the object files. + self.cmd.arg("/DEBUG"); + + // This will cause the Microsoft linker to embed .natvis info into the the PDB file + let sysroot = self.sess.sysroot(); + let natvis_dir_path = sysroot.join("lib\\rustlib\\etc"); + if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) { + // LLVM 5.0.0's lld-link frontend doesn't yet recognize, and chokes + // on, the /NATVIS:... flags. LLVM 6 (or earlier) should at worst ignore + // them, eventually mooting this workaround, per this landed patch: + // https://github.com/llvm-mirror/lld/commit/27b9c4285364d8d76bb43839daa100 + if let Some(ref linker_path) = self.sess.opts.cg.linker { + if let Some(linker_name) = Path::new(&linker_path).file_stem() { + if linker_name.to_str().unwrap().to_lowercase() == "lld-link" { + self.sess.warn("not embedding natvis: lld-link may not support the flag"); + return; + } + } + } + for entry in natvis_dir { + match entry { + Ok(entry) => { + let path = entry.path(); + if path.extension() == Some("natvis".as_ref()) { + let mut arg = OsString::from("/NATVIS:"); + arg.push(path); + self.cmd.arg(arg); + } + }, + Err(err) => { + self.sess.warn(&format!("error enumerating natvis directory: {}", err)); + }, + } + } + } + } + + // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to + // export symbols from a dynamic library. When building a dynamic library, + // however, we're going to want some symbols exported, so this function + // generates a DEF file which lists all the symbols. + // + // The linker will read this `*.def` file and export all the symbols from + // the dynamic library. Note that this is not as simple as just exporting + // all the symbols in the current crate (as specified by `codegen.reachable`) + // but rather we also need to possibly export the symbols of upstream + // crates. Upstream rlibs may be linked statically to this dynamic library, + // in which case they may continue to transitively be used and hence need + // their symbols exported. + fn export_symbols(&mut self, + tmpdir: &Path, + crate_type: CrateType) { + let path = tmpdir.join("lib.def"); + let res = (|| -> io::Result<()> { + let mut f = BufWriter::new(File::create(&path)?); + + // Start off with the standard module name header and then go + // straight to exports. + writeln!(f, "LIBRARY")?; + writeln!(f, "EXPORTS")?; + for symbol in self.info.exports[&crate_type].iter() { + debug!(" _{}", symbol); + writeln!(f, " {}", symbol)?; + } + Ok(()) + })(); + if let Err(e) = res { + self.sess.fatal(&format!("failed to write lib.def file: {}", e)); + } + let mut arg = OsString::from("/DEF:"); + arg.push(path); + self.cmd.arg(&arg); + } + + fn subsystem(&mut self, subsystem: &str) { + // Note that previous passes of the compiler validated this subsystem, + // so we just blindly pass it to the linker. + self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem)); + + // Windows has two subsystems we're interested in right now, the console + // and windows subsystems. These both implicitly have different entry + // points (starting symbols). The console entry point starts with + // `mainCRTStartup` and the windows entry point starts with + // `WinMainCRTStartup`. These entry points, defined in system libraries, + // will then later probe for either `main` or `WinMain`, respectively to + // start the application. + // + // In Rust we just always generate a `main` function so we want control + // to always start there, so we force the entry point on the windows + // subsystem to be `mainCRTStartup` to get everything booted up + // correctly. + // + // For more information see RFC #1665 + if subsystem == "windows" { + self.cmd.arg("/ENTRY:mainCRTStartup"); + } + } + + fn finalize(&mut self) -> Command { + let mut cmd = Command::new(""); + ::std::mem::swap(&mut cmd, &mut self.cmd); + cmd + } + + // MSVC doesn't need group indicators + fn group_start(&mut self) {} + fn group_end(&mut self) {} + + fn cross_lang_lto(&mut self) { + // Do nothing + } +} + +pub struct EmLinker<'a> { + cmd: Command, + sess: &'a Session, + info: &'a LinkerInfo +} + +impl<'a> Linker for EmLinker<'a> { + fn include_path(&mut self, path: &Path) { + self.cmd.arg("-L").arg(path); + } + + fn link_staticlib(&mut self, lib: &str) { + self.cmd.arg("-l").arg(lib); + } + + fn output_filename(&mut self, path: &Path) { + self.cmd.arg("-o").arg(path); + } + + fn add_object(&mut self, path: &Path) { + self.cmd.arg(path); + } + + fn link_dylib(&mut self, lib: &str) { + // Emscripten always links statically + self.link_staticlib(lib); + } + + fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) { + // not supported? + self.link_staticlib(lib); + } + + fn link_whole_rlib(&mut self, lib: &Path) { + // not supported? + self.link_rlib(lib); + } + + fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { + self.link_dylib(lib); + } + + fn link_rlib(&mut self, lib: &Path) { + self.add_object(lib); + } + + fn position_independent_executable(&mut self) { + // noop + } + + fn no_position_independent_executable(&mut self) { + // noop + } + + fn full_relro(&mut self) { + // noop + } + + fn partial_relro(&mut self) { + // noop + } + + fn no_relro(&mut self) { + // noop + } + + fn args(&mut self, args: &[String]) { + self.cmd.args(args); + } + + fn framework_path(&mut self, _path: &Path) { + bug!("frameworks are not supported on Emscripten") + } + + fn link_framework(&mut self, _framework: &str) { + bug!("frameworks are not supported on Emscripten") + } + + fn gc_sections(&mut self, _keep_metadata: bool) { + // noop + } + + fn optimize(&mut self) { + // Emscripten performs own optimizations + self.cmd.arg(match self.sess.opts.optimize { + OptLevel::No => "-O0", + OptLevel::Less => "-O1", + OptLevel::Default => "-O2", + OptLevel::Aggressive => "-O3", + OptLevel::Size => "-Os", + OptLevel::SizeMin => "-Oz" + }); + // Unusable until https://github.com/rust-lang/rust/issues/38454 is resolved + self.cmd.args(&["--memory-init-file", "0"]); + } + + fn pgo_gen(&mut self) { + // noop, but maybe we need something like the gnu linker? + } + + fn debuginfo(&mut self) { + // Preserve names or generate source maps depending on debug info + self.cmd.arg(match self.sess.opts.debuginfo { + DebugInfoLevel::NoDebugInfo => "-g0", + DebugInfoLevel::LimitedDebugInfo => "-g3", + DebugInfoLevel::FullDebugInfo => "-g4" + }); + } + + fn no_default_libraries(&mut self) { + self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]); + } + + fn build_dylib(&mut self, _out_filename: &Path) { + bug!("building dynamic library is unsupported on Emscripten") + } + + fn build_static_executable(&mut self) { + // noop + } + + fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) { + let symbols = &self.info.exports[&crate_type]; + + debug!("EXPORTED SYMBOLS:"); + + self.cmd.arg("-s"); + + let mut arg = OsString::from("EXPORTED_FUNCTIONS="); + let mut encoded = String::new(); + + { + let mut encoder = json::Encoder::new(&mut encoded); + let res = encoder.emit_seq(symbols.len(), |encoder| { + for (i, sym) in symbols.iter().enumerate() { + encoder.emit_seq_elt(i, |encoder| { + encoder.emit_str(&("_".to_string() + sym)) + })?; + } + Ok(()) + }); + if let Err(e) = res { + self.sess.fatal(&format!("failed to encode exported symbols: {}", e)); + } + } + debug!("{}", encoded); + arg.push(encoded); + + self.cmd.arg(arg); + } + + fn subsystem(&mut self, _subsystem: &str) { + // noop + } + + fn finalize(&mut self) -> Command { + let mut cmd = Command::new(""); + ::std::mem::swap(&mut cmd, &mut self.cmd); + cmd + } + + // Appears not necessary on Emscripten + fn group_start(&mut self) {} + fn group_end(&mut self) {} + + fn cross_lang_lto(&mut self) { + // Do nothing + } +} + +fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec { + let mut symbols = Vec::new(); + + let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); + for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() { + if level.is_below_threshold(export_threshold) { + symbols.push(symbol.symbol_name(tcx).to_string()); + } + } + + let formats = tcx.sess.dependency_formats.borrow(); + let deps = formats[&crate_type].iter(); + + for (index, dep_format) in deps.enumerate() { + let cnum = CrateNum::new(index + 1); + // For each dependency that we are linking to statically ... + if *dep_format == Linkage::Static { + // ... we add its symbol list to our export list. + for &(symbol, level) in tcx.exported_symbols(cnum).iter() { + if level.is_below_threshold(export_threshold) { + symbols.push(symbol.symbol_name(tcx).to_string()); + } + } + } + } + + symbols +} + +pub struct WasmLd { + cmd: Command, +} + +impl Linker for WasmLd { + fn link_dylib(&mut self, lib: &str) { + self.cmd.arg("-l").arg(lib); + } + + fn link_staticlib(&mut self, lib: &str) { + self.cmd.arg("-l").arg(lib); + } + + fn link_rlib(&mut self, lib: &Path) { + self.cmd.arg(lib); + } + + fn include_path(&mut self, path: &Path) { + self.cmd.arg("-L").arg(path); + } + + fn framework_path(&mut self, _path: &Path) { + panic!("frameworks not supported") + } + + fn output_filename(&mut self, path: &Path) { + self.cmd.arg("-o").arg(path); + } + + fn add_object(&mut self, path: &Path) { + self.cmd.arg(path); + } + + fn position_independent_executable(&mut self) { + } + + fn full_relro(&mut self) { + } + + fn partial_relro(&mut self) { + } + + fn no_relro(&mut self) { + } + + fn build_static_executable(&mut self) { + } + + fn args(&mut self, args: &[String]) { + self.cmd.args(args); + } + + fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { + self.cmd.arg("-l").arg(lib); + } + + fn link_framework(&mut self, _framework: &str) { + panic!("frameworks not supported") + } + + fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) { + self.cmd.arg("-l").arg(lib); + } + + fn link_whole_rlib(&mut self, lib: &Path) { + self.cmd.arg(lib); + } + + fn gc_sections(&mut self, _keep_metadata: bool) { + } + + fn optimize(&mut self) { + } + + fn pgo_gen(&mut self) { + } + + fn debuginfo(&mut self) { + } + + fn no_default_libraries(&mut self) { + } + + fn build_dylib(&mut self, _out_filename: &Path) { + } + + fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) { + } + + fn subsystem(&mut self, _subsystem: &str) { + } + + fn no_position_independent_executable(&mut self) { + } + + fn finalize(&mut self) -> Command { + // There have been reports in the wild (rustwasm/wasm-bindgen#119) of + // using threads causing weird hangs and bugs. Disable it entirely as + // this isn't yet the bottleneck of compilation at all anyway. + self.cmd.arg("--no-threads"); + + self.cmd.arg("-z").arg("stack-size=1048576"); + + // FIXME we probably shouldn't pass this but instead pass an explicit + // whitelist of symbols we'll allow to be undefined. Unfortunately + // though we can't handle symbols like `log10` that LLVM injects at a + // super late date without actually parsing object files. For now let's + // stick to this and hopefully fix it before stabilization happens. + self.cmd.arg("--allow-undefined"); + + // For now we just never have an entry symbol + self.cmd.arg("--no-entry"); + + let mut cmd = Command::new(""); + ::std::mem::swap(&mut cmd, &mut self.cmd); + cmd + } + + // Not needed for now with LLD + fn group_start(&mut self) {} + fn group_end(&mut self) {} + + fn cross_lang_lto(&mut self) { + // Do nothing for now + } +} diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs new file mode 100644 index 00000000000..96eda50d788 --- /dev/null +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -0,0 +1,773 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION}; +use back::symbol_export; +use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext}; +use back::write; +use errors::{FatalError, Handler}; +use llvm::archive_ro::ArchiveRO; +use llvm::{ModuleRef, TargetMachineRef, True, False}; +use llvm; +use rustc::hir::def_id::LOCAL_CRATE; +use rustc::middle::exported_symbols::SymbolExportLevel; +use rustc::session::config::{self, Lto}; +use rustc::util::common::time_ext; +use time_graph::Timeline; +use {ModuleCodegen, ModuleLlvm, ModuleKind, ModuleSource}; + +use libc; + +use std::ffi::CString; +use std::ptr; +use std::slice; +use std::sync::Arc; + +pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool { + match crate_type { + config::CrateTypeExecutable | + config::CrateTypeStaticlib | + config::CrateTypeCdylib => true, + + config::CrateTypeDylib | + config::CrateTypeRlib | + config::CrateTypeProcMacro => false, + } +} + +pub(crate) enum LtoModuleCodegen { + Fat { + module: Option, + _serialized_bitcode: Vec, + }, + + Thin(ThinModule), +} + +impl LtoModuleCodegen { + pub fn name(&self) -> &str { + match *self { + LtoModuleCodegen::Fat { .. } => "everything", + LtoModuleCodegen::Thin(ref m) => m.name(), + } + } + + /// Optimize this module within the given codegen context. + /// + /// This function is unsafe as it'll return a `ModuleCodegen` still + /// points to LLVM data structures owned by this `LtoModuleCodegen`. + /// It's intended that the module returned is immediately code generated and + /// dropped, and then this LTO module is dropped. + pub(crate) unsafe fn optimize(&mut self, + cgcx: &CodegenContext, + timeline: &mut Timeline) + -> Result + { + match *self { + LtoModuleCodegen::Fat { ref mut module, .. } => { + let module = module.take().unwrap(); + let config = cgcx.config(module.kind); + let llmod = module.llvm().unwrap().llmod; + let tm = module.llvm().unwrap().tm; + run_pass_manager(cgcx, tm, llmod, config, false); + timeline.record("fat-done"); + Ok(module) + } + LtoModuleCodegen::Thin(ref mut thin) => thin.optimize(cgcx, timeline), + } + } + + /// A "gauge" of how costly it is to optimize this module, used to sort + /// biggest modules first. + pub fn cost(&self) -> u64 { + match *self { + // Only one module with fat LTO, so the cost doesn't matter. + LtoModuleCodegen::Fat { .. } => 0, + LtoModuleCodegen::Thin(ref m) => m.cost(), + } + } +} + +pub(crate) fn run(cgcx: &CodegenContext, + modules: Vec, + timeline: &mut Timeline) + -> Result, FatalError> +{ + let diag_handler = cgcx.create_diag_handler(); + let export_threshold = match cgcx.lto { + // We're just doing LTO for our one crate + Lto::ThinLocal => SymbolExportLevel::Rust, + + // We're doing LTO for the entire crate graph + Lto::Yes | Lto::Fat | Lto::Thin => { + symbol_export::crates_export_threshold(&cgcx.crate_types) + } + + Lto::No => panic!("didn't request LTO but we're doing LTO"), + }; + + let symbol_filter = &|&(ref name, level): &(String, SymbolExportLevel)| { + if level.is_below_threshold(export_threshold) { + let mut bytes = Vec::with_capacity(name.len() + 1); + bytes.extend(name.bytes()); + Some(CString::new(bytes).unwrap()) + } else { + None + } + }; + let exported_symbols = cgcx.exported_symbols + .as_ref().expect("needs exported symbols for LTO"); + let mut symbol_white_list = exported_symbols[&LOCAL_CRATE] + .iter() + .filter_map(symbol_filter) + .collect::>(); + timeline.record("whitelist"); + info!("{} symbols to preserve in this crate", symbol_white_list.len()); + + // If we're performing LTO for the entire crate graph, then for each of our + // upstream dependencies, find the corresponding rlib and load the bitcode + // from the archive. + // + // We save off all the bytecode and LLVM module ids for later processing + // with either fat or thin LTO + let mut upstream_modules = Vec::new(); + if cgcx.lto != Lto::ThinLocal { + if cgcx.opts.cg.prefer_dynamic { + diag_handler.struct_err("cannot prefer dynamic linking when performing LTO") + .note("only 'staticlib', 'bin', and 'cdylib' outputs are \ + supported with LTO") + .emit(); + return Err(FatalError) + } + + // Make sure we actually can run LTO + for crate_type in cgcx.crate_types.iter() { + if !crate_type_allows_lto(*crate_type) { + let e = diag_handler.fatal("lto can only be run for executables, cdylibs and \ + static library outputs"); + return Err(e) + } + } + + for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() { + let exported_symbols = cgcx.exported_symbols + .as_ref().expect("needs exported symbols for LTO"); + symbol_white_list.extend( + exported_symbols[&cnum] + .iter() + .filter_map(symbol_filter)); + + let archive = ArchiveRO::open(&path).expect("wanted an rlib"); + let bytecodes = archive.iter().filter_map(|child| { + child.ok().and_then(|c| c.name().map(|name| (name, c))) + }).filter(|&(name, _)| name.ends_with(RLIB_BYTECODE_EXTENSION)); + for (name, data) in bytecodes { + info!("adding bytecode {}", name); + let bc_encoded = data.data(); + + let (bc, id) = time_ext(cgcx.time_passes, None, &format!("decode {}", name), || { + match DecodedBytecode::new(bc_encoded) { + Ok(b) => Ok((b.bytecode(), b.identifier().to_string())), + Err(e) => Err(diag_handler.fatal(&e)), + } + })?; + let bc = SerializedModule::FromRlib(bc); + upstream_modules.push((bc, CString::new(id).unwrap())); + } + timeline.record(&format!("load: {}", path.display())); + } + } + + let arr = symbol_white_list.iter().map(|c| c.as_ptr()).collect::>(); + match cgcx.lto { + Lto::Yes | // `-C lto` == fat LTO by default + Lto::Fat => { + fat_lto(cgcx, &diag_handler, modules, upstream_modules, &arr, timeline) + } + Lto::Thin | + Lto::ThinLocal => { + thin_lto(&diag_handler, modules, upstream_modules, &arr, timeline) + } + Lto::No => unreachable!(), + } +} + +fn fat_lto(cgcx: &CodegenContext, + diag_handler: &Handler, + mut modules: Vec, + mut serialized_modules: Vec<(SerializedModule, CString)>, + symbol_white_list: &[*const libc::c_char], + timeline: &mut Timeline) + -> Result, FatalError> +{ + info!("going for a fat lto"); + + // Find the "costliest" module and merge everything into that codegen unit. + // All the other modules will be serialized and reparsed into the new + // context, so this hopefully avoids serializing and parsing the largest + // codegen unit. + // + // Additionally use a regular module as the base here to ensure that various + // file copy operations in the backend work correctly. The only other kind + // of module here should be an allocator one, and if your crate is smaller + // than the allocator module then the size doesn't really matter anyway. + let (_, costliest_module) = modules.iter() + .enumerate() + .filter(|&(_, module)| module.kind == ModuleKind::Regular) + .map(|(i, module)| { + let cost = unsafe { + llvm::LLVMRustModuleCost(module.llvm().unwrap().llmod) + }; + (cost, i) + }) + .max() + .expect("must be codegen'ing at least one module"); + let module = modules.remove(costliest_module); + let llmod = module.llvm().expect("can't lto pre-codegened modules").llmod; + info!("using {:?} as a base module", module.llmod_id); + + // For all other modules we codegened we'll need to link them into our own + // bitcode. All modules were codegened in their own LLVM context, however, + // and we want to move everything to the same LLVM context. Currently the + // way we know of to do that is to serialize them to a string and them parse + // them later. Not great but hey, that's why it's "fat" LTO, right? + for module in modules { + let llvm = module.llvm().expect("can't lto pre-codegened modules"); + let buffer = ModuleBuffer::new(llvm.llmod); + let llmod_id = CString::new(&module.llmod_id[..]).unwrap(); + serialized_modules.push((SerializedModule::Local(buffer), llmod_id)); + } + + // For all serialized bitcode files we parse them and link them in as we did + // above, this is all mostly handled in C++. Like above, though, we don't + // know much about the memory management here so we err on the side of being + // save and persist everything with the original module. + let mut serialized_bitcode = Vec::new(); + let mut linker = Linker::new(llmod); + for (bc_decoded, name) in serialized_modules { + info!("linking {:?}", name); + time_ext(cgcx.time_passes, None, &format!("ll link {:?}", name), || { + let data = bc_decoded.data(); + linker.add(&data).map_err(|()| { + let msg = format!("failed to load bc of {:?}", name); + write::llvm_err(&diag_handler, msg) + }) + })?; + timeline.record(&format!("link {:?}", name)); + serialized_bitcode.push(bc_decoded); + } + drop(linker); + cgcx.save_temp_bitcode(&module, "lto.input"); + + // Internalize everything that *isn't* in our whitelist to help strip out + // more modules and such + unsafe { + let ptr = symbol_white_list.as_ptr(); + llvm::LLVMRustRunRestrictionPass(llmod, + ptr as *const *const libc::c_char, + symbol_white_list.len() as libc::size_t); + cgcx.save_temp_bitcode(&module, "lto.after-restriction"); + } + + if cgcx.no_landing_pads { + unsafe { + llvm::LLVMRustMarkAllFunctionsNounwind(llmod); + } + cgcx.save_temp_bitcode(&module, "lto.after-nounwind"); + } + timeline.record("passes"); + + Ok(vec![LtoModuleCodegen::Fat { + module: Some(module), + _serialized_bitcode: serialized_bitcode, + }]) +} + +struct Linker(llvm::LinkerRef); + +impl Linker { + fn new(llmod: ModuleRef) -> Linker { + unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) } + } + + fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { + unsafe { + if llvm::LLVMRustLinkerAdd(self.0, + bytecode.as_ptr() as *const libc::c_char, + bytecode.len()) { + Ok(()) + } else { + Err(()) + } + } + } +} + +impl Drop for Linker { + fn drop(&mut self) { + unsafe { llvm::LLVMRustLinkerFree(self.0); } + } +} + +/// Prepare "thin" LTO to get run on these modules. +/// +/// The general structure of ThinLTO is quite different from the structure of +/// "fat" LTO above. With "fat" LTO all LLVM modules in question are merged into +/// one giant LLVM module, and then we run more optimization passes over this +/// big module after internalizing most symbols. Thin LTO, on the other hand, +/// avoid this large bottleneck through more targeted optimization. +/// +/// At a high level Thin LTO looks like: +/// +/// 1. Prepare a "summary" of each LLVM module in question which describes +/// the values inside, cost of the values, etc. +/// 2. Merge the summaries of all modules in question into one "index" +/// 3. Perform some global analysis on this index +/// 4. For each module, use the index and analysis calculated previously to +/// perform local transformations on the module, for example inlining +/// small functions from other modules. +/// 5. Run thin-specific optimization passes over each module, and then code +/// generate everything at the end. +/// +/// The summary for each module is intended to be quite cheap, and the global +/// index is relatively quite cheap to create as well. As a result, the goal of +/// ThinLTO is to reduce the bottleneck on LTO and enable LTO to be used in more +/// situations. For example one cheap optimization is that we can parallelize +/// all codegen modules, easily making use of all the cores on a machine. +/// +/// With all that in mind, the function here is designed at specifically just +/// calculating the *index* for ThinLTO. This index will then be shared amongst +/// all of the `LtoModuleCodegen` units returned below and destroyed once +/// they all go out of scope. +fn thin_lto(diag_handler: &Handler, + modules: Vec, + serialized_modules: Vec<(SerializedModule, CString)>, + symbol_white_list: &[*const libc::c_char], + timeline: &mut Timeline) + -> Result, FatalError> +{ + unsafe { + info!("going for that thin, thin LTO"); + + let mut thin_buffers = Vec::new(); + let mut module_names = Vec::new(); + let mut thin_modules = Vec::new(); + + // FIXME: right now, like with fat LTO, we serialize all in-memory + // modules before working with them and ThinLTO. We really + // shouldn't do this, however, and instead figure out how to + // extract a summary from an in-memory module and then merge that + // into the global index. It turns out that this loop is by far + // the most expensive portion of this small bit of global + // analysis! + for (i, module) in modules.iter().enumerate() { + info!("local module: {} - {}", i, module.llmod_id); + let llvm = module.llvm().expect("can't lto precodegened module"); + let name = CString::new(module.llmod_id.clone()).unwrap(); + let buffer = ThinBuffer::new(llvm.llmod); + thin_modules.push(llvm::ThinLTOModule { + identifier: name.as_ptr(), + data: buffer.data().as_ptr(), + len: buffer.data().len(), + }); + thin_buffers.push(buffer); + module_names.push(name); + timeline.record(&module.llmod_id); + } + + // FIXME: All upstream crates are deserialized internally in the + // function below to extract their summary and modules. Note that + // unlike the loop above we *must* decode and/or read something + // here as these are all just serialized files on disk. An + // improvement, however, to make here would be to store the + // module summary separately from the actual module itself. Right + // now this is store in one large bitcode file, and the entire + // file is deflate-compressed. We could try to bypass some of the + // decompression by storing the index uncompressed and only + // lazily decompressing the bytecode if necessary. + // + // Note that truly taking advantage of this optimization will + // likely be further down the road. We'd have to implement + // incremental ThinLTO first where we could actually avoid + // looking at upstream modules entirely sometimes (the contents, + // we must always unconditionally look at the index). + let mut serialized = Vec::new(); + for (module, name) in serialized_modules { + info!("foreign module {:?}", name); + thin_modules.push(llvm::ThinLTOModule { + identifier: name.as_ptr(), + data: module.data().as_ptr(), + len: module.data().len(), + }); + serialized.push(module); + module_names.push(name); + } + + // Delegate to the C++ bindings to create some data here. Once this is a + // tried-and-true interface we may wish to try to upstream some of this + // to LLVM itself, right now we reimplement a lot of what they do + // upstream... + let data = llvm::LLVMRustCreateThinLTOData( + thin_modules.as_ptr(), + thin_modules.len() as u32, + symbol_white_list.as_ptr(), + symbol_white_list.len() as u32, + ); + if data.is_null() { + let msg = format!("failed to prepare thin LTO context"); + return Err(write::llvm_err(&diag_handler, msg)) + } + let data = ThinData(data); + info!("thin LTO data created"); + timeline.record("data"); + + // Throw our data in an `Arc` as we'll be sharing it across threads. We + // also put all memory referenced by the C++ data (buffers, ids, etc) + // into the arc as well. After this we'll create a thin module + // codegen per module in this data. + let shared = Arc::new(ThinShared { + data, + thin_buffers, + serialized_modules: serialized, + module_names, + }); + Ok((0..shared.module_names.len()).map(|i| { + LtoModuleCodegen::Thin(ThinModule { + shared: shared.clone(), + idx: i, + }) + }).collect()) + } +} + +fn run_pass_manager(cgcx: &CodegenContext, + tm: TargetMachineRef, + llmod: ModuleRef, + config: &ModuleConfig, + thin: bool) { + // Now we have one massive module inside of llmod. Time to run the + // LTO-specific optimization passes that LLVM provides. + // + // This code is based off the code found in llvm's LTO code generator: + // tools/lto/LTOCodeGenerator.cpp + debug!("running the pass manager"); + unsafe { + let pm = llvm::LLVMCreatePassManager(); + llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod); + let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _); + assert!(!pass.is_null()); + llvm::LLVMRustAddPass(pm, pass); + + // When optimizing for LTO we don't actually pass in `-O0`, but we force + // it to always happen at least with `-O1`. + // + // With ThinLTO we mess around a lot with symbol visibility in a way + // that will actually cause linking failures if we optimize at O0 which + // notable is lacking in dead code elimination. To ensure we at least + // get some optimizations and correctly link we forcibly switch to `-O1` + // to get dead code elimination. + // + // Note that in general this shouldn't matter too much as you typically + // only turn on ThinLTO when you're compiling with optimizations + // otherwise. + let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None); + let opt_level = match opt_level { + llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less, + level => level, + }; + with_llvm_pmb(llmod, config, opt_level, false, &mut |b| { + if thin { + if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) { + panic!("this version of LLVM does not support ThinLTO"); + } + } else { + llvm::LLVMPassManagerBuilderPopulateLTOPassManager(b, pm, + /* Internalize = */ False, + /* RunInliner = */ True); + } + }); + + let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _); + assert!(!pass.is_null()); + llvm::LLVMRustAddPass(pm, pass); + + time_ext(cgcx.time_passes, None, "LTO passes", || + llvm::LLVMRunPassManager(pm, llmod)); + + llvm::LLVMDisposePassManager(pm); + } + debug!("lto done"); +} + +pub enum SerializedModule { + Local(ModuleBuffer), + FromRlib(Vec), +} + +impl SerializedModule { + fn data(&self) -> &[u8] { + match *self { + SerializedModule::Local(ref m) => m.data(), + SerializedModule::FromRlib(ref m) => m, + } + } +} + +pub struct ModuleBuffer(*mut llvm::ModuleBuffer); + +unsafe impl Send for ModuleBuffer {} +unsafe impl Sync for ModuleBuffer {} + +impl ModuleBuffer { + pub fn new(m: ModuleRef) -> ModuleBuffer { + ModuleBuffer(unsafe { + llvm::LLVMRustModuleBufferCreate(m) + }) + } + + pub fn data(&self) -> &[u8] { + unsafe { + let ptr = llvm::LLVMRustModuleBufferPtr(self.0); + let len = llvm::LLVMRustModuleBufferLen(self.0); + slice::from_raw_parts(ptr, len) + } + } +} + +impl Drop for ModuleBuffer { + fn drop(&mut self) { + unsafe { llvm::LLVMRustModuleBufferFree(self.0); } + } +} + +pub struct ThinModule { + shared: Arc, + idx: usize, +} + +struct ThinShared { + data: ThinData, + thin_buffers: Vec, + serialized_modules: Vec, + module_names: Vec, +} + +struct ThinData(*mut llvm::ThinLTOData); + +unsafe impl Send for ThinData {} +unsafe impl Sync for ThinData {} + +impl Drop for ThinData { + fn drop(&mut self) { + unsafe { + llvm::LLVMRustFreeThinLTOData(self.0); + } + } +} + +pub struct ThinBuffer(*mut llvm::ThinLTOBuffer); + +unsafe impl Send for ThinBuffer {} +unsafe impl Sync for ThinBuffer {} + +impl ThinBuffer { + pub fn new(m: ModuleRef) -> ThinBuffer { + unsafe { + let buffer = llvm::LLVMRustThinLTOBufferCreate(m); + ThinBuffer(buffer) + } + } + + pub fn data(&self) -> &[u8] { + unsafe { + let ptr = llvm::LLVMRustThinLTOBufferPtr(self.0) as *const _; + let len = llvm::LLVMRustThinLTOBufferLen(self.0); + slice::from_raw_parts(ptr, len) + } + } +} + +impl Drop for ThinBuffer { + fn drop(&mut self) { + unsafe { + llvm::LLVMRustThinLTOBufferFree(self.0); + } + } +} + +impl ThinModule { + fn name(&self) -> &str { + self.shared.module_names[self.idx].to_str().unwrap() + } + + fn cost(&self) -> u64 { + // Yes, that's correct, we're using the size of the bytecode as an + // indicator for how costly this codegen unit is. + self.data().len() as u64 + } + + fn data(&self) -> &[u8] { + let a = self.shared.thin_buffers.get(self.idx).map(|b| b.data()); + a.unwrap_or_else(|| { + let len = self.shared.thin_buffers.len(); + self.shared.serialized_modules[self.idx - len].data() + }) + } + + unsafe fn optimize(&mut self, cgcx: &CodegenContext, timeline: &mut Timeline) + -> Result + { + let diag_handler = cgcx.create_diag_handler(); + let tm = (cgcx.tm_factory)().map_err(|e| { + write::llvm_err(&diag_handler, e) + })?; + + // Right now the implementation we've got only works over serialized + // modules, so we create a fresh new LLVM context and parse the module + // into that context. One day, however, we may do this for upstream + // crates but for locally codegened modules we may be able to reuse + // that LLVM Context and Module. + let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); + let llmod = llvm::LLVMRustParseBitcodeForThinLTO( + llcx, + self.data().as_ptr(), + self.data().len(), + self.shared.module_names[self.idx].as_ptr(), + ); + if llmod.is_null() { + let msg = format!("failed to parse bitcode for thin LTO module"); + return Err(write::llvm_err(&diag_handler, msg)); + } + let module = ModuleCodegen { + source: ModuleSource::Codegened(ModuleLlvm { + llmod, + llcx, + tm, + }), + llmod_id: self.name().to_string(), + name: self.name().to_string(), + kind: ModuleKind::Regular, + }; + cgcx.save_temp_bitcode(&module, "thin-lto-input"); + + // Before we do much else find the "main" `DICompileUnit` that we'll be + // using below. If we find more than one though then rustc has changed + // in a way we're not ready for, so generate an ICE by returning + // an error. + let mut cu1 = ptr::null_mut(); + let mut cu2 = ptr::null_mut(); + llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2); + if !cu2.is_null() { + let msg = format!("multiple source DICompileUnits found"); + return Err(write::llvm_err(&diag_handler, msg)) + } + + // Like with "fat" LTO, get some better optimizations if landing pads + // are disabled by removing all landing pads. + if cgcx.no_landing_pads { + llvm::LLVMRustMarkAllFunctionsNounwind(llmod); + cgcx.save_temp_bitcode(&module, "thin-lto-after-nounwind"); + timeline.record("nounwind"); + } + + // Up next comes the per-module local analyses that we do for Thin LTO. + // Each of these functions is basically copied from the LLVM + // implementation and then tailored to suit this implementation. Ideally + // each of these would be supported by upstream LLVM but that's perhaps + // a patch for another day! + // + // You can find some more comments about these functions in the LLVM + // bindings we've got (currently `PassWrapper.cpp`) + if !llvm::LLVMRustPrepareThinLTORename(self.shared.data.0, llmod) { + let msg = format!("failed to prepare thin LTO module"); + return Err(write::llvm_err(&diag_handler, msg)) + } + cgcx.save_temp_bitcode(&module, "thin-lto-after-rename"); + timeline.record("rename"); + if !llvm::LLVMRustPrepareThinLTOResolveWeak(self.shared.data.0, llmod) { + let msg = format!("failed to prepare thin LTO module"); + return Err(write::llvm_err(&diag_handler, msg)) + } + cgcx.save_temp_bitcode(&module, "thin-lto-after-resolve"); + timeline.record("resolve"); + if !llvm::LLVMRustPrepareThinLTOInternalize(self.shared.data.0, llmod) { + let msg = format!("failed to prepare thin LTO module"); + return Err(write::llvm_err(&diag_handler, msg)) + } + cgcx.save_temp_bitcode(&module, "thin-lto-after-internalize"); + timeline.record("internalize"); + if !llvm::LLVMRustPrepareThinLTOImport(self.shared.data.0, llmod) { + let msg = format!("failed to prepare thin LTO module"); + return Err(write::llvm_err(&diag_handler, msg)) + } + cgcx.save_temp_bitcode(&module, "thin-lto-after-import"); + timeline.record("import"); + + // Ok now this is a bit unfortunate. This is also something you won't + // find upstream in LLVM's ThinLTO passes! This is a hack for now to + // work around bugs in LLVM. + // + // First discovered in #45511 it was found that as part of ThinLTO + // importing passes LLVM will import `DICompileUnit` metadata + // information across modules. This means that we'll be working with one + // LLVM module that has multiple `DICompileUnit` instances in it (a + // bunch of `llvm.dbg.cu` members). Unfortunately there's a number of + // bugs in LLVM's backend which generates invalid DWARF in a situation + // like this: + // + // https://bugs.llvm.org/show_bug.cgi?id=35212 + // https://bugs.llvm.org/show_bug.cgi?id=35562 + // + // While the first bug there is fixed the second ended up causing #46346 + // which was basically a resurgence of #45511 after LLVM's bug 35212 was + // fixed. + // + // This function below is a huge hack around this problem. The function + // below is defined in `PassWrapper.cpp` and will basically "merge" + // all `DICompileUnit` instances in a module. Basically it'll take all + // the objects, rewrite all pointers of `DISubprogram` to point to the + // first `DICompileUnit`, and then delete all the other units. + // + // This is probably mangling to the debug info slightly (but hopefully + // not too much) but for now at least gets LLVM to emit valid DWARF (or + // so it appears). Hopefully we can remove this once upstream bugs are + // fixed in LLVM. + llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1); + cgcx.save_temp_bitcode(&module, "thin-lto-after-patch"); + timeline.record("patch"); + + // Alright now that we've done everything related to the ThinLTO + // analysis it's time to run some optimizations! Here we use the same + // `run_pass_manager` as the "fat" LTO above except that we tell it to + // populate a thin-specific pass manager, which presumably LLVM treats a + // little differently. + info!("running thin lto passes over {}", module.name); + let config = cgcx.config(module.kind); + run_pass_manager(cgcx, tm, llmod, config, true); + cgcx.save_temp_bitcode(&module, "thin-lto-after-pm"); + timeline.record("thin-done"); + + // FIXME: this is a hack around a bug in LLVM right now. Discovered in + // #46910 it was found out that on 32-bit MSVC LLVM will hit a codegen + // error if there's an available_externally function in the LLVM module. + // Typically we don't actually use these functions but ThinLTO makes + // heavy use of them when inlining across modules. + // + // Tracked upstream at https://bugs.llvm.org/show_bug.cgi?id=35736 this + // function call (and its definition on the C++ side of things) + // shouldn't be necessary eventually and we can safetly delete these few + // lines. + llvm::LLVMRustThinLTORemoveAvailableExternally(llmod); + cgcx.save_temp_bitcode(&module, "thin-lto-after-rm-ae"); + timeline.record("no-ae"); + + Ok(module) + } +} diff --git a/src/librustc_codegen_llvm/back/rpath.rs b/src/librustc_codegen_llvm/back/rpath.rs new file mode 100644 index 00000000000..8e5e7d37648 --- /dev/null +++ b/src/librustc_codegen_llvm/back/rpath.rs @@ -0,0 +1,282 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::HashSet; +use std::env; +use std::path::{Path, PathBuf}; +use std::fs; + +use rustc::hir::def_id::CrateNum; +use rustc::middle::cstore::LibSource; + +pub struct RPathConfig<'a> { + pub used_crates: &'a [(CrateNum, LibSource)], + pub out_filename: PathBuf, + pub is_like_osx: bool, + pub has_rpath: bool, + pub linker_is_gnu: bool, + pub get_install_prefix_lib_path: &'a mut FnMut() -> PathBuf, +} + +pub fn get_rpath_flags(config: &mut RPathConfig) -> Vec { + // No rpath on windows + if !config.has_rpath { + return Vec::new(); + } + + let mut flags = Vec::new(); + + debug!("preparing the RPATH!"); + + let libs = config.used_crates.clone(); + let libs = libs.iter().filter_map(|&(_, ref l)| l.option()).collect::>(); + let rpaths = get_rpaths(config, &libs); + flags.extend_from_slice(&rpaths_to_flags(&rpaths)); + + // Use DT_RUNPATH instead of DT_RPATH if available + if config.linker_is_gnu { + flags.push("-Wl,--enable-new-dtags".to_string()); + } + + flags +} + +fn rpaths_to_flags(rpaths: &[String]) -> Vec { + let mut ret = Vec::new(); + for rpath in rpaths { + if rpath.contains(',') { + ret.push("-Wl,-rpath".into()); + ret.push("-Xlinker".into()); + ret.push(rpath.clone()); + } else { + ret.push(format!("-Wl,-rpath,{}", &(*rpath))); + } + } + return ret; +} + +fn get_rpaths(config: &mut RPathConfig, libs: &[PathBuf]) -> Vec { + debug!("output: {:?}", config.out_filename.display()); + debug!("libs:"); + for libpath in libs { + debug!(" {:?}", libpath.display()); + } + + // Use relative paths to the libraries. Binaries can be moved + // as long as they maintain the relative relationship to the + // crates they depend on. + let rel_rpaths = get_rpaths_relative_to_output(config, libs); + + // And a final backup rpath to the global library location. + let fallback_rpaths = vec![get_install_prefix_rpath(config)]; + + fn log_rpaths(desc: &str, rpaths: &[String]) { + debug!("{} rpaths:", desc); + for rpath in rpaths { + debug!(" {}", *rpath); + } + } + + log_rpaths("relative", &rel_rpaths); + log_rpaths("fallback", &fallback_rpaths); + + let mut rpaths = rel_rpaths; + rpaths.extend_from_slice(&fallback_rpaths); + + // Remove duplicates + let rpaths = minimize_rpaths(&rpaths); + return rpaths; +} + +fn get_rpaths_relative_to_output(config: &mut RPathConfig, + libs: &[PathBuf]) -> Vec { + libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect() +} + +fn get_rpath_relative_to_output(config: &mut RPathConfig, lib: &Path) -> String { + // Mac doesn't appear to support $ORIGIN + let prefix = if config.is_like_osx { + "@loader_path" + } else { + "$ORIGIN" + }; + + let cwd = env::current_dir().unwrap(); + let mut lib = fs::canonicalize(&cwd.join(lib)).unwrap_or(cwd.join(lib)); + lib.pop(); + let mut output = cwd.join(&config.out_filename); + output.pop(); + let output = fs::canonicalize(&output).unwrap_or(output); + let relative = path_relative_from(&lib, &output) + .expect(&format!("couldn't create relative path from {:?} to {:?}", output, lib)); + // FIXME (#9639): This needs to handle non-utf8 paths + format!("{}/{}", prefix, + relative.to_str().expect("non-utf8 component in path")) +} + +// This routine is adapted from the *old* Path's `path_relative_from` +// function, which works differently from the new `relative_from` function. +// In particular, this handles the case on unix where both paths are +// absolute but with only the root as the common directory. +fn path_relative_from(path: &Path, base: &Path) -> Option { + use std::path::Component; + + if path.is_absolute() != base.is_absolute() { + if path.is_absolute() { + Some(PathBuf::from(path)) + } else { + None + } + } else { + let mut ita = path.components(); + let mut itb = base.components(); + let mut comps: Vec = vec![]; + loop { + match (ita.next(), itb.next()) { + (None, None) => break, + (Some(a), None) => { + comps.push(a); + comps.extend(ita.by_ref()); + break; + } + (None, _) => comps.push(Component::ParentDir), + (Some(a), Some(b)) if comps.is_empty() && a == b => (), + (Some(a), Some(b)) if b == Component::CurDir => comps.push(a), + (Some(_), Some(b)) if b == Component::ParentDir => return None, + (Some(a), Some(_)) => { + comps.push(Component::ParentDir); + for _ in itb { + comps.push(Component::ParentDir); + } + comps.push(a); + comps.extend(ita.by_ref()); + break; + } + } + } + Some(comps.iter().map(|c| c.as_os_str()).collect()) + } +} + + +fn get_install_prefix_rpath(config: &mut RPathConfig) -> String { + let path = (config.get_install_prefix_lib_path)(); + let path = env::current_dir().unwrap().join(&path); + // FIXME (#9639): This needs to handle non-utf8 paths + path.to_str().expect("non-utf8 component in rpath").to_string() +} + +fn minimize_rpaths(rpaths: &[String]) -> Vec { + let mut set = HashSet::new(); + let mut minimized = Vec::new(); + for rpath in rpaths { + if set.insert(rpath) { + minimized.push(rpath.clone()); + } + } + minimized +} + +#[cfg(all(unix, test))] +mod tests { + use super::{RPathConfig}; + use super::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output}; + use std::path::{Path, PathBuf}; + + #[test] + fn test_rpaths_to_flags() { + let flags = rpaths_to_flags(&[ + "path1".to_string(), + "path2".to_string() + ]); + assert_eq!(flags, + ["-Wl,-rpath,path1", + "-Wl,-rpath,path2"]); + } + + #[test] + fn test_minimize1() { + let res = minimize_rpaths(&[ + "rpath1".to_string(), + "rpath2".to_string(), + "rpath1".to_string() + ]); + assert!(res == [ + "rpath1", + "rpath2", + ]); + } + + #[test] + fn test_minimize2() { + let res = minimize_rpaths(&[ + "1a".to_string(), + "2".to_string(), + "2".to_string(), + "1a".to_string(), + "4a".to_string(), + "1a".to_string(), + "2".to_string(), + "3".to_string(), + "4a".to_string(), + "3".to_string() + ]); + assert!(res == [ + "1a", + "2", + "4a", + "3", + ]); + } + + #[test] + fn test_rpath_relative() { + if cfg!(target_os = "macos") { + let config = &mut RPathConfig { + used_crates: Vec::new(), + has_rpath: true, + is_like_osx: true, + linker_is_gnu: false, + out_filename: PathBuf::from("bin/rustc"), + get_install_prefix_lib_path: &mut || panic!(), + }; + let res = get_rpath_relative_to_output(config, + Path::new("lib/libstd.so")); + assert_eq!(res, "@loader_path/../lib"); + } else { + let config = &mut RPathConfig { + used_crates: Vec::new(), + out_filename: PathBuf::from("bin/rustc"), + get_install_prefix_lib_path: &mut || panic!(), + has_rpath: true, + is_like_osx: false, + linker_is_gnu: true, + }; + let res = get_rpath_relative_to_output(config, + Path::new("lib/libstd.so")); + assert_eq!(res, "$ORIGIN/../lib"); + } + } + + #[test] + fn test_xlinker() { + let args = rpaths_to_flags(&[ + "a/normal/path".to_string(), + "a,comma,path".to_string() + ]); + + assert_eq!(args, vec![ + "-Wl,-rpath,a/normal/path".to_string(), + "-Wl,-rpath".to_string(), + "-Xlinker".to_string(), + "a,comma,path".to_string() + ]); + } +} diff --git a/src/librustc_codegen_llvm/back/symbol_export.rs b/src/librustc_codegen_llvm/back/symbol_export.rs new file mode 100644 index 00000000000..81ac684aee2 --- /dev/null +++ b/src/librustc_codegen_llvm/back/symbol_export.rs @@ -0,0 +1,396 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc_data_structures::sync::Lrc; +use std::sync::Arc; + +use monomorphize::Instance; +use rustc::hir; +use rustc::hir::CodegenFnAttrFlags; +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; +use rustc::ich::Fingerprint; +use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name}; +use rustc::session::config; +use rustc::ty::{TyCtxt, SymbolName}; +use rustc::ty::maps::Providers; +use rustc::ty::subst::Substs; +use rustc::util::nodemap::{FxHashMap, DefIdMap}; +use rustc_allocator::ALLOCATOR_METHODS; +use rustc_data_structures::indexed_vec::IndexVec; +use std::collections::hash_map::Entry::*; + +pub type ExportedSymbols = FxHashMap< + CrateNum, + Arc>, +>; + +pub fn threshold(tcx: TyCtxt) -> SymbolExportLevel { + crates_export_threshold(&tcx.sess.crate_types.borrow()) +} + +fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel { + match crate_type { + config::CrateTypeExecutable | + config::CrateTypeStaticlib | + config::CrateTypeProcMacro | + config::CrateTypeCdylib => SymbolExportLevel::C, + config::CrateTypeRlib | + config::CrateTypeDylib => SymbolExportLevel::Rust, + } +} + +pub fn crates_export_threshold(crate_types: &[config::CrateType]) + -> SymbolExportLevel { + if crate_types.iter().any(|&crate_type| { + crate_export_threshold(crate_type) == SymbolExportLevel::Rust + }) { + SymbolExportLevel::Rust + } else { + SymbolExportLevel::C + } +} + +fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + cnum: CrateNum) + -> Lrc> +{ + assert_eq!(cnum, LOCAL_CRATE); + + if !tcx.sess.opts.output_types.should_codegen() { + return Lrc::new(DefIdMap()) + } + + // Check to see if this crate is a "special runtime crate". These + // crates, implementation details of the standard library, typically + // have a bunch of `pub extern` and `#[no_mangle]` functions as the + // ABI between them. We don't want their symbols to have a `C` + // export level, however, as they're just implementation details. + // Down below we'll hardwire all of the symbols to the `Rust` export + // level instead. + let special_runtime_crate = tcx.is_panic_runtime(LOCAL_CRATE) || + tcx.is_compiler_builtins(LOCAL_CRATE); + + let mut reachable_non_generics: DefIdMap<_> = tcx.reachable_set(LOCAL_CRATE).0 + .iter() + .filter_map(|&node_id| { + // We want to ignore some FFI functions that are not exposed from + // this crate. Reachable FFI functions can be lumped into two + // categories: + // + // 1. Those that are included statically via a static library + // 2. Those included otherwise (e.g. dynamically or via a framework) + // + // Although our LLVM module is not literally emitting code for the + // statically included symbols, it's an export of our library which + // needs to be passed on to the linker and encoded in the metadata. + // + // As a result, if this id is an FFI item (foreign item) then we only + // let it through if it's included statically. + match tcx.hir.get(node_id) { + hir::map::NodeForeignItem(..) => { + let def_id = tcx.hir.local_def_id(node_id); + if tcx.is_statically_included_foreign_item(def_id) { + Some(def_id) + } else { + None + } + } + + // Only consider nodes that actually have exported symbols. + hir::map::NodeItem(&hir::Item { + node: hir::ItemStatic(..), + .. + }) | + hir::map::NodeItem(&hir::Item { + node: hir::ItemFn(..), .. + }) | + hir::map::NodeImplItem(&hir::ImplItem { + node: hir::ImplItemKind::Method(..), + .. + }) => { + let def_id = tcx.hir.local_def_id(node_id); + let generics = tcx.generics_of(def_id); + if !generics.requires_monomorphization(tcx) && + // Functions marked with #[inline] are only ever codegened + // with "internal" linkage and are never exported. + !Instance::mono(tcx, def_id).def.requires_local(tcx) { + Some(def_id) + } else { + None + } + } + + _ => None + } + }) + .map(|def_id| { + let export_level = if special_runtime_crate { + let name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str(); + // We can probably do better here by just ensuring that + // it has hidden visibility rather than public + // visibility, as this is primarily here to ensure it's + // not stripped during LTO. + // + // In general though we won't link right if these + // symbols are stripped, and LTO currently strips them. + if &*name == "rust_eh_personality" || + &*name == "rust_eh_register_frames" || + &*name == "rust_eh_unregister_frames" { + SymbolExportLevel::C + } else { + SymbolExportLevel::Rust + } + } else { + symbol_export_level(tcx, def_id) + }; + debug!("EXPORTED SYMBOL (local): {} ({:?})", + tcx.symbol_name(Instance::mono(tcx, def_id)), + export_level); + (def_id, export_level) + }) + .collect(); + + if let Some(id) = *tcx.sess.derive_registrar_fn.get() { + let def_id = tcx.hir.local_def_id(id); + reachable_non_generics.insert(def_id, SymbolExportLevel::C); + } + + if let Some(id) = *tcx.sess.plugin_registrar_fn.get() { + let def_id = tcx.hir.local_def_id(id); + reachable_non_generics.insert(def_id, SymbolExportLevel::C); + } + + Lrc::new(reachable_non_generics) +} + +fn is_reachable_non_generic_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> bool { + let export_threshold = threshold(tcx); + + if let Some(&level) = tcx.reachable_non_generics(def_id.krate).get(&def_id) { + level.is_below_threshold(export_threshold) + } else { + false + } +} + +fn is_reachable_non_generic_provider_extern<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> bool { + tcx.reachable_non_generics(def_id.krate).contains_key(&def_id) +} + +fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + cnum: CrateNum) + -> Arc, + SymbolExportLevel)>> +{ + assert_eq!(cnum, LOCAL_CRATE); + + if !tcx.sess.opts.output_types.should_codegen() { + return Arc::new(vec![]) + } + + let mut symbols: Vec<_> = tcx.reachable_non_generics(LOCAL_CRATE) + .iter() + .map(|(&def_id, &level)| { + (ExportedSymbol::NonGeneric(def_id), level) + }) + .collect(); + + if let Some(_) = *tcx.sess.entry_fn.borrow() { + let symbol_name = "main".to_string(); + let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name)); + + symbols.push((exported_symbol, SymbolExportLevel::C)); + } + + if tcx.sess.allocator_kind.get().is_some() { + for method in ALLOCATOR_METHODS { + let symbol_name = format!("__rust_{}", method.name); + let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name)); + + symbols.push((exported_symbol, SymbolExportLevel::Rust)); + } + } + + if tcx.sess.opts.debugging_opts.pgo_gen.is_some() { + // These are weak symbols that point to the profile version and the + // profile name, which need to be treated as exported so LTO doesn't nix + // them. + const PROFILER_WEAK_SYMBOLS: [&'static str; 2] = [ + "__llvm_profile_raw_version", + "__llvm_profile_filename", + ]; + for sym in &PROFILER_WEAK_SYMBOLS { + let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(sym)); + symbols.push((exported_symbol, SymbolExportLevel::C)); + } + } + + if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) { + let symbol_name = metadata_symbol_name(tcx); + let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name)); + + symbols.push((exported_symbol, SymbolExportLevel::Rust)); + } + + if tcx.share_generics() && tcx.local_crate_exports_generics() { + use rustc::mir::mono::{Linkage, Visibility, MonoItem}; + use rustc::ty::InstanceDef; + + // Normally, we require that shared monomorphizations are not hidden, + // because if we want to re-use a monomorphization from a Rust dylib, it + // needs to be exported. + // However, on platforms that don't allow for Rust dylibs, having + // external linkage is enough for monomorphization to be linked to. + let need_visibility = tcx.sess.target.target.options.dynamic_linking && + !tcx.sess.target.target.options.only_cdylib; + + let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); + + for (mono_item, &(linkage, visibility)) in cgus.iter() + .flat_map(|cgu| cgu.items().iter()) { + if linkage != Linkage::External { + // We can only re-use things with external linkage, otherwise + // we'll get a linker error + continue + } + + if need_visibility && visibility == Visibility::Hidden { + // If we potentially share things from Rust dylibs, they must + // not be hidden + continue + } + + if let &MonoItem::Fn(Instance { + def: InstanceDef::Item(def_id), + substs, + }) = mono_item { + if substs.types().next().is_some() { + symbols.push((ExportedSymbol::Generic(def_id, substs), + SymbolExportLevel::Rust)); + } + } + } + } + + // Sort so we get a stable incr. comp. hash. + symbols.sort_unstable_by(|&(ref symbol1, ..), &(ref symbol2, ..)| { + symbol1.compare_stable(tcx, symbol2) + }); + + Arc::new(symbols) +} + +fn upstream_monomorphizations_provider<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + cnum: CrateNum) + -> Lrc, CrateNum>>>> +{ + debug_assert!(cnum == LOCAL_CRATE); + + let cnums = tcx.all_crate_nums(LOCAL_CRATE); + + let mut instances = DefIdMap(); + + let cnum_stable_ids: IndexVec = { + let mut cnum_stable_ids = IndexVec::from_elem_n(Fingerprint::ZERO, + cnums.len() + 1); + + for &cnum in cnums.iter() { + cnum_stable_ids[cnum] = tcx.def_path_hash(DefId { + krate: cnum, + index: CRATE_DEF_INDEX, + }).0; + } + + cnum_stable_ids + }; + + for &cnum in cnums.iter() { + for &(ref exported_symbol, _) in tcx.exported_symbols(cnum).iter() { + if let &ExportedSymbol::Generic(def_id, substs) = exported_symbol { + let substs_map = instances.entry(def_id) + .or_insert_with(|| FxHashMap()); + + match substs_map.entry(substs) { + Occupied(mut e) => { + // If there are multiple monomorphizations available, + // we select one deterministically. + let other_cnum = *e.get(); + if cnum_stable_ids[other_cnum] > cnum_stable_ids[cnum] { + e.insert(cnum); + } + } + Vacant(e) => { + e.insert(cnum); + } + } + } + } + } + + Lrc::new(instances.into_iter() + .map(|(key, value)| (key, Lrc::new(value))) + .collect()) +} + +fn upstream_monomorphizations_for_provider<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> Option, CrateNum>>> +{ + debug_assert!(!def_id.is_local()); + tcx.upstream_monomorphizations(LOCAL_CRATE) + .get(&def_id) + .cloned() +} + +fn is_unreachable_local_definition_provider(tcx: TyCtxt, def_id: DefId) -> bool { + if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { + !tcx.reachable_set(LOCAL_CRATE).0.contains(&node_id) + } else { + bug!("is_unreachable_local_definition called with non-local DefId: {:?}", + def_id) + } +} + +pub fn provide(providers: &mut Providers) { + providers.reachable_non_generics = reachable_non_generics_provider; + providers.is_reachable_non_generic = is_reachable_non_generic_provider_local; + providers.exported_symbols = exported_symbols_provider_local; + providers.upstream_monomorphizations = upstream_monomorphizations_provider; + providers.is_unreachable_local_definition = is_unreachable_local_definition_provider; +} + +pub fn provide_extern(providers: &mut Providers) { + providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern; + providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider; +} + +fn symbol_export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel { + // We export anything that's not mangled at the "C" layer as it probably has + // to do with ABI concerns. We do not, however, apply such treatment to + // special symbols in the standard library for various plumbing between + // core/std/allocators/etc. For example symbols used to hook up allocation + // are not considered for export + let codegen_fn_attrs = tcx.codegen_fn_attrs(sym_def_id); + let is_extern = codegen_fn_attrs.contains_extern_indicator(); + let std_internal = + codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); + + if is_extern && !std_internal { + SymbolExportLevel::C + } else { + SymbolExportLevel::Rust + } +} diff --git a/src/librustc_codegen_llvm/back/wasm.rs b/src/librustc_codegen_llvm/back/wasm.rs new file mode 100644 index 00000000000..d6d386c9fbe --- /dev/null +++ b/src/librustc_codegen_llvm/back/wasm.rs @@ -0,0 +1,261 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::BTreeMap; +use std::fs; +use std::path::Path; +use std::str; + +use rustc_data_structures::fx::FxHashMap; +use serialize::leb128; + +// https://webassembly.github.io/spec/core/binary/modules.html#binary-importsec +const WASM_IMPORT_SECTION_ID: u8 = 2; + +const WASM_EXTERNAL_KIND_FUNCTION: u8 = 0; +const WASM_EXTERNAL_KIND_TABLE: u8 = 1; +const WASM_EXTERNAL_KIND_MEMORY: u8 = 2; +const WASM_EXTERNAL_KIND_GLOBAL: u8 = 3; + +/// Append all the custom sections listed in `sections` to the wasm binary +/// specified at `path`. +/// +/// LLVM 6 which we're using right now doesn't have the ability to create custom +/// sections in wasm files nor does LLD have the ability to merge these sections +/// into one larger section when linking. It's expected that this will +/// eventually get implemented, however! +/// +/// Until that time though this is a custom implementation in rustc to append +/// all sections to a wasm file to the finished product that LLD produces. +/// +/// Support for this is landing in LLVM in https://reviews.llvm.org/D43097, +/// although after that support will need to be in LLD as well. +pub fn add_custom_sections(path: &Path, sections: &BTreeMap>) { + if sections.len() == 0 { + return + } + + let wasm = fs::read(path).expect("failed to read wasm output"); + + // see https://webassembly.github.io/spec/core/binary/modules.html#custom-section + let mut wasm = WasmEncoder { data: wasm }; + for (section, bytes) in sections { + // write the `id` identifier, 0 for a custom section + wasm.byte(0); + + // figure out how long our name descriptor will be + let mut name = WasmEncoder::new(); + name.str(section); + + // write the length of the payload followed by all its contents + wasm.u32((bytes.len() + name.data.len()) as u32); + wasm.data.extend_from_slice(&name.data); + wasm.data.extend_from_slice(bytes); + } + + fs::write(path, &wasm.data).expect("failed to write wasm output"); +} + +/// Rewrite the module imports are listed from in a wasm module given the field +/// name to module name mapping in `import_map`. +/// +/// LLVM 6 which we're using right now doesn't have the ability to configure the +/// module a wasm symbol is import from. Rather all imported symbols come from +/// the bland `"env"` module unconditionally. Furthermore we'd *also* need +/// support in LLD for preserving these import modules, which it unfortunately +/// currently does not. +/// +/// This function is intended as a hack for now where we manually rewrite the +/// wasm output by LLVM to have the correct import modules listed. The +/// `#[wasm_import_module]` attribute in Rust translates to the module that each +/// symbol is imported from, so here we manually go through the wasm file, +/// decode it, rewrite imports, and then rewrite the wasm module. +/// +/// Support for this was added to LLVM in +/// https://github.com/llvm-mirror/llvm/commit/0f32e1365, although support still +/// needs to be added (AFAIK at the time of this writing) to LLD +pub fn rewrite_imports(path: &Path, import_map: &FxHashMap) { + if import_map.len() == 0 { + return + } + + let wasm = fs::read(path).expect("failed to read wasm output"); + let mut ret = WasmEncoder::new(); + ret.data.extend(&wasm[..8]); + + // skip the 8 byte wasm/version header + for (id, raw) in WasmSections(WasmDecoder::new(&wasm[8..])) { + ret.byte(id); + if id == WASM_IMPORT_SECTION_ID { + info!("rewriting import section"); + let data = rewrite_import_section( + &mut WasmDecoder::new(raw), + import_map, + ); + ret.bytes(&data); + } else { + info!("carry forward section {}, {} bytes long", id, raw.len()); + ret.bytes(raw); + } + } + + fs::write(path, &ret.data).expect("failed to write wasm output"); + + fn rewrite_import_section( + wasm: &mut WasmDecoder, + import_map: &FxHashMap, + ) + -> Vec + { + let mut dst = WasmEncoder::new(); + let n = wasm.u32(); + dst.u32(n); + info!("rewriting {} imports", n); + for _ in 0..n { + rewrite_import_entry(wasm, &mut dst, import_map); + } + return dst.data + } + + fn rewrite_import_entry(wasm: &mut WasmDecoder, + dst: &mut WasmEncoder, + import_map: &FxHashMap) { + // More info about the binary format here is available at: + // https://webassembly.github.io/spec/core/binary/modules.html#import-section + // + // Note that you can also find the whole point of existence of this + // function here, where we map the `module` name to a different one if + // we've got one listed. + let module = wasm.str(); + let field = wasm.str(); + let new_module = if module == "env" { + import_map.get(field).map(|s| &**s).unwrap_or(module) + } else { + module + }; + info!("import rewrite ({} => {}) / {}", module, new_module, field); + dst.str(new_module); + dst.str(field); + let kind = wasm.byte(); + dst.byte(kind); + match kind { + WASM_EXTERNAL_KIND_FUNCTION => dst.u32(wasm.u32()), + WASM_EXTERNAL_KIND_TABLE => { + dst.byte(wasm.byte()); // element_type + dst.limits(wasm.limits()); + } + WASM_EXTERNAL_KIND_MEMORY => dst.limits(wasm.limits()), + WASM_EXTERNAL_KIND_GLOBAL => { + dst.byte(wasm.byte()); // content_type + dst.bool(wasm.bool()); // mutable + } + b => panic!("unknown kind: {}", b), + } + } +} + +struct WasmSections<'a>(WasmDecoder<'a>); + +impl<'a> Iterator for WasmSections<'a> { + type Item = (u8, &'a [u8]); + + fn next(&mut self) -> Option<(u8, &'a [u8])> { + if self.0.data.len() == 0 { + return None + } + + // see https://webassembly.github.io/spec/core/binary/modules.html#sections + let id = self.0.byte(); + let section_len = self.0.u32(); + info!("new section {} / {} bytes", id, section_len); + let section = self.0.skip(section_len as usize); + Some((id, section)) + } +} + +struct WasmDecoder<'a> { + data: &'a [u8], +} + +impl<'a> WasmDecoder<'a> { + fn new(data: &'a [u8]) -> WasmDecoder<'a> { + WasmDecoder { data } + } + + fn byte(&mut self) -> u8 { + self.skip(1)[0] + } + + fn u32(&mut self) -> u32 { + let (n, l1) = leb128::read_u32_leb128(self.data); + self.data = &self.data[l1..]; + return n + } + + fn skip(&mut self, amt: usize) -> &'a [u8] { + let (data, rest) = self.data.split_at(amt); + self.data = rest; + data + } + + fn str(&mut self) -> &'a str { + let len = self.u32(); + str::from_utf8(self.skip(len as usize)).unwrap() + } + + fn bool(&mut self) -> bool { + self.byte() == 1 + } + + fn limits(&mut self) -> (u32, Option) { + let has_max = self.bool(); + (self.u32(), if has_max { Some(self.u32()) } else { None }) + } +} + +struct WasmEncoder { + data: Vec, +} + +impl WasmEncoder { + fn new() -> WasmEncoder { + WasmEncoder { data: Vec::new() } + } + + fn u32(&mut self, val: u32) { + let at = self.data.len(); + leb128::write_u32_leb128(&mut self.data, at, val); + } + + fn byte(&mut self, val: u8) { + self.data.push(val); + } + + fn bytes(&mut self, val: &[u8]) { + self.u32(val.len() as u32); + self.data.extend_from_slice(val); + } + + fn str(&mut self, val: &str) { + self.bytes(val.as_bytes()) + } + + fn bool(&mut self, b: bool) { + self.byte(b as u8); + } + + fn limits(&mut self, limits: (u32, Option)) { + self.bool(limits.1.is_some()); + self.u32(limits.0); + if let Some(c) = limits.1 { + self.u32(c); + } + } +} diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs new file mode 100644 index 00000000000..1151e013131 --- /dev/null +++ b/src/librustc_codegen_llvm/back/write.rs @@ -0,0 +1,2390 @@ +// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use attributes; +use back::bytecode::{self, RLIB_BYTECODE_EXTENSION}; +use back::lto::{self, ModuleBuffer, ThinBuffer}; +use back::link::{self, get_linker, remove}; +use back::command::Command; +use back::linker::LinkerInfo; +use back::symbol_export::ExportedSymbols; +use base; +use consts; +use rustc_incremental::{copy_cgu_workproducts_to_incr_comp_cache_dir, in_incr_comp_dir}; +use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind}; +use rustc::middle::cstore::{LinkMeta, EncodedMetadata}; +use rustc::session::config::{self, OutputFilenames, OutputType, Passes, SomePasses, + AllPasses, Sanitizer, Lto}; +use rustc::session::Session; +use rustc::util::nodemap::FxHashMap; +use time_graph::{self, TimeGraph, Timeline}; +use llvm; +use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef}; +use llvm::{SMDiagnosticRef, ContextRef}; +use {CodegenResults, ModuleSource, ModuleCodegen, CompiledModule, ModuleKind}; +use CrateInfo; +use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; +use rustc::ty::TyCtxt; +use rustc::util::common::{time_ext, time_depth, set_time_depth, print_time_passes_entry}; +use rustc::util::common::path2cstr; +use rustc::util::fs::{link_or_copy}; +use errors::{self, Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId}; +use errors::emitter::{Emitter}; +use syntax::attr; +use syntax::ext::hygiene::Mark; +use syntax_pos::MultiSpan; +use syntax_pos::symbol::Symbol; +use type_::Type; +use context::{is_pie_binary, get_reloc_model}; +use common::{C_bytes_in_context, val_ty}; +use jobserver::{Client, Acquired}; +use rustc_demangle; + +use std::any::Any; +use std::ffi::{CString, CStr}; +use std::fs; +use std::io::{self, Write}; +use std::mem; +use std::path::{Path, PathBuf}; +use std::str; +use std::sync::Arc; +use std::sync::mpsc::{channel, Sender, Receiver}; +use std::slice; +use std::time::Instant; +use std::thread; +use libc::{c_uint, c_void, c_char, size_t}; + +pub const RELOC_MODEL_ARGS : [(&'static str, llvm::RelocMode); 7] = [ + ("pic", llvm::RelocMode::PIC), + ("static", llvm::RelocMode::Static), + ("default", llvm::RelocMode::Default), + ("dynamic-no-pic", llvm::RelocMode::DynamicNoPic), + ("ropi", llvm::RelocMode::ROPI), + ("rwpi", llvm::RelocMode::RWPI), + ("ropi-rwpi", llvm::RelocMode::ROPI_RWPI), +]; + +pub const CODE_GEN_MODEL_ARGS: &[(&str, llvm::CodeModel)] = &[ + ("small", llvm::CodeModel::Small), + ("kernel", llvm::CodeModel::Kernel), + ("medium", llvm::CodeModel::Medium), + ("large", llvm::CodeModel::Large), +]; + +pub const TLS_MODEL_ARGS : [(&'static str, llvm::ThreadLocalMode); 4] = [ + ("global-dynamic", llvm::ThreadLocalMode::GeneralDynamic), + ("local-dynamic", llvm::ThreadLocalMode::LocalDynamic), + ("initial-exec", llvm::ThreadLocalMode::InitialExec), + ("local-exec", llvm::ThreadLocalMode::LocalExec), +]; + +pub fn llvm_err(handler: &errors::Handler, msg: String) -> FatalError { + match llvm::last_error() { + Some(err) => handler.fatal(&format!("{}: {}", msg, err)), + None => handler.fatal(&msg), + } +} + +pub fn write_output_file( + handler: &errors::Handler, + target: llvm::TargetMachineRef, + pm: llvm::PassManagerRef, + m: ModuleRef, + output: &Path, + file_type: llvm::FileType) -> Result<(), FatalError> { + unsafe { + let output_c = path2cstr(output); + let result = llvm::LLVMRustWriteOutputFile( + target, pm, m, output_c.as_ptr(), file_type); + if result.into_result().is_err() { + let msg = format!("could not write output to {}", output.display()); + Err(llvm_err(handler, msg)) + } else { + Ok(()) + } + } +} + +fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel { + match optimize { + config::OptLevel::No => llvm::CodeGenOptLevel::None, + config::OptLevel::Less => llvm::CodeGenOptLevel::Less, + config::OptLevel::Default => llvm::CodeGenOptLevel::Default, + config::OptLevel::Aggressive => llvm::CodeGenOptLevel::Aggressive, + _ => llvm::CodeGenOptLevel::Default, + } +} + +fn get_llvm_opt_size(optimize: config::OptLevel) -> llvm::CodeGenOptSize { + match optimize { + config::OptLevel::Size => llvm::CodeGenOptSizeDefault, + config::OptLevel::SizeMin => llvm::CodeGenOptSizeAggressive, + _ => llvm::CodeGenOptSizeNone, + } +} + +pub fn create_target_machine(sess: &Session, find_features: bool) -> TargetMachineRef { + target_machine_factory(sess, find_features)().unwrap_or_else(|err| { + llvm_err(sess.diagnostic(), err).raise() + }) +} + +// If find_features is true this won't access `sess.crate_types` by assuming +// that `is_pie_binary` is false. When we discover LLVM target features +// `sess.crate_types` is uninitialized so we cannot access it. +pub fn target_machine_factory(sess: &Session, find_features: bool) + -> Arc Result + Send + Sync> +{ + let reloc_model = get_reloc_model(sess); + + let opt_level = get_llvm_opt_level(sess.opts.optimize); + let use_softfp = sess.opts.cg.soft_float; + + let ffunction_sections = sess.target.target.options.function_sections; + let fdata_sections = ffunction_sections; + + let code_model_arg = sess.opts.cg.code_model.as_ref().or( + sess.target.target.options.code_model.as_ref(), + ); + + let code_model = match code_model_arg { + Some(s) => { + match CODE_GEN_MODEL_ARGS.iter().find(|arg| arg.0 == s) { + Some(x) => x.1, + _ => { + sess.err(&format!("{:?} is not a valid code model", + code_model_arg)); + sess.abort_if_errors(); + bug!(); + } + } + } + None => llvm::CodeModel::None, + }; + + let singlethread = sess.target.target.options.singlethread; + + let triple = &sess.target.target.llvm_target; + + let triple = CString::new(triple.as_bytes()).unwrap(); + let cpu = sess.target_cpu(); + let cpu = CString::new(cpu.as_bytes()).unwrap(); + let features = attributes::llvm_target_features(sess) + .collect::>() + .join(","); + let features = CString::new(features).unwrap(); + let is_pie_binary = !find_features && is_pie_binary(sess); + let trap_unreachable = sess.target.target.options.trap_unreachable; + + Arc::new(move || { + let tm = unsafe { + llvm::LLVMRustCreateTargetMachine( + triple.as_ptr(), cpu.as_ptr(), features.as_ptr(), + code_model, + reloc_model, + opt_level, + use_softfp, + is_pie_binary, + ffunction_sections, + fdata_sections, + trap_unreachable, + singlethread, + ) + }; + + if tm.is_null() { + Err(format!("Could not create LLVM TargetMachine for triple: {}", + triple.to_str().unwrap())) + } else { + Ok(tm) + } + }) +} + +/// Module-specific configuration for `optimize_and_codegen`. +pub struct ModuleConfig { + /// Names of additional optimization passes to run. + passes: Vec, + /// Some(level) to optimize at a certain level, or None to run + /// absolutely no optimizations (used for the metadata module). + pub opt_level: Option, + + /// Some(level) to optimize binary size, or None to not affect program size. + opt_size: Option, + + pgo_gen: Option, + pgo_use: String, + + // Flags indicating which outputs to produce. + emit_no_opt_bc: bool, + emit_bc: bool, + emit_bc_compressed: bool, + emit_lto_bc: bool, + emit_ir: bool, + emit_asm: bool, + emit_obj: bool, + // Miscellaneous flags. These are mostly copied from command-line + // options. + no_verify: bool, + no_prepopulate_passes: bool, + no_builtins: bool, + time_passes: bool, + vectorize_loop: bool, + vectorize_slp: bool, + merge_functions: bool, + inline_threshold: Option, + // Instead of creating an object file by doing LLVM codegen, just + // make the object file bitcode. Provides easy compatibility with + // emscripten's ecc compiler, when used as the linker. + obj_is_bitcode: bool, + no_integrated_as: bool, + embed_bitcode: bool, + embed_bitcode_marker: bool, +} + +impl ModuleConfig { + fn new(passes: Vec) -> ModuleConfig { + ModuleConfig { + passes, + opt_level: None, + opt_size: None, + + pgo_gen: None, + pgo_use: String::new(), + + emit_no_opt_bc: false, + emit_bc: false, + emit_bc_compressed: false, + emit_lto_bc: false, + emit_ir: false, + emit_asm: false, + emit_obj: false, + obj_is_bitcode: false, + embed_bitcode: false, + embed_bitcode_marker: false, + no_integrated_as: false, + + no_verify: false, + no_prepopulate_passes: false, + no_builtins: false, + time_passes: false, + vectorize_loop: false, + vectorize_slp: false, + merge_functions: false, + inline_threshold: None + } + } + + fn set_flags(&mut self, sess: &Session, no_builtins: bool) { + self.no_verify = sess.no_verify(); + self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes; + self.no_builtins = no_builtins || sess.target.target.options.no_builtins; + self.time_passes = sess.time_passes(); + self.inline_threshold = sess.opts.cg.inline_threshold; + self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode; + let embed_bitcode = sess.target.target.options.embed_bitcode || + sess.opts.debugging_opts.embed_bitcode || + sess.opts.debugging_opts.cross_lang_lto.embed_bitcode(); + if embed_bitcode { + match sess.opts.optimize { + config::OptLevel::No | + config::OptLevel::Less => { + self.embed_bitcode_marker = embed_bitcode; + } + _ => self.embed_bitcode = embed_bitcode, + } + } + + // Copy what clang does by turning on loop vectorization at O2 and + // slp vectorization at O3. Otherwise configure other optimization aspects + // of this pass manager builder. + // Turn off vectorization for emscripten, as it's not very well supported. + self.vectorize_loop = !sess.opts.cg.no_vectorize_loops && + (sess.opts.optimize == config::OptLevel::Default || + sess.opts.optimize == config::OptLevel::Aggressive) && + !sess.target.target.options.is_like_emscripten; + + self.vectorize_slp = !sess.opts.cg.no_vectorize_slp && + sess.opts.optimize == config::OptLevel::Aggressive && + !sess.target.target.options.is_like_emscripten; + + self.merge_functions = sess.opts.optimize == config::OptLevel::Default || + sess.opts.optimize == config::OptLevel::Aggressive; + } +} + +/// Assembler name and command used by codegen when no_integrated_as is enabled +struct AssemblerCommand { + name: PathBuf, + cmd: Command, +} + +/// Additional resources used by optimize_and_codegen (not module specific) +#[derive(Clone)] +pub struct CodegenContext { + // Resouces needed when running LTO + pub time_passes: bool, + pub lto: Lto, + pub no_landing_pads: bool, + pub save_temps: bool, + pub fewer_names: bool, + pub exported_symbols: Option>, + pub opts: Arc, + pub crate_types: Vec, + pub each_linked_rlib_for_lto: Vec<(CrateNum, PathBuf)>, + output_filenames: Arc, + regular_module_config: Arc, + metadata_module_config: Arc, + allocator_module_config: Arc, + pub tm_factory: Arc Result + Send + Sync>, + pub msvc_imps_needed: bool, + pub target_pointer_width: String, + debuginfo: config::DebugInfoLevel, + + // Number of cgus excluding the allocator/metadata modules + pub total_cgus: usize, + // Handler to use for diagnostics produced during codegen. + pub diag_emitter: SharedEmitter, + // LLVM passes added by plugins. + pub plugin_passes: Vec, + // LLVM optimizations for which we want to print remarks. + pub remark: Passes, + // Worker thread number + pub worker: usize, + // The incremental compilation session directory, or None if we are not + // compiling incrementally + pub incr_comp_session_dir: Option, + // Channel back to the main control thread to send messages to + coordinator_send: Sender>, + // A reference to the TimeGraph so we can register timings. None means that + // measuring is disabled. + time_graph: Option, + // The assembler command if no_integrated_as option is enabled, None otherwise + assembler_cmd: Option>, +} + +impl CodegenContext { + pub fn create_diag_handler(&self) -> Handler { + Handler::with_emitter(true, false, Box::new(self.diag_emitter.clone())) + } + + pub(crate) fn config(&self, kind: ModuleKind) -> &ModuleConfig { + match kind { + ModuleKind::Regular => &self.regular_module_config, + ModuleKind::Metadata => &self.metadata_module_config, + ModuleKind::Allocator => &self.allocator_module_config, + } + } + + pub(crate) fn save_temp_bitcode(&self, module: &ModuleCodegen, name: &str) { + if !self.save_temps { + return + } + unsafe { + let ext = format!("{}.bc", name); + let cgu = Some(&module.name[..]); + let path = self.output_filenames.temp_path_ext(&ext, cgu); + let cstr = path2cstr(&path); + let llmod = module.llvm().unwrap().llmod; + llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr()); + } + } +} + +struct DiagnosticHandlers<'a> { + inner: Box<(&'a CodegenContext, &'a Handler)>, + llcx: ContextRef, +} + +impl<'a> DiagnosticHandlers<'a> { + fn new(cgcx: &'a CodegenContext, + handler: &'a Handler, + llcx: ContextRef) -> DiagnosticHandlers<'a> { + let data = Box::new((cgcx, handler)); + unsafe { + let arg = &*data as &(_, _) as *const _ as *mut _; + llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, arg); + llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, arg); + } + DiagnosticHandlers { + inner: data, + llcx: llcx, + } + } +} + +impl<'a> Drop for DiagnosticHandlers<'a> { + fn drop(&mut self) { + unsafe { + llvm::LLVMRustSetInlineAsmDiagnosticHandler(self.llcx, inline_asm_handler, 0 as *mut _); + llvm::LLVMContextSetDiagnosticHandler(self.llcx, diagnostic_handler, 0 as *mut _); + } + } +} + +unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext, + msg: &'b str, + cookie: c_uint) { + cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_string()); +} + +unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef, + user: *const c_void, + cookie: c_uint) { + if user.is_null() { + return + } + let (cgcx, _) = *(user as *const (&CodegenContext, &Handler)); + + let msg = llvm::build_string(|s| llvm::LLVMRustWriteSMDiagnosticToString(diag, s)) + .expect("non-UTF8 SMDiagnostic"); + + report_inline_asm(cgcx, &msg, cookie); +} + +unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_void) { + if user.is_null() { + return + } + let (cgcx, diag_handler) = *(user as *const (&CodegenContext, &Handler)); + + match llvm::diagnostic::Diagnostic::unpack(info) { + llvm::diagnostic::InlineAsm(inline) => { + report_inline_asm(cgcx, + &llvm::twine_to_string(inline.message), + inline.cookie); + } + + llvm::diagnostic::Optimization(opt) => { + let enabled = match cgcx.remark { + AllPasses => true, + SomePasses(ref v) => v.iter().any(|s| *s == opt.pass_name), + }; + + if enabled { + diag_handler.note_without_error(&format!("optimization {} for {} at {}:{}:{}: {}", + opt.kind.describe(), + opt.pass_name, + opt.filename, + opt.line, + opt.column, + opt.message)); + } + } + llvm::diagnostic::PGO(diagnostic_ref) => { + let msg = llvm::build_string(|s| { + llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) + }).expect("non-UTF8 PGO diagnostic"); + diag_handler.warn(&msg); + } + llvm::diagnostic::UnknownDiagnostic(..) => {}, + } +} + +// Unsafe due to LLVM calls. +unsafe fn optimize(cgcx: &CodegenContext, + diag_handler: &Handler, + module: &ModuleCodegen, + config: &ModuleConfig, + timeline: &mut Timeline) + -> Result<(), FatalError> +{ + let (llmod, llcx, tm) = match module.source { + ModuleSource::Codegened(ref llvm) => (llvm.llmod, llvm.llcx, llvm.tm), + ModuleSource::Preexisting(_) => { + bug!("optimize_and_codegen: called with ModuleSource::Preexisting") + } + }; + + let _handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx); + + let module_name = module.name.clone(); + let module_name = Some(&module_name[..]); + + if config.emit_no_opt_bc { + let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name); + let out = path2cstr(&out); + llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); + } + + if config.opt_level.is_some() { + // Create the two optimizing pass managers. These mirror what clang + // does, and are by populated by LLVM's default PassManagerBuilder. + // Each manager has a different set of passes, but they also share + // some common passes. + let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod); + let mpm = llvm::LLVMCreatePassManager(); + + // If we're verifying or linting, add them to the function pass + // manager. + let addpass = |pass_name: &str| { + let pass_name = CString::new(pass_name).unwrap(); + let pass = llvm::LLVMRustFindAndCreatePass(pass_name.as_ptr()); + if pass.is_null() { + return false; + } + let pass_manager = match llvm::LLVMRustPassKind(pass) { + llvm::PassKind::Function => fpm, + llvm::PassKind::Module => mpm, + llvm::PassKind::Other => { + diag_handler.err("Encountered LLVM pass kind we can't handle"); + return true + }, + }; + llvm::LLVMRustAddPass(pass_manager, pass); + true + }; + + if !config.no_verify { assert!(addpass("verify")); } + if !config.no_prepopulate_passes { + llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod); + llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod); + let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None); + let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal; + with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| { + llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm); + llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm); + }) + } + + for pass in &config.passes { + if !addpass(pass) { + diag_handler.warn(&format!("unknown pass `{}`, ignoring", + pass)); + } + } + + for pass in &cgcx.plugin_passes { + if !addpass(pass) { + diag_handler.err(&format!("a plugin asked for LLVM pass \ + `{}` but LLVM does not \ + recognize it", pass)); + } + } + + diag_handler.abort_if_errors(); + + // Finally, run the actual optimization passes + time_ext(config.time_passes, + None, + &format!("llvm function passes [{}]", module_name.unwrap()), + || { + llvm::LLVMRustRunFunctionPassManager(fpm, llmod) + }); + timeline.record("fpm"); + time_ext(config.time_passes, + None, + &format!("llvm module passes [{}]", module_name.unwrap()), + || { + llvm::LLVMRunPassManager(mpm, llmod) + }); + + // Deallocate managers that we're now done with + llvm::LLVMDisposePassManager(fpm); + llvm::LLVMDisposePassManager(mpm); + } + Ok(()) +} + +fn generate_lto_work(cgcx: &CodegenContext, + modules: Vec) + -> Vec<(WorkItem, u64)> +{ + let mut timeline = cgcx.time_graph.as_ref().map(|tg| { + tg.start(CODEGEN_WORKER_TIMELINE, + CODEGEN_WORK_PACKAGE_KIND, + "generate lto") + }).unwrap_or(Timeline::noop()); + let lto_modules = lto::run(cgcx, modules, &mut timeline) + .unwrap_or_else(|e| e.raise()); + + lto_modules.into_iter().map(|module| { + let cost = module.cost(); + (WorkItem::LTO(module), cost) + }).collect() +} + +unsafe fn codegen(cgcx: &CodegenContext, + diag_handler: &Handler, + module: ModuleCodegen, + config: &ModuleConfig, + timeline: &mut Timeline) + -> Result +{ + timeline.record("codegen"); + let (llmod, llcx, tm) = match module.source { + ModuleSource::Codegened(ref llvm) => (llvm.llmod, llvm.llcx, llvm.tm), + ModuleSource::Preexisting(_) => { + bug!("codegen: called with ModuleSource::Preexisting") + } + }; + let module_name = module.name.clone(); + let module_name = Some(&module_name[..]); + let handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx); + + if cgcx.msvc_imps_needed { + create_msvc_imps(cgcx, llcx, llmod); + } + + // A codegen-specific pass manager is used to generate object + // files for an LLVM module. + // + // Apparently each of these pass managers is a one-shot kind of + // thing, so we create a new one for each type of output. The + // pass manager passed to the closure should be ensured to not + // escape the closure itself, and the manager should only be + // used once. + unsafe fn with_codegen(tm: TargetMachineRef, + llmod: ModuleRef, + no_builtins: bool, + f: F) -> R + where F: FnOnce(PassManagerRef) -> R, + { + let cpm = llvm::LLVMCreatePassManager(); + llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod); + llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); + f(cpm) + } + + // If we don't have the integrated assembler, then we need to emit asm + // from LLVM and use `gcc` to create the object file. + let asm_to_obj = config.emit_obj && config.no_integrated_as; + + // Change what we write and cleanup based on whether obj files are + // just llvm bitcode. In that case write bitcode, and possibly + // delete the bitcode if it wasn't requested. Don't generate the + // machine code, instead copy the .o file from the .bc + let write_bc = config.emit_bc || config.obj_is_bitcode; + let rm_bc = !config.emit_bc && config.obj_is_bitcode; + let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm_to_obj; + let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode; + + let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); + let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); + + + if write_bc || config.emit_bc_compressed || config.embed_bitcode { + let thin; + let old; + let data = if llvm::LLVMRustThinLTOAvailable() { + thin = ThinBuffer::new(llmod); + thin.data() + } else { + old = ModuleBuffer::new(llmod); + old.data() + }; + timeline.record("make-bc"); + + if write_bc { + if let Err(e) = fs::write(&bc_out, data) { + diag_handler.err(&format!("failed to write bytecode: {}", e)); + } + timeline.record("write-bc"); + } + + if config.embed_bitcode { + embed_bitcode(cgcx, llcx, llmod, Some(data)); + timeline.record("embed-bc"); + } + + if config.emit_bc_compressed { + let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION); + let data = bytecode::encode(&module.llmod_id, data); + if let Err(e) = fs::write(&dst, data) { + diag_handler.err(&format!("failed to write bytecode: {}", e)); + } + timeline.record("compress-bc"); + } + } else if config.embed_bitcode_marker { + embed_bitcode(cgcx, llcx, llmod, None); + } + + time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()), + || -> Result<(), FatalError> { + if config.emit_ir { + let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name); + let out = path2cstr(&out); + + extern "C" fn demangle_callback(input_ptr: *const c_char, + input_len: size_t, + output_ptr: *mut c_char, + output_len: size_t) -> size_t { + let input = unsafe { + slice::from_raw_parts(input_ptr as *const u8, input_len as usize) + }; + + let input = match str::from_utf8(input) { + Ok(s) => s, + Err(_) => return 0, + }; + + let output = unsafe { + slice::from_raw_parts_mut(output_ptr as *mut u8, output_len as usize) + }; + let mut cursor = io::Cursor::new(output); + + let demangled = match rustc_demangle::try_demangle(input) { + Ok(d) => d, + Err(_) => return 0, + }; + + if let Err(_) = write!(cursor, "{:#}", demangled) { + // Possible only if provided buffer is not big enough + return 0; + } + + cursor.position() as size_t + } + + with_codegen(tm, llmod, config.no_builtins, |cpm| { + llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr(), demangle_callback); + llvm::LLVMDisposePassManager(cpm); + }); + timeline.record("ir"); + } + + if config.emit_asm || asm_to_obj { + let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); + + // We can't use the same module for asm and binary output, because that triggers + // various errors like invalid IR or broken binaries, so we might have to clone the + // module to produce the asm output + let llmod = if config.emit_obj { + llvm::LLVMCloneModule(llmod) + } else { + llmod + }; + with_codegen(tm, llmod, config.no_builtins, |cpm| { + write_output_file(diag_handler, tm, cpm, llmod, &path, + llvm::FileType::AssemblyFile) + })?; + if config.emit_obj { + llvm::LLVMDisposeModule(llmod); + } + timeline.record("asm"); + } + + if write_obj { + with_codegen(tm, llmod, config.no_builtins, |cpm| { + write_output_file(diag_handler, tm, cpm, llmod, &obj_out, + llvm::FileType::ObjectFile) + })?; + timeline.record("obj"); + } else if asm_to_obj { + let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); + run_assembler(cgcx, diag_handler, &assembly, &obj_out); + timeline.record("asm_to_obj"); + + if !config.emit_asm && !cgcx.save_temps { + drop(fs::remove_file(&assembly)); + } + } + + Ok(()) + })?; + + if copy_bc_to_obj { + debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out); + if let Err(e) = link_or_copy(&bc_out, &obj_out) { + diag_handler.err(&format!("failed to copy bitcode to object file: {}", e)); + } + } + + if rm_bc { + debug!("removing_bitcode {:?}", bc_out); + if let Err(e) = fs::remove_file(&bc_out) { + diag_handler.err(&format!("failed to remove bitcode: {}", e)); + } + } + + drop(handlers); + Ok(module.into_compiled_module(config.emit_obj, + config.emit_bc, + config.emit_bc_compressed, + &cgcx.output_filenames)) +} + +/// Embed the bitcode of an LLVM module in the LLVM module itself. +/// +/// This is done primarily for iOS where it appears to be standard to compile C +/// code at least with `-fembed-bitcode` which creates two sections in the +/// executable: +/// +/// * __LLVM,__bitcode +/// * __LLVM,__cmdline +/// +/// It appears *both* of these sections are necessary to get the linker to +/// recognize what's going on. For us though we just always throw in an empty +/// cmdline section. +/// +/// Furthermore debug/O1 builds don't actually embed bitcode but rather just +/// embed an empty section. +/// +/// Basically all of this is us attempting to follow in the footsteps of clang +/// on iOS. See #35968 for lots more info. +unsafe fn embed_bitcode(cgcx: &CodegenContext, + llcx: ContextRef, + llmod: ModuleRef, + bitcode: Option<&[u8]>) { + let llconst = C_bytes_in_context(llcx, bitcode.unwrap_or(&[])); + let llglobal = llvm::LLVMAddGlobal( + llmod, + val_ty(llconst).to_ref(), + "rustc.embedded.module\0".as_ptr() as *const _, + ); + llvm::LLVMSetInitializer(llglobal, llconst); + + let is_apple = cgcx.opts.target_triple.triple().contains("-ios") || + cgcx.opts.target_triple.triple().contains("-darwin"); + + let section = if is_apple { + "__LLVM,__bitcode\0" + } else { + ".llvmbc\0" + }; + llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _); + llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::LLVMSetGlobalConstant(llglobal, llvm::True); + + let llconst = C_bytes_in_context(llcx, &[]); + let llglobal = llvm::LLVMAddGlobal( + llmod, + val_ty(llconst).to_ref(), + "rustc.embedded.cmdline\0".as_ptr() as *const _, + ); + llvm::LLVMSetInitializer(llglobal, llconst); + let section = if is_apple { + "__LLVM,__cmdline\0" + } else { + ".llvmcmd\0" + }; + llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _); + llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); +} + +pub(crate) struct CompiledModules { + pub modules: Vec, + pub metadata_module: CompiledModule, + pub allocator_module: Option, +} + +fn need_crate_bitcode_for_rlib(sess: &Session) -> bool { + sess.crate_types.borrow().contains(&config::CrateTypeRlib) && + sess.opts.output_types.contains_key(&OutputType::Exe) +} + +pub fn start_async_codegen(tcx: TyCtxt, + time_graph: Option, + link: LinkMeta, + metadata: EncodedMetadata, + coordinator_receive: Receiver>, + total_cgus: usize) + -> OngoingCodegen { + let sess = tcx.sess; + let crate_name = tcx.crate_name(LOCAL_CRATE); + let no_builtins = attr::contains_name(&tcx.hir.krate().attrs, "no_builtins"); + let subsystem = attr::first_attr_value_str_by_name(&tcx.hir.krate().attrs, + "windows_subsystem"); + let windows_subsystem = subsystem.map(|subsystem| { + if subsystem != "windows" && subsystem != "console" { + tcx.sess.fatal(&format!("invalid windows subsystem `{}`, only \ + `windows` and `console` are allowed", + subsystem)); + } + subsystem.to_string() + }); + + let linker_info = LinkerInfo::new(tcx); + let crate_info = CrateInfo::new(tcx); + + // Figure out what we actually need to build. + let mut modules_config = ModuleConfig::new(sess.opts.cg.passes.clone()); + let mut metadata_config = ModuleConfig::new(vec![]); + let mut allocator_config = ModuleConfig::new(vec![]); + + if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer { + match *sanitizer { + Sanitizer::Address => { + modules_config.passes.push("asan".to_owned()); + modules_config.passes.push("asan-module".to_owned()); + } + Sanitizer::Memory => { + modules_config.passes.push("msan".to_owned()) + } + Sanitizer::Thread => { + modules_config.passes.push("tsan".to_owned()) + } + _ => {} + } + } + + if sess.opts.debugging_opts.profile { + modules_config.passes.push("insert-gcov-profiling".to_owned()) + } + + modules_config.pgo_gen = sess.opts.debugging_opts.pgo_gen.clone(); + modules_config.pgo_use = sess.opts.debugging_opts.pgo_use.clone(); + + modules_config.opt_level = Some(get_llvm_opt_level(sess.opts.optimize)); + modules_config.opt_size = Some(get_llvm_opt_size(sess.opts.optimize)); + + // Save all versions of the bytecode if we're saving our temporaries. + if sess.opts.cg.save_temps { + modules_config.emit_no_opt_bc = true; + modules_config.emit_bc = true; + modules_config.emit_lto_bc = true; + metadata_config.emit_bc = true; + allocator_config.emit_bc = true; + } + + // Emit compressed bitcode files for the crate if we're emitting an rlib. + // Whenever an rlib is created, the bitcode is inserted into the archive in + // order to allow LTO against it. + if need_crate_bitcode_for_rlib(sess) { + modules_config.emit_bc_compressed = true; + allocator_config.emit_bc_compressed = true; + } + + modules_config.no_integrated_as = tcx.sess.opts.cg.no_integrated_as || + tcx.sess.target.target.options.no_integrated_as; + + for output_type in sess.opts.output_types.keys() { + match *output_type { + OutputType::Bitcode => { modules_config.emit_bc = true; } + OutputType::LlvmAssembly => { modules_config.emit_ir = true; } + OutputType::Assembly => { + modules_config.emit_asm = true; + // If we're not using the LLVM assembler, this function + // could be invoked specially with output_type_assembly, so + // in this case we still want the metadata object file. + if !sess.opts.output_types.contains_key(&OutputType::Assembly) { + metadata_config.emit_obj = true; + allocator_config.emit_obj = true; + } + } + OutputType::Object => { modules_config.emit_obj = true; } + OutputType::Metadata => { metadata_config.emit_obj = true; } + OutputType::Exe => { + modules_config.emit_obj = true; + metadata_config.emit_obj = true; + allocator_config.emit_obj = true; + }, + OutputType::Mir => {} + OutputType::DepInfo => {} + } + } + + modules_config.set_flags(sess, no_builtins); + metadata_config.set_flags(sess, no_builtins); + allocator_config.set_flags(sess, no_builtins); + + // Exclude metadata and allocator modules from time_passes output, since + // they throw off the "LLVM passes" measurement. + metadata_config.time_passes = false; + allocator_config.time_passes = false; + + let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); + let (codegen_worker_send, codegen_worker_receive) = channel(); + + let coordinator_thread = start_executing_work(tcx, + &crate_info, + shared_emitter, + codegen_worker_send, + coordinator_receive, + total_cgus, + sess.jobserver.clone(), + time_graph.clone(), + Arc::new(modules_config), + Arc::new(metadata_config), + Arc::new(allocator_config)); + + OngoingCodegen { + crate_name, + link, + metadata, + windows_subsystem, + linker_info, + crate_info, + + time_graph, + coordinator_send: tcx.tx_to_llvm_workers.lock().clone(), + codegen_worker_receive, + shared_emitter_main, + future: coordinator_thread, + output_filenames: tcx.output_filenames(LOCAL_CRATE), + } +} + +fn copy_all_cgu_workproducts_to_incr_comp_cache_dir( + sess: &Session, + compiled_modules: &CompiledModules +) -> FxHashMap { + let mut work_products = FxHashMap::default(); + + if sess.opts.incremental.is_none() { + return work_products; + } + + for module in compiled_modules.modules.iter() { + let mut files = vec![]; + + if let Some(ref path) = module.object { + files.push((WorkProductFileKind::Object, path.clone())); + } + if let Some(ref path) = module.bytecode { + files.push((WorkProductFileKind::Bytecode, path.clone())); + } + if let Some(ref path) = module.bytecode_compressed { + files.push((WorkProductFileKind::BytecodeCompressed, path.clone())); + } + + if let Some((id, product)) = + copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files) { + work_products.insert(id, product); + } + } + + work_products +} + +fn produce_final_output_artifacts(sess: &Session, + compiled_modules: &CompiledModules, + crate_output: &OutputFilenames) { + let mut user_wants_bitcode = false; + let mut user_wants_objects = false; + + // Produce final compile outputs. + let copy_gracefully = |from: &Path, to: &Path| { + if let Err(e) = fs::copy(from, to) { + sess.err(&format!("could not copy {:?} to {:?}: {}", from, to, e)); + } + }; + + let copy_if_one_unit = |output_type: OutputType, + keep_numbered: bool| { + if compiled_modules.modules.len() == 1 { + // 1) Only one codegen unit. In this case it's no difficulty + // to copy `foo.0.x` to `foo.x`. + let module_name = Some(&compiled_modules.modules[0].name[..]); + let path = crate_output.temp_path(output_type, module_name); + copy_gracefully(&path, + &crate_output.path(output_type)); + if !sess.opts.cg.save_temps && !keep_numbered { + // The user just wants `foo.x`, not `foo.#module-name#.x`. + remove(sess, &path); + } + } else { + let ext = crate_output.temp_path(output_type, None) + .extension() + .unwrap() + .to_str() + .unwrap() + .to_owned(); + + if crate_output.outputs.contains_key(&output_type) { + // 2) Multiple codegen units, with `--emit foo=some_name`. We have + // no good solution for this case, so warn the user. + sess.warn(&format!("ignoring emit path because multiple .{} files \ + were produced", ext)); + } else if crate_output.single_output_file.is_some() { + // 3) Multiple codegen units, with `-o some_name`. We have + // no good solution for this case, so warn the user. + sess.warn(&format!("ignoring -o because multiple .{} files \ + were produced", ext)); + } else { + // 4) Multiple codegen units, but no explicit name. We + // just leave the `foo.0.x` files in place. + // (We don't have to do any work in this case.) + } + } + }; + + // Flag to indicate whether the user explicitly requested bitcode. + // Otherwise, we produced it only as a temporary output, and will need + // to get rid of it. + for output_type in crate_output.outputs.keys() { + match *output_type { + OutputType::Bitcode => { + user_wants_bitcode = true; + // Copy to .bc, but always keep the .0.bc. There is a later + // check to figure out if we should delete .0.bc files, or keep + // them for making an rlib. + copy_if_one_unit(OutputType::Bitcode, true); + } + OutputType::LlvmAssembly => { + copy_if_one_unit(OutputType::LlvmAssembly, false); + } + OutputType::Assembly => { + copy_if_one_unit(OutputType::Assembly, false); + } + OutputType::Object => { + user_wants_objects = true; + copy_if_one_unit(OutputType::Object, true); + } + OutputType::Mir | + OutputType::Metadata | + OutputType::Exe | + OutputType::DepInfo => {} + } + } + + // Clean up unwanted temporary files. + + // We create the following files by default: + // - #crate#.#module-name#.bc + // - #crate#.#module-name#.o + // - #crate#.crate.metadata.bc + // - #crate#.crate.metadata.o + // - #crate#.o (linked from crate.##.o) + // - #crate#.bc (copied from crate.##.bc) + // We may create additional files if requested by the user (through + // `-C save-temps` or `--emit=` flags). + + if !sess.opts.cg.save_temps { + // Remove the temporary .#module-name#.o objects. If the user didn't + // explicitly request bitcode (with --emit=bc), and the bitcode is not + // needed for building an rlib, then we must remove .#module-name#.bc as + // well. + + // Specific rules for keeping .#module-name#.bc: + // - If the user requested bitcode (`user_wants_bitcode`), and + // codegen_units > 1, then keep it. + // - If the user requested bitcode but codegen_units == 1, then we + // can toss .#module-name#.bc because we copied it to .bc earlier. + // - If we're not building an rlib and the user didn't request + // bitcode, then delete .#module-name#.bc. + // If you change how this works, also update back::link::link_rlib, + // where .#module-name#.bc files are (maybe) deleted after making an + // rlib. + let needs_crate_object = crate_output.outputs.contains_key(&OutputType::Exe); + + let keep_numbered_bitcode = user_wants_bitcode && sess.codegen_units() > 1; + + let keep_numbered_objects = needs_crate_object || + (user_wants_objects && sess.codegen_units() > 1); + + for module in compiled_modules.modules.iter() { + if let Some(ref path) = module.object { + if !keep_numbered_objects { + remove(sess, path); + } + } + + if let Some(ref path) = module.bytecode { + if !keep_numbered_bitcode { + remove(sess, path); + } + } + } + + if !user_wants_bitcode { + if let Some(ref path) = compiled_modules.metadata_module.bytecode { + remove(sess, &path); + } + + if let Some(ref allocator_module) = compiled_modules.allocator_module { + if let Some(ref path) = allocator_module.bytecode { + remove(sess, path); + } + } + } + } + + // We leave the following files around by default: + // - #crate#.o + // - #crate#.crate.metadata.o + // - #crate#.bc + // These are used in linking steps and will be cleaned up afterward. +} + +pub(crate) fn dump_incremental_data(codegen_results: &CodegenResults) { + println!("[incremental] Re-using {} out of {} modules", + codegen_results.modules.iter().filter(|m| m.pre_existing).count(), + codegen_results.modules.len()); +} + +enum WorkItem { + Optimize(ModuleCodegen), + LTO(lto::LtoModuleCodegen), +} + +impl WorkItem { + fn kind(&self) -> ModuleKind { + match *self { + WorkItem::Optimize(ref m) => m.kind, + WorkItem::LTO(_) => ModuleKind::Regular, + } + } + + fn name(&self) -> String { + match *self { + WorkItem::Optimize(ref m) => format!("optimize: {}", m.name), + WorkItem::LTO(ref m) => format!("lto: {}", m.name()), + } + } +} + +enum WorkItemResult { + Compiled(CompiledModule), + NeedsLTO(ModuleCodegen), +} + +fn execute_work_item(cgcx: &CodegenContext, + work_item: WorkItem, + timeline: &mut Timeline) + -> Result +{ + let diag_handler = cgcx.create_diag_handler(); + let config = cgcx.config(work_item.kind()); + let module = match work_item { + WorkItem::Optimize(module) => module, + WorkItem::LTO(mut lto) => { + unsafe { + let module = lto.optimize(cgcx, timeline)?; + let module = codegen(cgcx, &diag_handler, module, config, timeline)?; + return Ok(WorkItemResult::Compiled(module)) + } + } + }; + let module_name = module.name.clone(); + + let pre_existing = match module.source { + ModuleSource::Codegened(_) => None, + ModuleSource::Preexisting(ref wp) => Some(wp.clone()), + }; + + if let Some(wp) = pre_existing { + let incr_comp_session_dir = cgcx.incr_comp_session_dir + .as_ref() + .unwrap(); + let name = &module.name; + let mut object = None; + let mut bytecode = None; + let mut bytecode_compressed = None; + for (kind, saved_file) in wp.saved_files { + let obj_out = match kind { + WorkProductFileKind::Object => { + let path = cgcx.output_filenames.temp_path(OutputType::Object, Some(name)); + object = Some(path.clone()); + path + } + WorkProductFileKind::Bytecode => { + let path = cgcx.output_filenames.temp_path(OutputType::Bitcode, Some(name)); + bytecode = Some(path.clone()); + path + } + WorkProductFileKind::BytecodeCompressed => { + let path = cgcx.output_filenames.temp_path(OutputType::Bitcode, Some(name)) + .with_extension(RLIB_BYTECODE_EXTENSION); + bytecode_compressed = Some(path.clone()); + path + } + }; + let source_file = in_incr_comp_dir(&incr_comp_session_dir, + &saved_file); + debug!("copying pre-existing module `{}` from {:?} to {}", + module.name, + source_file, + obj_out.display()); + match link_or_copy(&source_file, &obj_out) { + Ok(_) => { } + Err(err) => { + diag_handler.err(&format!("unable to copy {} to {}: {}", + source_file.display(), + obj_out.display(), + err)); + } + } + } + assert_eq!(object.is_some(), config.emit_obj); + assert_eq!(bytecode.is_some(), config.emit_bc); + assert_eq!(bytecode_compressed.is_some(), config.emit_bc_compressed); + + Ok(WorkItemResult::Compiled(CompiledModule { + llmod_id: module.llmod_id.clone(), + name: module_name, + kind: ModuleKind::Regular, + pre_existing: true, + object, + bytecode, + bytecode_compressed, + })) + } else { + debug!("llvm-optimizing {:?}", module_name); + + unsafe { + optimize(cgcx, &diag_handler, &module, config, timeline)?; + + // After we've done the initial round of optimizations we need to + // decide whether to synchronously codegen this module or ship it + // back to the coordinator thread for further LTO processing (which + // has to wait for all the initial modules to be optimized). + // + // Here we dispatch based on the `cgcx.lto` and kind of module we're + // codegenning... + let needs_lto = match cgcx.lto { + Lto::No => false, + + // Here we've got a full crate graph LTO requested. We ignore + // this, however, if the crate type is only an rlib as there's + // no full crate graph to process, that'll happen later. + // + // This use case currently comes up primarily for targets that + // require LTO so the request for LTO is always unconditionally + // passed down to the backend, but we don't actually want to do + // anything about it yet until we've got a final product. + Lto::Yes | Lto::Fat | Lto::Thin => { + cgcx.crate_types.len() != 1 || + cgcx.crate_types[0] != config::CrateTypeRlib + } + + // When we're automatically doing ThinLTO for multi-codegen-unit + // builds we don't actually want to LTO the allocator modules if + // it shows up. This is due to various linker shenanigans that + // we'll encounter later. + // + // Additionally here's where we also factor in the current LLVM + // version. If it doesn't support ThinLTO we skip this. + Lto::ThinLocal => { + module.kind != ModuleKind::Allocator && + llvm::LLVMRustThinLTOAvailable() + } + }; + + // Metadata modules never participate in LTO regardless of the lto + // settings. + let needs_lto = needs_lto && module.kind != ModuleKind::Metadata; + + // Don't run LTO passes when cross-lang LTO is enabled. The linker + // will do that for us in this case. + let needs_lto = needs_lto && + !cgcx.opts.debugging_opts.cross_lang_lto.embed_bitcode(); + + if needs_lto { + Ok(WorkItemResult::NeedsLTO(module)) + } else { + let module = codegen(cgcx, &diag_handler, module, config, timeline)?; + Ok(WorkItemResult::Compiled(module)) + } + } + } +} + +enum Message { + Token(io::Result), + NeedsLTO { + result: ModuleCodegen, + worker_id: usize, + }, + Done { + result: Result, + worker_id: usize, + }, + CodegenDone { + llvm_work_item: WorkItem, + cost: u64, + }, + CodegenComplete, + CodegenItem, +} + +struct Diagnostic { + msg: String, + code: Option, + lvl: Level, +} + +#[derive(PartialEq, Clone, Copy, Debug)] +enum MainThreadWorkerState { + Idle, + Codegenning, + LLVMing, +} + +fn start_executing_work(tcx: TyCtxt, + crate_info: &CrateInfo, + shared_emitter: SharedEmitter, + codegen_worker_send: Sender, + coordinator_receive: Receiver>, + total_cgus: usize, + jobserver: Client, + time_graph: Option, + modules_config: Arc, + metadata_config: Arc, + allocator_config: Arc) + -> thread::JoinHandle> { + let coordinator_send = tcx.tx_to_llvm_workers.lock().clone(); + let sess = tcx.sess; + + // Compute the set of symbols we need to retain when doing LTO (if we need to) + let exported_symbols = { + let mut exported_symbols = FxHashMap(); + + let copy_symbols = |cnum| { + let symbols = tcx.exported_symbols(cnum) + .iter() + .map(|&(s, lvl)| (s.symbol_name(tcx).to_string(), lvl)) + .collect(); + Arc::new(symbols) + }; + + match sess.lto() { + Lto::No => None, + Lto::ThinLocal => { + exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE)); + Some(Arc::new(exported_symbols)) + } + Lto::Yes | Lto::Fat | Lto::Thin => { + exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE)); + for &cnum in tcx.crates().iter() { + exported_symbols.insert(cnum, copy_symbols(cnum)); + } + Some(Arc::new(exported_symbols)) + } + } + }; + + // First up, convert our jobserver into a helper thread so we can use normal + // mpsc channels to manage our messages and such. + // After we've requested tokens then we'll, when we can, + // get tokens on `coordinator_receive` which will + // get managed in the main loop below. + let coordinator_send2 = coordinator_send.clone(); + let helper = jobserver.into_helper_thread(move |token| { + drop(coordinator_send2.send(Box::new(Message::Token(token)))); + }).expect("failed to spawn helper thread"); + + let mut each_linked_rlib_for_lto = Vec::new(); + drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| { + if link::ignored_for_lto(sess, crate_info, cnum) { + return + } + each_linked_rlib_for_lto.push((cnum, path.to_path_buf())); + })); + + let assembler_cmd = if modules_config.no_integrated_as { + // HACK: currently we use linker (gcc) as our assembler + let (name, mut cmd) = get_linker(sess); + cmd.args(&sess.target.target.options.asm_args); + Some(Arc::new(AssemblerCommand { + name, + cmd, + })) + } else { + None + }; + + let cgcx = CodegenContext { + crate_types: sess.crate_types.borrow().clone(), + each_linked_rlib_for_lto, + lto: sess.lto(), + no_landing_pads: sess.no_landing_pads(), + fewer_names: sess.fewer_names(), + save_temps: sess.opts.cg.save_temps, + opts: Arc::new(sess.opts.clone()), + time_passes: sess.time_passes(), + exported_symbols, + plugin_passes: sess.plugin_llvm_passes.borrow().clone(), + remark: sess.opts.cg.remark.clone(), + worker: 0, + incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()), + coordinator_send, + diag_emitter: shared_emitter.clone(), + time_graph, + output_filenames: tcx.output_filenames(LOCAL_CRATE), + regular_module_config: modules_config, + metadata_module_config: metadata_config, + allocator_module_config: allocator_config, + tm_factory: target_machine_factory(tcx.sess, false), + total_cgus, + msvc_imps_needed: msvc_imps_needed(tcx), + target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(), + debuginfo: tcx.sess.opts.debuginfo, + assembler_cmd, + }; + + // This is the "main loop" of parallel work happening for parallel codegen. + // It's here that we manage parallelism, schedule work, and work with + // messages coming from clients. + // + // There are a few environmental pre-conditions that shape how the system + // is set up: + // + // - Error reporting only can happen on the main thread because that's the + // only place where we have access to the compiler `Session`. + // - LLVM work can be done on any thread. + // - Codegen can only happen on the main thread. + // - Each thread doing substantial work most be in possession of a `Token` + // from the `Jobserver`. + // - The compiler process always holds one `Token`. Any additional `Tokens` + // have to be requested from the `Jobserver`. + // + // Error Reporting + // =============== + // The error reporting restriction is handled separately from the rest: We + // set up a `SharedEmitter` the holds an open channel to the main thread. + // When an error occurs on any thread, the shared emitter will send the + // error message to the receiver main thread (`SharedEmitterMain`). The + // main thread will periodically query this error message queue and emit + // any error messages it has received. It might even abort compilation if + // has received a fatal error. In this case we rely on all other threads + // being torn down automatically with the main thread. + // Since the main thread will often be busy doing codegen work, error + // reporting will be somewhat delayed, since the message queue can only be + // checked in between to work packages. + // + // Work Processing Infrastructure + // ============================== + // The work processing infrastructure knows three major actors: + // + // - the coordinator thread, + // - the main thread, and + // - LLVM worker threads + // + // The coordinator thread is running a message loop. It instructs the main + // thread about what work to do when, and it will spawn off LLVM worker + // threads as open LLVM WorkItems become available. + // + // The job of the main thread is to codegen CGUs into LLVM work package + // (since the main thread is the only thread that can do this). The main + // thread will block until it receives a message from the coordinator, upon + // which it will codegen one CGU, send it to the coordinator and block + // again. This way the coordinator can control what the main thread is + // doing. + // + // The coordinator keeps a queue of LLVM WorkItems, and when a `Token` is + // available, it will spawn off a new LLVM worker thread and let it process + // that a WorkItem. When a LLVM worker thread is done with its WorkItem, + // it will just shut down, which also frees all resources associated with + // the given LLVM module, and sends a message to the coordinator that the + // has been completed. + // + // Work Scheduling + // =============== + // The scheduler's goal is to minimize the time it takes to complete all + // work there is, however, we also want to keep memory consumption low + // if possible. These two goals are at odds with each other: If memory + // consumption were not an issue, we could just let the main thread produce + // LLVM WorkItems at full speed, assuring maximal utilization of + // Tokens/LLVM worker threads. However, since codegen usual is faster + // than LLVM processing, the queue of LLVM WorkItems would fill up and each + // WorkItem potentially holds on to a substantial amount of memory. + // + // So the actual goal is to always produce just enough LLVM WorkItems as + // not to starve our LLVM worker threads. That means, once we have enough + // WorkItems in our queue, we can block the main thread, so it does not + // produce more until we need them. + // + // Doing LLVM Work on the Main Thread + // ---------------------------------- + // Since the main thread owns the compiler processes implicit `Token`, it is + // wasteful to keep it blocked without doing any work. Therefore, what we do + // in this case is: We spawn off an additional LLVM worker thread that helps + // reduce the queue. The work it is doing corresponds to the implicit + // `Token`. The coordinator will mark the main thread as being busy with + // LLVM work. (The actual work happens on another OS thread but we just care + // about `Tokens`, not actual threads). + // + // When any LLVM worker thread finishes while the main thread is marked as + // "busy with LLVM work", we can do a little switcheroo: We give the Token + // of the just finished thread to the LLVM worker thread that is working on + // behalf of the main thread's implicit Token, thus freeing up the main + // thread again. The coordinator can then again decide what the main thread + // should do. This allows the coordinator to make decisions at more points + // in time. + // + // Striking a Balance between Throughput and Memory Consumption + // ------------------------------------------------------------ + // Since our two goals, (1) use as many Tokens as possible and (2) keep + // memory consumption as low as possible, are in conflict with each other, + // we have to find a trade off between them. Right now, the goal is to keep + // all workers busy, which means that no worker should find the queue empty + // when it is ready to start. + // How do we do achieve this? Good question :) We actually never know how + // many `Tokens` are potentially available so it's hard to say how much to + // fill up the queue before switching the main thread to LLVM work. Also we + // currently don't have a means to estimate how long a running LLVM worker + // will still be busy with it's current WorkItem. However, we know the + // maximal count of available Tokens that makes sense (=the number of CPU + // cores), so we can take a conservative guess. The heuristic we use here + // is implemented in the `queue_full_enough()` function. + // + // Some Background on Jobservers + // ----------------------------- + // It's worth also touching on the management of parallelism here. We don't + // want to just spawn a thread per work item because while that's optimal + // parallelism it may overload a system with too many threads or violate our + // configuration for the maximum amount of cpu to use for this process. To + // manage this we use the `jobserver` crate. + // + // Job servers are an artifact of GNU make and are used to manage + // parallelism between processes. A jobserver is a glorified IPC semaphore + // basically. Whenever we want to run some work we acquire the semaphore, + // and whenever we're done with that work we release the semaphore. In this + // manner we can ensure that the maximum number of parallel workers is + // capped at any one point in time. + // + // LTO and the coordinator thread + // ------------------------------ + // + // The final job the coordinator thread is responsible for is managing LTO + // and how that works. When LTO is requested what we'll to is collect all + // optimized LLVM modules into a local vector on the coordinator. Once all + // modules have been codegened and optimized we hand this to the `lto` + // module for further optimization. The `lto` module will return back a list + // of more modules to work on, which the coordinator will continue to spawn + // work for. + // + // Each LLVM module is automatically sent back to the coordinator for LTO if + // necessary. There's already optimizations in place to avoid sending work + // back to the coordinator if LTO isn't requested. + return thread::spawn(move || { + // We pretend to be within the top-level LLVM time-passes task here: + set_time_depth(1); + + let max_workers = ::num_cpus::get(); + let mut worker_id_counter = 0; + let mut free_worker_ids = Vec::new(); + let mut get_worker_id = |free_worker_ids: &mut Vec| { + if let Some(id) = free_worker_ids.pop() { + id + } else { + let id = worker_id_counter; + worker_id_counter += 1; + id + } + }; + + // This is where we collect codegen units that have gone all the way + // through codegen and LLVM. + let mut compiled_modules = vec![]; + let mut compiled_metadata_module = None; + let mut compiled_allocator_module = None; + let mut needs_lto = Vec::new(); + let mut started_lto = false; + + // This flag tracks whether all items have gone through codegens + let mut codegen_done = false; + + // This is the queue of LLVM work items that still need processing. + let mut work_items = Vec::<(WorkItem, u64)>::new(); + + // This are the Jobserver Tokens we currently hold. Does not include + // the implicit Token the compiler process owns no matter what. + let mut tokens = Vec::new(); + + let mut main_thread_worker_state = MainThreadWorkerState::Idle; + let mut running = 0; + + let mut llvm_start_time = None; + + // Run the message loop while there's still anything that needs message + // processing: + while !codegen_done || + work_items.len() > 0 || + running > 0 || + needs_lto.len() > 0 || + main_thread_worker_state != MainThreadWorkerState::Idle { + + // While there are still CGUs to be codegened, the coordinator has + // to decide how to utilize the compiler processes implicit Token: + // For codegenning more CGU or for running them through LLVM. + if !codegen_done { + if main_thread_worker_state == MainThreadWorkerState::Idle { + if !queue_full_enough(work_items.len(), running, max_workers) { + // The queue is not full enough, codegen more items: + if let Err(_) = codegen_worker_send.send(Message::CodegenItem) { + panic!("Could not send Message::CodegenItem to main thread") + } + main_thread_worker_state = MainThreadWorkerState::Codegenning; + } else { + // The queue is full enough to not let the worker + // threads starve. Use the implicit Token to do some + // LLVM work too. + let (item, _) = work_items.pop() + .expect("queue empty - queue_full_enough() broken?"); + let cgcx = CodegenContext { + worker: get_worker_id(&mut free_worker_ids), + .. cgcx.clone() + }; + maybe_start_llvm_timer(cgcx.config(item.kind()), + &mut llvm_start_time); + main_thread_worker_state = MainThreadWorkerState::LLVMing; + spawn_work(cgcx, item); + } + } + } else { + // If we've finished everything related to normal codegen + // then it must be the case that we've got some LTO work to do. + // Perform the serial work here of figuring out what we're + // going to LTO and then push a bunch of work items onto our + // queue to do LTO + if work_items.len() == 0 && + running == 0 && + main_thread_worker_state == MainThreadWorkerState::Idle { + assert!(!started_lto); + assert!(needs_lto.len() > 0); + started_lto = true; + let modules = mem::replace(&mut needs_lto, Vec::new()); + for (work, cost) in generate_lto_work(&cgcx, modules) { + let insertion_index = work_items + .binary_search_by_key(&cost, |&(_, cost)| cost) + .unwrap_or_else(|e| e); + work_items.insert(insertion_index, (work, cost)); + helper.request_token(); + } + } + + // In this branch, we know that everything has been codegened, + // so it's just a matter of determining whether the implicit + // Token is free to use for LLVM work. + match main_thread_worker_state { + MainThreadWorkerState::Idle => { + if let Some((item, _)) = work_items.pop() { + let cgcx = CodegenContext { + worker: get_worker_id(&mut free_worker_ids), + .. cgcx.clone() + }; + maybe_start_llvm_timer(cgcx.config(item.kind()), + &mut llvm_start_time); + main_thread_worker_state = MainThreadWorkerState::LLVMing; + spawn_work(cgcx, item); + } else { + // There is no unstarted work, so let the main thread + // take over for a running worker. Otherwise the + // implicit token would just go to waste. + // We reduce the `running` counter by one. The + // `tokens.truncate()` below will take care of + // giving the Token back. + debug_assert!(running > 0); + running -= 1; + main_thread_worker_state = MainThreadWorkerState::LLVMing; + } + } + MainThreadWorkerState::Codegenning => { + bug!("codegen worker should not be codegenning after \ + codegen was already completed") + } + MainThreadWorkerState::LLVMing => { + // Already making good use of that token + } + } + } + + // Spin up what work we can, only doing this while we've got available + // parallelism slots and work left to spawn. + while work_items.len() > 0 && running < tokens.len() { + let (item, _) = work_items.pop().unwrap(); + + maybe_start_llvm_timer(cgcx.config(item.kind()), + &mut llvm_start_time); + + let cgcx = CodegenContext { + worker: get_worker_id(&mut free_worker_ids), + .. cgcx.clone() + }; + + spawn_work(cgcx, item); + running += 1; + } + + // Relinquish accidentally acquired extra tokens + tokens.truncate(running); + + let msg = coordinator_receive.recv().unwrap(); + match *msg.downcast::().ok().unwrap() { + // Save the token locally and the next turn of the loop will use + // this to spawn a new unit of work, or it may get dropped + // immediately if we have no more work to spawn. + Message::Token(token) => { + match token { + Ok(token) => { + tokens.push(token); + + if main_thread_worker_state == MainThreadWorkerState::LLVMing { + // If the main thread token is used for LLVM work + // at the moment, we turn that thread into a regular + // LLVM worker thread, so the main thread is free + // to react to codegen demand. + main_thread_worker_state = MainThreadWorkerState::Idle; + running += 1; + } + } + Err(e) => { + let msg = &format!("failed to acquire jobserver token: {}", e); + shared_emitter.fatal(msg); + // Exit the coordinator thread + panic!("{}", msg) + } + } + } + + Message::CodegenDone { llvm_work_item, cost } => { + // We keep the queue sorted by estimated processing cost, + // so that more expensive items are processed earlier. This + // is good for throughput as it gives the main thread more + // time to fill up the queue and it avoids scheduling + // expensive items to the end. + // Note, however, that this is not ideal for memory + // consumption, as LLVM module sizes are not evenly + // distributed. + let insertion_index = + work_items.binary_search_by_key(&cost, |&(_, cost)| cost); + let insertion_index = match insertion_index { + Ok(idx) | Err(idx) => idx + }; + work_items.insert(insertion_index, (llvm_work_item, cost)); + + helper.request_token(); + assert_eq!(main_thread_worker_state, + MainThreadWorkerState::Codegenning); + main_thread_worker_state = MainThreadWorkerState::Idle; + } + + Message::CodegenComplete => { + codegen_done = true; + assert_eq!(main_thread_worker_state, + MainThreadWorkerState::Codegenning); + main_thread_worker_state = MainThreadWorkerState::Idle; + } + + // If a thread exits successfully then we drop a token associated + // with that worker and update our `running` count. We may later + // re-acquire a token to continue running more work. We may also not + // actually drop a token here if the worker was running with an + // "ephemeral token" + // + // Note that if the thread failed that means it panicked, so we + // abort immediately. + Message::Done { result: Ok(compiled_module), worker_id } => { + if main_thread_worker_state == MainThreadWorkerState::LLVMing { + main_thread_worker_state = MainThreadWorkerState::Idle; + } else { + running -= 1; + } + + free_worker_ids.push(worker_id); + + match compiled_module.kind { + ModuleKind::Regular => { + compiled_modules.push(compiled_module); + } + ModuleKind::Metadata => { + assert!(compiled_metadata_module.is_none()); + compiled_metadata_module = Some(compiled_module); + } + ModuleKind::Allocator => { + assert!(compiled_allocator_module.is_none()); + compiled_allocator_module = Some(compiled_module); + } + } + } + Message::NeedsLTO { result, worker_id } => { + assert!(!started_lto); + if main_thread_worker_state == MainThreadWorkerState::LLVMing { + main_thread_worker_state = MainThreadWorkerState::Idle; + } else { + running -= 1; + } + + free_worker_ids.push(worker_id); + needs_lto.push(result); + } + Message::Done { result: Err(()), worker_id: _ } => { + shared_emitter.fatal("aborting due to worker thread failure"); + // Exit the coordinator thread + return Err(()) + } + Message::CodegenItem => { + bug!("the coordinator should not receive codegen requests") + } + } + } + + if let Some(llvm_start_time) = llvm_start_time { + let total_llvm_time = Instant::now().duration_since(llvm_start_time); + // This is the top-level timing for all of LLVM, set the time-depth + // to zero. + set_time_depth(0); + print_time_passes_entry(cgcx.time_passes, + "LLVM passes", + total_llvm_time); + } + + // Regardless of what order these modules completed in, report them to + // the backend in the same order every time to ensure that we're handing + // out deterministic results. + compiled_modules.sort_by(|a, b| a.name.cmp(&b.name)); + + let compiled_metadata_module = compiled_metadata_module + .expect("Metadata module not compiled?"); + + Ok(CompiledModules { + modules: compiled_modules, + metadata_module: compiled_metadata_module, + allocator_module: compiled_allocator_module, + }) + }); + + // A heuristic that determines if we have enough LLVM WorkItems in the + // queue so that the main thread can do LLVM work instead of codegen + fn queue_full_enough(items_in_queue: usize, + workers_running: usize, + max_workers: usize) -> bool { + // Tune me, plz. + items_in_queue > 0 && + items_in_queue >= max_workers.saturating_sub(workers_running / 2) + } + + fn maybe_start_llvm_timer(config: &ModuleConfig, + llvm_start_time: &mut Option) { + // We keep track of the -Ztime-passes output manually, + // since the closure-based interface does not fit well here. + if config.time_passes { + if llvm_start_time.is_none() { + *llvm_start_time = Some(Instant::now()); + } + } + } +} + +pub const CODEGEN_WORKER_ID: usize = ::std::usize::MAX; +pub const CODEGEN_WORKER_TIMELINE: time_graph::TimelineId = + time_graph::TimelineId(CODEGEN_WORKER_ID); +pub const CODEGEN_WORK_PACKAGE_KIND: time_graph::WorkPackageKind = + time_graph::WorkPackageKind(&["#DE9597", "#FED1D3", "#FDC5C7", "#B46668", "#88494B"]); +const LLVM_WORK_PACKAGE_KIND: time_graph::WorkPackageKind = + time_graph::WorkPackageKind(&["#7DB67A", "#C6EEC4", "#ACDAAA", "#579354", "#3E6F3C"]); + +fn spawn_work(cgcx: CodegenContext, work: WorkItem) { + let depth = time_depth(); + + thread::spawn(move || { + set_time_depth(depth); + + // Set up a destructor which will fire off a message that we're done as + // we exit. + struct Bomb { + coordinator_send: Sender>, + result: Option, + worker_id: usize, + } + impl Drop for Bomb { + fn drop(&mut self) { + let worker_id = self.worker_id; + let msg = match self.result.take() { + Some(WorkItemResult::Compiled(m)) => { + Message::Done { result: Ok(m), worker_id } + } + Some(WorkItemResult::NeedsLTO(m)) => { + Message::NeedsLTO { result: m, worker_id } + } + None => Message::Done { result: Err(()), worker_id } + }; + drop(self.coordinator_send.send(Box::new(msg))); + } + } + + let mut bomb = Bomb { + coordinator_send: cgcx.coordinator_send.clone(), + result: None, + worker_id: cgcx.worker, + }; + + // Execute the work itself, and if it finishes successfully then flag + // ourselves as a success as well. + // + // Note that we ignore any `FatalError` coming out of `execute_work_item`, + // as a diagnostic was already sent off to the main thread - just + // surface that there was an error in this worker. + bomb.result = { + let timeline = cgcx.time_graph.as_ref().map(|tg| { + tg.start(time_graph::TimelineId(cgcx.worker), + LLVM_WORK_PACKAGE_KIND, + &work.name()) + }); + let mut timeline = timeline.unwrap_or(Timeline::noop()); + execute_work_item(&cgcx, work, &mut timeline).ok() + }; + }); +} + +pub fn run_assembler(cgcx: &CodegenContext, handler: &Handler, assembly: &Path, object: &Path) { + let assembler = cgcx.assembler_cmd + .as_ref() + .expect("cgcx.assembler_cmd is missing?"); + + let pname = &assembler.name; + let mut cmd = assembler.cmd.clone(); + cmd.arg("-c").arg("-o").arg(object).arg(assembly); + debug!("{:?}", cmd); + + match cmd.output() { + Ok(prog) => { + if !prog.status.success() { + let mut note = prog.stderr.clone(); + note.extend_from_slice(&prog.stdout); + + handler.struct_err(&format!("linking with `{}` failed: {}", + pname.display(), + prog.status)) + .note(&format!("{:?}", &cmd)) + .note(str::from_utf8(¬e[..]).unwrap()) + .emit(); + handler.abort_if_errors(); + } + }, + Err(e) => { + handler.err(&format!("could not exec the linker `{}`: {}", pname.display(), e)); + handler.abort_if_errors(); + } + } +} + +pub unsafe fn with_llvm_pmb(llmod: ModuleRef, + config: &ModuleConfig, + opt_level: llvm::CodeGenOptLevel, + prepare_for_thin_lto: bool, + f: &mut FnMut(llvm::PassManagerBuilderRef)) { + use std::ptr; + + // Create the PassManagerBuilder for LLVM. We configure it with + // reasonable defaults and prepare it to actually populate the pass + // manager. + let builder = llvm::LLVMPassManagerBuilderCreate(); + let opt_size = config.opt_size.unwrap_or(llvm::CodeGenOptSizeNone); + let inline_threshold = config.inline_threshold; + + let pgo_gen_path = config.pgo_gen.as_ref().map(|s| { + let s = if s.is_empty() { "default_%m.profraw" } else { s }; + CString::new(s.as_bytes()).unwrap() + }); + + let pgo_use_path = if config.pgo_use.is_empty() { + None + } else { + Some(CString::new(config.pgo_use.as_bytes()).unwrap()) + }; + + llvm::LLVMRustConfigurePassManagerBuilder( + builder, + opt_level, + config.merge_functions, + config.vectorize_slp, + config.vectorize_loop, + prepare_for_thin_lto, + pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()), + pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()), + ); + + llvm::LLVMPassManagerBuilderSetSizeLevel(builder, opt_size as u32); + + if opt_size != llvm::CodeGenOptSizeNone { + llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(builder, 1); + } + + llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins); + + // Here we match what clang does (kinda). For O0 we only inline + // always-inline functions (but don't add lifetime intrinsics), at O1 we + // inline with lifetime intrinsics, and O2+ we add an inliner with a + // thresholds copied from clang. + match (opt_level, opt_size, inline_threshold) { + (.., Some(t)) => { + llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32); + } + (llvm::CodeGenOptLevel::Aggressive, ..) => { + llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275); + } + (_, llvm::CodeGenOptSizeDefault, _) => { + llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 75); + } + (_, llvm::CodeGenOptSizeAggressive, _) => { + llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25); + } + (llvm::CodeGenOptLevel::None, ..) => { + llvm::LLVMRustAddAlwaysInlinePass(builder, false); + } + (llvm::CodeGenOptLevel::Less, ..) => { + llvm::LLVMRustAddAlwaysInlinePass(builder, true); + } + (llvm::CodeGenOptLevel::Default, ..) => { + llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225); + } + (llvm::CodeGenOptLevel::Other, ..) => { + bug!("CodeGenOptLevel::Other selected") + } + } + + f(builder); + llvm::LLVMPassManagerBuilderDispose(builder); +} + + +enum SharedEmitterMessage { + Diagnostic(Diagnostic), + InlineAsmError(u32, String), + AbortIfErrors, + Fatal(String), +} + +#[derive(Clone)] +pub struct SharedEmitter { + sender: Sender, +} + +pub struct SharedEmitterMain { + receiver: Receiver, +} + +impl SharedEmitter { + pub fn new() -> (SharedEmitter, SharedEmitterMain) { + let (sender, receiver) = channel(); + + (SharedEmitter { sender }, SharedEmitterMain { receiver }) + } + + fn inline_asm_error(&self, cookie: u32, msg: String) { + drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg))); + } + + fn fatal(&self, msg: &str) { + drop(self.sender.send(SharedEmitterMessage::Fatal(msg.to_string()))); + } +} + +impl Emitter for SharedEmitter { + fn emit(&mut self, db: &DiagnosticBuilder) { + drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { + msg: db.message(), + code: db.code.clone(), + lvl: db.level, + }))); + for child in &db.children { + drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { + msg: child.message(), + code: None, + lvl: child.level, + }))); + } + drop(self.sender.send(SharedEmitterMessage::AbortIfErrors)); + } +} + +impl SharedEmitterMain { + pub fn check(&self, sess: &Session, blocking: bool) { + loop { + let message = if blocking { + match self.receiver.recv() { + Ok(message) => Ok(message), + Err(_) => Err(()), + } + } else { + match self.receiver.try_recv() { + Ok(message) => Ok(message), + Err(_) => Err(()), + } + }; + + match message { + Ok(SharedEmitterMessage::Diagnostic(diag)) => { + let handler = sess.diagnostic(); + match diag.code { + Some(ref code) => { + handler.emit_with_code(&MultiSpan::new(), + &diag.msg, + code.clone(), + diag.lvl); + } + None => { + handler.emit(&MultiSpan::new(), + &diag.msg, + diag.lvl); + } + } + } + Ok(SharedEmitterMessage::InlineAsmError(cookie, msg)) => { + match Mark::from_u32(cookie).expn_info() { + Some(ei) => sess.span_err(ei.call_site, &msg), + None => sess.err(&msg), + } + } + Ok(SharedEmitterMessage::AbortIfErrors) => { + sess.abort_if_errors(); + } + Ok(SharedEmitterMessage::Fatal(msg)) => { + sess.fatal(&msg); + } + Err(_) => { + break; + } + } + + } + } +} + +pub struct OngoingCodegen { + crate_name: Symbol, + link: LinkMeta, + metadata: EncodedMetadata, + windows_subsystem: Option, + linker_info: LinkerInfo, + crate_info: CrateInfo, + time_graph: Option, + coordinator_send: Sender>, + codegen_worker_receive: Receiver, + shared_emitter_main: SharedEmitterMain, + future: thread::JoinHandle>, + output_filenames: Arc, +} + +impl OngoingCodegen { + pub(crate) fn join( + self, + sess: &Session + ) -> (CodegenResults, FxHashMap) { + self.shared_emitter_main.check(sess, true); + let compiled_modules = match self.future.join() { + Ok(Ok(compiled_modules)) => compiled_modules, + Ok(Err(())) => { + sess.abort_if_errors(); + panic!("expected abort due to worker thread errors") + }, + Err(_) => { + sess.fatal("Error during codegen/LLVM phase."); + } + }; + + sess.abort_if_errors(); + + if let Some(time_graph) = self.time_graph { + time_graph.dump(&format!("{}-timings", self.crate_name)); + } + + let work_products = copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess, + &compiled_modules); + + produce_final_output_artifacts(sess, + &compiled_modules, + &self.output_filenames); + + // FIXME: time_llvm_passes support - does this use a global context or + // something? + if sess.codegen_units() == 1 && sess.time_llvm_passes() { + unsafe { llvm::LLVMRustPrintPassTimings(); } + } + + (CodegenResults { + crate_name: self.crate_name, + link: self.link, + metadata: self.metadata, + windows_subsystem: self.windows_subsystem, + linker_info: self.linker_info, + crate_info: self.crate_info, + + modules: compiled_modules.modules, + allocator_module: compiled_modules.allocator_module, + metadata_module: compiled_modules.metadata_module, + }, work_products) + } + + pub(crate) fn submit_pre_codegened_module_to_llvm(&self, + tcx: TyCtxt, + module: ModuleCodegen) { + self.wait_for_signal_to_codegen_item(); + self.check_for_errors(tcx.sess); + + // These are generally cheap and won't through off scheduling. + let cost = 0; + submit_codegened_module_to_llvm(tcx, module, cost); + } + + pub fn codegen_finished(&self, tcx: TyCtxt) { + self.wait_for_signal_to_codegen_item(); + self.check_for_errors(tcx.sess); + drop(self.coordinator_send.send(Box::new(Message::CodegenComplete))); + } + + pub fn check_for_errors(&self, sess: &Session) { + self.shared_emitter_main.check(sess, false); + } + + pub fn wait_for_signal_to_codegen_item(&self) { + match self.codegen_worker_receive.recv() { + Ok(Message::CodegenItem) => { + // Nothing to do + } + Ok(_) => panic!("unexpected message"), + Err(_) => { + // One of the LLVM threads must have panicked, fall through so + // error handling can be reached. + } + } + } +} + +pub(crate) fn submit_codegened_module_to_llvm(tcx: TyCtxt, + module: ModuleCodegen, + cost: u64) { + let llvm_work_item = WorkItem::Optimize(module); + drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::CodegenDone { + llvm_work_item, + cost, + }))); +} + +fn msvc_imps_needed(tcx: TyCtxt) -> bool { + tcx.sess.target.target.options.is_like_msvc && + tcx.sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) +} + +// Create a `__imp_ = &symbol` global for every public static `symbol`. +// This is required to satisfy `dllimport` references to static data in .rlibs +// when using MSVC linker. We do this only for data, as linker can fix up +// code references on its own. +// See #26591, #27438 +fn create_msvc_imps(cgcx: &CodegenContext, llcx: ContextRef, llmod: ModuleRef) { + if !cgcx.msvc_imps_needed { + return + } + // The x86 ABI seems to require that leading underscores are added to symbol + // names, so we need an extra underscore on 32-bit. There's also a leading + // '\x01' here which disables LLVM's symbol mangling (e.g. no extra + // underscores added in front). + let prefix = if cgcx.target_pointer_width == "32" { + "\x01__imp__" + } else { + "\x01__imp_" + }; + unsafe { + let i8p_ty = Type::i8p_llcx(llcx); + let globals = base::iter_globals(llmod) + .filter(|&val| { + llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage && + llvm::LLVMIsDeclaration(val) == 0 + }) + .map(move |val| { + let name = CStr::from_ptr(llvm::LLVMGetValueName(val)); + let mut imp_name = prefix.as_bytes().to_vec(); + imp_name.extend(name.to_bytes()); + let imp_name = CString::new(imp_name).unwrap(); + (imp_name, val) + }) + .collect::>(); + for (imp_name, val) in globals { + let imp = llvm::LLVMAddGlobal(llmod, + i8p_ty.to_ref(), + imp_name.as_ptr() as *const _); + llvm::LLVMSetInitializer(imp, consts::ptrcast(val, i8p_ty)); + llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage); + } + } +} diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs new file mode 100644 index 00000000000..d04cb72d52d --- /dev/null +++ b/src/librustc_codegen_llvm/base.rs @@ -0,0 +1,1411 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Codegen the completed AST to the LLVM IR. +//! +//! Some functions here, such as codegen_block and codegen_expr, return a value -- +//! the result of the codegen to LLVM -- while others, such as codegen_fn +//! and mono_item, are called only for the side effect of adding a +//! particular definition to the LLVM IR output we're producing. +//! +//! Hopefully useful general knowledge about codegen: +//! +//! * There's no way to find out the Ty type of a ValueRef. Doing so +//! would be "trying to get the eggs out of an omelette" (credit: +//! pcwalton). You can, instead, find out its TypeRef by calling val_ty, +//! but one TypeRef corresponds to many `Ty`s; for instance, tup(int, int, +//! int) and rec(x=int, y=int, z=int) will have the same TypeRef. + +use super::ModuleLlvm; +use super::ModuleSource; +use super::ModuleCodegen; +use super::ModuleKind; + +use abi; +use back::link; +use back::write::{self, OngoingCodegen, create_target_machine}; +use llvm::{ContextRef, ModuleRef, ValueRef, Vector, get_param}; +use llvm; +use metadata; +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc::middle::lang_items::StartFnLangItem; +use rustc::middle::weak_lang_items; +use rustc::mir::mono::{Linkage, Visibility, Stats}; +use rustc::middle::cstore::{EncodedMetadata}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::layout::{self, Align, TyLayout, LayoutOf}; +use rustc::ty::maps::Providers; +use rustc::dep_graph::{DepNode, DepConstructor}; +use rustc::ty::subst::Kind; +use rustc::middle::cstore::{self, LinkMeta, LinkagePreference}; +use rustc::middle::exported_symbols; +use rustc::util::common::{time, print_time_passes_entry}; +use rustc::session::config::{self, NoDebugInfo}; +use rustc::session::Session; +use rustc_incremental; +use allocator; +use mir::place::PlaceRef; +use attributes; +use builder::{Builder, MemFlags}; +use callee; +use common::{C_bool, C_bytes_in_context, C_i32, C_usize}; +use rustc_mir::monomorphize::collector::{self, MonoItemCollectionMode}; +use common::{self, C_struct_in_context, C_array, val_ty}; +use consts; +use context::{self, CodegenCx}; +use debuginfo; +use declare; +use meth; +use mir; +use monomorphize::Instance; +use monomorphize::partitioning::{self, PartitioningStrategy, CodegenUnit, CodegenUnitExt}; +use rustc_codegen_utils::symbol_names_test; +use time_graph; +use mono_item::{MonoItem, BaseMonoItemExt, MonoItemExt, DefPathBasedNames}; +use type_::Type; +use type_of::LayoutLlvmExt; +use rustc::util::nodemap::{FxHashMap, FxHashSet, DefIdSet}; +use CrateInfo; +use rustc_data_structures::sync::Lrc; +use rustc_target::spec::TargetTriple; + +use std::any::Any; +use std::collections::BTreeMap; +use std::ffi::CString; +use std::str; +use std::sync::Arc; +use std::time::{Instant, Duration}; +use std::i32; +use std::cmp; +use std::sync::mpsc; +use syntax_pos::Span; +use syntax_pos::symbol::InternedString; +use syntax::attr; +use rustc::hir; +use syntax::ast; + +use mir::operand::OperandValue; + +pub use rustc_codegen_utils::check_for_rustc_errors_attr; + +pub struct StatRecorder<'a, 'tcx: 'a> { + cx: &'a CodegenCx<'a, 'tcx>, + name: Option, + istart: usize, +} + +impl<'a, 'tcx> StatRecorder<'a, 'tcx> { + pub fn new(cx: &'a CodegenCx<'a, 'tcx>, name: String) -> StatRecorder<'a, 'tcx> { + let istart = cx.stats.borrow().n_llvm_insns; + StatRecorder { + cx, + name: Some(name), + istart, + } + } +} + +impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { + fn drop(&mut self) { + if self.cx.sess().codegen_stats() { + let mut stats = self.cx.stats.borrow_mut(); + let iend = stats.n_llvm_insns; + stats.fn_stats.push((self.name.take().unwrap(), iend - self.istart)); + stats.n_fns += 1; + // Reset LLVM insn count to avoid compound costs. + stats.n_llvm_insns = self.istart; + } + } +} + +pub fn bin_op_to_icmp_predicate(op: hir::BinOp_, + signed: bool) + -> llvm::IntPredicate { + match op { + hir::BiEq => llvm::IntEQ, + hir::BiNe => llvm::IntNE, + hir::BiLt => if signed { llvm::IntSLT } else { llvm::IntULT }, + hir::BiLe => if signed { llvm::IntSLE } else { llvm::IntULE }, + hir::BiGt => if signed { llvm::IntSGT } else { llvm::IntUGT }, + hir::BiGe => if signed { llvm::IntSGE } else { llvm::IntUGE }, + op => { + bug!("comparison_op_to_icmp_predicate: expected comparison operator, \ + found {:?}", + op) + } + } +} + +pub fn bin_op_to_fcmp_predicate(op: hir::BinOp_) -> llvm::RealPredicate { + match op { + hir::BiEq => llvm::RealOEQ, + hir::BiNe => llvm::RealUNE, + hir::BiLt => llvm::RealOLT, + hir::BiLe => llvm::RealOLE, + hir::BiGt => llvm::RealOGT, + hir::BiGe => llvm::RealOGE, + op => { + bug!("comparison_op_to_fcmp_predicate: expected comparison operator, \ + found {:?}", + op); + } + } +} + +pub fn compare_simd_types<'a, 'tcx>( + bx: &Builder<'a, 'tcx>, + lhs: ValueRef, + rhs: ValueRef, + t: Ty<'tcx>, + ret_ty: Type, + op: hir::BinOp_ +) -> ValueRef { + let signed = match t.sty { + ty::TyFloat(_) => { + let cmp = bin_op_to_fcmp_predicate(op); + return bx.sext(bx.fcmp(cmp, lhs, rhs), ret_ty); + }, + ty::TyUint(_) => false, + ty::TyInt(_) => true, + _ => bug!("compare_simd_types: invalid SIMD type"), + }; + + let cmp = bin_op_to_icmp_predicate(op, signed); + // LLVM outputs an `< size x i1 >`, so we need to perform a sign extension + // to get the correctly sized type. This will compile to a single instruction + // once the IR is converted to assembly if the SIMD instruction is supported + // by the target architecture. + bx.sext(bx.icmp(cmp, lhs, rhs), ret_ty) +} + +/// Retrieve the information we are losing (making dynamic) in an unsizing +/// adjustment. +/// +/// The `old_info` argument is a bit funny. It is intended for use +/// in an upcast, where the new vtable for an object will be derived +/// from the old one. +pub fn unsized_info<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>, + source: Ty<'tcx>, + target: Ty<'tcx>, + old_info: Option) + -> ValueRef { + let (source, target) = cx.tcx.struct_lockstep_tails(source, target); + match (&source.sty, &target.sty) { + (&ty::TyArray(_, len), &ty::TySlice(_)) => { + C_usize(cx, len.unwrap_usize(cx.tcx)) + } + (&ty::TyDynamic(..), &ty::TyDynamic(..)) => { + // For now, upcasts are limited to changes in marker + // traits, and hence never actually require an actual + // change to the vtable. + old_info.expect("unsized_info: missing old info for trait upcast") + } + (_, &ty::TyDynamic(ref data, ..)) => { + let vtable_ptr = cx.layout_of(cx.tcx.mk_mut_ptr(target)) + .field(cx, abi::FAT_PTR_EXTRA); + consts::ptrcast(meth::get_vtable(cx, source, data.principal()), + vtable_ptr.llvm_type(cx)) + } + _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", + source, + target), + } +} + +/// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer. +pub fn unsize_thin_ptr<'a, 'tcx>( + bx: &Builder<'a, 'tcx>, + src: ValueRef, + src_ty: Ty<'tcx>, + dst_ty: Ty<'tcx> +) -> (ValueRef, ValueRef) { + debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty); + match (&src_ty.sty, &dst_ty.sty) { + (&ty::TyRef(_, a, _), + &ty::TyRef(_, b, _)) | + (&ty::TyRef(_, a, _), + &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) | + (&ty::TyRawPtr(ty::TypeAndMut { ty: a, .. }), + &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => { + assert!(bx.cx.type_is_sized(a)); + let ptr_ty = bx.cx.layout_of(b).llvm_type(bx.cx).ptr_to(); + (bx.pointercast(src, ptr_ty), unsized_info(bx.cx, a, b, None)) + } + (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => { + let (a, b) = (src_ty.boxed_ty(), dst_ty.boxed_ty()); + assert!(bx.cx.type_is_sized(a)); + let ptr_ty = bx.cx.layout_of(b).llvm_type(bx.cx).ptr_to(); + (bx.pointercast(src, ptr_ty), unsized_info(bx.cx, a, b, None)) + } + (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => { + assert_eq!(def_a, def_b); + + let src_layout = bx.cx.layout_of(src_ty); + let dst_layout = bx.cx.layout_of(dst_ty); + let mut result = None; + for i in 0..src_layout.fields.count() { + let src_f = src_layout.field(bx.cx, i); + assert_eq!(src_layout.fields.offset(i).bytes(), 0); + assert_eq!(dst_layout.fields.offset(i).bytes(), 0); + if src_f.is_zst() { + continue; + } + assert_eq!(src_layout.size, src_f.size); + + let dst_f = dst_layout.field(bx.cx, i); + assert_ne!(src_f.ty, dst_f.ty); + assert_eq!(result, None); + result = Some(unsize_thin_ptr(bx, src, src_f.ty, dst_f.ty)); + } + let (lldata, llextra) = result.unwrap(); + // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. + (bx.bitcast(lldata, dst_layout.scalar_pair_element_llvm_type(bx.cx, 0)), + bx.bitcast(llextra, dst_layout.scalar_pair_element_llvm_type(bx.cx, 1))) + } + _ => bug!("unsize_thin_ptr: called on bad types"), + } +} + +/// Coerce `src`, which is a reference to a value of type `src_ty`, +/// to a value of type `dst_ty` and store the result in `dst` +pub fn coerce_unsized_into<'a, 'tcx>(bx: &Builder<'a, 'tcx>, + src: PlaceRef<'tcx>, + dst: PlaceRef<'tcx>) { + let src_ty = src.layout.ty; + let dst_ty = dst.layout.ty; + let coerce_ptr = || { + let (base, info) = match src.load(bx).val { + OperandValue::Pair(base, info) => { + // fat-ptr to fat-ptr unsize preserves the vtable + // i.e. &'a fmt::Debug+Send => &'a fmt::Debug + // So we need to pointercast the base to ensure + // the types match up. + let thin_ptr = dst.layout.field(bx.cx, abi::FAT_PTR_ADDR); + (bx.pointercast(base, thin_ptr.llvm_type(bx.cx)), info) + } + OperandValue::Immediate(base) => { + unsize_thin_ptr(bx, base, src_ty, dst_ty) + } + OperandValue::Ref(..) => bug!() + }; + OperandValue::Pair(base, info).store(bx, dst); + }; + match (&src_ty.sty, &dst_ty.sty) { + (&ty::TyRef(..), &ty::TyRef(..)) | + (&ty::TyRef(..), &ty::TyRawPtr(..)) | + (&ty::TyRawPtr(..), &ty::TyRawPtr(..)) => { + coerce_ptr() + } + (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => { + coerce_ptr() + } + + (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => { + assert_eq!(def_a, def_b); + + for i in 0..def_a.variants[0].fields.len() { + let src_f = src.project_field(bx, i); + let dst_f = dst.project_field(bx, i); + + if dst_f.layout.is_zst() { + continue; + } + + if src_f.layout.ty == dst_f.layout.ty { + memcpy_ty(bx, dst_f.llval, src_f.llval, src_f.layout, + src_f.align.min(dst_f.align), MemFlags::empty()); + } else { + coerce_unsized_into(bx, src_f, dst_f); + } + } + } + _ => bug!("coerce_unsized_into: invalid coercion {:?} -> {:?}", + src_ty, + dst_ty), + } +} + +pub fn cast_shift_expr_rhs( + cx: &Builder, op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef +) -> ValueRef { + cast_shift_rhs(op, lhs, rhs, |a, b| cx.trunc(a, b), |a, b| cx.zext(a, b)) +} + +fn cast_shift_rhs(op: hir::BinOp_, + lhs: ValueRef, + rhs: ValueRef, + trunc: F, + zext: G) + -> ValueRef + where F: FnOnce(ValueRef, Type) -> ValueRef, + G: FnOnce(ValueRef, Type) -> ValueRef +{ + // Shifts may have any size int on the rhs + if op.is_shift() { + let mut rhs_llty = val_ty(rhs); + let mut lhs_llty = val_ty(lhs); + if rhs_llty.kind() == Vector { + rhs_llty = rhs_llty.element_type() + } + if lhs_llty.kind() == Vector { + lhs_llty = lhs_llty.element_type() + } + let rhs_sz = rhs_llty.int_width(); + let lhs_sz = lhs_llty.int_width(); + if lhs_sz < rhs_sz { + trunc(rhs, lhs_llty) + } else if lhs_sz > rhs_sz { + // FIXME (#1877: If shifting by negative + // values becomes not undefined then this is wrong. + zext(rhs, lhs_llty) + } else { + rhs + } + } else { + rhs + } +} + +/// Returns whether this session's target will use SEH-based unwinding. +/// +/// This is only true for MSVC targets, and even then the 64-bit MSVC target +/// currently uses SEH-ish unwinding with DWARF info tables to the side (same as +/// 64-bit MinGW) instead of "full SEH". +pub fn wants_msvc_seh(sess: &Session) -> bool { + sess.target.target.options.is_like_msvc +} + +pub fn call_assume<'a, 'tcx>(bx: &Builder<'a, 'tcx>, val: ValueRef) { + let assume_intrinsic = bx.cx.get_intrinsic("llvm.assume"); + bx.call(assume_intrinsic, &[val], None); +} + +pub fn from_immediate(bx: &Builder, val: ValueRef) -> ValueRef { + if val_ty(val) == Type::i1(bx.cx) { + bx.zext(val, Type::i8(bx.cx)) + } else { + val + } +} + +pub fn to_immediate(bx: &Builder, val: ValueRef, layout: layout::TyLayout) -> ValueRef { + if let layout::Abi::Scalar(ref scalar) = layout.abi { + if scalar.is_bool() { + return bx.trunc(val, Type::i1(bx.cx)); + } + } + val +} + +pub fn call_memcpy(bx: &Builder, + dst: ValueRef, + src: ValueRef, + n_bytes: ValueRef, + align: Align, + flags: MemFlags) { + if flags.contains(MemFlags::NONTEMPORAL) { + // HACK(nox): This is inefficient but there is no nontemporal memcpy. + let val = bx.load(src, align); + let ptr = bx.pointercast(dst, val_ty(val).ptr_to()); + bx.store_with_flags(val, ptr, align, flags); + return; + } + let cx = bx.cx; + let ptr_width = &cx.sess().target.target.target_pointer_width; + let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width); + let memcpy = cx.get_intrinsic(&key); + let src_ptr = bx.pointercast(src, Type::i8p(cx)); + let dst_ptr = bx.pointercast(dst, Type::i8p(cx)); + let size = bx.intcast(n_bytes, cx.isize_ty, false); + let align = C_i32(cx, align.abi() as i32); + let volatile = C_bool(cx, flags.contains(MemFlags::VOLATILE)); + bx.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None); +} + +pub fn memcpy_ty<'a, 'tcx>( + bx: &Builder<'a, 'tcx>, + dst: ValueRef, + src: ValueRef, + layout: TyLayout<'tcx>, + align: Align, + flags: MemFlags, +) { + let size = layout.size.bytes(); + if size == 0 { + return; + } + + call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, flags); +} + +pub fn call_memset<'a, 'tcx>(bx: &Builder<'a, 'tcx>, + ptr: ValueRef, + fill_byte: ValueRef, + size: ValueRef, + align: ValueRef, + volatile: bool) -> ValueRef { + let ptr_width = &bx.cx.sess().target.target.target_pointer_width; + let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width); + let llintrinsicfn = bx.cx.get_intrinsic(&intrinsic_key); + let volatile = C_bool(bx.cx, volatile); + bx.call(llintrinsicfn, &[ptr, fill_byte, size, align, volatile], None) +} + +pub fn codegen_instance<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, instance: Instance<'tcx>) { + let _s = if cx.sess().codegen_stats() { + let mut instance_name = String::new(); + DefPathBasedNames::new(cx.tcx, true, true) + .push_def_path(instance.def_id(), &mut instance_name); + Some(StatRecorder::new(cx, instance_name)) + } else { + None + }; + + // this is an info! to allow collecting monomorphization statistics + // and to allow finding the last function before LLVM aborts from + // release builds. + info!("codegen_instance({})", instance); + + let fn_ty = instance.ty(cx.tcx); + let sig = common::ty_fn_sig(cx, fn_ty); + let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + + let lldecl = match cx.instances.borrow().get(&instance) { + Some(&val) => val, + None => bug!("Instance `{:?}` not already declared", instance) + }; + + cx.stats.borrow_mut().n_closures += 1; + + // The `uwtable` attribute according to LLVM is: + // + // This attribute indicates that the ABI being targeted requires that an + // unwind table entry be produced for this function even if we can show + // that no exceptions passes by it. This is normally the case for the + // ELF x86-64 abi, but it can be disabled for some compilation units. + // + // Typically when we're compiling with `-C panic=abort` (which implies this + // `no_landing_pads` check) we don't need `uwtable` because we can't + // generate any exceptions! On Windows, however, exceptions include other + // events such as illegal instructions, segfaults, etc. This means that on + // Windows we end up still needing the `uwtable` attribute even if the `-C + // panic=abort` flag is passed. + // + // You can also find more info on why Windows is whitelisted here in: + // https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 + if !cx.sess().no_landing_pads() || + cx.sess().target.target.options.requires_uwtable { + attributes::emit_uwtable(lldecl, true); + } + + let mir = cx.tcx.instance_mir(instance.def); + mir::codegen_mir(cx, lldecl, &mir, instance, sig); +} + +pub fn set_link_section(cx: &CodegenCx, + llval: ValueRef, + attrs: &[ast::Attribute]) { + if let Some(sect) = attr::first_attr_value_str_by_name(attrs, "link_section") { + if contains_null(§.as_str()) { + cx.sess().fatal(&format!("Illegal null byte in link_section value: `{}`", §)); + } + unsafe { + let buf = CString::new(sect.as_str().as_bytes()).unwrap(); + llvm::LLVMSetSection(llval, buf.as_ptr()); + } + } +} + +/// Create the `main` function which will initialize the rust runtime and call +/// users main function. +fn maybe_create_entry_wrapper(cx: &CodegenCx) { + let (main_def_id, span) = match *cx.sess().entry_fn.borrow() { + Some((id, span, _)) => { + (cx.tcx.hir.local_def_id(id), span) + } + None => return, + }; + + let instance = Instance::mono(cx.tcx, main_def_id); + + if !cx.codegen_unit.contains_item(&MonoItem::Fn(instance)) { + // We want to create the wrapper in the same codegen unit as Rust's main + // function. + return; + } + + let main_llfn = callee::get_fn(cx, instance); + + let et = cx.sess().entry_fn.get().map(|e| e.2); + match et { + Some(config::EntryMain) => create_entry_fn(cx, span, main_llfn, main_def_id, true), + Some(config::EntryStart) => create_entry_fn(cx, span, main_llfn, main_def_id, false), + None => {} // Do nothing. + } + + fn create_entry_fn<'cx>(cx: &'cx CodegenCx, + sp: Span, + rust_main: ValueRef, + rust_main_def_id: DefId, + use_start_lang_item: bool) { + let llfty = Type::func(&[Type::c_int(cx), Type::i8p(cx).ptr_to()], &Type::c_int(cx)); + + let main_ret_ty = cx.tcx.fn_sig(rust_main_def_id).output(); + // Given that `main()` has no arguments, + // then its return type cannot have + // late-bound regions, since late-bound + // regions must appear in the argument + // listing. + let main_ret_ty = cx.tcx.erase_regions( + &main_ret_ty.no_late_bound_regions().unwrap(), + ); + + if declare::get_defined_value(cx, "main").is_some() { + // FIXME: We should be smart and show a better diagnostic here. + cx.sess().struct_span_err(sp, "entry symbol `main` defined multiple times") + .help("did you use #[no_mangle] on `fn main`? Use #[start] instead") + .emit(); + cx.sess().abort_if_errors(); + bug!(); + } + let llfn = declare::declare_cfn(cx, "main", llfty); + + // `main` should respect same config for frame pointer elimination as rest of code + attributes::set_frame_pointer_elimination(cx, llfn); + + let bx = Builder::new_block(cx, llfn, "top"); + + debuginfo::gdb::insert_reference_to_gdb_debug_scripts_section_global(&bx); + + // Params from native main() used as args for rust start function + let param_argc = get_param(llfn, 0); + let param_argv = get_param(llfn, 1); + let arg_argc = bx.intcast(param_argc, cx.isize_ty, true); + let arg_argv = param_argv; + + let (start_fn, args) = if use_start_lang_item { + let start_def_id = cx.tcx.require_lang_item(StartFnLangItem); + let start_fn = callee::resolve_and_get_fn( + cx, + start_def_id, + cx.tcx.intern_substs(&[Kind::from(main_ret_ty)]), + ); + (start_fn, vec![bx.pointercast(rust_main, Type::i8p(cx).ptr_to()), + arg_argc, arg_argv]) + } else { + debug!("using user-defined start fn"); + (rust_main, vec![arg_argc, arg_argv]) + }; + + let result = bx.call(start_fn, &args, None); + bx.ret(bx.intcast(result, Type::c_int(cx), true)); + } +} + +fn contains_null(s: &str) -> bool { + s.bytes().any(|b| b == 0) +} + +fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, + llmod_id: &str, + link_meta: &LinkMeta) + -> (ContextRef, ModuleRef, EncodedMetadata) { + use std::io::Write; + use flate2::Compression; + use flate2::write::DeflateEncoder; + + let (metadata_llcx, metadata_llmod) = unsafe { + context::create_context_and_module(tcx.sess, llmod_id) + }; + + #[derive(PartialEq, Eq, PartialOrd, Ord)] + enum MetadataKind { + None, + Uncompressed, + Compressed + } + + let kind = tcx.sess.crate_types.borrow().iter().map(|ty| { + match *ty { + config::CrateTypeExecutable | + config::CrateTypeStaticlib | + config::CrateTypeCdylib => MetadataKind::None, + + config::CrateTypeRlib => MetadataKind::Uncompressed, + + config::CrateTypeDylib | + config::CrateTypeProcMacro => MetadataKind::Compressed, + } + }).max().unwrap(); + + if kind == MetadataKind::None { + return (metadata_llcx, + metadata_llmod, + EncodedMetadata::new()); + } + + let metadata = tcx.encode_metadata(link_meta); + if kind == MetadataKind::Uncompressed { + return (metadata_llcx, metadata_llmod, metadata); + } + + assert!(kind == MetadataKind::Compressed); + let mut compressed = tcx.metadata_encoding_version(); + DeflateEncoder::new(&mut compressed, Compression::fast()) + .write_all(&metadata.raw_data).unwrap(); + + let llmeta = C_bytes_in_context(metadata_llcx, &compressed); + let llconst = C_struct_in_context(metadata_llcx, &[llmeta], false); + let name = exported_symbols::metadata_symbol_name(tcx); + let buf = CString::new(name).unwrap(); + let llglobal = unsafe { + llvm::LLVMAddGlobal(metadata_llmod, val_ty(llconst).to_ref(), buf.as_ptr()) + }; + unsafe { + llvm::LLVMSetInitializer(llglobal, llconst); + let section_name = metadata::metadata_section_name(&tcx.sess.target.target); + let name = CString::new(section_name).unwrap(); + llvm::LLVMSetSection(llglobal, name.as_ptr()); + + // Also generate a .section directive to force no + // flags, at least for ELF outputs, so that the + // metadata doesn't get loaded into memory. + let directive = format!(".section {}", section_name); + let directive = CString::new(directive).unwrap(); + llvm::LLVMSetModuleInlineAsm(metadata_llmod, directive.as_ptr()) + } + return (metadata_llcx, metadata_llmod, metadata); +} + +pub struct ValueIter { + cur: ValueRef, + step: unsafe extern "C" fn(ValueRef) -> ValueRef, +} + +impl Iterator for ValueIter { + type Item = ValueRef; + + fn next(&mut self) -> Option { + let old = self.cur; + if !old.is_null() { + self.cur = unsafe { (self.step)(old) }; + Some(old) + } else { + None + } + } +} + +pub fn iter_globals(llmod: llvm::ModuleRef) -> ValueIter { + unsafe { + ValueIter { + cur: llvm::LLVMGetFirstGlobal(llmod), + step: llvm::LLVMGetNextGlobal, + } + } +} + +pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + rx: mpsc::Receiver>) + -> OngoingCodegen { + + check_for_rustc_errors_attr(tcx); + + if let Some(true) = tcx.sess.opts.debugging_opts.thinlto { + if unsafe { !llvm::LLVMRustThinLTOAvailable() } { + tcx.sess.fatal("this compiler's LLVM does not support ThinLTO"); + } + } + + if (tcx.sess.opts.debugging_opts.pgo_gen.is_some() || + !tcx.sess.opts.debugging_opts.pgo_use.is_empty()) && + unsafe { !llvm::LLVMRustPGOAvailable() } + { + tcx.sess.fatal("this compiler's LLVM does not support PGO"); + } + + let crate_hash = tcx.crate_hash(LOCAL_CRATE); + let link_meta = link::build_link_meta(crate_hash); + + // Codegen the metadata. + let llmod_id = "metadata"; + let (metadata_llcx, metadata_llmod, metadata) = + time(tcx.sess, "write metadata", || { + write_metadata(tcx, llmod_id, &link_meta) + }); + + let metadata_module = ModuleCodegen { + name: link::METADATA_MODULE_NAME.to_string(), + llmod_id: llmod_id.to_string(), + source: ModuleSource::Codegened(ModuleLlvm { + llcx: metadata_llcx, + llmod: metadata_llmod, + tm: create_target_machine(tcx.sess, false), + }), + kind: ModuleKind::Metadata, + }; + + let time_graph = if tcx.sess.opts.debugging_opts.codegen_time_graph { + Some(time_graph::TimeGraph::new()) + } else { + None + }; + + // Skip crate items and just output metadata in -Z no-codegen mode. + if tcx.sess.opts.debugging_opts.no_codegen || + !tcx.sess.opts.output_types.should_codegen() { + let ongoing_codegen = write::start_async_codegen( + tcx, + time_graph.clone(), + link_meta, + metadata, + rx, + 1); + + ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module); + ongoing_codegen.codegen_finished(tcx); + + assert_and_save_dep_graph(tcx); + + ongoing_codegen.check_for_errors(tcx.sess); + + return ongoing_codegen; + } + + // Run the monomorphization collector and partition the collected items into + // codegen units. + let codegen_units = + tcx.collect_and_partition_mono_items(LOCAL_CRATE).1; + let codegen_units = (*codegen_units).clone(); + + // Force all codegen_unit queries so they are already either red or green + // when compile_codegen_unit accesses them. We are not able to re-execute + // the codegen_unit query from just the DepNode, so an unknown color would + // lead to having to re-execute compile_codegen_unit, possibly + // unnecessarily. + if tcx.dep_graph.is_fully_enabled() { + for cgu in &codegen_units { + tcx.codegen_unit(cgu.name().clone()); + } + } + + let ongoing_codegen = write::start_async_codegen( + tcx, + time_graph.clone(), + link_meta, + metadata, + rx, + codegen_units.len()); + + // Codegen an allocator shim, if any + let allocator_module = if let Some(kind) = *tcx.sess.allocator_kind.get() { + unsafe { + let llmod_id = "allocator"; + let (llcx, llmod) = + context::create_context_and_module(tcx.sess, llmod_id); + let modules = ModuleLlvm { + llmod, + llcx, + tm: create_target_machine(tcx.sess, false), + }; + time(tcx.sess, "write allocator module", || { + allocator::codegen(tcx, &modules, kind) + }); + + Some(ModuleCodegen { + name: link::ALLOCATOR_MODULE_NAME.to_string(), + llmod_id: llmod_id.to_string(), + source: ModuleSource::Codegened(modules), + kind: ModuleKind::Allocator, + }) + } + } else { + None + }; + + if let Some(allocator_module) = allocator_module { + ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, allocator_module); + } + + ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module); + + // We sort the codegen units by size. This way we can schedule work for LLVM + // a bit more efficiently. + let codegen_units = { + let mut codegen_units = codegen_units; + codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); + codegen_units + }; + + let mut total_codegen_time = Duration::new(0, 0); + let mut all_stats = Stats::default(); + + for cgu in codegen_units.into_iter() { + ongoing_codegen.wait_for_signal_to_codegen_item(); + ongoing_codegen.check_for_errors(tcx.sess); + + // First, if incremental compilation is enabled, we try to re-use the + // codegen unit from the cache. + if tcx.dep_graph.is_fully_enabled() { + let cgu_id = cgu.work_product_id(); + + // Check whether there is a previous work-product we can + // re-use. Not only must the file exist, and the inputs not + // be dirty, but the hash of the symbols we will generate must + // be the same. + if let Some(buf) = tcx.dep_graph.previous_work_product(&cgu_id) { + let dep_node = &DepNode::new(tcx, + DepConstructor::CompileCodegenUnit(cgu.name().clone())); + + // We try to mark the DepNode::CompileCodegenUnit green. If we + // succeed it means that none of the dependencies has changed + // and we can safely re-use. + if let Some(dep_node_index) = tcx.dep_graph.try_mark_green(tcx, dep_node) { + // Append ".rs" to LLVM module identifier. + // + // LLVM code generator emits a ".file filename" directive + // for ELF backends. Value of the "filename" is set as the + // LLVM module identifier. Due to a LLVM MC bug[1], LLVM + // crashes if the module identifier is same as other symbols + // such as a function name in the module. + // 1. http://llvm.org/bugs/show_bug.cgi?id=11479 + let llmod_id = format!("{}.rs", cgu.name()); + + let module = ModuleCodegen { + name: cgu.name().to_string(), + source: ModuleSource::Preexisting(buf), + kind: ModuleKind::Regular, + llmod_id, + }; + tcx.dep_graph.mark_loaded_from_cache(dep_node_index, true); + write::submit_codegened_module_to_llvm(tcx, module, 0); + // Continue to next cgu, this one is done. + continue + } + } else { + // This can happen if files were deleted from the cache + // directory for some reason. We just re-compile then. + } + } + + let _timing_guard = time_graph.as_ref().map(|time_graph| { + time_graph.start(write::CODEGEN_WORKER_TIMELINE, + write::CODEGEN_WORK_PACKAGE_KIND, + &format!("codegen {}", cgu.name())) + }); + let start_time = Instant::now(); + all_stats.extend(tcx.compile_codegen_unit(*cgu.name())); + total_codegen_time += start_time.elapsed(); + ongoing_codegen.check_for_errors(tcx.sess); + } + + ongoing_codegen.codegen_finished(tcx); + + // Since the main thread is sometimes blocked during codegen, we keep track + // -Ztime-passes output manually. + print_time_passes_entry(tcx.sess.time_passes(), + "codegen to LLVM IR", + total_codegen_time); + + if tcx.sess.opts.incremental.is_some() { + ::rustc_incremental::assert_module_sources::assert_module_sources(tcx); + } + + symbol_names_test::report_symbol_names(tcx); + + if tcx.sess.codegen_stats() { + println!("--- codegen stats ---"); + println!("n_glues_created: {}", all_stats.n_glues_created); + println!("n_null_glues: {}", all_stats.n_null_glues); + println!("n_real_glues: {}", all_stats.n_real_glues); + + println!("n_fns: {}", all_stats.n_fns); + println!("n_inlines: {}", all_stats.n_inlines); + println!("n_closures: {}", all_stats.n_closures); + println!("fn stats:"); + all_stats.fn_stats.sort_by_key(|&(_, insns)| insns); + for &(ref name, insns) in all_stats.fn_stats.iter() { + println!("{} insns, {}", insns, *name); + } + } + + if tcx.sess.count_llvm_insns() { + for (k, v) in all_stats.llvm_insns.iter() { + println!("{:7} {}", *v, *k); + } + } + + ongoing_codegen.check_for_errors(tcx.sess); + + assert_and_save_dep_graph(tcx); + ongoing_codegen +} + +fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + time(tcx.sess, + "assert dep graph", + || rustc_incremental::assert_dep_graph(tcx)); + + time(tcx.sess, + "serialize dep graph", + || rustc_incremental::save_dep_graph(tcx)); +} + +fn collect_and_partition_mono_items<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + cnum: CrateNum, +) -> (Arc, Arc>>>) +{ + assert_eq!(cnum, LOCAL_CRATE); + + let collection_mode = match tcx.sess.opts.debugging_opts.print_mono_items { + Some(ref s) => { + let mode_string = s.to_lowercase(); + let mode_string = mode_string.trim(); + if mode_string == "eager" { + MonoItemCollectionMode::Eager + } else { + if mode_string != "lazy" { + let message = format!("Unknown codegen-item collection mode '{}'. \ + Falling back to 'lazy' mode.", + mode_string); + tcx.sess.warn(&message); + } + + MonoItemCollectionMode::Lazy + } + } + None => { + if tcx.sess.opts.cg.link_dead_code { + MonoItemCollectionMode::Eager + } else { + MonoItemCollectionMode::Lazy + } + } + }; + + let (items, inlining_map) = + time(tcx.sess, "monomorphization collection", || { + collector::collect_crate_mono_items(tcx, collection_mode) + }); + + tcx.sess.abort_if_errors(); + + ::rustc_mir::monomorphize::assert_symbols_are_distinct(tcx, items.iter()); + + let strategy = if tcx.sess.opts.incremental.is_some() { + PartitioningStrategy::PerModule + } else { + PartitioningStrategy::FixedUnitCount(tcx.sess.codegen_units()) + }; + + let codegen_units = time(tcx.sess, "codegen unit partitioning", || { + partitioning::partition(tcx, + items.iter().cloned(), + strategy, + &inlining_map) + .into_iter() + .map(Arc::new) + .collect::>() + }); + + let mono_items: DefIdSet = items.iter().filter_map(|mono_item| { + match *mono_item { + MonoItem::Fn(ref instance) => Some(instance.def_id()), + MonoItem::Static(def_id) => Some(def_id), + _ => None, + } + }).collect(); + + if tcx.sess.opts.debugging_opts.print_mono_items.is_some() { + let mut item_to_cgus = FxHashMap(); + + for cgu in &codegen_units { + for (&mono_item, &linkage) in cgu.items() { + item_to_cgus.entry(mono_item) + .or_insert(Vec::new()) + .push((cgu.name().clone(), linkage)); + } + } + + let mut item_keys: Vec<_> = items + .iter() + .map(|i| { + let mut output = i.to_string(tcx); + output.push_str(" @@"); + let mut empty = Vec::new(); + let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); + cgus.as_mut_slice().sort_by_key(|&(ref name, _)| name.clone()); + cgus.dedup(); + for &(ref cgu_name, (linkage, _)) in cgus.iter() { + output.push_str(" "); + output.push_str(&cgu_name.as_str()); + + let linkage_abbrev = match linkage { + Linkage::External => "External", + Linkage::AvailableExternally => "Available", + Linkage::LinkOnceAny => "OnceAny", + Linkage::LinkOnceODR => "OnceODR", + Linkage::WeakAny => "WeakAny", + Linkage::WeakODR => "WeakODR", + Linkage::Appending => "Appending", + Linkage::Internal => "Internal", + Linkage::Private => "Private", + Linkage::ExternalWeak => "ExternalWeak", + Linkage::Common => "Common", + }; + + output.push_str("["); + output.push_str(linkage_abbrev); + output.push_str("]"); + } + output + }) + .collect(); + + item_keys.sort(); + + for item in item_keys { + println!("MONO_ITEM {}", item); + } + } + + (Arc::new(mono_items), Arc::new(codegen_units)) +} + +impl CrateInfo { + pub fn new(tcx: TyCtxt) -> CrateInfo { + let mut info = CrateInfo { + panic_runtime: None, + compiler_builtins: None, + profiler_runtime: None, + sanitizer_runtime: None, + is_no_builtins: FxHashSet(), + native_libraries: FxHashMap(), + used_libraries: tcx.native_libraries(LOCAL_CRATE), + link_args: tcx.link_args(LOCAL_CRATE), + crate_name: FxHashMap(), + used_crates_dynamic: cstore::used_crates(tcx, LinkagePreference::RequireDynamic), + used_crates_static: cstore::used_crates(tcx, LinkagePreference::RequireStatic), + used_crate_source: FxHashMap(), + wasm_custom_sections: BTreeMap::new(), + wasm_imports: FxHashMap(), + lang_item_to_crate: FxHashMap(), + missing_lang_items: FxHashMap(), + }; + let lang_items = tcx.lang_items(); + + let load_wasm_items = tcx.sess.crate_types.borrow() + .iter() + .any(|c| *c != config::CrateTypeRlib) && + tcx.sess.opts.target_triple == TargetTriple::from_triple("wasm32-unknown-unknown"); + + if load_wasm_items { + info!("attempting to load all wasm sections"); + for &id in tcx.wasm_custom_sections(LOCAL_CRATE).iter() { + let (name, contents) = fetch_wasm_section(tcx, id); + info.wasm_custom_sections.entry(name) + .or_insert(Vec::new()) + .extend(contents); + } + info.load_wasm_imports(tcx, LOCAL_CRATE); + } + + for &cnum in tcx.crates().iter() { + info.native_libraries.insert(cnum, tcx.native_libraries(cnum)); + info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string()); + info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum)); + if tcx.is_panic_runtime(cnum) { + info.panic_runtime = Some(cnum); + } + if tcx.is_compiler_builtins(cnum) { + info.compiler_builtins = Some(cnum); + } + if tcx.is_profiler_runtime(cnum) { + info.profiler_runtime = Some(cnum); + } + if tcx.is_sanitizer_runtime(cnum) { + info.sanitizer_runtime = Some(cnum); + } + if tcx.is_no_builtins(cnum) { + info.is_no_builtins.insert(cnum); + } + if load_wasm_items { + for &id in tcx.wasm_custom_sections(cnum).iter() { + let (name, contents) = fetch_wasm_section(tcx, id); + info.wasm_custom_sections.entry(name) + .or_insert(Vec::new()) + .extend(contents); + } + info.load_wasm_imports(tcx, cnum); + } + let missing = tcx.missing_lang_items(cnum); + for &item in missing.iter() { + if let Ok(id) = lang_items.require(item) { + info.lang_item_to_crate.insert(item, id.krate); + } + } + + // No need to look for lang items that are whitelisted and don't + // actually need to exist. + let missing = missing.iter() + .cloned() + .filter(|&l| !weak_lang_items::whitelisted(tcx, l)) + .collect(); + info.missing_lang_items.insert(cnum, missing); + } + + return info + } + + fn load_wasm_imports(&mut self, tcx: TyCtxt, cnum: CrateNum) { + for (&id, module) in tcx.wasm_import_module_map(cnum).iter() { + let instance = Instance::mono(tcx, id); + let import_name = tcx.symbol_name(instance); + self.wasm_imports.insert(import_name.to_string(), module.clone()); + } + } +} + +fn is_codegened_item(tcx: TyCtxt, id: DefId) -> bool { + let (all_mono_items, _) = + tcx.collect_and_partition_mono_items(LOCAL_CRATE); + all_mono_items.contains(&id) +} + +fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + cgu: InternedString) -> Stats { + let cgu = tcx.codegen_unit(cgu); + + let start_time = Instant::now(); + let (stats, module) = module_codegen(tcx, cgu); + let time_to_codegen = start_time.elapsed(); + + // We assume that the cost to run LLVM on a CGU is proportional to + // the time we needed for codegenning it. + let cost = time_to_codegen.as_secs() * 1_000_000_000 + + time_to_codegen.subsec_nanos() as u64; + + write::submit_codegened_module_to_llvm(tcx, + module, + cost); + return stats; + + fn module_codegen<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + cgu: Arc>) + -> (Stats, ModuleCodegen) + { + let cgu_name = cgu.name().to_string(); + + // Append ".rs" to LLVM module identifier. + // + // LLVM code generator emits a ".file filename" directive + // for ELF backends. Value of the "filename" is set as the + // LLVM module identifier. Due to a LLVM MC bug[1], LLVM + // crashes if the module identifier is same as other symbols + // such as a function name in the module. + // 1. http://llvm.org/bugs/show_bug.cgi?id=11479 + let llmod_id = format!("{}-{}.rs", + cgu.name(), + tcx.crate_disambiguator(LOCAL_CRATE) + .to_fingerprint().to_hex()); + + // Instantiate monomorphizations without filling out definitions yet... + let cx = CodegenCx::new(tcx, cgu, &llmod_id); + let module = { + let mono_items = cx.codegen_unit + .items_in_deterministic_order(cx.tcx); + for &(mono_item, (linkage, visibility)) in &mono_items { + mono_item.predefine(&cx, linkage, visibility); + } + + // ... and now that we have everything pre-defined, fill out those definitions. + for &(mono_item, _) in &mono_items { + mono_item.define(&cx); + } + + // If this codegen unit contains the main function, also create the + // wrapper here + maybe_create_entry_wrapper(&cx); + + // Run replace-all-uses-with for statics that need it + for &(old_g, new_g) in cx.statics_to_rauw.borrow().iter() { + unsafe { + let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g)); + llvm::LLVMReplaceAllUsesWith(old_g, bitcast); + llvm::LLVMDeleteGlobal(old_g); + } + } + + // Create the llvm.used variable + // This variable has type [N x i8*] and is stored in the llvm.metadata section + if !cx.used_statics.borrow().is_empty() { + let name = CString::new("llvm.used").unwrap(); + let section = CString::new("llvm.metadata").unwrap(); + let array = C_array(Type::i8(&cx).ptr_to(), &*cx.used_statics.borrow()); + + unsafe { + let g = llvm::LLVMAddGlobal(cx.llmod, + val_ty(array).to_ref(), + name.as_ptr()); + llvm::LLVMSetInitializer(g, array); + llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage); + llvm::LLVMSetSection(g, section.as_ptr()); + } + } + + // Finalize debuginfo + if cx.sess().opts.debuginfo != NoDebugInfo { + debuginfo::finalize(&cx); + } + + let llvm_module = ModuleLlvm { + llcx: cx.llcx, + llmod: cx.llmod, + tm: create_target_machine(cx.sess(), false), + }; + + ModuleCodegen { + name: cgu_name, + source: ModuleSource::Codegened(llvm_module), + kind: ModuleKind::Regular, + llmod_id, + } + }; + + (cx.into_stats(), module) + } +} + +pub fn provide(providers: &mut Providers) { + providers.collect_and_partition_mono_items = + collect_and_partition_mono_items; + + providers.is_codegened_item = is_codegened_item; + + providers.codegen_unit = |tcx, name| { + let (_, all) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); + all.iter() + .find(|cgu| *cgu.name() == name) + .cloned() + .expect(&format!("failed to find cgu with name {:?}", name)) + }; + providers.compile_codegen_unit = compile_codegen_unit; + + provide_extern(providers); +} + +pub fn provide_extern(providers: &mut Providers) { + providers.dllimport_foreign_items = |tcx, krate| { + let module_map = tcx.foreign_modules(krate); + let module_map = module_map.iter() + .map(|lib| (lib.def_id, lib)) + .collect::>(); + + let dllimports = tcx.native_libraries(krate) + .iter() + .filter(|lib| { + if lib.kind != cstore::NativeLibraryKind::NativeUnknown { + return false + } + let cfg = match lib.cfg { + Some(ref cfg) => cfg, + None => return true, + }; + attr::cfg_matches(cfg, &tcx.sess.parse_sess, None) + }) + .filter_map(|lib| lib.foreign_module) + .map(|id| &module_map[&id]) + .flat_map(|module| module.foreign_items.iter().cloned()) + .collect(); + Lrc::new(dllimports) + }; + + providers.is_dllimport_foreign_item = |tcx, def_id| { + tcx.dllimport_foreign_items(def_id.krate).contains(&def_id) + }; +} + +pub fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage { + match linkage { + Linkage::External => llvm::Linkage::ExternalLinkage, + Linkage::AvailableExternally => llvm::Linkage::AvailableExternallyLinkage, + Linkage::LinkOnceAny => llvm::Linkage::LinkOnceAnyLinkage, + Linkage::LinkOnceODR => llvm::Linkage::LinkOnceODRLinkage, + Linkage::WeakAny => llvm::Linkage::WeakAnyLinkage, + Linkage::WeakODR => llvm::Linkage::WeakODRLinkage, + Linkage::Appending => llvm::Linkage::AppendingLinkage, + Linkage::Internal => llvm::Linkage::InternalLinkage, + Linkage::Private => llvm::Linkage::PrivateLinkage, + Linkage::ExternalWeak => llvm::Linkage::ExternalWeakLinkage, + Linkage::Common => llvm::Linkage::CommonLinkage, + } +} + +pub fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility { + match linkage { + Visibility::Default => llvm::Visibility::Default, + Visibility::Hidden => llvm::Visibility::Hidden, + Visibility::Protected => llvm::Visibility::Protected, + } +} + +// FIXME(mw): Anything that is produced via DepGraph::with_task() must implement +// the HashStable trait. Normally DepGraph::with_task() calls are +// hidden behind queries, but CGU creation is a special case in two +// ways: (1) it's not a query and (2) CGU are output nodes, so their +// Fingerprints are not actually needed. It remains to be clarified +// how exactly this case will be handled in the red/green system but +// for now we content ourselves with providing a no-op HashStable +// implementation for CGUs. +mod temp_stable_hash_impls { + use rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher, + HashStable}; + use ModuleCodegen; + + impl HashStable for ModuleCodegen { + fn hash_stable(&self, + _: &mut HCX, + _: &mut StableHasher) { + // do nothing + } + } +} + +fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec) { + use rustc::mir::interpret::GlobalId; + use rustc::middle::const_val::ConstVal; + + info!("loading wasm section {:?}", id); + + let section = tcx.get_attrs(id) + .iter() + .find(|a| a.check_name("wasm_custom_section")) + .expect("missing #[wasm_custom_section] attribute") + .value_str() + .expect("malformed #[wasm_custom_section] attribute"); + + let instance = ty::Instance::mono(tcx, id); + let cid = GlobalId { + instance, + promoted: None + }; + let param_env = ty::ParamEnv::reveal_all(); + let val = tcx.const_eval(param_env.and(cid)).unwrap(); + + let const_val = match val.val { + ConstVal::Value(val) => val, + ConstVal::Unevaluated(..) => bug!("should be evaluated"), + }; + + let alloc = tcx.const_value_to_allocation((const_val, val.ty)); + (section.to_string(), alloc.bytes.clone()) +} diff --git a/src/librustc_codegen_llvm/build.rs b/src/librustc_codegen_llvm/build.rs new file mode 100644 index 00000000000..97accbb4b8f --- /dev/null +++ b/src/librustc_codegen_llvm/build.rs @@ -0,0 +1,16 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-env-changed=CFG_VERSION"); + println!("cargo:rerun-if-env-changed=CFG_PREFIX"); + println!("cargo:rerun-if-env-changed=CFG_LLVM_ROOT"); +} diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs new file mode 100644 index 00000000000..7b4998e8588 --- /dev/null +++ b/src/librustc_codegen_llvm/builder.rs @@ -0,0 +1,1425 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] // FFI wrappers + +use llvm; +use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect}; +use llvm::{Opcode, IntPredicate, RealPredicate, False, OperandBundleDef}; +use llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef}; +use common::*; +use type_::Type; +use value::Value; +use libc::{c_uint, c_char}; +use rustc::ty::TyCtxt; +use rustc::ty::layout::{Align, Size}; +use rustc::session::{config, Session}; + +use std::borrow::Cow; +use std::ffi::CString; +use std::ops::Range; +use std::ptr; +use syntax_pos::Span; + +// All Builders must have an llfn associated with them +#[must_use] +pub struct Builder<'a, 'tcx: 'a> { + pub llbuilder: BuilderRef, + pub cx: &'a CodegenCx<'a, 'tcx>, +} + +impl<'a, 'tcx> Drop for Builder<'a, 'tcx> { + fn drop(&mut self) { + unsafe { + llvm::LLVMDisposeBuilder(self.llbuilder); + } + } +} + +// This is a really awful way to get a zero-length c-string, but better (and a +// lot more efficient) than doing str::as_c_str("", ...) every time. +fn noname() -> *const c_char { + static CNULL: c_char = 0; + &CNULL +} + +bitflags! { + pub struct MemFlags: u8 { + const VOLATILE = 1 << 0; + const NONTEMPORAL = 1 << 1; + } +} + +impl<'a, 'tcx> Builder<'a, 'tcx> { + pub fn new_block<'b>(cx: &'a CodegenCx<'a, 'tcx>, llfn: ValueRef, name: &'b str) -> Self { + let bx = Builder::with_cx(cx); + let llbb = unsafe { + let name = CString::new(name).unwrap(); + llvm::LLVMAppendBasicBlockInContext( + cx.llcx, + llfn, + name.as_ptr() + ) + }; + bx.position_at_end(llbb); + bx + } + + pub fn with_cx(cx: &'a CodegenCx<'a, 'tcx>) -> Self { + // Create a fresh builder from the crate context. + let llbuilder = unsafe { + llvm::LLVMCreateBuilderInContext(cx.llcx) + }; + Builder { + llbuilder, + cx, + } + } + + pub fn build_sibling_block<'b>(&self, name: &'b str) -> Builder<'a, 'tcx> { + Builder::new_block(self.cx, self.llfn(), name) + } + + pub fn sess(&self) -> &Session { + self.cx.sess() + } + + pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { + self.cx.tcx + } + + pub fn llfn(&self) -> ValueRef { + unsafe { + llvm::LLVMGetBasicBlockParent(self.llbb()) + } + } + + pub fn llbb(&self) -> BasicBlockRef { + unsafe { + llvm::LLVMGetInsertBlock(self.llbuilder) + } + } + + fn count_insn(&self, category: &str) { + if self.cx.sess().codegen_stats() { + self.cx.stats.borrow_mut().n_llvm_insns += 1; + } + if self.cx.sess().count_llvm_insns() { + *self.cx.stats + .borrow_mut() + .llvm_insns + .entry(category.to_string()) + .or_insert(0) += 1; + } + } + + pub fn set_value_name(&self, value: ValueRef, name: &str) { + let cname = CString::new(name.as_bytes()).unwrap(); + unsafe { + llvm::LLVMSetValueName(value, cname.as_ptr()); + } + } + + pub fn position_before(&self, insn: ValueRef) { + unsafe { + llvm::LLVMPositionBuilderBefore(self.llbuilder, insn); + } + } + + pub fn position_at_end(&self, llbb: BasicBlockRef) { + unsafe { + llvm::LLVMPositionBuilderAtEnd(self.llbuilder, llbb); + } + } + + pub fn position_at_start(&self, llbb: BasicBlockRef) { + unsafe { + llvm::LLVMRustPositionBuilderAtStart(self.llbuilder, llbb); + } + } + + pub fn ret_void(&self) { + self.count_insn("retvoid"); + unsafe { + llvm::LLVMBuildRetVoid(self.llbuilder); + } + } + + pub fn ret(&self, v: ValueRef) { + self.count_insn("ret"); + unsafe { + llvm::LLVMBuildRet(self.llbuilder, v); + } + } + + pub fn aggregate_ret(&self, ret_vals: &[ValueRef]) { + unsafe { + llvm::LLVMBuildAggregateRet(self.llbuilder, + ret_vals.as_ptr(), + ret_vals.len() as c_uint); + } + } + + pub fn br(&self, dest: BasicBlockRef) { + self.count_insn("br"); + unsafe { + llvm::LLVMBuildBr(self.llbuilder, dest); + } + } + + pub fn cond_br(&self, cond: ValueRef, then_llbb: BasicBlockRef, else_llbb: BasicBlockRef) { + self.count_insn("condbr"); + unsafe { + llvm::LLVMBuildCondBr(self.llbuilder, cond, then_llbb, else_llbb); + } + } + + pub fn switch(&self, v: ValueRef, else_llbb: BasicBlockRef, num_cases: usize) -> ValueRef { + unsafe { + llvm::LLVMBuildSwitch(self.llbuilder, v, else_llbb, num_cases as c_uint) + } + } + + pub fn indirect_br(&self, addr: ValueRef, num_dests: usize) { + self.count_insn("indirectbr"); + unsafe { + llvm::LLVMBuildIndirectBr(self.llbuilder, addr, num_dests as c_uint); + } + } + + pub fn invoke(&self, + llfn: ValueRef, + args: &[ValueRef], + then: BasicBlockRef, + catch: BasicBlockRef, + bundle: Option<&OperandBundleDef>) -> ValueRef { + self.count_insn("invoke"); + + debug!("Invoke {:?} with args ({})", + Value(llfn), + args.iter() + .map(|&v| format!("{:?}", Value(v))) + .collect::>() + .join(", ")); + + let args = self.check_call("invoke", llfn, args); + let bundle = bundle.as_ref().map(|b| b.raw()).unwrap_or(ptr::null_mut()); + + unsafe { + llvm::LLVMRustBuildInvoke(self.llbuilder, + llfn, + args.as_ptr(), + args.len() as c_uint, + then, + catch, + bundle, + noname()) + } + } + + pub fn unreachable(&self) { + self.count_insn("unreachable"); + unsafe { + llvm::LLVMBuildUnreachable(self.llbuilder); + } + } + + /* Arithmetic */ + pub fn add(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("add"); + unsafe { + llvm::LLVMBuildAdd(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn nswadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("nswadd"); + unsafe { + llvm::LLVMBuildNSWAdd(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn nuwadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("nuwadd"); + unsafe { + llvm::LLVMBuildNUWAdd(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn fadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("fadd"); + unsafe { + llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn fadd_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("fadd"); + unsafe { + let instr = llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname()); + llvm::LLVMRustSetHasUnsafeAlgebra(instr); + instr + } + } + + pub fn sub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("sub"); + unsafe { + llvm::LLVMBuildSub(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn nswsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("nwsub"); + unsafe { + llvm::LLVMBuildNSWSub(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn nuwsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("nuwsub"); + unsafe { + llvm::LLVMBuildNUWSub(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn fsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("sub"); + unsafe { + llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn fsub_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("sub"); + unsafe { + let instr = llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname()); + llvm::LLVMRustSetHasUnsafeAlgebra(instr); + instr + } + } + + pub fn mul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("mul"); + unsafe { + llvm::LLVMBuildMul(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn nswmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("nswmul"); + unsafe { + llvm::LLVMBuildNSWMul(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn nuwmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("nuwmul"); + unsafe { + llvm::LLVMBuildNUWMul(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn fmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("fmul"); + unsafe { + llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn fmul_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("fmul"); + unsafe { + let instr = llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname()); + llvm::LLVMRustSetHasUnsafeAlgebra(instr); + instr + } + } + + + pub fn udiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("udiv"); + unsafe { + llvm::LLVMBuildUDiv(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn exactudiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("exactudiv"); + unsafe { + llvm::LLVMBuildExactUDiv(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn sdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("sdiv"); + unsafe { + llvm::LLVMBuildSDiv(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn exactsdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("exactsdiv"); + unsafe { + llvm::LLVMBuildExactSDiv(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn fdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("fdiv"); + unsafe { + llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn fdiv_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("fdiv"); + unsafe { + let instr = llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname()); + llvm::LLVMRustSetHasUnsafeAlgebra(instr); + instr + } + } + + pub fn urem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("urem"); + unsafe { + llvm::LLVMBuildURem(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn srem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("srem"); + unsafe { + llvm::LLVMBuildSRem(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn frem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("frem"); + unsafe { + llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn frem_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("frem"); + unsafe { + let instr = llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname()); + llvm::LLVMRustSetHasUnsafeAlgebra(instr); + instr + } + } + + pub fn shl(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("shl"); + unsafe { + llvm::LLVMBuildShl(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn lshr(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("lshr"); + unsafe { + llvm::LLVMBuildLShr(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn ashr(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("ashr"); + unsafe { + llvm::LLVMBuildAShr(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn and(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("and"); + unsafe { + llvm::LLVMBuildAnd(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn or(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("or"); + unsafe { + llvm::LLVMBuildOr(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn xor(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("xor"); + unsafe { + llvm::LLVMBuildXor(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn binop(&self, op: Opcode, lhs: ValueRef, rhs: ValueRef) + -> ValueRef { + self.count_insn("binop"); + unsafe { + llvm::LLVMBuildBinOp(self.llbuilder, op, lhs, rhs, noname()) + } + } + + pub fn neg(&self, v: ValueRef) -> ValueRef { + self.count_insn("neg"); + unsafe { + llvm::LLVMBuildNeg(self.llbuilder, v, noname()) + } + } + + pub fn nswneg(&self, v: ValueRef) -> ValueRef { + self.count_insn("nswneg"); + unsafe { + llvm::LLVMBuildNSWNeg(self.llbuilder, v, noname()) + } + } + + pub fn nuwneg(&self, v: ValueRef) -> ValueRef { + self.count_insn("nuwneg"); + unsafe { + llvm::LLVMBuildNUWNeg(self.llbuilder, v, noname()) + } + } + pub fn fneg(&self, v: ValueRef) -> ValueRef { + self.count_insn("fneg"); + unsafe { + llvm::LLVMBuildFNeg(self.llbuilder, v, noname()) + } + } + + pub fn not(&self, v: ValueRef) -> ValueRef { + self.count_insn("not"); + unsafe { + llvm::LLVMBuildNot(self.llbuilder, v, noname()) + } + } + + pub fn alloca(&self, ty: Type, name: &str, align: Align) -> ValueRef { + let bx = Builder::with_cx(self.cx); + bx.position_at_start(unsafe { + llvm::LLVMGetFirstBasicBlock(self.llfn()) + }); + bx.dynamic_alloca(ty, name, align) + } + + pub fn dynamic_alloca(&self, ty: Type, name: &str, align: Align) -> ValueRef { + self.count_insn("alloca"); + unsafe { + let alloca = if name.is_empty() { + llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname()) + } else { + let name = CString::new(name).unwrap(); + llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), + name.as_ptr()) + }; + llvm::LLVMSetAlignment(alloca, align.abi() as c_uint); + alloca + } + } + + pub fn free(&self, ptr: ValueRef) { + self.count_insn("free"); + unsafe { + llvm::LLVMBuildFree(self.llbuilder, ptr); + } + } + + pub fn load(&self, ptr: ValueRef, align: Align) -> ValueRef { + self.count_insn("load"); + unsafe { + let load = llvm::LLVMBuildLoad(self.llbuilder, ptr, noname()); + llvm::LLVMSetAlignment(load, align.abi() as c_uint); + load + } + } + + pub fn volatile_load(&self, ptr: ValueRef) -> ValueRef { + self.count_insn("load.volatile"); + unsafe { + let insn = llvm::LLVMBuildLoad(self.llbuilder, ptr, noname()); + llvm::LLVMSetVolatile(insn, llvm::True); + insn + } + } + + pub fn atomic_load(&self, ptr: ValueRef, order: AtomicOrdering, align: Align) -> ValueRef { + self.count_insn("load.atomic"); + unsafe { + let load = llvm::LLVMRustBuildAtomicLoad(self.llbuilder, ptr, noname(), order); + // FIXME(eddyb) Isn't it UB to use `pref` instead of `abi` here? + // However, 64-bit atomic loads on `i686-apple-darwin` appear to + // require `___atomic_load` with ABI-alignment, so it's staying. + llvm::LLVMSetAlignment(load, align.pref() as c_uint); + load + } + } + + + pub fn range_metadata(&self, load: ValueRef, range: Range) { + unsafe { + let llty = val_ty(load); + let v = [ + C_uint_big(llty, range.start), + C_uint_big(llty, range.end) + ]; + + llvm::LLVMSetMetadata(load, llvm::MD_range as c_uint, + llvm::LLVMMDNodeInContext(self.cx.llcx, + v.as_ptr(), + v.len() as c_uint)); + } + } + + pub fn nonnull_metadata(&self, load: ValueRef) { + unsafe { + llvm::LLVMSetMetadata(load, llvm::MD_nonnull as c_uint, + llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0)); + } + } + + pub fn store(&self, val: ValueRef, ptr: ValueRef, align: Align) -> ValueRef { + self.store_with_flags(val, ptr, align, MemFlags::empty()) + } + + pub fn store_with_flags( + &self, + val: ValueRef, + ptr: ValueRef, + align: Align, + flags: MemFlags, + ) -> ValueRef { + debug!("Store {:?} -> {:?} ({:?})", Value(val), Value(ptr), flags); + assert!(!self.llbuilder.is_null()); + self.count_insn("store"); + let ptr = self.check_store(val, ptr); + unsafe { + let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr); + llvm::LLVMSetAlignment(store, align.abi() as c_uint); + if flags.contains(MemFlags::VOLATILE) { + llvm::LLVMSetVolatile(store, llvm::True); + } + if flags.contains(MemFlags::NONTEMPORAL) { + // According to LLVM [1] building a nontemporal store must + // *always* point to a metadata value of the integer 1. + // + // [1]: http://llvm.org/docs/LangRef.html#store-instruction + let one = C_i32(self.cx, 1); + let node = llvm::LLVMMDNodeInContext(self.cx.llcx, &one, 1); + llvm::LLVMSetMetadata(store, llvm::MD_nontemporal as c_uint, node); + } + store + } + } + + pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef, + order: AtomicOrdering, align: Align) { + debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); + self.count_insn("store.atomic"); + let ptr = self.check_store(val, ptr); + unsafe { + let store = llvm::LLVMRustBuildAtomicStore(self.llbuilder, val, ptr, order); + // FIXME(eddyb) Isn't it UB to use `pref` instead of `abi` here? + // Also see `atomic_load` for more context. + llvm::LLVMSetAlignment(store, align.pref() as c_uint); + } + } + + pub fn gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef { + self.count_insn("gep"); + unsafe { + llvm::LLVMBuildGEP(self.llbuilder, ptr, indices.as_ptr(), + indices.len() as c_uint, noname()) + } + } + + pub fn inbounds_gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef { + self.count_insn("inboundsgep"); + unsafe { + llvm::LLVMBuildInBoundsGEP( + self.llbuilder, ptr, indices.as_ptr(), indices.len() as c_uint, noname()) + } + } + + pub fn struct_gep(&self, ptr: ValueRef, idx: u64) -> ValueRef { + self.count_insn("structgep"); + assert_eq!(idx as c_uint as u64, idx); + unsafe { + llvm::LLVMBuildStructGEP(self.llbuilder, ptr, idx as c_uint, noname()) + } + } + + pub fn global_string(&self, _str: *const c_char) -> ValueRef { + self.count_insn("globalstring"); + unsafe { + llvm::LLVMBuildGlobalString(self.llbuilder, _str, noname()) + } + } + + pub fn global_string_ptr(&self, _str: *const c_char) -> ValueRef { + self.count_insn("globalstringptr"); + unsafe { + llvm::LLVMBuildGlobalStringPtr(self.llbuilder, _str, noname()) + } + } + + /* Casts */ + pub fn trunc(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("trunc"); + unsafe { + llvm::LLVMBuildTrunc(self.llbuilder, val, dest_ty.to_ref(), noname()) + } + } + + pub fn zext(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("zext"); + unsafe { + llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty.to_ref(), noname()) + } + } + + pub fn sext(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("sext"); + unsafe { + llvm::LLVMBuildSExt(self.llbuilder, val, dest_ty.to_ref(), noname()) + } + } + + pub fn fptoui(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("fptoui"); + unsafe { + llvm::LLVMBuildFPToUI(self.llbuilder, val, dest_ty.to_ref(), noname()) + } + } + + pub fn fptosi(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("fptosi"); + unsafe { + llvm::LLVMBuildFPToSI(self.llbuilder, val, dest_ty.to_ref(),noname()) + } + } + + pub fn uitofp(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("uitofp"); + unsafe { + llvm::LLVMBuildUIToFP(self.llbuilder, val, dest_ty.to_ref(), noname()) + } + } + + pub fn sitofp(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("sitofp"); + unsafe { + llvm::LLVMBuildSIToFP(self.llbuilder, val, dest_ty.to_ref(), noname()) + } + } + + pub fn fptrunc(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("fptrunc"); + unsafe { + llvm::LLVMBuildFPTrunc(self.llbuilder, val, dest_ty.to_ref(), noname()) + } + } + + pub fn fpext(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("fpext"); + unsafe { + llvm::LLVMBuildFPExt(self.llbuilder, val, dest_ty.to_ref(), noname()) + } + } + + pub fn ptrtoint(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("ptrtoint"); + unsafe { + llvm::LLVMBuildPtrToInt(self.llbuilder, val, dest_ty.to_ref(), noname()) + } + } + + pub fn inttoptr(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("inttoptr"); + unsafe { + llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty.to_ref(), noname()) + } + } + + pub fn bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("bitcast"); + unsafe { + llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty.to_ref(), noname()) + } + } + + pub fn zext_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("zextorbitcast"); + unsafe { + llvm::LLVMBuildZExtOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname()) + } + } + + pub fn sext_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("sextorbitcast"); + unsafe { + llvm::LLVMBuildSExtOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname()) + } + } + + pub fn trunc_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("truncorbitcast"); + unsafe { + llvm::LLVMBuildTruncOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname()) + } + } + + pub fn cast(&self, op: Opcode, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("cast"); + unsafe { + llvm::LLVMBuildCast(self.llbuilder, op, val, dest_ty.to_ref(), noname()) + } + } + + pub fn pointercast(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("pointercast"); + unsafe { + llvm::LLVMBuildPointerCast(self.llbuilder, val, dest_ty.to_ref(), noname()) + } + } + + pub fn intcast(&self, val: ValueRef, dest_ty: Type, is_signed: bool) -> ValueRef { + self.count_insn("intcast"); + unsafe { + llvm::LLVMRustBuildIntCast(self.llbuilder, val, dest_ty.to_ref(), is_signed) + } + } + + pub fn fpcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef { + self.count_insn("fpcast"); + unsafe { + llvm::LLVMBuildFPCast(self.llbuilder, val, dest_ty.to_ref(), noname()) + } + } + + + /* Comparisons */ + pub fn icmp(&self, op: IntPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("icmp"); + unsafe { + llvm::LLVMBuildICmp(self.llbuilder, op as c_uint, lhs, rhs, noname()) + } + } + + pub fn fcmp(&self, op: RealPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("fcmp"); + unsafe { + llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, noname()) + } + } + + /* Miscellaneous instructions */ + pub fn empty_phi(&self, ty: Type) -> ValueRef { + self.count_insn("emptyphi"); + unsafe { + llvm::LLVMBuildPhi(self.llbuilder, ty.to_ref(), noname()) + } + } + + pub fn phi(&self, ty: Type, vals: &[ValueRef], bbs: &[BasicBlockRef]) -> ValueRef { + assert_eq!(vals.len(), bbs.len()); + let phi = self.empty_phi(ty); + self.count_insn("addincoming"); + unsafe { + llvm::LLVMAddIncoming(phi, vals.as_ptr(), + bbs.as_ptr(), + vals.len() as c_uint); + phi + } + } + + pub fn add_span_comment(&self, sp: Span, text: &str) { + if self.cx.sess().asm_comments() { + let s = format!("{} ({})", + text, + self.cx.sess().codemap().span_to_string(sp)); + debug!("{}", s); + self.add_comment(&s); + } + } + + pub fn add_comment(&self, text: &str) { + if self.cx.sess().asm_comments() { + let sanitized = text.replace("$", ""); + let comment_text = format!("{} {}", "#", + sanitized.replace("\n", "\n\t# ")); + self.count_insn("inlineasm"); + let comment_text = CString::new(comment_text).unwrap(); + let asm = unsafe { + llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.cx)).to_ref(), + comment_text.as_ptr(), noname(), False, + False) + }; + self.call(asm, &[], None); + } + } + + pub fn inline_asm_call(&self, asm: *const c_char, cons: *const c_char, + inputs: &[ValueRef], output: Type, + volatile: bool, alignstack: bool, + dia: AsmDialect) -> ValueRef { + self.count_insn("inlineasm"); + + let volatile = if volatile { llvm::True } + else { llvm::False }; + let alignstack = if alignstack { llvm::True } + else { llvm::False }; + + let argtys = inputs.iter().map(|v| { + debug!("Asm Input Type: {:?}", Value(*v)); + val_ty(*v) + }).collect::>(); + + debug!("Asm Output Type: {:?}", output); + let fty = Type::func(&argtys[..], &output); + unsafe { + let v = llvm::LLVMRustInlineAsm( + fty.to_ref(), asm, cons, volatile, alignstack, dia); + self.call(v, inputs, None) + } + } + + pub fn call(&self, llfn: ValueRef, args: &[ValueRef], + bundle: Option<&OperandBundleDef>) -> ValueRef { + self.count_insn("call"); + + debug!("Call {:?} with args ({})", + Value(llfn), + args.iter() + .map(|&v| format!("{:?}", Value(v))) + .collect::>() + .join(", ")); + + let args = self.check_call("call", llfn, args); + let bundle = bundle.as_ref().map(|b| b.raw()).unwrap_or(ptr::null_mut()); + + unsafe { + llvm::LLVMRustBuildCall(self.llbuilder, llfn, args.as_ptr(), + args.len() as c_uint, bundle, noname()) + } + } + + pub fn minnum(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("minnum"); + unsafe { + let instr = llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs); + if instr.is_null() { + bug!("LLVMRustBuildMinNum is not available in LLVM version < 6.0"); + } + instr + } + } + pub fn maxnum(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("maxnum"); + unsafe { + let instr = llvm::LLVMRustBuildMaxNum(self.llbuilder, lhs, rhs); + if instr.is_null() { + bug!("LLVMRustBuildMaxNum is not available in LLVM version < 6.0"); + } + instr + } + } + + pub fn select(&self, cond: ValueRef, then_val: ValueRef, else_val: ValueRef) -> ValueRef { + self.count_insn("select"); + unsafe { + llvm::LLVMBuildSelect(self.llbuilder, cond, then_val, else_val, noname()) + } + } + + pub fn va_arg(&self, list: ValueRef, ty: Type) -> ValueRef { + self.count_insn("vaarg"); + unsafe { + llvm::LLVMBuildVAArg(self.llbuilder, list, ty.to_ref(), noname()) + } + } + + pub fn extract_element(&self, vec: ValueRef, idx: ValueRef) -> ValueRef { + self.count_insn("extractelement"); + unsafe { + llvm::LLVMBuildExtractElement(self.llbuilder, vec, idx, noname()) + } + } + + pub fn insert_element(&self, vec: ValueRef, elt: ValueRef, idx: ValueRef) -> ValueRef { + self.count_insn("insertelement"); + unsafe { + llvm::LLVMBuildInsertElement(self.llbuilder, vec, elt, idx, noname()) + } + } + + pub fn shuffle_vector(&self, v1: ValueRef, v2: ValueRef, mask: ValueRef) -> ValueRef { + self.count_insn("shufflevector"); + unsafe { + llvm::LLVMBuildShuffleVector(self.llbuilder, v1, v2, mask, noname()) + } + } + + pub fn vector_splat(&self, num_elts: usize, elt: ValueRef) -> ValueRef { + unsafe { + let elt_ty = val_ty(elt); + let undef = llvm::LLVMGetUndef(Type::vector(&elt_ty, num_elts as u64).to_ref()); + let vec = self.insert_element(undef, elt, C_i32(self.cx, 0)); + let vec_i32_ty = Type::vector(&Type::i32(self.cx), num_elts as u64); + self.shuffle_vector(vec, undef, C_null(vec_i32_ty)) + } + } + + pub fn vector_reduce_fadd_fast(&self, acc: ValueRef, src: ValueRef) -> ValueRef { + self.count_insn("vector.reduce.fadd_fast"); + unsafe { + // FIXME: add a non-fast math version once + // https://bugs.llvm.org/show_bug.cgi?id=36732 + // is fixed. + let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceFAdd is not available in LLVM version < 5.0"); + } + llvm::LLVMRustSetHasUnsafeAlgebra(instr); + instr + } + } + pub fn vector_reduce_fmul_fast(&self, acc: ValueRef, src: ValueRef) -> ValueRef { + self.count_insn("vector.reduce.fmul_fast"); + unsafe { + // FIXME: add a non-fast math version once + // https://bugs.llvm.org/show_bug.cgi?id=36732 + // is fixed. + let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceFMul is not available in LLVM version < 5.0"); + } + llvm::LLVMRustSetHasUnsafeAlgebra(instr); + instr + } + } + pub fn vector_reduce_add(&self, src: ValueRef) -> ValueRef { + self.count_insn("vector.reduce.add"); + unsafe { + let instr = llvm::LLVMRustBuildVectorReduceAdd(self.llbuilder, src); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceAdd is not available in LLVM version < 5.0"); + } + instr + } + } + pub fn vector_reduce_mul(&self, src: ValueRef) -> ValueRef { + self.count_insn("vector.reduce.mul"); + unsafe { + let instr = llvm::LLVMRustBuildVectorReduceMul(self.llbuilder, src); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceMul is not available in LLVM version < 5.0"); + } + instr + } + } + pub fn vector_reduce_and(&self, src: ValueRef) -> ValueRef { + self.count_insn("vector.reduce.and"); + unsafe { + let instr = llvm::LLVMRustBuildVectorReduceAnd(self.llbuilder, src); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceAnd is not available in LLVM version < 5.0"); + } + instr + } + } + pub fn vector_reduce_or(&self, src: ValueRef) -> ValueRef { + self.count_insn("vector.reduce.or"); + unsafe { + let instr = llvm::LLVMRustBuildVectorReduceOr(self.llbuilder, src); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceOr is not available in LLVM version < 5.0"); + } + instr + } + } + pub fn vector_reduce_xor(&self, src: ValueRef) -> ValueRef { + self.count_insn("vector.reduce.xor"); + unsafe { + let instr = llvm::LLVMRustBuildVectorReduceXor(self.llbuilder, src); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceXor is not available in LLVM version < 5.0"); + } + instr + } + } + pub fn vector_reduce_fmin(&self, src: ValueRef) -> ValueRef { + self.count_insn("vector.reduce.fmin"); + unsafe { + let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ false); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0"); + } + instr + } + } + pub fn vector_reduce_fmax(&self, src: ValueRef) -> ValueRef { + self.count_insn("vector.reduce.fmax"); + unsafe { + let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ false); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0"); + } + instr + } + } + pub fn vector_reduce_fmin_fast(&self, src: ValueRef) -> ValueRef { + self.count_insn("vector.reduce.fmin_fast"); + unsafe { + let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ true); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0"); + } + llvm::LLVMRustSetHasUnsafeAlgebra(instr); + instr + } + } + pub fn vector_reduce_fmax_fast(&self, src: ValueRef) -> ValueRef { + self.count_insn("vector.reduce.fmax_fast"); + unsafe { + let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ true); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0"); + } + llvm::LLVMRustSetHasUnsafeAlgebra(instr); + instr + } + } + pub fn vector_reduce_min(&self, src: ValueRef, is_signed: bool) -> ValueRef { + self.count_insn("vector.reduce.min"); + unsafe { + let instr = llvm::LLVMRustBuildVectorReduceMin(self.llbuilder, src, is_signed); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceMin is not available in LLVM version < 5.0"); + } + instr + } + } + pub fn vector_reduce_max(&self, src: ValueRef, is_signed: bool) -> ValueRef { + self.count_insn("vector.reduce.max"); + unsafe { + let instr = llvm::LLVMRustBuildVectorReduceMax(self.llbuilder, src, is_signed); + if instr.is_null() { + bug!("LLVMRustBuildVectorReduceMax is not available in LLVM version < 5.0"); + } + instr + } + } + + pub fn extract_value(&self, agg_val: ValueRef, idx: u64) -> ValueRef { + self.count_insn("extractvalue"); + assert_eq!(idx as c_uint as u64, idx); + unsafe { + llvm::LLVMBuildExtractValue(self.llbuilder, agg_val, idx as c_uint, noname()) + } + } + + pub fn insert_value(&self, agg_val: ValueRef, elt: ValueRef, + idx: u64) -> ValueRef { + self.count_insn("insertvalue"); + assert_eq!(idx as c_uint as u64, idx); + unsafe { + llvm::LLVMBuildInsertValue(self.llbuilder, agg_val, elt, idx as c_uint, + noname()) + } + } + + pub fn is_null(&self, val: ValueRef) -> ValueRef { + self.count_insn("isnull"); + unsafe { + llvm::LLVMBuildIsNull(self.llbuilder, val, noname()) + } + } + + pub fn is_not_null(&self, val: ValueRef) -> ValueRef { + self.count_insn("isnotnull"); + unsafe { + llvm::LLVMBuildIsNotNull(self.llbuilder, val, noname()) + } + } + + pub fn ptrdiff(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("ptrdiff"); + unsafe { + llvm::LLVMBuildPtrDiff(self.llbuilder, lhs, rhs, noname()) + } + } + + pub fn trap(&self) { + unsafe { + let bb: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder); + let fn_: ValueRef = llvm::LLVMGetBasicBlockParent(bb); + let m: ModuleRef = llvm::LLVMGetGlobalParent(fn_); + let p = "llvm.trap\0".as_ptr(); + let t: ValueRef = llvm::LLVMGetNamedFunction(m, p as *const _); + assert!((t as isize != 0)); + let args: &[ValueRef] = &[]; + self.count_insn("trap"); + llvm::LLVMRustBuildCall(self.llbuilder, t, + args.as_ptr(), args.len() as c_uint, + ptr::null_mut(), + noname()); + } + } + + pub fn landing_pad(&self, ty: Type, pers_fn: ValueRef, + num_clauses: usize) -> ValueRef { + self.count_insn("landingpad"); + unsafe { + llvm::LLVMBuildLandingPad(self.llbuilder, ty.to_ref(), pers_fn, + num_clauses as c_uint, noname()) + } + } + + pub fn add_clause(&self, landing_pad: ValueRef, clause: ValueRef) { + unsafe { + llvm::LLVMAddClause(landing_pad, clause); + } + } + + pub fn set_cleanup(&self, landing_pad: ValueRef) { + self.count_insn("setcleanup"); + unsafe { + llvm::LLVMSetCleanup(landing_pad, llvm::True); + } + } + + pub fn resume(&self, exn: ValueRef) -> ValueRef { + self.count_insn("resume"); + unsafe { + llvm::LLVMBuildResume(self.llbuilder, exn) + } + } + + pub fn cleanup_pad(&self, + parent: Option, + args: &[ValueRef]) -> ValueRef { + self.count_insn("cleanuppad"); + let parent = parent.unwrap_or(ptr::null_mut()); + let name = CString::new("cleanuppad").unwrap(); + let ret = unsafe { + llvm::LLVMRustBuildCleanupPad(self.llbuilder, + parent, + args.len() as c_uint, + args.as_ptr(), + name.as_ptr()) + }; + assert!(!ret.is_null(), "LLVM does not have support for cleanuppad"); + return ret + } + + pub fn cleanup_ret(&self, cleanup: ValueRef, + unwind: Option) -> ValueRef { + self.count_insn("cleanupret"); + let unwind = unwind.unwrap_or(ptr::null_mut()); + let ret = unsafe { + llvm::LLVMRustBuildCleanupRet(self.llbuilder, cleanup, unwind) + }; + assert!(!ret.is_null(), "LLVM does not have support for cleanupret"); + return ret + } + + pub fn catch_pad(&self, + parent: ValueRef, + args: &[ValueRef]) -> ValueRef { + self.count_insn("catchpad"); + let name = CString::new("catchpad").unwrap(); + let ret = unsafe { + llvm::LLVMRustBuildCatchPad(self.llbuilder, parent, + args.len() as c_uint, args.as_ptr(), + name.as_ptr()) + }; + assert!(!ret.is_null(), "LLVM does not have support for catchpad"); + return ret + } + + pub fn catch_ret(&self, pad: ValueRef, unwind: BasicBlockRef) -> ValueRef { + self.count_insn("catchret"); + let ret = unsafe { + llvm::LLVMRustBuildCatchRet(self.llbuilder, pad, unwind) + }; + assert!(!ret.is_null(), "LLVM does not have support for catchret"); + return ret + } + + pub fn catch_switch(&self, + parent: Option, + unwind: Option, + num_handlers: usize) -> ValueRef { + self.count_insn("catchswitch"); + let parent = parent.unwrap_or(ptr::null_mut()); + let unwind = unwind.unwrap_or(ptr::null_mut()); + let name = CString::new("catchswitch").unwrap(); + let ret = unsafe { + llvm::LLVMRustBuildCatchSwitch(self.llbuilder, parent, unwind, + num_handlers as c_uint, + name.as_ptr()) + }; + assert!(!ret.is_null(), "LLVM does not have support for catchswitch"); + return ret + } + + pub fn add_handler(&self, catch_switch: ValueRef, handler: BasicBlockRef) { + unsafe { + llvm::LLVMRustAddHandler(catch_switch, handler); + } + } + + pub fn set_personality_fn(&self, personality: ValueRef) { + unsafe { + llvm::LLVMSetPersonalityFn(self.llfn(), personality); + } + } + + // Atomic Operations + pub fn atomic_cmpxchg(&self, dst: ValueRef, + cmp: ValueRef, src: ValueRef, + order: AtomicOrdering, + failure_order: AtomicOrdering, + weak: llvm::Bool) -> ValueRef { + unsafe { + llvm::LLVMRustBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src, + order, failure_order, weak) + } + } + pub fn atomic_rmw(&self, op: AtomicRmwBinOp, + dst: ValueRef, src: ValueRef, + order: AtomicOrdering) -> ValueRef { + unsafe { + llvm::LLVMBuildAtomicRMW(self.llbuilder, op, dst, src, order, False) + } + } + + pub fn atomic_fence(&self, order: AtomicOrdering, scope: SynchronizationScope) { + unsafe { + llvm::LLVMRustBuildAtomicFence(self.llbuilder, order, scope); + } + } + + pub fn add_case(&self, s: ValueRef, on_val: ValueRef, dest: BasicBlockRef) { + unsafe { + llvm::LLVMAddCase(s, on_val, dest) + } + } + + pub fn add_incoming_to_phi(&self, phi: ValueRef, val: ValueRef, bb: BasicBlockRef) { + unsafe { + llvm::LLVMAddIncoming(phi, &val, &bb, 1 as c_uint); + } + } + + pub fn set_invariant_load(&self, load: ValueRef) { + unsafe { + llvm::LLVMSetMetadata(load, llvm::MD_invariant_load as c_uint, + llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0)); + } + } + + /// Returns the ptr value that should be used for storing `val`. + fn check_store<'b>(&self, + val: ValueRef, + ptr: ValueRef) -> ValueRef { + let dest_ptr_ty = val_ty(ptr); + let stored_ty = val_ty(val); + let stored_ptr_ty = stored_ty.ptr_to(); + + assert_eq!(dest_ptr_ty.kind(), llvm::TypeKind::Pointer); + + if dest_ptr_ty == stored_ptr_ty { + ptr + } else { + debug!("Type mismatch in store. \ + Expected {:?}, got {:?}; inserting bitcast", + dest_ptr_ty, stored_ptr_ty); + self.bitcast(ptr, stored_ptr_ty) + } + } + + /// Returns the args that should be used for a call to `llfn`. + fn check_call<'b>(&self, + typ: &str, + llfn: ValueRef, + args: &'b [ValueRef]) -> Cow<'b, [ValueRef]> { + let mut fn_ty = val_ty(llfn); + // Strip off pointers + while fn_ty.kind() == llvm::TypeKind::Pointer { + fn_ty = fn_ty.element_type(); + } + + assert!(fn_ty.kind() == llvm::TypeKind::Function, + "builder::{} not passed a function, but {:?}", typ, fn_ty); + + let param_tys = fn_ty.func_params(); + + let all_args_match = param_tys.iter() + .zip(args.iter().map(|&v| val_ty(v))) + .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty); + + if all_args_match { + return Cow::Borrowed(args); + } + + let casted_args: Vec<_> = param_tys.into_iter() + .zip(args.iter()) + .enumerate() + .map(|(i, (expected_ty, &actual_val))| { + let actual_ty = val_ty(actual_val); + if expected_ty != actual_ty { + debug!("Type mismatch in function call of {:?}. \ + Expected {:?} for param {}, got {:?}; injecting bitcast", + Value(llfn), + expected_ty, i, actual_ty); + self.bitcast(actual_val, expected_ty) + } else { + actual_val + } + }) + .collect(); + + return Cow::Owned(casted_args); + } + + pub fn lifetime_start(&self, ptr: ValueRef, size: Size) { + self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size); + } + + pub fn lifetime_end(&self, ptr: ValueRef, size: Size) { + self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size); + } + + /// If LLVM lifetime intrinsic support is enabled (i.e. optimizations + /// on), and `ptr` is nonzero-sized, then extracts the size of `ptr` + /// and the intrinsic for `lt` and passes them to `emit`, which is in + /// charge of generating code to call the passed intrinsic on whatever + /// block of generated code is targeted for the intrinsic. + /// + /// If LLVM lifetime intrinsic support is disabled (i.e. optimizations + /// off) or `ptr` is zero-sized, then no-op (does not call `emit`). + fn call_lifetime_intrinsic(&self, intrinsic: &str, ptr: ValueRef, size: Size) { + if self.cx.sess().opts.optimize == config::OptLevel::No { + return; + } + + let size = size.bytes(); + if size == 0 { + return; + } + + let lifetime_intrinsic = self.cx.get_intrinsic(intrinsic); + + let ptr = self.pointercast(ptr, Type::i8p(self.cx)); + self.call(lifetime_intrinsic, &[C_u64(self.cx, size), ptr], None); + } +} diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs new file mode 100644 index 00000000000..a3dbc450ce7 --- /dev/null +++ b/src/librustc_codegen_llvm/callee.rs @@ -0,0 +1,232 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Handles codegen of callees as well as other call-related +//! things. Callees are a superset of normal rust values and sometimes +//! have different representations. In particular, top-level fn items +//! and methods are represented as just a fn ptr and not a full +//! closure. + +use attributes; +use common::{self, CodegenCx}; +use consts; +use declare; +use llvm::{self, ValueRef}; +use monomorphize::Instance; +use type_of::LayoutLlvmExt; + +use rustc::hir::def_id::DefId; +use rustc::ty::{self, TypeFoldable}; +use rustc::ty::layout::LayoutOf; +use rustc::ty::subst::Substs; +use rustc_target::spec::PanicStrategy; + +/// Codegens a reference to a fn/method item, monomorphizing and +/// inlining as it goes. +/// +/// # Parameters +/// +/// - `cx`: the crate context +/// - `instance`: the instance to be instantiated +pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + instance: Instance<'tcx>) + -> ValueRef +{ + let tcx = cx.tcx; + + debug!("get_fn(instance={:?})", instance); + + assert!(!instance.substs.needs_infer()); + assert!(!instance.substs.has_escaping_regions()); + assert!(!instance.substs.has_param_types()); + + let fn_ty = instance.ty(cx.tcx); + if let Some(&llfn) = cx.instances.borrow().get(&instance) { + return llfn; + } + + let sym = tcx.symbol_name(instance).as_str(); + debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym); + + // Create a fn pointer with the substituted signature. + let fn_ptr_ty = tcx.mk_fn_ptr(common::ty_fn_sig(cx, fn_ty)); + let llptrty = cx.layout_of(fn_ptr_ty).llvm_type(cx); + + let llfn = if let Some(llfn) = declare::get_declared_value(cx, &sym) { + // This is subtle and surprising, but sometimes we have to bitcast + // the resulting fn pointer. The reason has to do with external + // functions. If you have two crates that both bind the same C + // library, they may not use precisely the same types: for + // example, they will probably each declare their own structs, + // which are distinct types from LLVM's point of view (nominal + // types). + // + // Now, if those two crates are linked into an application, and + // they contain inlined code, you can wind up with a situation + // where both of those functions wind up being loaded into this + // application simultaneously. In that case, the same function + // (from LLVM's point of view) requires two types. But of course + // LLVM won't allow one function to have two types. + // + // What we currently do, therefore, is declare the function with + // one of the two types (whichever happens to come first) and then + // bitcast as needed when the function is referenced to make sure + // it has the type we expect. + // + // This can occur on either a crate-local or crate-external + // reference. It also occurs when testing libcore and in some + // other weird situations. Annoying. + if common::val_ty(llfn) != llptrty { + debug!("get_fn: casting {:?} to {:?}", llfn, llptrty); + consts::ptrcast(llfn, llptrty) + } else { + debug!("get_fn: not casting pointer!"); + llfn + } + } else { + let llfn = declare::declare_fn(cx, &sym, fn_ty); + assert_eq!(common::val_ty(llfn), llptrty); + debug!("get_fn: not casting pointer!"); + + if instance.def.is_inline(tcx) { + attributes::inline(llfn, attributes::InlineAttr::Hint); + } + attributes::from_fn_attrs(cx, llfn, instance.def.def_id()); + + let instance_def_id = instance.def_id(); + + // Perhaps questionable, but we assume that anything defined + // *in Rust code* may unwind. Foreign items like `extern "C" { + // fn foo(); }` are assumed not to unwind **unless** they have + // a `#[unwind]` attribute. + if tcx.sess.panic_strategy() == PanicStrategy::Unwind { + if !tcx.is_foreign_item(instance_def_id) { + attributes::unwind(llfn, true); + } + } + + // Apply an appropriate linkage/visibility value to our item that we + // just declared. + // + // This is sort of subtle. Inside our codegen unit we started off + // compilation by predefining all our own `MonoItem` instances. That + // is, everything we're codegenning ourselves is already defined. That + // means that anything we're actually codegenning in this codegen unit + // will have hit the above branch in `get_declared_value`. As a result, + // we're guaranteed here that we're declaring a symbol that won't get + // defined, or in other words we're referencing a value from another + // codegen unit or even another crate. + // + // So because this is a foreign value we blanket apply an external + // linkage directive because it's coming from a different object file. + // The visibility here is where it gets tricky. This symbol could be + // referencing some foreign crate or foreign library (an `extern` + // block) in which case we want to leave the default visibility. We may + // also, though, have multiple codegen units. It could be a + // monomorphization, in which case its expected visibility depends on + // whether we are sharing generics or not. The important thing here is + // that the visibility we apply to the declaration is the same one that + // has been applied to the definition (wherever that definition may be). + unsafe { + llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); + + let is_generic = instance.substs.types().next().is_some(); + + if is_generic { + // This is a monomorphization. Its expected visibility depends + // on whether we are in share-generics mode. + + if cx.tcx.share_generics() { + // We are in share_generics mode. + + if instance_def_id.is_local() { + // This is a definition from the current crate. If the + // definition is unreachable for downstream crates or + // the current crate does not re-export generics, the + // definition of the instance will have been declared + // as `hidden`. + if cx.tcx.is_unreachable_local_definition(instance_def_id) || + !cx.tcx.local_crate_exports_generics() { + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + } + } else { + // This is a monomorphization of a generic function + // defined in an upstream crate. + if cx.tcx.upstream_monomorphizations_for(instance_def_id) + .map(|set| set.contains_key(instance.substs)) + .unwrap_or(false) { + // This is instantiated in another crate. It cannot + // be `hidden`. + } else { + // This is a local instantiation of an upstream definition. + // If the current crate does not re-export it + // (because it is a C library or an executable), it + // will have been declared `hidden`. + if !cx.tcx.local_crate_exports_generics() { + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + } + } + } + } else { + // When not sharing generics, all instances are in the same + // crate and have hidden visibility + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + } + } else { + // This is a non-generic function + if cx.tcx.is_codegened_item(instance_def_id) { + // This is a function that is instantiated in the local crate + + if instance_def_id.is_local() { + // This is function that is defined in the local crate. + // If it is not reachable, it is hidden. + if !cx.tcx.is_reachable_non_generic(instance_def_id) { + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + } + } else { + // This is a function from an upstream crate that has + // been instantiated here. These are always hidden. + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + } + } + } + } + + if cx.use_dll_storage_attrs && + tcx.is_dllimport_foreign_item(instance_def_id) + { + unsafe { + llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); + } + } + + llfn + }; + + cx.instances.borrow_mut().insert(instance, llfn); + + llfn +} + +pub fn resolve_and_get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>) + -> ValueRef +{ + get_fn( + cx, + ty::Instance::resolve( + cx.tcx, + ty::ParamEnv::reveal_all(), + def_id, + substs + ).unwrap() + ) +} diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs new file mode 100644 index 00000000000..10ca8e43ce6 --- /dev/null +++ b/src/librustc_codegen_llvm/common.rs @@ -0,0 +1,448 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_camel_case_types, non_snake_case)] + +//! Code that is useful in various codegen modules. + +use llvm; +use llvm::{ValueRef, ContextRef, TypeKind}; +use llvm::{True, False, Bool, OperandBundleDef}; +use rustc::hir::def_id::DefId; +use rustc::middle::lang_items::LangItem; +use abi; +use base; +use builder::Builder; +use consts; +use declare; +use type_::Type; +use type_of::LayoutLlvmExt; +use value::Value; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::layout::{HasDataLayout, LayoutOf}; +use rustc::hir; + +use libc::{c_uint, c_char}; +use std::iter; + +use rustc_target::spec::abi::Abi; +use syntax::symbol::LocalInternedString; +use syntax_pos::{Span, DUMMY_SP}; + +pub use context::CodegenCx; + +pub fn type_needs_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) +} + +pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.is_sized(tcx.at(DUMMY_SP), ty::ParamEnv::reveal_all()) +} + +pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.is_freeze(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP) +} + +/* +* A note on nomenclature of linking: "extern", "foreign", and "upcall". +* +* An "extern" is an LLVM symbol we wind up emitting an undefined external +* reference to. This means "we don't have the thing in this compilation unit, +* please make sure you link it in at runtime". This could be a reference to +* C code found in a C library, or rust code found in a rust crate. +* +* Most "externs" are implicitly declared (automatically) as a result of a +* user declaring an extern _module_ dependency; this causes the rust driver +* to locate an extern crate, scan its compilation metadata, and emit extern +* declarations for any symbols used by the declaring crate. +* +* A "foreign" is an extern that references C (or other non-rust ABI) code. +* There is no metadata to scan for extern references so in these cases either +* a header-digester like bindgen, or manual function prototypes, have to +* serve as declarators. So these are usually given explicitly as prototype +* declarations, in rust code, with ABI attributes on them noting which ABI to +* link via. +* +* An "upcall" is a foreign call generated by the compiler (not corresponding +* to any user-written call in the code) into the runtime library, to perform +* some helper task such as bringing a task to life, allocating memory, etc. +* +*/ + +/// A structure representing an active landing pad for the duration of a basic +/// block. +/// +/// Each `Block` may contain an instance of this, indicating whether the block +/// is part of a landing pad or not. This is used to make decision about whether +/// to emit `invoke` instructions (e.g. in a landing pad we don't continue to +/// use `invoke`) and also about various function call metadata. +/// +/// For GNU exceptions (`landingpad` + `resume` instructions) this structure is +/// just a bunch of `None` instances (not too interesting), but for MSVC +/// exceptions (`cleanuppad` + `cleanupret` instructions) this contains data. +/// When inside of a landing pad, each function call in LLVM IR needs to be +/// annotated with which landing pad it's a part of. This is accomplished via +/// the `OperandBundleDef` value created for MSVC landing pads. +pub struct Funclet { + cleanuppad: ValueRef, + operand: OperandBundleDef, +} + +impl Funclet { + pub fn new(cleanuppad: ValueRef) -> Funclet { + Funclet { + cleanuppad, + operand: OperandBundleDef::new("funclet", &[cleanuppad]), + } + } + + pub fn cleanuppad(&self) -> ValueRef { + self.cleanuppad + } + + pub fn bundle(&self) -> &OperandBundleDef { + &self.operand + } +} + +pub fn val_ty(v: ValueRef) -> Type { + unsafe { + Type::from_ref(llvm::LLVMTypeOf(v)) + } +} + +// LLVM constant constructors. +pub fn C_null(t: Type) -> ValueRef { + unsafe { + llvm::LLVMConstNull(t.to_ref()) + } +} + +pub fn C_undef(t: Type) -> ValueRef { + unsafe { + llvm::LLVMGetUndef(t.to_ref()) + } +} + +pub fn C_int(t: Type, i: i64) -> ValueRef { + unsafe { + llvm::LLVMConstInt(t.to_ref(), i as u64, True) + } +} + +pub fn C_uint(t: Type, i: u64) -> ValueRef { + unsafe { + llvm::LLVMConstInt(t.to_ref(), i, False) + } +} + +pub fn C_uint_big(t: Type, u: u128) -> ValueRef { + unsafe { + let words = [u as u64, (u >> 64) as u64]; + llvm::LLVMConstIntOfArbitraryPrecision(t.to_ref(), 2, words.as_ptr()) + } +} + +pub fn C_bool(cx: &CodegenCx, val: bool) -> ValueRef { + C_uint(Type::i1(cx), val as u64) +} + +pub fn C_i32(cx: &CodegenCx, i: i32) -> ValueRef { + C_int(Type::i32(cx), i as i64) +} + +pub fn C_u32(cx: &CodegenCx, i: u32) -> ValueRef { + C_uint(Type::i32(cx), i as u64) +} + +pub fn C_u64(cx: &CodegenCx, i: u64) -> ValueRef { + C_uint(Type::i64(cx), i) +} + +pub fn C_usize(cx: &CodegenCx, i: u64) -> ValueRef { + let bit_size = cx.data_layout().pointer_size.bits(); + if bit_size < 64 { + // make sure it doesn't overflow + assert!(i < (1< ValueRef { + C_uint(Type::i8(cx), i as u64) +} + + +// This is a 'c-like' raw string, which differs from +// our boxed-and-length-annotated strings. +pub fn C_cstr(cx: &CodegenCx, s: LocalInternedString, null_terminated: bool) -> ValueRef { + unsafe { + if let Some(&llval) = cx.const_cstr_cache.borrow().get(&s) { + return llval; + } + + let sc = llvm::LLVMConstStringInContext(cx.llcx, + s.as_ptr() as *const c_char, + s.len() as c_uint, + !null_terminated as Bool); + let sym = cx.generate_local_symbol_name("str"); + let g = declare::define_global(cx, &sym[..], val_ty(sc)).unwrap_or_else(||{ + bug!("symbol `{}` is already defined", sym); + }); + llvm::LLVMSetInitializer(g, sc); + llvm::LLVMSetGlobalConstant(g, True); + llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage); + + cx.const_cstr_cache.borrow_mut().insert(s, g); + g + } +} + +// NB: Do not use `do_spill_noroot` to make this into a constant string, or +// you will be kicked off fast isel. See issue #4352 for an example of this. +pub fn C_str_slice(cx: &CodegenCx, s: LocalInternedString) -> ValueRef { + let len = s.len(); + let cs = consts::ptrcast(C_cstr(cx, s, false), + cx.layout_of(cx.tcx.mk_str()).llvm_type(cx).ptr_to()); + C_fat_ptr(cx, cs, C_usize(cx, len as u64)) +} + +pub fn C_fat_ptr(cx: &CodegenCx, ptr: ValueRef, meta: ValueRef) -> ValueRef { + assert_eq!(abi::FAT_PTR_ADDR, 0); + assert_eq!(abi::FAT_PTR_EXTRA, 1); + C_struct(cx, &[ptr, meta], false) +} + +pub fn C_struct(cx: &CodegenCx, elts: &[ValueRef], packed: bool) -> ValueRef { + C_struct_in_context(cx.llcx, elts, packed) +} + +pub fn C_struct_in_context(llcx: ContextRef, elts: &[ValueRef], packed: bool) -> ValueRef { + unsafe { + llvm::LLVMConstStructInContext(llcx, + elts.as_ptr(), elts.len() as c_uint, + packed as Bool) + } +} + +pub fn C_array(ty: Type, elts: &[ValueRef]) -> ValueRef { + unsafe { + return llvm::LLVMConstArray(ty.to_ref(), elts.as_ptr(), elts.len() as c_uint); + } +} + +pub fn C_vector(elts: &[ValueRef]) -> ValueRef { + unsafe { + return llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint); + } +} + +pub fn C_bytes(cx: &CodegenCx, bytes: &[u8]) -> ValueRef { + C_bytes_in_context(cx.llcx, bytes) +} + +pub fn C_bytes_in_context(llcx: ContextRef, bytes: &[u8]) -> ValueRef { + unsafe { + let ptr = bytes.as_ptr() as *const c_char; + return llvm::LLVMConstStringInContext(llcx, ptr, bytes.len() as c_uint, True); + } +} + +pub fn const_get_elt(v: ValueRef, idx: u64) -> ValueRef { + unsafe { + assert_eq!(idx as c_uint as u64, idx); + let us = &[idx as c_uint]; + let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint); + + debug!("const_get_elt(v={:?}, idx={}, r={:?})", + Value(v), idx, Value(r)); + + r + } +} + +pub fn const_get_real(v: ValueRef) -> Option<(f64, bool)> { + unsafe { + if is_const_real(v) { + let mut loses_info: llvm::Bool = ::std::mem::uninitialized(); + let r = llvm::LLVMConstRealGetDouble(v, &mut loses_info as *mut llvm::Bool); + let loses_info = if loses_info == 1 { true } else { false }; + Some((r, loses_info)) + } else { + None + } + } +} + +pub fn const_to_uint(v: ValueRef) -> u64 { + unsafe { + llvm::LLVMConstIntGetZExtValue(v) + } +} + +pub fn is_const_integral(v: ValueRef) -> bool { + unsafe { + !llvm::LLVMIsAConstantInt(v).is_null() + } +} + +pub fn is_const_real(v: ValueRef) -> bool { + unsafe { + !llvm::LLVMIsAConstantFP(v).is_null() + } +} + + +#[inline] +fn hi_lo_to_u128(lo: u64, hi: u64) -> u128 { + ((hi as u128) << 64) | (lo as u128) +} + +pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option { + unsafe { + if is_const_integral(v) { + let (mut lo, mut hi) = (0u64, 0u64); + let success = llvm::LLVMRustConstInt128Get(v, sign_ext, + &mut hi as *mut u64, &mut lo as *mut u64); + if success { + Some(hi_lo_to_u128(lo, hi)) + } else { + None + } + } else { + None + } + } +} + +pub fn langcall(tcx: TyCtxt, + span: Option, + msg: &str, + li: LangItem) + -> DefId { + match tcx.lang_items().require(li) { + Ok(id) => id, + Err(s) => { + let msg = format!("{} {}", msg, s); + match span { + Some(span) => tcx.sess.span_fatal(span, &msg[..]), + None => tcx.sess.fatal(&msg[..]), + } + } + } +} + +// To avoid UB from LLVM, these two functions mask RHS with an +// appropriate mask unconditionally (i.e. the fallback behavior for +// all shifts). For 32- and 64-bit types, this matches the semantics +// of Java. (See related discussion on #1877 and #10183.) + +pub fn build_unchecked_lshift<'a, 'tcx>( + bx: &Builder<'a, 'tcx>, + lhs: ValueRef, + rhs: ValueRef +) -> ValueRef { + let rhs = base::cast_shift_expr_rhs(bx, hir::BinOp_::BiShl, lhs, rhs); + // #1877, #10183: Ensure that input is always valid + let rhs = shift_mask_rhs(bx, rhs); + bx.shl(lhs, rhs) +} + +pub fn build_unchecked_rshift<'a, 'tcx>( + bx: &Builder<'a, 'tcx>, lhs_t: Ty<'tcx>, lhs: ValueRef, rhs: ValueRef +) -> ValueRef { + let rhs = base::cast_shift_expr_rhs(bx, hir::BinOp_::BiShr, lhs, rhs); + // #1877, #10183: Ensure that input is always valid + let rhs = shift_mask_rhs(bx, rhs); + let is_signed = lhs_t.is_signed(); + if is_signed { + bx.ashr(lhs, rhs) + } else { + bx.lshr(lhs, rhs) + } +} + +fn shift_mask_rhs<'a, 'tcx>(bx: &Builder<'a, 'tcx>, rhs: ValueRef) -> ValueRef { + let rhs_llty = val_ty(rhs); + bx.and(rhs, shift_mask_val(bx, rhs_llty, rhs_llty, false)) +} + +pub fn shift_mask_val<'a, 'tcx>( + bx: &Builder<'a, 'tcx>, + llty: Type, + mask_llty: Type, + invert: bool +) -> ValueRef { + let kind = llty.kind(); + match kind { + TypeKind::Integer => { + // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc. + let val = llty.int_width() - 1; + if invert { + C_int(mask_llty, !val as i64) + } else { + C_uint(mask_llty, val) + } + }, + TypeKind::Vector => { + let mask = shift_mask_val(bx, llty.element_type(), mask_llty.element_type(), invert); + bx.vector_splat(mask_llty.vector_length(), mask) + }, + _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind), + } +} + +pub fn ty_fn_sig<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + ty: Ty<'tcx>) + -> ty::PolyFnSig<'tcx> +{ + match ty.sty { + ty::TyFnDef(..) | + // Shims currently have type TyFnPtr. Not sure this should remain. + ty::TyFnPtr(_) => ty.fn_sig(cx.tcx), + ty::TyClosure(def_id, substs) => { + let tcx = cx.tcx; + let sig = substs.closure_sig(def_id, tcx); + + let env_ty = tcx.closure_env_ty(def_id, substs).unwrap(); + sig.map_bound(|sig| tcx.mk_fn_sig( + iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), + sig.output(), + sig.variadic, + sig.unsafety, + sig.abi + )) + } + ty::TyGenerator(def_id, substs, _) => { + let tcx = cx.tcx; + let sig = substs.poly_sig(def_id, cx.tcx); + + let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv); + let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); + + sig.map_bound(|sig| { + let state_did = tcx.lang_items().gen_state().unwrap(); + let state_adt_ref = tcx.adt_def(state_did); + let state_substs = tcx.mk_substs([sig.yield_ty.into(), + sig.return_ty.into()].iter()); + let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); + + tcx.mk_fn_sig(iter::once(env_ty), + ret_ty, + false, + hir::Unsafety::Normal, + Abi::Rust + ) + }) + } + _ => bug!("unexpected type {:?} to ty_fn_sig", ty) + } +} diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs new file mode 100644 index 00000000000..afa81465ea2 --- /dev/null +++ b/src/librustc_codegen_llvm/consts.rs @@ -0,0 +1,322 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use llvm; +use llvm::{SetUnnamedAddr}; +use llvm::{ValueRef, True}; +use rustc::hir::def_id::DefId; +use rustc::hir::map as hir_map; +use debuginfo; +use base; +use monomorphize::MonoItem; +use common::{CodegenCx, val_ty}; +use declare; +use monomorphize::Instance; +use type_::Type; +use type_of::LayoutLlvmExt; +use rustc::ty; +use rustc::ty::layout::{Align, LayoutOf}; + +use rustc::hir; + +use std::ffi::{CStr, CString}; +use syntax::ast; +use syntax::attr; + +pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef { + unsafe { + llvm::LLVMConstPointerCast(val, ty.to_ref()) + } +} + +pub fn bitcast(val: ValueRef, ty: Type) -> ValueRef { + unsafe { + llvm::LLVMConstBitCast(val, ty.to_ref()) + } +} + +fn set_global_alignment(cx: &CodegenCx, + gv: ValueRef, + mut align: Align) { + // The target may require greater alignment for globals than the type does. + // Note: GCC and Clang also allow `__attribute__((aligned))` on variables, + // which can force it to be smaller. Rust doesn't support this yet. + if let Some(min) = cx.sess().target.target.options.min_global_align { + match ty::layout::Align::from_bits(min, min) { + Ok(min) => align = align.max(min), + Err(err) => { + cx.sess().err(&format!("invalid minimum global alignment: {}", err)); + } + } + } + unsafe { + llvm::LLVMSetAlignment(gv, align.abi() as u32); + } +} + +pub fn addr_of_mut(cx: &CodegenCx, + cv: ValueRef, + align: Align, + kind: &str) + -> ValueRef { + unsafe { + let name = cx.generate_local_symbol_name(kind); + let gv = declare::define_global(cx, &name[..], val_ty(cv)).unwrap_or_else(||{ + bug!("symbol `{}` is already defined", name); + }); + llvm::LLVMSetInitializer(gv, cv); + set_global_alignment(cx, gv, align); + llvm::LLVMRustSetLinkage(gv, llvm::Linkage::PrivateLinkage); + SetUnnamedAddr(gv, true); + gv + } +} + +pub fn addr_of(cx: &CodegenCx, + cv: ValueRef, + align: Align, + kind: &str) + -> ValueRef { + if let Some(&gv) = cx.const_globals.borrow().get(&cv) { + unsafe { + // Upgrade the alignment in cases where the same constant is used with different + // alignment requirements + let llalign = align.abi() as u32; + if llalign > llvm::LLVMGetAlignment(gv) { + llvm::LLVMSetAlignment(gv, llalign); + } + } + return gv; + } + let gv = addr_of_mut(cx, cv, align, kind); + unsafe { + llvm::LLVMSetGlobalConstant(gv, True); + } + cx.const_globals.borrow_mut().insert(cv, gv); + gv +} + +pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { + let instance = Instance::mono(cx.tcx, def_id); + if let Some(&g) = cx.instances.borrow().get(&instance) { + return g; + } + + let defined_in_current_codegen_unit = cx.codegen_unit + .items() + .contains_key(&MonoItem::Static(def_id)); + assert!(!defined_in_current_codegen_unit, + "consts::get_static() should always hit the cache for \ + statics defined in the same CGU, but did not for `{:?}`", + def_id); + + let ty = instance.ty(cx.tcx); + let sym = cx.tcx.symbol_name(instance).as_str(); + + let g = if let Some(id) = cx.tcx.hir.as_local_node_id(def_id) { + + let llty = cx.layout_of(ty).llvm_type(cx); + let (g, attrs) = match cx.tcx.hir.get(id) { + hir_map::NodeItem(&hir::Item { + ref attrs, span, node: hir::ItemStatic(..), .. + }) => { + if declare::get_declared_value(cx, &sym[..]).is_some() { + span_bug!(span, "Conflicting symbol names for static?"); + } + + let g = declare::define_global(cx, &sym[..], llty).unwrap(); + + if !cx.tcx.is_reachable_non_generic(def_id) { + unsafe { + llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden); + } + } + + (g, attrs) + } + + hir_map::NodeForeignItem(&hir::ForeignItem { + ref attrs, span, node: hir::ForeignItemStatic(..), .. + }) => { + let g = if let Some(linkage) = cx.tcx.codegen_fn_attrs(def_id).linkage { + // If this is a static with a linkage specified, then we need to handle + // it a little specially. The typesystem prevents things like &T and + // extern "C" fn() from being non-null, so we can't just declare a + // static and call it a day. Some linkages (like weak) will make it such + // that the static actually has a null value. + let llty2 = match ty.sty { + ty::TyRawPtr(ref mt) => cx.layout_of(mt.ty).llvm_type(cx), + _ => { + cx.sess().span_fatal(span, "must have type `*const T` or `*mut T`"); + } + }; + unsafe { + // Declare a symbol `foo` with the desired linkage. + let g1 = declare::declare_global(cx, &sym, llty2); + llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage)); + + // Declare an internal global `extern_with_linkage_foo` which + // is initialized with the address of `foo`. If `foo` is + // discarded during linking (for example, if `foo` has weak + // linkage and there are no definitions), then + // `extern_with_linkage_foo` will instead be initialized to + // zero. + let mut real_name = "_rust_extern_with_linkage_".to_string(); + real_name.push_str(&sym); + let g2 = declare::define_global(cx, &real_name, llty).unwrap_or_else(||{ + cx.sess().span_fatal(span, + &format!("symbol `{}` is already defined", &sym)) + }); + llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage); + llvm::LLVMSetInitializer(g2, g1); + g2 + } + } else { + // Generate an external declaration. + declare::declare_global(cx, &sym, llty) + }; + + (g, attrs) + } + + item => bug!("get_static: expected static, found {:?}", item) + }; + + for attr in attrs { + if attr.check_name("thread_local") { + llvm::set_thread_local_mode(g, cx.tls_model); + } + } + + g + } else { + // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? + // FIXME(nagisa): investigate whether it can be changed into define_global + let g = declare::declare_global(cx, &sym, cx.layout_of(ty).llvm_type(cx)); + // Thread-local statics in some other crate need to *always* be linked + // against in a thread-local fashion, so we need to be sure to apply the + // thread-local attribute locally if it was present remotely. If we + // don't do this then linker errors can be generated where the linker + // complains that one object files has a thread local version of the + // symbol and another one doesn't. + for attr in cx.tcx.get_attrs(def_id).iter() { + if attr.check_name("thread_local") { + llvm::set_thread_local_mode(g, cx.tls_model); + } + } + if cx.use_dll_storage_attrs && !cx.tcx.is_foreign_item(def_id) { + // This item is external but not foreign, i.e. it originates from an external Rust + // crate. Since we don't know whether this crate will be linked dynamically or + // statically in the final application, we always mark such symbols as 'dllimport'. + // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs to + // make things work. + // + // However, in some scenarios we defer emission of statics to downstream + // crates, so there are cases where a static with an upstream DefId + // is actually present in the current crate. We can find out via the + // is_codegened_item query. + if !cx.tcx.is_codegened_item(def_id) { + unsafe { + llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); + } + } + } + g + }; + + if cx.use_dll_storage_attrs && cx.tcx.is_dllimport_foreign_item(def_id) { + // For foreign (native) libs we know the exact storage type to use. + unsafe { + llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); + } + } + + cx.instances.borrow_mut().insert(instance, g); + cx.statics.borrow_mut().insert(g, def_id); + g +} + +pub fn codegen_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + def_id: DefId, + is_mutable: bool, + attrs: &[ast::Attribute]) { + unsafe { + let g = get_static(cx, def_id); + + let v = match ::mir::codegen_static_initializer(cx, def_id) { + Ok(v) => v, + // Error has already been reported + Err(_) => return, + }; + + // boolean SSA values are i1, but they have to be stored in i8 slots, + // otherwise some LLVM optimization passes don't work as expected + let mut val_llty = val_ty(v); + let v = if val_llty == Type::i1(cx) { + val_llty = Type::i8(cx); + llvm::LLVMConstZExt(v, val_llty.to_ref()) + } else { + v + }; + + let instance = Instance::mono(cx.tcx, def_id); + let ty = instance.ty(cx.tcx); + let llty = cx.layout_of(ty).llvm_type(cx); + let g = if val_llty == llty { + g + } else { + // If we created the global with the wrong type, + // correct the type. + let empty_string = CString::new("").unwrap(); + let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(g)); + let name_string = CString::new(name_str_ref.to_bytes()).unwrap(); + llvm::LLVMSetValueName(g, empty_string.as_ptr()); + + let linkage = llvm::LLVMRustGetLinkage(g); + let visibility = llvm::LLVMRustGetVisibility(g); + + let new_g = llvm::LLVMRustGetOrInsertGlobal( + cx.llmod, name_string.as_ptr(), val_llty.to_ref()); + + llvm::LLVMRustSetLinkage(new_g, linkage); + llvm::LLVMRustSetVisibility(new_g, visibility); + + // To avoid breaking any invariants, we leave around the old + // global for the moment; we'll replace all references to it + // with the new global later. (See base::codegen_backend.) + cx.statics_to_rauw.borrow_mut().push((g, new_g)); + new_g + }; + set_global_alignment(cx, g, cx.align_of(ty)); + llvm::LLVMSetInitializer(g, v); + + // As an optimization, all shared statics which do not have interior + // mutability are placed into read-only memory. + if !is_mutable { + if cx.type_is_freeze(ty) { + llvm::LLVMSetGlobalConstant(g, llvm::True); + } + } + + debuginfo::create_global_var_metadata(cx, def_id, g); + + if attr::contains_name(attrs, "thread_local") { + llvm::set_thread_local_mode(g, cx.tls_model); + } + + base::set_link_section(cx, g, attrs); + + if attr::contains_name(attrs, "used") { + // This static will be stored in the llvm.used variable which is an array of i8* + let cast = llvm::LLVMConstPointerCast(g, Type::i8p(cx).to_ref()); + cx.used_statics.borrow_mut().push(cast); + } + } +} diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs new file mode 100644 index 00000000000..9b1de3d44ea --- /dev/null +++ b/src/librustc_codegen_llvm/context.rs @@ -0,0 +1,666 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use common; +use llvm; +use llvm::{ContextRef, ModuleRef, ValueRef}; +use rustc::dep_graph::DepGraphSafe; +use rustc::hir; +use rustc::hir::def_id::DefId; +use debuginfo; +use callee; +use base; +use declare; +use monomorphize::Instance; + +use monomorphize::partitioning::CodegenUnit; +use type_::Type; +use type_of::PointeeInfo; + +use rustc_data_structures::base_n; +use rustc::mir::mono::Stats; +use rustc::session::config::{self, NoDebugInfo}; +use rustc::session::Session; +use rustc::ty::layout::{LayoutError, LayoutOf, Size, TyLayout}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::util::nodemap::FxHashMap; +use rustc_target::spec::{HasTargetSpec, Target}; + +use std::ffi::{CStr, CString}; +use std::cell::{Cell, RefCell}; +use std::ptr; +use std::iter; +use std::str; +use std::sync::Arc; +use syntax::symbol::LocalInternedString; +use abi::Abi; + +/// There is one `CodegenCx` per compilation unit. Each one has its own LLVM +/// `ContextRef` so that several compilation units may be optimized in parallel. +/// All other LLVM data structures in the `CodegenCx` are tied to that `ContextRef`. +pub struct CodegenCx<'a, 'tcx: 'a> { + pub tcx: TyCtxt<'a, 'tcx, 'tcx>, + pub check_overflow: bool, + pub use_dll_storage_attrs: bool, + pub tls_model: llvm::ThreadLocalMode, + + pub llmod: ModuleRef, + pub llcx: ContextRef, + pub stats: RefCell, + pub codegen_unit: Arc>, + + /// Cache instances of monomorphic and polymorphic items + pub instances: RefCell, ValueRef>>, + /// Cache generated vtables + pub vtables: RefCell, + Option>), ValueRef>>, + /// Cache of constant strings, + pub const_cstr_cache: RefCell>, + + /// Reverse-direction for const ptrs cast from globals. + /// Key is a ValueRef holding a *T, + /// Val is a ValueRef holding a *[T]. + /// + /// Needed because LLVM loses pointer->pointee association + /// when we ptrcast, and we have to ptrcast during codegen + /// of a [T] const because we form a slice, a (*T,usize) pair, not + /// a pointer to an LLVM array type. Similar for trait objects. + pub const_unsized: RefCell>, + + /// Cache of emitted const globals (value -> global) + pub const_globals: RefCell>, + + /// Mapping from static definitions to their DefId's. + pub statics: RefCell>, + + /// List of globals for static variables which need to be passed to the + /// LLVM function ReplaceAllUsesWith (RAUW) when codegen is complete. + /// (We have to make sure we don't invalidate any ValueRefs referring + /// to constants.) + pub statics_to_rauw: RefCell>, + + /// Statics that will be placed in the llvm.used variable + /// See http://llvm.org/docs/LangRef.html#the-llvm-used-global-variable for details + pub used_statics: RefCell>, + + pub lltypes: RefCell, Option), Type>>, + pub scalar_lltypes: RefCell, Type>>, + pub pointee_infos: RefCell, Size), Option>>, + pub isize_ty: Type, + + pub dbg_cx: Option>, + + eh_personality: Cell>, + eh_unwind_resume: Cell>, + pub rust_try_fn: Cell>, + + intrinsics: RefCell>, + + /// A counter that is used for generating local symbol names + local_gen_sym_counter: Cell, +} + +impl<'a, 'tcx> DepGraphSafe for CodegenCx<'a, 'tcx> { +} + +pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode { + let reloc_model_arg = match sess.opts.cg.relocation_model { + Some(ref s) => &s[..], + None => &sess.target.target.options.relocation_model[..], + }; + + match ::back::write::RELOC_MODEL_ARGS.iter().find( + |&&arg| arg.0 == reloc_model_arg) { + Some(x) => x.1, + _ => { + sess.err(&format!("{:?} is not a valid relocation mode", + reloc_model_arg)); + sess.abort_if_errors(); + bug!(); + } + } +} + +fn get_tls_model(sess: &Session) -> llvm::ThreadLocalMode { + let tls_model_arg = match sess.opts.debugging_opts.tls_model { + Some(ref s) => &s[..], + None => &sess.target.target.options.tls_model[..], + }; + + match ::back::write::TLS_MODEL_ARGS.iter().find( + |&&arg| arg.0 == tls_model_arg) { + Some(x) => x.1, + _ => { + sess.err(&format!("{:?} is not a valid TLS model", + tls_model_arg)); + sess.abort_if_errors(); + bug!(); + } + } +} + +fn is_any_library(sess: &Session) -> bool { + sess.crate_types.borrow().iter().any(|ty| { + *ty != config::CrateTypeExecutable + }) +} + +pub fn is_pie_binary(sess: &Session) -> bool { + !is_any_library(sess) && get_reloc_model(sess) == llvm::RelocMode::PIC +} + +pub unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) { + let llcx = llvm::LLVMRustContextCreate(sess.fewer_names()); + let mod_name = CString::new(mod_name).unwrap(); + let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); + + // Ensure the data-layout values hardcoded remain the defaults. + if sess.target.target.options.is_builtin { + let tm = ::back::write::create_target_machine(sess, false); + llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm); + llvm::LLVMRustDisposeTargetMachine(tm); + + let data_layout = llvm::LLVMGetDataLayout(llmod); + let data_layout = str::from_utf8(CStr::from_ptr(data_layout).to_bytes()) + .ok().expect("got a non-UTF8 data-layout from LLVM"); + + // Unfortunately LLVM target specs change over time, and right now we + // don't have proper support to work with any more than one + // `data_layout` than the one that is in the rust-lang/rust repo. If + // this compiler is configured against a custom LLVM, we may have a + // differing data layout, even though we should update our own to use + // that one. + // + // As an interim hack, if CFG_LLVM_ROOT is not an empty string then we + // disable this check entirely as we may be configured with something + // that has a different target layout. + // + // Unsure if this will actually cause breakage when rustc is configured + // as such. + // + // FIXME(#34960) + let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or(""); + let custom_llvm_used = cfg_llvm_root.trim() != ""; + + if !custom_llvm_used && sess.target.target.data_layout != data_layout { + bug!("data-layout for builtin `{}` target, `{}`, \ + differs from LLVM default, `{}`", + sess.target.target.llvm_target, + sess.target.target.data_layout, + data_layout); + } + } + + let data_layout = CString::new(&sess.target.target.data_layout[..]).unwrap(); + llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); + + let llvm_target = sess.target.target.llvm_target.as_bytes(); + let llvm_target = CString::new(llvm_target).unwrap(); + llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); + + if is_pie_binary(sess) { + llvm::LLVMRustSetModulePIELevel(llmod); + } + + (llcx, llmod) +} + +impl<'a, 'tcx> CodegenCx<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, + codegen_unit: Arc>, + llmod_id: &str) + -> CodegenCx<'a, 'tcx> { + // An interesting part of Windows which MSVC forces our hand on (and + // apparently MinGW didn't) is the usage of `dllimport` and `dllexport` + // attributes in LLVM IR as well as native dependencies (in C these + // correspond to `__declspec(dllimport)`). + // + // Whenever a dynamic library is built by MSVC it must have its public + // interface specified by functions tagged with `dllexport` or otherwise + // they're not available to be linked against. This poses a few problems + // for the compiler, some of which are somewhat fundamental, but we use + // the `use_dll_storage_attrs` variable below to attach the `dllexport` + // attribute to all LLVM functions that are exported e.g. they're + // already tagged with external linkage). This is suboptimal for a few + // reasons: + // + // * If an object file will never be included in a dynamic library, + // there's no need to attach the dllexport attribute. Most object + // files in Rust are not destined to become part of a dll as binaries + // are statically linked by default. + // * If the compiler is emitting both an rlib and a dylib, the same + // source object file is currently used but with MSVC this may be less + // feasible. The compiler may be able to get around this, but it may + // involve some invasive changes to deal with this. + // + // The flipside of this situation is that whenever you link to a dll and + // you import a function from it, the import should be tagged with + // `dllimport`. At this time, however, the compiler does not emit + // `dllimport` for any declarations other than constants (where it is + // required), which is again suboptimal for even more reasons! + // + // * Calling a function imported from another dll without using + // `dllimport` causes the linker/compiler to have extra overhead (one + // `jmp` instruction on x86) when calling the function. + // * The same object file may be used in different circumstances, so a + // function may be imported from a dll if the object is linked into a + // dll, but it may be just linked against if linked into an rlib. + // * The compiler has no knowledge about whether native functions should + // be tagged dllimport or not. + // + // For now the compiler takes the perf hit (I do not have any numbers to + // this effect) by marking very little as `dllimport` and praying the + // linker will take care of everything. Fixing this problem will likely + // require adding a few attributes to Rust itself (feature gated at the + // start) and then strongly recommending static linkage on MSVC! + let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_msvc; + + let check_overflow = tcx.sess.overflow_checks(); + + let tls_model = get_tls_model(&tcx.sess); + + unsafe { + let (llcx, llmod) = create_context_and_module(&tcx.sess, + &llmod_id[..]); + + let dbg_cx = if tcx.sess.opts.debuginfo != NoDebugInfo { + let dctx = debuginfo::CrateDebugContext::new(llmod); + debuginfo::metadata::compile_unit_metadata(tcx, + &codegen_unit.name().as_str(), + &dctx); + Some(dctx) + } else { + None + }; + + let mut cx = CodegenCx { + tcx, + check_overflow, + use_dll_storage_attrs, + tls_model, + llmod, + llcx, + stats: RefCell::new(Stats::default()), + codegen_unit, + instances: RefCell::new(FxHashMap()), + vtables: RefCell::new(FxHashMap()), + const_cstr_cache: RefCell::new(FxHashMap()), + const_unsized: RefCell::new(FxHashMap()), + const_globals: RefCell::new(FxHashMap()), + statics: RefCell::new(FxHashMap()), + statics_to_rauw: RefCell::new(Vec::new()), + used_statics: RefCell::new(Vec::new()), + lltypes: RefCell::new(FxHashMap()), + scalar_lltypes: RefCell::new(FxHashMap()), + pointee_infos: RefCell::new(FxHashMap()), + isize_ty: Type::from_ref(ptr::null_mut()), + dbg_cx, + eh_personality: Cell::new(None), + eh_unwind_resume: Cell::new(None), + rust_try_fn: Cell::new(None), + intrinsics: RefCell::new(FxHashMap()), + local_gen_sym_counter: Cell::new(0), + }; + cx.isize_ty = Type::isize(&cx); + cx + } + } + + pub fn into_stats(self) -> Stats { + self.stats.into_inner() + } +} + +impl<'b, 'tcx> CodegenCx<'b, 'tcx> { + pub fn sess<'a>(&'a self) -> &'a Session { + &self.tcx.sess + } + + pub fn get_intrinsic(&self, key: &str) -> ValueRef { + if let Some(v) = self.intrinsics.borrow().get(key).cloned() { + return v; + } + match declare_intrinsic(self, key) { + Some(v) => return v, + None => bug!("unknown intrinsic '{}'", key) + } + } + + /// Generate a new symbol name with the given prefix. This symbol name must + /// only be used for definitions with `internal` or `private` linkage. + pub fn generate_local_symbol_name(&self, prefix: &str) -> String { + let idx = self.local_gen_sym_counter.get(); + self.local_gen_sym_counter.set(idx + 1); + // Include a '.' character, so there can be no accidental conflicts with + // user defined names + let mut name = String::with_capacity(prefix.len() + 6); + name.push_str(prefix); + name.push_str("."); + base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name); + name + } + + pub fn eh_personality(&self) -> ValueRef { + // The exception handling personality function. + // + // If our compilation unit has the `eh_personality` lang item somewhere + // within it, then we just need to codegen that. Otherwise, we're + // building an rlib which will depend on some upstream implementation of + // this function, so we just codegen a generic reference to it. We don't + // specify any of the types for the function, we just make it a symbol + // that LLVM can later use. + // + // Note that MSVC is a little special here in that we don't use the + // `eh_personality` lang item at all. Currently LLVM has support for + // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the + // *name of the personality function* to decide what kind of unwind side + // tables/landing pads to emit. It looks like Dwarf is used by default, + // injecting a dependency on the `_Unwind_Resume` symbol for resuming + // an "exception", but for MSVC we want to force SEH. This means that we + // can't actually have the personality function be our standard + // `rust_eh_personality` function, but rather we wired it up to the + // CRT's custom personality function, which forces LLVM to consider + // landing pads as "landing pads for SEH". + if let Some(llpersonality) = self.eh_personality.get() { + return llpersonality + } + let tcx = self.tcx; + let llfn = match tcx.lang_items().eh_personality() { + Some(def_id) if !base::wants_msvc_seh(self.sess()) => { + callee::resolve_and_get_fn(self, def_id, tcx.intern_substs(&[])) + } + _ => { + let name = if base::wants_msvc_seh(self.sess()) { + "__CxxFrameHandler3" + } else { + "rust_eh_personality" + }; + let fty = Type::variadic_func(&[], &Type::i32(self)); + declare::declare_cfn(self, name, fty) + } + }; + self.eh_personality.set(Some(llfn)); + llfn + } + + // Returns a ValueRef of the "eh_unwind_resume" lang item if one is defined, + // otherwise declares it as an external function. + pub fn eh_unwind_resume(&self) -> ValueRef { + use attributes; + let unwresume = &self.eh_unwind_resume; + if let Some(llfn) = unwresume.get() { + return llfn; + } + + let tcx = self.tcx; + assert!(self.sess().target.target.options.custom_unwind_resume); + if let Some(def_id) = tcx.lang_items().eh_unwind_resume() { + let llfn = callee::resolve_and_get_fn(self, def_id, tcx.intern_substs(&[])); + unwresume.set(Some(llfn)); + return llfn; + } + + let ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( + iter::once(tcx.mk_mut_ptr(tcx.types.u8)), + tcx.types.never, + false, + hir::Unsafety::Unsafe, + Abi::C + ))); + + let llfn = declare::declare_fn(self, "rust_eh_unwind_resume", ty); + attributes::unwind(llfn, true); + unwresume.set(Some(llfn)); + llfn + } + + pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { + common::type_needs_drop(self.tcx, ty) + } + + pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { + common::type_is_sized(self.tcx, ty) + } + + pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { + common::type_is_freeze(self.tcx, ty) + } + + pub fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool { + use syntax_pos::DUMMY_SP; + if ty.is_sized(self.tcx.at(DUMMY_SP), ty::ParamEnv::reveal_all()) { + return false; + } + + let tail = self.tcx.struct_tail(ty); + match tail.sty { + ty::TyForeign(..) => false, + ty::TyStr | ty::TySlice(..) | ty::TyDynamic(..) => true, + _ => bug!("unexpected unsized tail: {:?}", tail.sty), + } + } +} + +impl<'a, 'tcx> ty::layout::HasDataLayout for &'a CodegenCx<'a, 'tcx> { + fn data_layout(&self) -> &ty::layout::TargetDataLayout { + &self.tcx.data_layout + } +} + +impl<'a, 'tcx> HasTargetSpec for &'a CodegenCx<'a, 'tcx> { + fn target_spec(&self) -> &Target { + &self.tcx.sess.target.target + } +} + +impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a CodegenCx<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { + self.tcx + } +} + +impl<'a, 'tcx> LayoutOf for &'a CodegenCx<'a, 'tcx> { + type Ty = Ty<'tcx>; + type TyLayout = TyLayout<'tcx>; + + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { + self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) + .unwrap_or_else(|e| match e { + LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()), + _ => bug!("failed to get layout for `{}`: {}", ty, e) + }) + } +} + +/// Declare any llvm intrinsics that you might need +fn declare_intrinsic(cx: &CodegenCx, key: &str) -> Option { + macro_rules! ifn { + ($name:expr, fn() -> $ret:expr) => ( + if key == $name { + let f = declare::declare_cfn(cx, $name, Type::func(&[], &$ret)); + llvm::SetUnnamedAddr(f, false); + cx.intrinsics.borrow_mut().insert($name, f.clone()); + return Some(f); + } + ); + ($name:expr, fn(...) -> $ret:expr) => ( + if key == $name { + let f = declare::declare_cfn(cx, $name, Type::variadic_func(&[], &$ret)); + llvm::SetUnnamedAddr(f, false); + cx.intrinsics.borrow_mut().insert($name, f.clone()); + return Some(f); + } + ); + ($name:expr, fn($($arg:expr),*) -> $ret:expr) => ( + if key == $name { + let f = declare::declare_cfn(cx, $name, Type::func(&[$($arg),*], &$ret)); + llvm::SetUnnamedAddr(f, false); + cx.intrinsics.borrow_mut().insert($name, f.clone()); + return Some(f); + } + ); + } + macro_rules! mk_struct { + ($($field_ty:expr),*) => (Type::struct_(cx, &[$($field_ty),*], false)) + } + + let i8p = Type::i8p(cx); + let void = Type::void(cx); + let i1 = Type::i1(cx); + let t_i8 = Type::i8(cx); + let t_i16 = Type::i16(cx); + let t_i32 = Type::i32(cx); + let t_i64 = Type::i64(cx); + let t_i128 = Type::i128(cx); + let t_f32 = Type::f32(cx); + let t_f64 = Type::f64(cx); + + ifn!("llvm.memcpy.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void); + ifn!("llvm.memcpy.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void); + ifn!("llvm.memcpy.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void); + ifn!("llvm.memmove.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void); + ifn!("llvm.memmove.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void); + ifn!("llvm.memmove.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void); + ifn!("llvm.memset.p0i8.i16", fn(i8p, t_i8, t_i16, t_i32, i1) -> void); + ifn!("llvm.memset.p0i8.i32", fn(i8p, t_i8, t_i32, t_i32, i1) -> void); + ifn!("llvm.memset.p0i8.i64", fn(i8p, t_i8, t_i64, t_i32, i1) -> void); + + ifn!("llvm.trap", fn() -> void); + ifn!("llvm.debugtrap", fn() -> void); + ifn!("llvm.frameaddress", fn(t_i32) -> i8p); + + ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32); + ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64); + ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32); + ifn!("llvm.pow.f64", fn(t_f64, t_f64) -> t_f64); + + ifn!("llvm.sqrt.f32", fn(t_f32) -> t_f32); + ifn!("llvm.sqrt.f64", fn(t_f64) -> t_f64); + ifn!("llvm.sin.f32", fn(t_f32) -> t_f32); + ifn!("llvm.sin.f64", fn(t_f64) -> t_f64); + ifn!("llvm.cos.f32", fn(t_f32) -> t_f32); + ifn!("llvm.cos.f64", fn(t_f64) -> t_f64); + ifn!("llvm.exp.f32", fn(t_f32) -> t_f32); + ifn!("llvm.exp.f64", fn(t_f64) -> t_f64); + ifn!("llvm.exp2.f32", fn(t_f32) -> t_f32); + ifn!("llvm.exp2.f64", fn(t_f64) -> t_f64); + ifn!("llvm.log.f32", fn(t_f32) -> t_f32); + ifn!("llvm.log.f64", fn(t_f64) -> t_f64); + ifn!("llvm.log10.f32", fn(t_f32) -> t_f32); + ifn!("llvm.log10.f64", fn(t_f64) -> t_f64); + ifn!("llvm.log2.f32", fn(t_f32) -> t_f32); + ifn!("llvm.log2.f64", fn(t_f64) -> t_f64); + + ifn!("llvm.fma.f32", fn(t_f32, t_f32, t_f32) -> t_f32); + ifn!("llvm.fma.f64", fn(t_f64, t_f64, t_f64) -> t_f64); + + ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32); + ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64); + + ifn!("llvm.floor.f32", fn(t_f32) -> t_f32); + ifn!("llvm.floor.f64", fn(t_f64) -> t_f64); + ifn!("llvm.ceil.f32", fn(t_f32) -> t_f32); + ifn!("llvm.ceil.f64", fn(t_f64) -> t_f64); + ifn!("llvm.trunc.f32", fn(t_f32) -> t_f32); + ifn!("llvm.trunc.f64", fn(t_f64) -> t_f64); + + ifn!("llvm.copysign.f32", fn(t_f32, t_f32) -> t_f32); + ifn!("llvm.copysign.f64", fn(t_f64, t_f64) -> t_f64); + ifn!("llvm.round.f32", fn(t_f32) -> t_f32); + ifn!("llvm.round.f64", fn(t_f64) -> t_f64); + + ifn!("llvm.rint.f32", fn(t_f32) -> t_f32); + ifn!("llvm.rint.f64", fn(t_f64) -> t_f64); + ifn!("llvm.nearbyint.f32", fn(t_f32) -> t_f32); + ifn!("llvm.nearbyint.f64", fn(t_f64) -> t_f64); + + ifn!("llvm.ctpop.i8", fn(t_i8) -> t_i8); + ifn!("llvm.ctpop.i16", fn(t_i16) -> t_i16); + ifn!("llvm.ctpop.i32", fn(t_i32) -> t_i32); + ifn!("llvm.ctpop.i64", fn(t_i64) -> t_i64); + ifn!("llvm.ctpop.i128", fn(t_i128) -> t_i128); + + ifn!("llvm.ctlz.i8", fn(t_i8 , i1) -> t_i8); + ifn!("llvm.ctlz.i16", fn(t_i16, i1) -> t_i16); + ifn!("llvm.ctlz.i32", fn(t_i32, i1) -> t_i32); + ifn!("llvm.ctlz.i64", fn(t_i64, i1) -> t_i64); + ifn!("llvm.ctlz.i128", fn(t_i128, i1) -> t_i128); + + ifn!("llvm.cttz.i8", fn(t_i8 , i1) -> t_i8); + ifn!("llvm.cttz.i16", fn(t_i16, i1) -> t_i16); + ifn!("llvm.cttz.i32", fn(t_i32, i1) -> t_i32); + ifn!("llvm.cttz.i64", fn(t_i64, i1) -> t_i64); + ifn!("llvm.cttz.i128", fn(t_i128, i1) -> t_i128); + + ifn!("llvm.bswap.i16", fn(t_i16) -> t_i16); + ifn!("llvm.bswap.i32", fn(t_i32) -> t_i32); + ifn!("llvm.bswap.i64", fn(t_i64) -> t_i64); + ifn!("llvm.bswap.i128", fn(t_i128) -> t_i128); + + ifn!("llvm.bitreverse.i8", fn(t_i8) -> t_i8); + ifn!("llvm.bitreverse.i16", fn(t_i16) -> t_i16); + ifn!("llvm.bitreverse.i32", fn(t_i32) -> t_i32); + ifn!("llvm.bitreverse.i64", fn(t_i64) -> t_i64); + ifn!("llvm.bitreverse.i128", fn(t_i128) -> t_i128); + + ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); + ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); + ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); + ifn!("llvm.sadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.sadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); + + ifn!("llvm.uadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); + ifn!("llvm.uadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); + ifn!("llvm.uadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); + ifn!("llvm.uadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.uadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); + + ifn!("llvm.ssub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); + ifn!("llvm.ssub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); + ifn!("llvm.ssub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); + ifn!("llvm.ssub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.ssub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); + + ifn!("llvm.usub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); + ifn!("llvm.usub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); + ifn!("llvm.usub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); + ifn!("llvm.usub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.usub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); + + ifn!("llvm.smul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); + ifn!("llvm.smul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); + ifn!("llvm.smul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); + ifn!("llvm.smul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.smul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); + + ifn!("llvm.umul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); + ifn!("llvm.umul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); + ifn!("llvm.umul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); + ifn!("llvm.umul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.umul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); + + ifn!("llvm.lifetime.start", fn(t_i64,i8p) -> void); + ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void); + + ifn!("llvm.expect.i1", fn(i1, i1) -> i1); + ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32); + ifn!("llvm.localescape", fn(...) -> void); + ifn!("llvm.localrecover", fn(i8p, i8p, t_i32) -> i8p); + ifn!("llvm.x86.seh.recoverfp", fn(i8p, i8p) -> i8p); + + ifn!("llvm.assume", fn(i1) -> void); + ifn!("llvm.prefetch", fn(i8p, t_i32, t_i32, t_i32) -> void); + + if cx.sess().opts.debuginfo != NoDebugInfo { + ifn!("llvm.dbg.declare", fn(Type::metadata(cx), Type::metadata(cx)) -> void); + ifn!("llvm.dbg.value", fn(Type::metadata(cx), t_i64, Type::metadata(cx)) -> void); + } + return None; +} diff --git a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs new file mode 100644 index 00000000000..bddb3d90940 --- /dev/null +++ b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs @@ -0,0 +1,136 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::{FunctionDebugContext, FunctionDebugContextData}; +use super::metadata::file_metadata; +use super::utils::{DIB, span_start}; + +use llvm; +use llvm::debuginfo::DIScope; +use common::CodegenCx; +use rustc::mir::{Mir, VisibilityScope}; + +use libc::c_uint; +use std::ptr; + +use syntax_pos::Pos; + +use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; + +use syntax_pos::BytePos; + +#[derive(Clone, Copy, Debug)] +pub struct MirDebugScope { + pub scope_metadata: DIScope, + // Start and end offsets of the file to which this DIScope belongs. + // These are used to quickly determine whether some span refers to the same file. + pub file_start_pos: BytePos, + pub file_end_pos: BytePos, +} + +impl MirDebugScope { + pub fn is_valid(&self) -> bool { + !self.scope_metadata.is_null() + } +} + +/// Produce DIScope DIEs for each MIR Scope which has variables defined in it. +/// If debuginfo is disabled, the returned vector is empty. +pub fn create_mir_scopes(cx: &CodegenCx, mir: &Mir, debug_context: &FunctionDebugContext) + -> IndexVec { + let null_scope = MirDebugScope { + scope_metadata: ptr::null_mut(), + file_start_pos: BytePos(0), + file_end_pos: BytePos(0) + }; + let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes); + + let debug_context = match *debug_context { + FunctionDebugContext::RegularContext(ref data) => data, + FunctionDebugContext::DebugInfoDisabled | + FunctionDebugContext::FunctionWithoutDebugInfo => { + return scopes; + } + }; + + // Find all the scopes with variables defined in them. + let mut has_variables = BitVector::new(mir.visibility_scopes.len()); + for var in mir.vars_iter() { + let decl = &mir.local_decls[var]; + has_variables.insert(decl.source_info.scope.index()); + } + + // Instantiate all scopes. + for idx in 0..mir.visibility_scopes.len() { + let scope = VisibilityScope::new(idx); + make_mir_scope(cx, &mir, &has_variables, debug_context, scope, &mut scopes); + } + + scopes +} + +fn make_mir_scope(cx: &CodegenCx, + mir: &Mir, + has_variables: &BitVector, + debug_context: &FunctionDebugContextData, + scope: VisibilityScope, + scopes: &mut IndexVec) { + if scopes[scope].is_valid() { + return; + } + + let scope_data = &mir.visibility_scopes[scope]; + let parent_scope = if let Some(parent) = scope_data.parent_scope { + make_mir_scope(cx, mir, has_variables, debug_context, parent, scopes); + scopes[parent] + } else { + // The root is the function itself. + let loc = span_start(cx, mir.span); + scopes[scope] = MirDebugScope { + scope_metadata: debug_context.fn_metadata, + file_start_pos: loc.file.start_pos, + file_end_pos: loc.file.end_pos, + }; + return; + }; + + if !has_variables.contains(scope.index()) { + // Do not create a DIScope if there are no variables + // defined in this MIR Scope, to avoid debuginfo bloat. + + // However, we don't skip creating a nested scope if + // our parent is the root, because we might want to + // put arguments in the root and not have shadowing. + if parent_scope.scope_metadata != debug_context.fn_metadata { + scopes[scope] = parent_scope; + return; + } + } + + let loc = span_start(cx, scope_data.span); + let file_metadata = file_metadata(cx, + &loc.file.name, + debug_context.defining_crate); + + let scope_metadata = unsafe { + llvm::LLVMRustDIBuilderCreateLexicalBlock( + DIB(cx), + parent_scope.scope_metadata, + file_metadata, + loc.line as c_uint, + loc.col.to_usize() as c_uint) + }; + scopes[scope] = MirDebugScope { + scope_metadata, + file_start_pos: loc.file.start_pos, + file_end_pos: loc.file.end_pos, + }; +} diff --git a/src/librustc_codegen_llvm/debuginfo/doc.rs b/src/librustc_codegen_llvm/debuginfo/doc.rs new file mode 100644 index 00000000000..ce0476b07eb --- /dev/null +++ b/src/librustc_codegen_llvm/debuginfo/doc.rs @@ -0,0 +1,189 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! # Debug Info Module +//! +//! This module serves the purpose of generating debug symbols. We use LLVM's +//! [source level debugging](http://!llvm.org/docs/SourceLevelDebugging.html) +//! features for generating the debug information. The general principle is +//! this: +//! +//! Given the right metadata in the LLVM IR, the LLVM code generator is able to +//! create DWARF debug symbols for the given code. The +//! [metadata](http://!llvm.org/docs/LangRef.html#metadata-type) is structured +//! much like DWARF *debugging information entries* (DIE), representing type +//! information such as datatype layout, function signatures, block layout, +//! variable location and scope information, etc. It is the purpose of this +//! module to generate correct metadata and insert it into the LLVM IR. +//! +//! As the exact format of metadata trees may change between different LLVM +//! versions, we now use LLVM +//! [DIBuilder](http://!llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html) +//! to create metadata where possible. This will hopefully ease the adaption of +//! this module to future LLVM versions. +//! +//! The public API of the module is a set of functions that will insert the +//! correct metadata into the LLVM IR when called with the right parameters. +//! The module is thus driven from an outside client with functions like +//! `debuginfo::create_local_var_metadata(bx: block, local: &ast::local)`. +//! +//! Internally the module will try to reuse already created metadata by +//! utilizing a cache. The way to get a shared metadata node when needed is +//! thus to just call the corresponding function in this module: +//! +//! let file_metadata = file_metadata(crate_context, path); +//! +//! The function will take care of probing the cache for an existing node for +//! that exact file path. +//! +//! All private state used by the module is stored within either the +//! CrateDebugContext struct (owned by the CodegenCx) or the +//! FunctionDebugContext (owned by the FunctionCx). +//! +//! This file consists of three conceptual sections: +//! 1. The public interface of the module +//! 2. Module-internal metadata creation functions +//! 3. Minor utility functions +//! +//! +//! ## Recursive Types +//! +//! Some kinds of types, such as structs and enums can be recursive. That means +//! that the type definition of some type X refers to some other type which in +//! turn (transitively) refers to X. This introduces cycles into the type +//! referral graph. A naive algorithm doing an on-demand, depth-first traversal +//! of this graph when describing types, can get trapped in an endless loop +//! when it reaches such a cycle. +//! +//! For example, the following simple type for a singly-linked list... +//! +//! ``` +//! struct List { +//! value: i32, +//! tail: Option>, +//! } +//! ``` +//! +//! will generate the following callstack with a naive DFS algorithm: +//! +//! ``` +//! describe(t = List) +//! describe(t = i32) +//! describe(t = Option>) +//! describe(t = Box) +//! describe(t = List) // at the beginning again... +//! ... +//! ``` +//! +//! To break cycles like these, we use "forward declarations". That is, when +//! the algorithm encounters a possibly recursive type (any struct or enum), it +//! immediately creates a type description node and inserts it into the cache +//! *before* describing the members of the type. This type description is just +//! a stub (as type members are not described and added to it yet) but it +//! allows the algorithm to already refer to the type. After the stub is +//! inserted into the cache, the algorithm continues as before. If it now +//! encounters a recursive reference, it will hit the cache and does not try to +//! describe the type anew. +//! +//! This behavior is encapsulated in the 'RecursiveTypeDescription' enum, +//! which represents a kind of continuation, storing all state needed to +//! continue traversal at the type members after the type has been registered +//! with the cache. (This implementation approach might be a tad over- +//! engineered and may change in the future) +//! +//! +//! ## Source Locations and Line Information +//! +//! In addition to data type descriptions the debugging information must also +//! allow to map machine code locations back to source code locations in order +//! to be useful. This functionality is also handled in this module. The +//! following functions allow to control source mappings: +//! +//! + set_source_location() +//! + clear_source_location() +//! + start_emitting_source_locations() +//! +//! `set_source_location()` allows to set the current source location. All IR +//! instructions created after a call to this function will be linked to the +//! given source location, until another location is specified with +//! `set_source_location()` or the source location is cleared with +//! `clear_source_location()`. In the later case, subsequent IR instruction +//! will not be linked to any source location. As you can see, this is a +//! stateful API (mimicking the one in LLVM), so be careful with source +//! locations set by previous calls. It's probably best to not rely on any +//! specific state being present at a given point in code. +//! +//! One topic that deserves some extra attention is *function prologues*. At +//! the beginning of a function's machine code there are typically a few +//! instructions for loading argument values into allocas and checking if +//! there's enough stack space for the function to execute. This *prologue* is +//! not visible in the source code and LLVM puts a special PROLOGUE END marker +//! into the line table at the first non-prologue instruction of the function. +//! In order to find out where the prologue ends, LLVM looks for the first +//! instruction in the function body that is linked to a source location. So, +//! when generating prologue instructions we have to make sure that we don't +//! emit source location information until the 'real' function body begins. For +//! this reason, source location emission is disabled by default for any new +//! function being codegened and is only activated after a call to the third +//! function from the list above, `start_emitting_source_locations()`. This +//! function should be called right before regularly starting to codegen the +//! top-level block of the given function. +//! +//! There is one exception to the above rule: `llvm.dbg.declare` instruction +//! must be linked to the source location of the variable being declared. For +//! function parameters these `llvm.dbg.declare` instructions typically occur +//! in the middle of the prologue, however, they are ignored by LLVM's prologue +//! detection. The `create_argument_metadata()` and related functions take care +//! of linking the `llvm.dbg.declare` instructions to the correct source +//! locations even while source location emission is still disabled, so there +//! is no need to do anything special with source location handling here. +//! +//! ## Unique Type Identification +//! +//! In order for link-time optimization to work properly, LLVM needs a unique +//! type identifier that tells it across compilation units which types are the +//! same as others. This type identifier is created by +//! TypeMap::get_unique_type_id_of_type() using the following algorithm: +//! +//! (1) Primitive types have their name as ID +//! (2) Structs, enums and traits have a multipart identifier +//! +//! (1) The first part is the SVH (strict version hash) of the crate they +//! were originally defined in +//! +//! (2) The second part is the ast::NodeId of the definition in their +//! original crate +//! +//! (3) The final part is a concatenation of the type IDs of their concrete +//! type arguments if they are generic types. +//! +//! (3) Tuple-, pointer and function types are structurally identified, which +//! means that they are equivalent if their component types are equivalent +//! (i.e. (i32, i32) is the same regardless in which crate it is used). +//! +//! This algorithm also provides a stable ID for types that are defined in one +//! crate but instantiated from metadata within another crate. We just have to +//! take care to always map crate and node IDs back to the original crate +//! context. +//! +//! As a side-effect these unique type IDs also help to solve a problem arising +//! from lifetime parameters. Since lifetime parameters are completely omitted +//! in debuginfo, more than one `Ty` instance may map to the same debuginfo +//! type metadata, that is, some struct `Struct<'a>` may have N instantiations +//! with different concrete substitutions for `'a`, and thus there will be N +//! `Ty` instances for the type `Struct<'a>` even though it is not generic +//! otherwise. Unfortunately this means that we cannot use `ty::type_id()` as +//! cheap identifier for type metadata---we have done this in the past, but it +//! led to unnecessary metadata duplication in the best case and LLVM +//! assertions in the worst. However, the unique type ID as described above +//! *can* be used as identifier. Since it is comparatively expensive to +//! construct, though, `ty::type_id()` is still used additionally as an +//! optimization for cases where the exact same type has been seen before +//! (which is most of the time). diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs new file mode 100644 index 00000000000..0b4858c7ab0 --- /dev/null +++ b/src/librustc_codegen_llvm/debuginfo/gdb.rs @@ -0,0 +1,88 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// .debug_gdb_scripts binary section. + +use llvm; + +use common::{C_bytes, CodegenCx, C_i32}; +use builder::Builder; +use declare; +use type_::Type; +use rustc::session::config::NoDebugInfo; + +use std::ptr; +use syntax::attr; + + +/// Inserts a side-effect free instruction sequence that makes sure that the +/// .debug_gdb_scripts global is referenced, so it isn't removed by the linker. +pub fn insert_reference_to_gdb_debug_scripts_section_global(bx: &Builder) { + if needs_gdb_debug_scripts_section(bx.cx) { + let gdb_debug_scripts_section = get_or_insert_gdb_debug_scripts_section_global(bx.cx); + // Load just the first byte as that's all that's necessary to force + // LLVM to keep around the reference to the global. + let indices = [C_i32(bx.cx, 0), C_i32(bx.cx, 0)]; + let element = bx.inbounds_gep(gdb_debug_scripts_section, &indices); + let volative_load_instruction = bx.volatile_load(element); + unsafe { + llvm::LLVMSetAlignment(volative_load_instruction, 1); + } + } +} + +/// Allocates the global variable responsible for the .debug_gdb_scripts binary +/// section. +pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx) + -> llvm::ValueRef { + let c_section_var_name = "__rustc_debug_gdb_scripts_section__\0"; + let section_var_name = &c_section_var_name[..c_section_var_name.len()-1]; + + let section_var = unsafe { + llvm::LLVMGetNamedGlobal(cx.llmod, + c_section_var_name.as_ptr() as *const _) + }; + + if section_var == ptr::null_mut() { + let section_name = b".debug_gdb_scripts\0"; + let section_contents = b"\x01gdb_load_rust_pretty_printers.py\0"; + + unsafe { + let llvm_type = Type::array(&Type::i8(cx), + section_contents.len() as u64); + + let section_var = declare::define_global(cx, section_var_name, + llvm_type).unwrap_or_else(||{ + bug!("symbol `{}` is already defined", section_var_name) + }); + llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _); + llvm::LLVMSetInitializer(section_var, C_bytes(cx, section_contents)); + llvm::LLVMSetGlobalConstant(section_var, llvm::True); + llvm::LLVMSetUnnamedAddr(section_var, llvm::True); + llvm::LLVMRustSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage); + // This should make sure that the whole section is not larger than + // the string it contains. Otherwise we get a warning from GDB. + llvm::LLVMSetAlignment(section_var, 1); + section_var + } + } else { + section_var + } +} + +pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx) -> bool { + let omit_gdb_pretty_printer_section = + attr::contains_name(&cx.tcx.hir.krate_attrs(), + "omit_gdb_pretty_printer_section"); + + !omit_gdb_pretty_printer_section && + cx.sess().opts.debuginfo != NoDebugInfo && + cx.sess().target.target.options.emit_debug_gdb_scripts +} diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs new file mode 100644 index 00000000000..ee60711c11d --- /dev/null +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -0,0 +1,1773 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use self::RecursiveTypeDescription::*; +use self::MemberDescriptionFactory::*; +use self::EnumDiscriminantInfo::*; + +use super::utils::{debug_context, DIB, span_start, + get_namespace_for_item, create_DIArray, is_node_local_to_unit}; +use super::namespace::mangled_name_of_instance; +use super::type_names::compute_debuginfo_type_name; +use super::{CrateDebugContext}; +use abi; + +use llvm::{self, ValueRef}; +use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, + DICompositeType, DILexicalBlock, DIFlags}; + +use rustc::hir::CodegenFnAttrFlags; +use rustc::hir::def::CtorKind; +use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; +use rustc::ty::fold::TypeVisitor; +use rustc::ty::util::TypeIdHasher; +use rustc::ich::Fingerprint; +use rustc::ty::Instance; +use common::CodegenCx; +use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; +use rustc::ty::layout::{self, Align, LayoutOf, PrimitiveExt, Size, TyLayout}; +use rustc::session::config; +use rustc::util::nodemap::FxHashMap; +use rustc::util::common::path2cstr; + +use libc::{c_uint, c_longlong}; +use std::ffi::CString; +use std::fmt::Write; +use std::ptr; +use std::path::{Path, PathBuf}; +use syntax::ast; +use syntax::symbol::{Interner, InternedString, Symbol}; +use syntax_pos::{self, Span, FileName}; + + +// From DWARF 5. +// See http://www.dwarfstd.org/ShowIssue.php?issue=140129.1 +const DW_LANG_RUST: c_uint = 0x1c; +#[allow(non_upper_case_globals)] +const DW_ATE_boolean: c_uint = 0x02; +#[allow(non_upper_case_globals)] +const DW_ATE_float: c_uint = 0x04; +#[allow(non_upper_case_globals)] +const DW_ATE_signed: c_uint = 0x05; +#[allow(non_upper_case_globals)] +const DW_ATE_unsigned: c_uint = 0x07; +#[allow(non_upper_case_globals)] +const DW_ATE_unsigned_char: c_uint = 0x08; + +pub const UNKNOWN_LINE_NUMBER: c_uint = 0; +pub const UNKNOWN_COLUMN_NUMBER: c_uint = 0; + +// ptr::null() doesn't work :( +pub const NO_SCOPE_METADATA: DIScope = (0 as DIScope); + +#[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)] +pub struct UniqueTypeId(ast::Name); + +// The TypeMap is where the CrateDebugContext holds the type metadata nodes +// created so far. The metadata nodes are indexed by UniqueTypeId, and, for +// faster lookup, also by Ty. The TypeMap is responsible for creating +// UniqueTypeIds. +pub struct TypeMap<'tcx> { + // The UniqueTypeIds created so far + unique_id_interner: Interner, + // A map from UniqueTypeId to debuginfo metadata for that type. This is a 1:1 mapping. + unique_id_to_metadata: FxHashMap, + // A map from types to debuginfo metadata. This is a N:1 mapping. + type_to_metadata: FxHashMap, DIType>, + // A map from types to UniqueTypeId. This is a N:1 mapping. + type_to_unique_id: FxHashMap, UniqueTypeId> +} + +impl<'tcx> TypeMap<'tcx> { + pub fn new() -> TypeMap<'tcx> { + TypeMap { + unique_id_interner: Interner::new(), + type_to_metadata: FxHashMap(), + unique_id_to_metadata: FxHashMap(), + type_to_unique_id: FxHashMap(), + } + } + + // Adds a Ty to metadata mapping to the TypeMap. The method will fail if + // the mapping already exists. + fn register_type_with_metadata<'a>(&mut self, + type_: Ty<'tcx>, + metadata: DIType) { + if self.type_to_metadata.insert(type_, metadata).is_some() { + bug!("Type metadata for Ty '{}' is already in the TypeMap!", type_); + } + } + + // Adds a UniqueTypeId to metadata mapping to the TypeMap. The method will + // fail if the mapping already exists. + fn register_unique_id_with_metadata(&mut self, + unique_type_id: UniqueTypeId, + metadata: DIType) { + if self.unique_id_to_metadata.insert(unique_type_id, metadata).is_some() { + bug!("Type metadata for unique id '{}' is already in the TypeMap!", + self.get_unique_type_id_as_string(unique_type_id)); + } + } + + fn find_metadata_for_type(&self, type_: Ty<'tcx>) -> Option { + self.type_to_metadata.get(&type_).cloned() + } + + fn find_metadata_for_unique_id(&self, unique_type_id: UniqueTypeId) -> Option { + self.unique_id_to_metadata.get(&unique_type_id).cloned() + } + + // Get the string representation of a UniqueTypeId. This method will fail if + // the id is unknown. + fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> &str { + let UniqueTypeId(interner_key) = unique_type_id; + self.unique_id_interner.get(interner_key) + } + + // Get the UniqueTypeId for the given type. If the UniqueTypeId for the given + // type has been requested before, this is just a table lookup. Otherwise an + // ID will be generated and stored for later lookup. + fn get_unique_type_id_of_type<'a>(&mut self, cx: &CodegenCx<'a, 'tcx>, + type_: Ty<'tcx>) -> UniqueTypeId { + // Let's see if we already have something in the cache + match self.type_to_unique_id.get(&type_).cloned() { + Some(unique_type_id) => return unique_type_id, + None => { /* generate one */} + }; + + // The hasher we are using to generate the UniqueTypeId. We want + // something that provides more than the 64 bits of the DefaultHasher. + let mut type_id_hasher = TypeIdHasher::::new(cx.tcx); + type_id_hasher.visit_ty(type_); + let unique_type_id = type_id_hasher.finish().to_hex(); + + let key = self.unique_id_interner.intern(&unique_type_id); + self.type_to_unique_id.insert(type_, UniqueTypeId(key)); + + return UniqueTypeId(key); + } + + // Get the UniqueTypeId for an enum variant. Enum variants are not really + // types of their own, so they need special handling. We still need a + // UniqueTypeId for them, since to debuginfo they *are* real types. + fn get_unique_type_id_of_enum_variant<'a>(&mut self, + cx: &CodegenCx<'a, 'tcx>, + enum_type: Ty<'tcx>, + variant_name: &str) + -> UniqueTypeId { + let enum_type_id = self.get_unique_type_id_of_type(cx, enum_type); + let enum_variant_type_id = format!("{}::{}", + self.get_unique_type_id_as_string(enum_type_id), + variant_name); + let interner_key = self.unique_id_interner.intern(&enum_variant_type_id); + UniqueTypeId(interner_key) + } +} + +// A description of some recursive type. It can either be already finished (as +// with FinalMetadata) or it is not yet finished, but contains all information +// needed to generate the missing parts of the description. See the +// documentation section on Recursive Types at the top of this file for more +// information. +enum RecursiveTypeDescription<'tcx> { + UnfinishedMetadata { + unfinished_type: Ty<'tcx>, + unique_type_id: UniqueTypeId, + metadata_stub: DICompositeType, + member_description_factory: MemberDescriptionFactory<'tcx>, + }, + FinalMetadata(DICompositeType) +} + +fn create_and_register_recursive_type_forward_declaration<'a, 'tcx>( + cx: &CodegenCx<'a, 'tcx>, + unfinished_type: Ty<'tcx>, + unique_type_id: UniqueTypeId, + metadata_stub: DICompositeType, + member_description_factory: MemberDescriptionFactory<'tcx>) + -> RecursiveTypeDescription<'tcx> { + + // Insert the stub into the TypeMap in order to allow for recursive references + let mut type_map = debug_context(cx).type_map.borrow_mut(); + type_map.register_unique_id_with_metadata(unique_type_id, metadata_stub); + type_map.register_type_with_metadata(unfinished_type, metadata_stub); + + UnfinishedMetadata { + unfinished_type, + unique_type_id, + metadata_stub, + member_description_factory, + } +} + +impl<'tcx> RecursiveTypeDescription<'tcx> { + // Finishes up the description of the type in question (mostly by providing + // descriptions of the fields of the given type) and returns the final type + // metadata. + fn finalize<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> MetadataCreationResult { + match *self { + FinalMetadata(metadata) => MetadataCreationResult::new(metadata, false), + UnfinishedMetadata { + unfinished_type, + unique_type_id, + metadata_stub, + ref member_description_factory, + } => { + // Make sure that we have a forward declaration of the type in + // the TypeMap so that recursive references are possible. This + // will always be the case if the RecursiveTypeDescription has + // been properly created through the + // create_and_register_recursive_type_forward_declaration() + // function. + { + let type_map = debug_context(cx).type_map.borrow(); + if type_map.find_metadata_for_unique_id(unique_type_id).is_none() || + type_map.find_metadata_for_type(unfinished_type).is_none() { + bug!("Forward declaration of potentially recursive type \ + '{:?}' was not found in TypeMap!", + unfinished_type); + } + } + + // ... then create the member descriptions ... + let member_descriptions = + member_description_factory.create_member_descriptions(cx); + + // ... and attach them to the stub to complete it. + set_members_of_composite_type(cx, + metadata_stub, + &member_descriptions[..]); + return MetadataCreationResult::new(metadata_stub, true); + } + } + } +} + +// Returns from the enclosing function if the type metadata with the given +// unique id can be found in the type map +macro_rules! return_if_metadata_created_in_meantime { + ($cx: expr, $unique_type_id: expr) => ( + match debug_context($cx).type_map + .borrow() + .find_metadata_for_unique_id($unique_type_id) { + Some(metadata) => return MetadataCreationResult::new(metadata, true), + None => { /* proceed normally */ } + } + ) +} + +fn fixed_vec_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + unique_type_id: UniqueTypeId, + array_or_slice_type: Ty<'tcx>, + element_type: Ty<'tcx>, + span: Span) + -> MetadataCreationResult { + let element_type_metadata = type_metadata(cx, element_type, span); + + return_if_metadata_created_in_meantime!(cx, unique_type_id); + + let (size, align) = cx.size_and_align_of(array_or_slice_type); + + let upper_bound = match array_or_slice_type.sty { + ty::TyArray(_, len) => { + len.unwrap_usize(cx.tcx) as c_longlong + } + _ => -1 + }; + + let subrange = unsafe { + llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) + }; + + let subscripts = create_DIArray(DIB(cx), &[subrange]); + let metadata = unsafe { + llvm::LLVMRustDIBuilderCreateArrayType( + DIB(cx), + size.bits(), + align.abi_bits() as u32, + element_type_metadata, + subscripts) + }; + + return MetadataCreationResult::new(metadata, false); +} + +fn vec_slice_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + slice_ptr_type: Ty<'tcx>, + element_type: Ty<'tcx>, + unique_type_id: UniqueTypeId, + span: Span) + -> MetadataCreationResult { + let data_ptr_type = cx.tcx.mk_imm_ptr(element_type); + + let data_ptr_metadata = type_metadata(cx, data_ptr_type, span); + + return_if_metadata_created_in_meantime!(cx, unique_type_id); + + let slice_type_name = compute_debuginfo_type_name(cx, slice_ptr_type, true); + + let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type); + let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize); + + let member_descriptions = [ + MemberDescription { + name: "data_ptr".to_string(), + type_metadata: data_ptr_metadata, + offset: Size::from_bytes(0), + size: pointer_size, + align: pointer_align, + flags: DIFlags::FlagZero, + }, + MemberDescription { + name: "length".to_string(), + type_metadata: type_metadata(cx, cx.tcx.types.usize, span), + offset: pointer_size, + size: usize_size, + align: usize_align, + flags: DIFlags::FlagZero, + }, + ]; + + let file_metadata = unknown_file_metadata(cx); + + let metadata = composite_type_metadata(cx, + slice_ptr_type, + &slice_type_name[..], + unique_type_id, + &member_descriptions, + NO_SCOPE_METADATA, + file_metadata, + span); + MetadataCreationResult::new(metadata, false) +} + +fn subroutine_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + unique_type_id: UniqueTypeId, + signature: ty::PolyFnSig<'tcx>, + span: Span) + -> MetadataCreationResult +{ + let signature = cx.tcx.normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &signature, + ); + + let mut signature_metadata: Vec = Vec::with_capacity(signature.inputs().len() + 1); + + // return type + signature_metadata.push(match signature.output().sty { + ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(), + _ => type_metadata(cx, signature.output(), span) + }); + + // regular arguments + for &argument_type in signature.inputs() { + signature_metadata.push(type_metadata(cx, argument_type, span)); + } + + return_if_metadata_created_in_meantime!(cx, unique_type_id); + + return MetadataCreationResult::new( + unsafe { + llvm::LLVMRustDIBuilderCreateSubroutineType( + DIB(cx), + unknown_file_metadata(cx), + create_DIArray(DIB(cx), &signature_metadata[..])) + }, + false); +} + +// FIXME(1563) This is all a bit of a hack because 'trait pointer' is an ill- +// defined concept. For the case of an actual trait pointer (i.e., Box, +// &Trait), trait_object_type should be the whole thing (e.g, Box) and +// trait_type should be the actual trait (e.g., Trait). Where the trait is part +// of a DST struct, there is no trait_object_type and the results of this +// function will be a little bit weird. +fn trait_pointer_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + trait_type: Ty<'tcx>, + trait_object_type: Option>, + unique_type_id: UniqueTypeId) + -> DIType { + // The implementation provided here is a stub. It makes sure that the trait + // type is assigned the correct name, size, namespace, and source location. + // But it does not describe the trait's methods. + + let containing_scope = match trait_type.sty { + ty::TyDynamic(ref data, ..) => if let Some(principal) = data.principal() { + let def_id = principal.def_id(); + get_namespace_for_item(cx, def_id) + } else { + NO_SCOPE_METADATA + }, + _ => { + bug!("debuginfo: Unexpected trait-object type in \ + trait_pointer_metadata(): {:?}", + trait_type); + } + }; + + let trait_object_type = trait_object_type.unwrap_or(trait_type); + let trait_type_name = + compute_debuginfo_type_name(cx, trait_object_type, false); + + let file_metadata = unknown_file_metadata(cx); + + let layout = cx.layout_of(cx.tcx.mk_mut_ptr(trait_type)); + + assert_eq!(abi::FAT_PTR_ADDR, 0); + assert_eq!(abi::FAT_PTR_EXTRA, 1); + + let data_ptr_field = layout.field(cx, 0); + let vtable_field = layout.field(cx, 1); + let member_descriptions = [ + MemberDescription { + name: "pointer".to_string(), + type_metadata: type_metadata(cx, + cx.tcx.mk_mut_ptr(cx.tcx.types.u8), + syntax_pos::DUMMY_SP), + offset: layout.fields.offset(0), + size: data_ptr_field.size, + align: data_ptr_field.align, + flags: DIFlags::FlagArtificial, + }, + MemberDescription { + name: "vtable".to_string(), + type_metadata: type_metadata(cx, vtable_field.ty, syntax_pos::DUMMY_SP), + offset: layout.fields.offset(1), + size: vtable_field.size, + align: vtable_field.align, + flags: DIFlags::FlagArtificial, + }, + ]; + + composite_type_metadata(cx, + trait_object_type, + &trait_type_name[..], + unique_type_id, + &member_descriptions, + containing_scope, + file_metadata, + syntax_pos::DUMMY_SP) +} + +pub fn type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + t: Ty<'tcx>, + usage_site_span: Span) + -> DIType { + // Get the unique type id of this type. + let unique_type_id = { + let mut type_map = debug_context(cx).type_map.borrow_mut(); + // First, try to find the type in TypeMap. If we have seen it before, we + // can exit early here. + match type_map.find_metadata_for_type(t) { + Some(metadata) => { + return metadata; + }, + None => { + // The Ty is not in the TypeMap but maybe we have already seen + // an equivalent type (e.g. only differing in region arguments). + // In order to find out, generate the unique type id and look + // that up. + let unique_type_id = type_map.get_unique_type_id_of_type(cx, t); + match type_map.find_metadata_for_unique_id(unique_type_id) { + Some(metadata) => { + // There is already an equivalent type in the TypeMap. + // Register this Ty as an alias in the cache and + // return the cached metadata. + type_map.register_type_with_metadata(t, metadata); + return metadata; + }, + None => { + // There really is no type metadata for this type, so + // proceed by creating it. + unique_type_id + } + } + } + } + }; + + debug!("type_metadata: {:?}", t); + + let ptr_metadata = |ty: Ty<'tcx>| { + match ty.sty { + ty::TySlice(typ) => { + Ok(vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span)) + } + ty::TyStr => { + Ok(vec_slice_metadata(cx, t, cx.tcx.types.u8, unique_type_id, usage_site_span)) + } + ty::TyDynamic(..) => { + Ok(MetadataCreationResult::new( + trait_pointer_metadata(cx, ty, Some(t), unique_type_id), + false)) + } + _ => { + let pointee_metadata = type_metadata(cx, ty, usage_site_span); + + match debug_context(cx).type_map + .borrow() + .find_metadata_for_unique_id(unique_type_id) { + Some(metadata) => return Err(metadata), + None => { /* proceed normally */ } + }; + + Ok(MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), + false)) + } + } + }; + + let MetadataCreationResult { metadata, already_stored_in_typemap } = match t.sty { + ty::TyNever | + ty::TyBool | + ty::TyChar | + ty::TyInt(_) | + ty::TyUint(_) | + ty::TyFloat(_) => { + MetadataCreationResult::new(basic_type_metadata(cx, t), false) + } + ty::TyTuple(ref elements) if elements.is_empty() => { + MetadataCreationResult::new(basic_type_metadata(cx, t), false) + } + ty::TyArray(typ, _) | + ty::TySlice(typ) => { + fixed_vec_metadata(cx, unique_type_id, t, typ, usage_site_span) + } + ty::TyStr => { + fixed_vec_metadata(cx, unique_type_id, t, cx.tcx.types.i8, usage_site_span) + } + ty::TyDynamic(..) => { + MetadataCreationResult::new( + trait_pointer_metadata(cx, t, None, unique_type_id), + false) + } + ty::TyForeign(..) => { + MetadataCreationResult::new( + foreign_type_metadata(cx, t, unique_type_id), + false) + } + ty::TyRawPtr(ty::TypeAndMut{ty, ..}) | + ty::TyRef(_, ty, _) => { + match ptr_metadata(ty) { + Ok(res) => res, + Err(metadata) => return metadata, + } + } + ty::TyAdt(def, _) if def.is_box() => { + match ptr_metadata(t.boxed_ty()) { + Ok(res) => res, + Err(metadata) => return metadata, + } + } + ty::TyFnDef(..) | ty::TyFnPtr(_) => { + let fn_metadata = subroutine_type_metadata(cx, + unique_type_id, + t.fn_sig(cx.tcx), + usage_site_span).metadata; + match debug_context(cx).type_map + .borrow() + .find_metadata_for_unique_id(unique_type_id) { + Some(metadata) => return metadata, + None => { /* proceed normally */ } + }; + + // This is actually a function pointer, so wrap it in pointer DI + MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false) + + } + ty::TyClosure(def_id, substs) => { + let upvar_tys : Vec<_> = substs.upvar_tys(def_id, cx.tcx).collect(); + prepare_tuple_metadata(cx, + t, + &upvar_tys, + unique_type_id, + usage_site_span).finalize(cx) + } + ty::TyGenerator(def_id, substs, _) => { + let upvar_tys : Vec<_> = substs.field_tys(def_id, cx.tcx).map(|t| { + cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t) + }).collect(); + prepare_tuple_metadata(cx, + t, + &upvar_tys, + unique_type_id, + usage_site_span).finalize(cx) + } + ty::TyAdt(def, ..) => match def.adt_kind() { + AdtKind::Struct => { + prepare_struct_metadata(cx, + t, + unique_type_id, + usage_site_span).finalize(cx) + } + AdtKind::Union => { + prepare_union_metadata(cx, + t, + unique_type_id, + usage_site_span).finalize(cx) + } + AdtKind::Enum => { + prepare_enum_metadata(cx, + t, + def.did, + unique_type_id, + usage_site_span).finalize(cx) + } + }, + ty::TyTuple(ref elements) => { + prepare_tuple_metadata(cx, + t, + &elements[..], + unique_type_id, + usage_site_span).finalize(cx) + } + _ => { + bug!("debuginfo: unexpected type in type_metadata: {:?}", t) + } + }; + + { + let mut type_map = debug_context(cx).type_map.borrow_mut(); + + if already_stored_in_typemap { + // Also make sure that we already have a TypeMap entry for the unique type id. + let metadata_for_uid = match type_map.find_metadata_for_unique_id(unique_type_id) { + Some(metadata) => metadata, + None => { + span_bug!(usage_site_span, + "Expected type metadata for unique \ + type id '{}' to already be in \ + the debuginfo::TypeMap but it \ + was not. (Ty = {})", + type_map.get_unique_type_id_as_string(unique_type_id), + t); + } + }; + + match type_map.find_metadata_for_type(t) { + Some(metadata) => { + if metadata != metadata_for_uid { + span_bug!(usage_site_span, + "Mismatch between Ty and \ + UniqueTypeId maps in \ + debuginfo::TypeMap. \ + UniqueTypeId={}, Ty={}", + type_map.get_unique_type_id_as_string(unique_type_id), + t); + } + } + None => { + type_map.register_type_with_metadata(t, metadata); + } + } + } else { + type_map.register_type_with_metadata(t, metadata); + type_map.register_unique_id_with_metadata(unique_type_id, metadata); + } + } + + metadata +} + +pub fn file_metadata(cx: &CodegenCx, + file_name: &FileName, + defining_crate: CrateNum) -> DIFile { + debug!("file_metadata: file_name: {}, defining_crate: {}", + file_name, + defining_crate); + + let directory = if defining_crate == LOCAL_CRATE { + &cx.sess().working_dir.0 + } else { + // If the path comes from an upstream crate we assume it has been made + // independent of the compiler's working directory one way or another. + Path::new("") + }; + + file_metadata_raw(cx, &file_name.to_string(), &directory.to_string_lossy()) +} + +pub fn unknown_file_metadata(cx: &CodegenCx) -> DIFile { + file_metadata_raw(cx, "", "") +} + +fn file_metadata_raw(cx: &CodegenCx, + file_name: &str, + directory: &str) + -> DIFile { + let key = (Symbol::intern(file_name), Symbol::intern(directory)); + + if let Some(file_metadata) = debug_context(cx).created_files.borrow().get(&key) { + return *file_metadata; + } + + debug!("file_metadata: file_name: {}, directory: {}", file_name, directory); + + let file_name = CString::new(file_name).unwrap(); + let directory = CString::new(directory).unwrap(); + + let file_metadata = unsafe { + llvm::LLVMRustDIBuilderCreateFile(DIB(cx), + file_name.as_ptr(), + directory.as_ptr()) + }; + + let mut created_files = debug_context(cx).created_files.borrow_mut(); + created_files.insert(key, file_metadata); + file_metadata +} + +fn basic_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + t: Ty<'tcx>) -> DIType { + + debug!("basic_type_metadata: {:?}", t); + + let (name, encoding) = match t.sty { + ty::TyNever => ("!", DW_ATE_unsigned), + ty::TyTuple(ref elements) if elements.is_empty() => + ("()", DW_ATE_unsigned), + ty::TyBool => ("bool", DW_ATE_boolean), + ty::TyChar => ("char", DW_ATE_unsigned_char), + ty::TyInt(int_ty) => { + (int_ty.ty_to_string(), DW_ATE_signed) + }, + ty::TyUint(uint_ty) => { + (uint_ty.ty_to_string(), DW_ATE_unsigned) + }, + ty::TyFloat(float_ty) => { + (float_ty.ty_to_string(), DW_ATE_float) + }, + _ => bug!("debuginfo::basic_type_metadata - t is invalid type") + }; + + let (size, align) = cx.size_and_align_of(t); + let name = CString::new(name).unwrap(); + let ty_metadata = unsafe { + llvm::LLVMRustDIBuilderCreateBasicType( + DIB(cx), + name.as_ptr(), + size.bits(), + align.abi_bits() as u32, + encoding) + }; + + return ty_metadata; +} + +fn foreign_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + t: Ty<'tcx>, + unique_type_id: UniqueTypeId) -> DIType { + debug!("foreign_type_metadata: {:?}", t); + + let name = compute_debuginfo_type_name(cx, t, false); + create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA) +} + +fn pointer_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + pointer_type: Ty<'tcx>, + pointee_type_metadata: DIType) + -> DIType { + let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type); + let name = compute_debuginfo_type_name(cx, pointer_type, false); + let name = CString::new(name).unwrap(); + unsafe { + llvm::LLVMRustDIBuilderCreatePointerType( + DIB(cx), + pointee_type_metadata, + pointer_size.bits(), + pointer_align.abi_bits() as u32, + name.as_ptr()) + } +} + +pub fn compile_unit_metadata(tcx: TyCtxt, + codegen_unit_name: &str, + debug_context: &CrateDebugContext) + -> DIDescriptor { + let mut name_in_debuginfo = match tcx.sess.local_crate_source_file { + Some(ref path) => path.clone(), + None => PathBuf::from(&*tcx.crate_name(LOCAL_CRATE).as_str()), + }; + + // The OSX linker has an idiosyncrasy where it will ignore some debuginfo + // if multiple object files with the same DW_AT_name are linked together. + // As a workaround we generate unique names for each object file. Those do + // not correspond to an actual source file but that should be harmless. + if tcx.sess.target.target.options.is_like_osx { + name_in_debuginfo.push("@"); + name_in_debuginfo.push(codegen_unit_name); + } + + debug!("compile_unit_metadata: {:?}", name_in_debuginfo); + // FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice. + let producer = format!("clang LLVM (rustc version {})", + (option_env!("CFG_VERSION")).expect("CFG_VERSION")); + + let name_in_debuginfo = name_in_debuginfo.to_string_lossy().into_owned(); + let name_in_debuginfo = CString::new(name_in_debuginfo).unwrap(); + let work_dir = CString::new(&tcx.sess.working_dir.0.to_string_lossy()[..]).unwrap(); + let producer = CString::new(producer).unwrap(); + let flags = "\0"; + let split_name = "\0"; + + unsafe { + let file_metadata = llvm::LLVMRustDIBuilderCreateFile( + debug_context.builder, name_in_debuginfo.as_ptr(), work_dir.as_ptr()); + + let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit( + debug_context.builder, + DW_LANG_RUST, + file_metadata, + producer.as_ptr(), + tcx.sess.opts.optimize != config::OptLevel::No, + flags.as_ptr() as *const _, + 0, + split_name.as_ptr() as *const _); + + if tcx.sess.opts.debugging_opts.profile { + let cu_desc_metadata = llvm::LLVMRustMetadataAsValue(debug_context.llcontext, + unit_metadata); + + let gcov_cu_info = [ + path_to_mdstring(debug_context.llcontext, + &tcx.output_filenames(LOCAL_CRATE).with_extension("gcno")), + path_to_mdstring(debug_context.llcontext, + &tcx.output_filenames(LOCAL_CRATE).with_extension("gcda")), + cu_desc_metadata, + ]; + let gcov_metadata = llvm::LLVMMDNodeInContext(debug_context.llcontext, + gcov_cu_info.as_ptr(), + gcov_cu_info.len() as c_uint); + + let llvm_gcov_ident = CString::new("llvm.gcov").unwrap(); + llvm::LLVMAddNamedMetadataOperand(debug_context.llmod, + llvm_gcov_ident.as_ptr(), + gcov_metadata); + } + + return unit_metadata; + }; + + fn path_to_mdstring(llcx: llvm::ContextRef, path: &Path) -> llvm::ValueRef { + let path_str = path2cstr(path); + unsafe { + llvm::LLVMMDStringInContext(llcx, + path_str.as_ptr(), + path_str.as_bytes().len() as c_uint) + } + } +} + +struct MetadataCreationResult { + metadata: DIType, + already_stored_in_typemap: bool +} + +impl MetadataCreationResult { + fn new(metadata: DIType, already_stored_in_typemap: bool) -> MetadataCreationResult { + MetadataCreationResult { + metadata, + already_stored_in_typemap, + } + } +} + +// Description of a type member, which can either be a regular field (as in +// structs or tuples) or an enum variant. +#[derive(Debug)] +struct MemberDescription { + name: String, + type_metadata: DIType, + offset: Size, + size: Size, + align: Align, + flags: DIFlags, +} + +// A factory for MemberDescriptions. It produces a list of member descriptions +// for some record-like type. MemberDescriptionFactories are used to defer the +// creation of type member descriptions in order to break cycles arising from +// recursive type definitions. +enum MemberDescriptionFactory<'tcx> { + StructMDF(StructMemberDescriptionFactory<'tcx>), + TupleMDF(TupleMemberDescriptionFactory<'tcx>), + EnumMDF(EnumMemberDescriptionFactory<'tcx>), + UnionMDF(UnionMemberDescriptionFactory<'tcx>), + VariantMDF(VariantMemberDescriptionFactory<'tcx>) +} + +impl<'tcx> MemberDescriptionFactory<'tcx> { + fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>) + -> Vec { + match *self { + StructMDF(ref this) => { + this.create_member_descriptions(cx) + } + TupleMDF(ref this) => { + this.create_member_descriptions(cx) + } + EnumMDF(ref this) => { + this.create_member_descriptions(cx) + } + UnionMDF(ref this) => { + this.create_member_descriptions(cx) + } + VariantMDF(ref this) => { + this.create_member_descriptions(cx) + } + } + } +} + +//=----------------------------------------------------------------------------- +// Structs +//=----------------------------------------------------------------------------- + +// Creates MemberDescriptions for the fields of a struct +struct StructMemberDescriptionFactory<'tcx> { + ty: Ty<'tcx>, + variant: &'tcx ty::VariantDef, + span: Span, +} + +impl<'tcx> StructMemberDescriptionFactory<'tcx> { + fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>) + -> Vec { + let layout = cx.layout_of(self.ty); + self.variant.fields.iter().enumerate().map(|(i, f)| { + let name = if self.variant.ctor_kind == CtorKind::Fn { + format!("__{}", i) + } else { + f.name.to_string() + }; + let field = layout.field(cx, i); + let (size, align) = field.size_and_align(); + MemberDescription { + name, + type_metadata: type_metadata(cx, field.ty, self.span), + offset: layout.fields.offset(i), + size, + align, + flags: DIFlags::FlagZero, + } + }).collect() + } +} + + +fn prepare_struct_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + struct_type: Ty<'tcx>, + unique_type_id: UniqueTypeId, + span: Span) + -> RecursiveTypeDescription<'tcx> { + let struct_name = compute_debuginfo_type_name(cx, struct_type, false); + + let (struct_def_id, variant) = match struct_type.sty { + ty::TyAdt(def, _) => (def.did, def.non_enum_variant()), + _ => bug!("prepare_struct_metadata on a non-ADT") + }; + + let containing_scope = get_namespace_for_item(cx, struct_def_id); + + let struct_metadata_stub = create_struct_stub(cx, + struct_type, + &struct_name, + unique_type_id, + containing_scope); + + create_and_register_recursive_type_forward_declaration( + cx, + struct_type, + unique_type_id, + struct_metadata_stub, + StructMDF(StructMemberDescriptionFactory { + ty: struct_type, + variant, + span, + }) + ) +} + +//=----------------------------------------------------------------------------- +// Tuples +//=----------------------------------------------------------------------------- + +// Creates MemberDescriptions for the fields of a tuple +struct TupleMemberDescriptionFactory<'tcx> { + ty: Ty<'tcx>, + component_types: Vec>, + span: Span, +} + +impl<'tcx> TupleMemberDescriptionFactory<'tcx> { + fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>) + -> Vec { + let layout = cx.layout_of(self.ty); + self.component_types.iter().enumerate().map(|(i, &component_type)| { + let (size, align) = cx.size_and_align_of(component_type); + MemberDescription { + name: format!("__{}", i), + type_metadata: type_metadata(cx, component_type, self.span), + offset: layout.fields.offset(i), + size, + align, + flags: DIFlags::FlagZero, + } + }).collect() + } +} + +fn prepare_tuple_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + tuple_type: Ty<'tcx>, + component_types: &[Ty<'tcx>], + unique_type_id: UniqueTypeId, + span: Span) + -> RecursiveTypeDescription<'tcx> { + let tuple_name = compute_debuginfo_type_name(cx, tuple_type, false); + + create_and_register_recursive_type_forward_declaration( + cx, + tuple_type, + unique_type_id, + create_struct_stub(cx, + tuple_type, + &tuple_name[..], + unique_type_id, + NO_SCOPE_METADATA), + TupleMDF(TupleMemberDescriptionFactory { + ty: tuple_type, + component_types: component_types.to_vec(), + span, + }) + ) +} + +//=----------------------------------------------------------------------------- +// Unions +//=----------------------------------------------------------------------------- + +struct UnionMemberDescriptionFactory<'tcx> { + layout: TyLayout<'tcx>, + variant: &'tcx ty::VariantDef, + span: Span, +} + +impl<'tcx> UnionMemberDescriptionFactory<'tcx> { + fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>) + -> Vec { + self.variant.fields.iter().enumerate().map(|(i, f)| { + let field = self.layout.field(cx, i); + let (size, align) = field.size_and_align(); + MemberDescription { + name: f.name.to_string(), + type_metadata: type_metadata(cx, field.ty, self.span), + offset: Size::from_bytes(0), + size, + align, + flags: DIFlags::FlagZero, + } + }).collect() + } +} + +fn prepare_union_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + union_type: Ty<'tcx>, + unique_type_id: UniqueTypeId, + span: Span) + -> RecursiveTypeDescription<'tcx> { + let union_name = compute_debuginfo_type_name(cx, union_type, false); + + let (union_def_id, variant) = match union_type.sty { + ty::TyAdt(def, _) => (def.did, def.non_enum_variant()), + _ => bug!("prepare_union_metadata on a non-ADT") + }; + + let containing_scope = get_namespace_for_item(cx, union_def_id); + + let union_metadata_stub = create_union_stub(cx, + union_type, + &union_name, + unique_type_id, + containing_scope); + + create_and_register_recursive_type_forward_declaration( + cx, + union_type, + unique_type_id, + union_metadata_stub, + UnionMDF(UnionMemberDescriptionFactory { + layout: cx.layout_of(union_type), + variant, + span, + }) + ) +} + +//=----------------------------------------------------------------------------- +// Enums +//=----------------------------------------------------------------------------- + +// Describes the members of an enum value: An enum is described as a union of +// structs in DWARF. This MemberDescriptionFactory provides the description for +// the members of this union; so for every variant of the given enum, this +// factory will produce one MemberDescription (all with no name and a fixed +// offset of zero bytes). +struct EnumMemberDescriptionFactory<'tcx> { + enum_type: Ty<'tcx>, + layout: TyLayout<'tcx>, + discriminant_type_metadata: Option, + containing_scope: DIScope, + span: Span, +} + +impl<'tcx> EnumMemberDescriptionFactory<'tcx> { + fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>) + -> Vec { + let adt = &self.enum_type.ty_adt_def().unwrap(); + match self.layout.variants { + layout::Variants::Single { .. } if adt.variants.is_empty() => vec![], + layout::Variants::Single { index } => { + let (variant_type_metadata, member_description_factory) = + describe_enum_variant(cx, + self.layout, + &adt.variants[index], + NoDiscriminant, + self.containing_scope, + self.span); + + let member_descriptions = + member_description_factory.create_member_descriptions(cx); + + set_members_of_composite_type(cx, + variant_type_metadata, + &member_descriptions[..]); + vec![ + MemberDescription { + name: "".to_string(), + type_metadata: variant_type_metadata, + offset: Size::from_bytes(0), + size: self.layout.size, + align: self.layout.align, + flags: DIFlags::FlagZero + } + ] + } + layout::Variants::Tagged { ref variants, .. } => { + let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata + .expect("")); + (0..variants.len()).map(|i| { + let variant = self.layout.for_variant(cx, i); + let (variant_type_metadata, member_desc_factory) = + describe_enum_variant(cx, + variant, + &adt.variants[i], + discriminant_info, + self.containing_scope, + self.span); + + let member_descriptions = member_desc_factory + .create_member_descriptions(cx); + + set_members_of_composite_type(cx, + variant_type_metadata, + &member_descriptions); + MemberDescription { + name: "".to_string(), + type_metadata: variant_type_metadata, + offset: Size::from_bytes(0), + size: variant.size, + align: variant.align, + flags: DIFlags::FlagZero + } + }).collect() + } + layout::Variants::NicheFilling { dataful_variant, ref niche_variants, .. } => { + let variant = self.layout.for_variant(cx, dataful_variant); + // Create a description of the non-null variant + let (variant_type_metadata, member_description_factory) = + describe_enum_variant(cx, + variant, + &adt.variants[dataful_variant], + OptimizedDiscriminant, + self.containing_scope, + self.span); + + let variant_member_descriptions = + member_description_factory.create_member_descriptions(cx); + + set_members_of_composite_type(cx, + variant_type_metadata, + &variant_member_descriptions[..]); + + // Encode the information about the null variant in the union + // member's name. + let mut name = String::from("RUST$ENCODED$ENUM$"); + // HACK(eddyb) the debuggers should just handle offset+size + // of discriminant instead of us having to recover its path. + // Right now it's not even going to work for `niche_start > 0`, + // and for multiple niche variants it only supports the first. + fn compute_field_path<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + name: &mut String, + layout: TyLayout<'tcx>, + offset: Size, + size: Size) { + for i in 0..layout.fields.count() { + let field_offset = layout.fields.offset(i); + if field_offset > offset { + continue; + } + let inner_offset = offset - field_offset; + let field = layout.field(cx, i); + if inner_offset + size <= field.size { + write!(name, "{}$", i).unwrap(); + compute_field_path(cx, name, field, inner_offset, size); + } + } + } + compute_field_path(cx, &mut name, + self.layout, + self.layout.fields.offset(0), + self.layout.field(cx, 0).size); + name.push_str(&adt.variants[*niche_variants.start()].name.as_str()); + + // Create the (singleton) list of descriptions of union members. + vec![ + MemberDescription { + name, + type_metadata: variant_type_metadata, + offset: Size::from_bytes(0), + size: variant.size, + align: variant.align, + flags: DIFlags::FlagZero + } + ] + } + } + } +} + +// Creates MemberDescriptions for the fields of a single enum variant. +struct VariantMemberDescriptionFactory<'tcx> { + // Cloned from the layout::Struct describing the variant. + offsets: Vec, + args: Vec<(String, Ty<'tcx>)>, + discriminant_type_metadata: Option, + span: Span, +} + +impl<'tcx> VariantMemberDescriptionFactory<'tcx> { + fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>) + -> Vec { + self.args.iter().enumerate().map(|(i, &(ref name, ty))| { + let (size, align) = cx.size_and_align_of(ty); + MemberDescription { + name: name.to_string(), + type_metadata: match self.discriminant_type_metadata { + Some(metadata) if i == 0 => metadata, + _ => type_metadata(cx, ty, self.span) + }, + offset: self.offsets[i], + size, + align, + flags: DIFlags::FlagZero + } + }).collect() + } +} + +#[derive(Copy, Clone)] +enum EnumDiscriminantInfo { + RegularDiscriminant(DIType), + OptimizedDiscriminant, + NoDiscriminant +} + +// Returns a tuple of (1) type_metadata_stub of the variant, (2) the llvm_type +// of the variant, and (3) a MemberDescriptionFactory for producing the +// descriptions of the fields of the variant. This is a rudimentary version of a +// full RecursiveTypeDescription. +fn describe_enum_variant<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + layout: layout::TyLayout<'tcx>, + variant: &'tcx ty::VariantDef, + discriminant_info: EnumDiscriminantInfo, + containing_scope: DIScope, + span: Span) + -> (DICompositeType, MemberDescriptionFactory<'tcx>) { + let variant_name = variant.name.as_str(); + let unique_type_id = debug_context(cx).type_map + .borrow_mut() + .get_unique_type_id_of_enum_variant( + cx, + layout.ty, + &variant_name); + + let metadata_stub = create_struct_stub(cx, + layout.ty, + &variant_name, + unique_type_id, + containing_scope); + + // If this is not a univariant enum, there is also the discriminant field. + let (discr_offset, discr_arg) = match discriminant_info { + RegularDiscriminant(_) => { + let enum_layout = cx.layout_of(layout.ty); + (Some(enum_layout.fields.offset(0)), + Some(("RUST$ENUM$DISR".to_string(), enum_layout.field(cx, 0).ty))) + } + _ => (None, None), + }; + let offsets = discr_offset.into_iter().chain((0..layout.fields.count()).map(|i| { + layout.fields.offset(i) + })).collect(); + + // Build an array of (field name, field type) pairs to be captured in the factory closure. + let args = discr_arg.into_iter().chain((0..layout.fields.count()).map(|i| { + let name = if variant.ctor_kind == CtorKind::Fn { + format!("__{}", i) + } else { + variant.fields[i].name.to_string() + }; + (name, layout.field(cx, i).ty) + })).collect(); + + let member_description_factory = + VariantMDF(VariantMemberDescriptionFactory { + offsets, + args, + discriminant_type_metadata: match discriminant_info { + RegularDiscriminant(discriminant_type_metadata) => { + Some(discriminant_type_metadata) + } + _ => None + }, + span, + }); + + (metadata_stub, member_description_factory) +} + +fn prepare_enum_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + enum_type: Ty<'tcx>, + enum_def_id: DefId, + unique_type_id: UniqueTypeId, + span: Span) + -> RecursiveTypeDescription<'tcx> { + let enum_name = compute_debuginfo_type_name(cx, enum_type, false); + + let containing_scope = get_namespace_for_item(cx, enum_def_id); + // FIXME: This should emit actual file metadata for the enum, but we + // currently can't get the necessary information when it comes to types + // imported from other crates. Formerly we violated the ODR when performing + // LTO because we emitted debuginfo for the same type with varying file + // metadata, so as a workaround we pretend that the type comes from + // + let file_metadata = unknown_file_metadata(cx); + + let def = enum_type.ty_adt_def().unwrap(); + let enumerators_metadata: Vec = def.discriminants(cx.tcx) + .zip(&def.variants) + .map(|(discr, v)| { + let token = v.name.as_str(); + let name = CString::new(token.as_bytes()).unwrap(); + unsafe { + llvm::LLVMRustDIBuilderCreateEnumerator( + DIB(cx), + name.as_ptr(), + // FIXME: what if enumeration has i128 discriminant? + discr.val as u64) + } + }) + .collect(); + + let discriminant_type_metadata = |discr: layout::Primitive| { + let disr_type_key = (enum_def_id, discr); + let cached_discriminant_type_metadata = debug_context(cx).created_enum_disr_types + .borrow() + .get(&disr_type_key).cloned(); + match cached_discriminant_type_metadata { + Some(discriminant_type_metadata) => discriminant_type_metadata, + None => { + let (discriminant_size, discriminant_align) = + (discr.size(cx), discr.align(cx)); + let discriminant_base_type_metadata = + type_metadata(cx, discr.to_ty(cx.tcx), syntax_pos::DUMMY_SP); + let discriminant_name = get_enum_discriminant_name(cx, enum_def_id).as_str(); + + let name = CString::new(discriminant_name.as_bytes()).unwrap(); + let discriminant_type_metadata = unsafe { + llvm::LLVMRustDIBuilderCreateEnumerationType( + DIB(cx), + containing_scope, + name.as_ptr(), + file_metadata, + UNKNOWN_LINE_NUMBER, + discriminant_size.bits(), + discriminant_align.abi_bits() as u32, + create_DIArray(DIB(cx), &enumerators_metadata), + discriminant_base_type_metadata) + }; + + debug_context(cx).created_enum_disr_types + .borrow_mut() + .insert(disr_type_key, discriminant_type_metadata); + + discriminant_type_metadata + } + } + }; + + let layout = cx.layout_of(enum_type); + + let discriminant_type_metadata = match layout.variants { + layout::Variants::Single { .. } | + layout::Variants::NicheFilling { .. } => None, + layout::Variants::Tagged { ref tag, .. } => { + Some(discriminant_type_metadata(tag.value)) + } + }; + + match (&layout.abi, discriminant_type_metadata) { + (&layout::Abi::Scalar(_), Some(discr)) => return FinalMetadata(discr), + _ => {} + } + + let (enum_type_size, enum_type_align) = layout.size_and_align(); + + let enum_name = CString::new(enum_name).unwrap(); + let unique_type_id_str = CString::new( + debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes() + ).unwrap(); + let enum_metadata = unsafe { + llvm::LLVMRustDIBuilderCreateUnionType( + DIB(cx), + containing_scope, + enum_name.as_ptr(), + file_metadata, + UNKNOWN_LINE_NUMBER, + enum_type_size.bits(), + enum_type_align.abi_bits() as u32, + DIFlags::FlagZero, + ptr::null_mut(), + 0, // RuntimeLang + unique_type_id_str.as_ptr()) + }; + + return create_and_register_recursive_type_forward_declaration( + cx, + enum_type, + unique_type_id, + enum_metadata, + EnumMDF(EnumMemberDescriptionFactory { + enum_type, + layout, + discriminant_type_metadata, + containing_scope, + span, + }), + ); + + fn get_enum_discriminant_name(cx: &CodegenCx, + def_id: DefId) + -> InternedString { + cx.tcx.item_name(def_id) + } +} + +/// Creates debug information for a composite type, that is, anything that +/// results in a LLVM struct. +/// +/// Examples of Rust types to use this are: structs, tuples, boxes, vecs, and enums. +fn composite_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + composite_type: Ty<'tcx>, + composite_type_name: &str, + composite_type_unique_id: UniqueTypeId, + member_descriptions: &[MemberDescription], + containing_scope: DIScope, + + // Ignore source location information as long as it + // can't be reconstructed for non-local crates. + _file_metadata: DIFile, + _definition_span: Span) + -> DICompositeType { + // Create the (empty) struct metadata node ... + let composite_type_metadata = create_struct_stub(cx, + composite_type, + composite_type_name, + composite_type_unique_id, + containing_scope); + // ... and immediately create and add the member descriptions. + set_members_of_composite_type(cx, + composite_type_metadata, + member_descriptions); + + return composite_type_metadata; +} + +fn set_members_of_composite_type(cx: &CodegenCx, + composite_type_metadata: DICompositeType, + member_descriptions: &[MemberDescription]) { + // In some rare cases LLVM metadata uniquing would lead to an existing type + // description being used instead of a new one created in + // create_struct_stub. This would cause a hard to trace assertion in + // DICompositeType::SetTypeArray(). The following check makes sure that we + // get a better error message if this should happen again due to some + // regression. + { + let mut composite_types_completed = + debug_context(cx).composite_types_completed.borrow_mut(); + if composite_types_completed.contains(&composite_type_metadata) { + bug!("debuginfo::set_members_of_composite_type() - \ + Already completed forward declaration re-encountered."); + } else { + composite_types_completed.insert(composite_type_metadata); + } + } + + let member_metadata: Vec = member_descriptions + .iter() + .map(|member_description| { + let member_name = member_description.name.as_bytes(); + let member_name = CString::new(member_name).unwrap(); + unsafe { + llvm::LLVMRustDIBuilderCreateMemberType( + DIB(cx), + composite_type_metadata, + member_name.as_ptr(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + member_description.size.bits(), + member_description.align.abi_bits() as u32, + member_description.offset.bits(), + member_description.flags, + member_description.type_metadata) + } + }) + .collect(); + + unsafe { + let type_array = create_DIArray(DIB(cx), &member_metadata[..]); + llvm::LLVMRustDICompositeTypeSetTypeArray( + DIB(cx), composite_type_metadata, type_array); + } +} + +// A convenience wrapper around LLVMRustDIBuilderCreateStructType(). Does not do +// any caching, does not add any fields to the struct. This can be done later +// with set_members_of_composite_type(). +fn create_struct_stub<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + struct_type: Ty<'tcx>, + struct_type_name: &str, + unique_type_id: UniqueTypeId, + containing_scope: DIScope) + -> DICompositeType { + let (struct_size, struct_align) = cx.size_and_align_of(struct_type); + + let name = CString::new(struct_type_name).unwrap(); + let unique_type_id = CString::new( + debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes() + ).unwrap(); + let metadata_stub = unsafe { + // LLVMRustDIBuilderCreateStructType() wants an empty array. A null + // pointer will lead to hard to trace and debug LLVM assertions + // later on in llvm/lib/IR/Value.cpp. + let empty_array = create_DIArray(DIB(cx), &[]); + + llvm::LLVMRustDIBuilderCreateStructType( + DIB(cx), + containing_scope, + name.as_ptr(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + struct_size.bits(), + struct_align.abi_bits() as u32, + DIFlags::FlagZero, + ptr::null_mut(), + empty_array, + 0, + ptr::null_mut(), + unique_type_id.as_ptr()) + }; + + return metadata_stub; +} + +fn create_union_stub<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + union_type: Ty<'tcx>, + union_type_name: &str, + unique_type_id: UniqueTypeId, + containing_scope: DIScope) + -> DICompositeType { + let (union_size, union_align) = cx.size_and_align_of(union_type); + + let name = CString::new(union_type_name).unwrap(); + let unique_type_id = CString::new( + debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes() + ).unwrap(); + let metadata_stub = unsafe { + // LLVMRustDIBuilderCreateUnionType() wants an empty array. A null + // pointer will lead to hard to trace and debug LLVM assertions + // later on in llvm/lib/IR/Value.cpp. + let empty_array = create_DIArray(DIB(cx), &[]); + + llvm::LLVMRustDIBuilderCreateUnionType( + DIB(cx), + containing_scope, + name.as_ptr(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + union_size.bits(), + union_align.abi_bits() as u32, + DIFlags::FlagZero, + empty_array, + 0, // RuntimeLang + unique_type_id.as_ptr()) + }; + + return metadata_stub; +} + +/// Creates debug information for the given global variable. +/// +/// Adds the created metadata nodes directly to the crate's IR. +pub fn create_global_var_metadata(cx: &CodegenCx, + def_id: DefId, + global: ValueRef) { + if cx.dbg_cx.is_none() { + return; + } + + let tcx = cx.tcx; + let attrs = tcx.codegen_fn_attrs(def_id); + + if attrs.flags.contains(CodegenFnAttrFlags::NO_DEBUG) { + return; + } + + let no_mangle = attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE); + // We may want to remove the namespace scope if we're in an extern block, see: + // https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952 + let var_scope = get_namespace_for_item(cx, def_id); + let span = tcx.def_span(def_id); + + let (file_metadata, line_number) = if span != syntax_pos::DUMMY_SP { + let loc = span_start(cx, span); + (file_metadata(cx, &loc.file.name, LOCAL_CRATE), loc.line as c_uint) + } else { + (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER) + }; + + let is_local_to_unit = is_node_local_to_unit(cx, def_id); + let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx); + let type_metadata = type_metadata(cx, variable_type, span); + let var_name = tcx.item_name(def_id).to_string(); + let var_name = CString::new(var_name).unwrap(); + let linkage_name = if no_mangle { + None + } else { + let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)); + Some(CString::new(linkage_name.to_string()).unwrap()) + }; + + let global_align = cx.align_of(variable_type); + + unsafe { + llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx), + var_scope, + var_name.as_ptr(), + // If null, linkage_name field is omitted, + // which is what we want for no_mangle statics + linkage_name.as_ref() + .map_or(ptr::null(), |name| name.as_ptr()), + file_metadata, + line_number, + type_metadata, + is_local_to_unit, + global, + ptr::null_mut(), + global_align.abi() as u32, + ); + } +} + +// Creates an "extension" of an existing DIScope into another file. +pub fn extend_scope_to_file(cx: &CodegenCx, + scope_metadata: DIScope, + file: &syntax_pos::FileMap, + defining_crate: CrateNum) + -> DILexicalBlock { + let file_metadata = file_metadata(cx, &file.name, defining_crate); + unsafe { + llvm::LLVMRustDIBuilderCreateLexicalBlockFile( + DIB(cx), + scope_metadata, + file_metadata) + } +} + +/// Creates debug information for the given vtable, which is for the +/// given type. +/// +/// Adds the created metadata nodes directly to the crate's IR. +pub fn create_vtable_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + ty: ty::Ty<'tcx>, + vtable: ValueRef) { + if cx.dbg_cx.is_none() { + return; + } + + let type_metadata = type_metadata(cx, ty, syntax_pos::DUMMY_SP); + + unsafe { + // LLVMRustDIBuilderCreateStructType() wants an empty array. A null + // pointer will lead to hard to trace and debug LLVM assertions + // later on in llvm/lib/IR/Value.cpp. + let empty_array = create_DIArray(DIB(cx), &[]); + + let name = CString::new("vtable").unwrap(); + + // Create a new one each time. We don't want metadata caching + // here, because each vtable will refer to a unique containing + // type. + let vtable_type = llvm::LLVMRustDIBuilderCreateStructType( + DIB(cx), + NO_SCOPE_METADATA, + name.as_ptr(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + Size::from_bytes(0).bits(), + cx.tcx.data_layout.pointer_align.abi_bits() as u32, + DIFlags::FlagArtificial, + ptr::null_mut(), + empty_array, + 0, + type_metadata, + name.as_ptr() + ); + + llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx), + NO_SCOPE_METADATA, + name.as_ptr(), + // LLVM 3.9 + // doesn't accept + // null here, so + // pass the name + // as the linkage + // name. + name.as_ptr(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + vtable_type, + true, + vtable, + ptr::null_mut(), + 0); + } +} diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs new file mode 100644 index 00000000000..294d8cbbd93 --- /dev/null +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -0,0 +1,542 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// See doc.rs for documentation. +mod doc; + +use self::VariableAccess::*; +use self::VariableKind::*; + +use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit}; +use self::namespace::mangled_name_of_instance; +use self::type_names::compute_debuginfo_type_name; +use self::metadata::{type_metadata, file_metadata, TypeMap}; +use self::source_loc::InternalDebugLocation::{self, UnknownLocation}; + +use llvm; +use llvm::{ModuleRef, ContextRef, ValueRef}; +use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, DIFlags}; +use rustc::hir::CodegenFnAttrFlags; +use rustc::hir::def_id::{DefId, CrateNum}; +use rustc::ty::subst::{Substs, UnpackedKind}; + +use abi::Abi; +use common::CodegenCx; +use builder::Builder; +use monomorphize::Instance; +use rustc::ty::{self, ParamEnv, Ty, InstanceDef}; +use rustc::mir; +use rustc::session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; +use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet}; + +use libc::c_uint; +use std::cell::{Cell, RefCell}; +use std::ffi::CString; +use std::ptr; + +use syntax_pos::{self, Span, Pos}; +use syntax::ast; +use syntax::symbol::{Symbol, InternedString}; +use rustc::ty::layout::{self, LayoutOf}; + +pub mod gdb; +mod utils; +mod namespace; +mod type_names; +pub mod metadata; +mod create_scope_map; +mod source_loc; + +pub use self::create_scope_map::{create_mir_scopes, MirDebugScope}; +pub use self::source_loc::start_emitting_source_locations; +pub use self::metadata::create_global_var_metadata; +pub use self::metadata::create_vtable_metadata; +pub use self::metadata::extend_scope_to_file; +pub use self::source_loc::set_source_location; + +#[allow(non_upper_case_globals)] +const DW_TAG_auto_variable: c_uint = 0x100; +#[allow(non_upper_case_globals)] +const DW_TAG_arg_variable: c_uint = 0x101; + +/// A context object for maintaining all state needed by the debuginfo module. +pub struct CrateDebugContext<'tcx> { + llcontext: ContextRef, + llmod: ModuleRef, + builder: DIBuilderRef, + created_files: RefCell>, + created_enum_disr_types: RefCell>, + + type_map: RefCell>, + namespace_map: RefCell>, + + // This collection is used to assert that composite types (structs, enums, + // ...) have their members only set once: + composite_types_completed: RefCell>, +} + +impl<'tcx> CrateDebugContext<'tcx> { + pub fn new(llmod: ModuleRef) -> CrateDebugContext<'tcx> { + debug!("CrateDebugContext::new"); + let builder = unsafe { llvm::LLVMRustDIBuilderCreate(llmod) }; + // DIBuilder inherits context from the module, so we'd better use the same one + let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) }; + CrateDebugContext { + llcontext, + llmod, + builder, + created_files: RefCell::new(FxHashMap()), + created_enum_disr_types: RefCell::new(FxHashMap()), + type_map: RefCell::new(TypeMap::new()), + namespace_map: RefCell::new(DefIdMap()), + composite_types_completed: RefCell::new(FxHashSet()), + } + } +} + +pub enum FunctionDebugContext { + RegularContext(FunctionDebugContextData), + DebugInfoDisabled, + FunctionWithoutDebugInfo, +} + +impl FunctionDebugContext { + pub fn get_ref<'a>(&'a self, span: Span) -> &'a FunctionDebugContextData { + match *self { + FunctionDebugContext::RegularContext(ref data) => data, + FunctionDebugContext::DebugInfoDisabled => { + span_bug!(span, "{}", FunctionDebugContext::debuginfo_disabled_message()); + } + FunctionDebugContext::FunctionWithoutDebugInfo => { + span_bug!(span, "{}", FunctionDebugContext::should_be_ignored_message()); + } + } + } + + fn debuginfo_disabled_message() -> &'static str { + "debuginfo: Error trying to access FunctionDebugContext although debug info is disabled!" + } + + fn should_be_ignored_message() -> &'static str { + "debuginfo: Error trying to access FunctionDebugContext for function that should be \ + ignored by debug info!" + } +} + +pub struct FunctionDebugContextData { + fn_metadata: DISubprogram, + source_locations_enabled: Cell, + pub defining_crate: CrateNum, +} + +pub enum VariableAccess<'a> { + // The llptr given is an alloca containing the variable's value + DirectVariable { alloca: ValueRef }, + // The llptr given is an alloca containing the start of some pointer chain + // leading to the variable's content. + IndirectVariable { alloca: ValueRef, address_operations: &'a [i64] } +} + +pub enum VariableKind { + ArgumentVariable(usize /*index*/), + LocalVariable, + CapturedVariable, +} + +/// Create any deferred debug metadata nodes +pub fn finalize(cx: &CodegenCx) { + if cx.dbg_cx.is_none() { + return; + } + + debug!("finalize"); + + if gdb::needs_gdb_debug_scripts_section(cx) { + // Add a .debug_gdb_scripts section to this compile-unit. This will + // cause GDB to try and load the gdb_load_rust_pretty_printers.py file, + // which activates the Rust pretty printers for binary this section is + // contained in. + gdb::get_or_insert_gdb_debug_scripts_section_global(cx); + } + + unsafe { + llvm::LLVMRustDIBuilderFinalize(DIB(cx)); + llvm::LLVMRustDIBuilderDispose(DIB(cx)); + // Debuginfo generation in LLVM by default uses a higher + // version of dwarf than macOS currently understands. We can + // instruct LLVM to emit an older version of dwarf, however, + // for macOS to understand. For more info see #11352 + // This can be overridden using --llvm-opts -dwarf-version,N. + // Android has the same issue (#22398) + if cx.sess().target.target.options.is_like_osx || + cx.sess().target.target.options.is_like_android { + llvm::LLVMRustAddModuleFlag(cx.llmod, + "Dwarf Version\0".as_ptr() as *const _, + 2) + } + + // Indicate that we want CodeView debug information on MSVC + if cx.sess().target.target.options.is_like_msvc { + llvm::LLVMRustAddModuleFlag(cx.llmod, + "CodeView\0".as_ptr() as *const _, + 1) + } + + // Prevent bitcode readers from deleting the debug info. + let ptr = "Debug Info Version\0".as_ptr(); + llvm::LLVMRustAddModuleFlag(cx.llmod, ptr as *const _, + llvm::LLVMRustDebugMetadataVersion()); + }; +} + +/// Creates the function-specific debug context. +/// +/// Returns the FunctionDebugContext for the function which holds state needed +/// for debug info creation. The function may also return another variant of the +/// FunctionDebugContext enum which indicates why no debuginfo should be created +/// for the function. +pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + instance: Instance<'tcx>, + sig: ty::FnSig<'tcx>, + llfn: ValueRef, + mir: &mir::Mir) -> FunctionDebugContext { + if cx.sess().opts.debuginfo == NoDebugInfo { + return FunctionDebugContext::DebugInfoDisabled; + } + + if let InstanceDef::Item(def_id) = instance.def { + if cx.tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_DEBUG) { + return FunctionDebugContext::FunctionWithoutDebugInfo; + } + } + + let span = mir.span; + + // This can be the case for functions inlined from another crate + if span == syntax_pos::DUMMY_SP { + // FIXME(simulacrum): Probably can't happen; remove. + return FunctionDebugContext::FunctionWithoutDebugInfo; + } + + let def_id = instance.def_id(); + let containing_scope = get_containing_scope(cx, instance); + let loc = span_start(cx, span); + let file_metadata = file_metadata(cx, &loc.file.name, def_id.krate); + + let function_type_metadata = unsafe { + let fn_signature = get_function_signature(cx, sig); + llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature) + }; + + // Find the enclosing function, in case this is a closure. + let def_key = cx.tcx.def_key(def_id); + let mut name = def_key.disambiguated_data.data.to_string(); + + let enclosing_fn_def_id = cx.tcx.closure_base_def_id(def_id); + + // Get_template_parameters() will append a `<...>` clause to the function + // name if necessary. + let generics = cx.tcx.generics_of(enclosing_fn_def_id); + let substs = instance.substs.truncate_to(cx.tcx, generics); + let template_parameters = get_template_parameters(cx, + &generics, + substs, + file_metadata, + &mut name); + + // Get the linkage_name, which is just the symbol name + let linkage_name = mangled_name_of_instance(cx, instance); + + let scope_line = span_start(cx, span).line; + let is_local_to_unit = is_node_local_to_unit(cx, def_id); + + let function_name = CString::new(name).unwrap(); + let linkage_name = CString::new(linkage_name.to_string()).unwrap(); + + let mut flags = DIFlags::FlagPrototyped; + + let local_id = cx.tcx.hir.as_local_node_id(def_id); + match *cx.sess().entry_fn.borrow() { + Some((id, _, _)) => { + if local_id == Some(id) { + flags = flags | DIFlags::FlagMainSubprogram; + } + } + None => {} + }; + if cx.layout_of(sig.output()).abi == ty::layout::Abi::Uninhabited { + flags = flags | DIFlags::FlagNoReturn; + } + + let fn_metadata = unsafe { + llvm::LLVMRustDIBuilderCreateFunction( + DIB(cx), + containing_scope, + function_name.as_ptr(), + linkage_name.as_ptr(), + file_metadata, + loc.line as c_uint, + function_type_metadata, + is_local_to_unit, + true, + scope_line as c_uint, + flags, + cx.sess().opts.optimize != config::OptLevel::No, + llfn, + template_parameters, + ptr::null_mut()) + }; + + // Initialize fn debug context (including scope map and namespace map) + let fn_debug_context = FunctionDebugContextData { + fn_metadata, + source_locations_enabled: Cell::new(false), + defining_crate: def_id.krate, + }; + + return FunctionDebugContext::RegularContext(fn_debug_context); + + fn get_function_signature<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + sig: ty::FnSig<'tcx>) -> DIArray { + if cx.sess().opts.debuginfo == LimitedDebugInfo { + return create_DIArray(DIB(cx), &[]); + } + + let mut signature = Vec::with_capacity(sig.inputs().len() + 1); + + // Return type -- llvm::DIBuilder wants this at index 0 + signature.push(match sig.output().sty { + ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(), + _ => type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP) + }); + + let inputs = if sig.abi == Abi::RustCall { + &sig.inputs()[..sig.inputs().len() - 1] + } else { + sig.inputs() + }; + + // Arguments types + if cx.sess().target.target.options.is_like_msvc { + // FIXME(#42800): + // There is a bug in MSDIA that leads to a crash when it encounters + // a fixed-size array of `u8` or something zero-sized in a + // function-type (see #40477). + // As a workaround, we replace those fixed-size arrays with a + // pointer-type. So a function `fn foo(a: u8, b: [u8; 4])` would + // appear as `fn foo(a: u8, b: *const u8)` in debuginfo, + // and a function `fn bar(x: [(); 7])` as `fn bar(x: *const ())`. + // This transformed type is wrong, but these function types are + // already inaccurate due to ABI adjustments (see #42800). + signature.extend(inputs.iter().map(|&t| { + let t = match t.sty { + ty::TyArray(ct, _) + if (ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() => { + cx.tcx.mk_imm_ptr(ct) + } + _ => t + }; + type_metadata(cx, t, syntax_pos::DUMMY_SP) + })); + } else { + signature.extend(inputs.iter().map(|t| { + type_metadata(cx, t, syntax_pos::DUMMY_SP) + })); + } + + if sig.abi == Abi::RustCall && !sig.inputs().is_empty() { + if let ty::TyTuple(args) = sig.inputs()[sig.inputs().len() - 1].sty { + for &argument_type in args { + signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP)); + } + } + } + + return create_DIArray(DIB(cx), &signature[..]); + } + + fn get_template_parameters<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + generics: &ty::Generics, + substs: &Substs<'tcx>, + file_metadata: DIFile, + name_to_append_suffix_to: &mut String) + -> DIArray + { + if substs.types().next().is_none() { + return create_DIArray(DIB(cx), &[]); + } + + name_to_append_suffix_to.push('<'); + for (i, actual_type) in substs.types().enumerate() { + if i != 0 { + name_to_append_suffix_to.push_str(","); + } + + let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), actual_type); + // Add actual type name to <...> clause of function name + let actual_type_name = compute_debuginfo_type_name(cx, + actual_type, + true); + name_to_append_suffix_to.push_str(&actual_type_name[..]); + } + name_to_append_suffix_to.push('>'); + + // Again, only create type information if full debuginfo is enabled + let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo { + let names = get_parameter_names(cx, generics); + substs.iter().zip(names).filter_map(|(kind, name)| { + if let UnpackedKind::Type(ty) = kind.unpack() { + let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); + let actual_type_metadata = + type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); + let name = CString::new(name.as_str().as_bytes()).unwrap(); + Some(unsafe { + llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( + DIB(cx), + ptr::null_mut(), + name.as_ptr(), + actual_type_metadata, + file_metadata, + 0, + 0) + }) + } else { + None + } + }).collect() + } else { + vec![] + }; + + return create_DIArray(DIB(cx), &template_params[..]); + } + + fn get_parameter_names(cx: &CodegenCx, + generics: &ty::Generics) + -> Vec { + let mut names = generics.parent.map_or(vec![], |def_id| { + get_parameter_names(cx, cx.tcx.generics_of(def_id)) + }); + names.extend(generics.params.iter().map(|param| param.name)); + names + } + + fn get_containing_scope<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>, + instance: Instance<'tcx>) + -> DIScope { + // First, let's see if this is a method within an inherent impl. Because + // if yes, we want to make the result subroutine DIE a child of the + // subroutine's self-type. + let self_type = cx.tcx.impl_of_method(instance.def_id()).and_then(|impl_def_id| { + // If the method does *not* belong to a trait, proceed + if cx.tcx.trait_id_of_impl(impl_def_id).is_none() { + let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions( + instance.substs, + ty::ParamEnv::reveal_all(), + &cx.tcx.type_of(impl_def_id), + ); + + // Only "class" methods are generally understood by LLVM, + // so avoid methods on other types (e.g. `<*mut T>::null`). + match impl_self_ty.sty { + ty::TyAdt(def, ..) if !def.is_box() => { + Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP)) + } + _ => None + } + } else { + // For trait method impls we still use the "parallel namespace" + // strategy + None + } + }); + + self_type.unwrap_or_else(|| { + namespace::item_namespace(cx, DefId { + krate: instance.def_id().krate, + index: cx.tcx + .def_key(instance.def_id()) + .parent + .expect("get_containing_scope: missing parent?") + }) + }) + } +} + +pub fn declare_local<'a, 'tcx>(bx: &Builder<'a, 'tcx>, + dbg_context: &FunctionDebugContext, + variable_name: ast::Name, + variable_type: Ty<'tcx>, + scope_metadata: DIScope, + variable_access: VariableAccess, + variable_kind: VariableKind, + span: Span) { + let cx = bx.cx; + + let file = span_start(cx, span).file; + let file_metadata = file_metadata(cx, + &file.name, + dbg_context.get_ref(span).defining_crate); + + let loc = span_start(cx, span); + let type_metadata = type_metadata(cx, variable_type, span); + + let (argument_index, dwarf_tag) = match variable_kind { + ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable), + LocalVariable | + CapturedVariable => (0, DW_TAG_auto_variable) + }; + let align = cx.align_of(variable_type); + + let name = CString::new(variable_name.as_str().as_bytes()).unwrap(); + match (variable_access, &[][..]) { + (DirectVariable { alloca }, address_operations) | + (IndirectVariable {alloca, address_operations}, _) => { + let metadata = unsafe { + llvm::LLVMRustDIBuilderCreateVariable( + DIB(cx), + dwarf_tag, + scope_metadata, + name.as_ptr(), + file_metadata, + loc.line as c_uint, + type_metadata, + cx.sess().opts.optimize != config::OptLevel::No, + DIFlags::FlagZero, + argument_index, + align.abi() as u32, + ) + }; + source_loc::set_debug_location(bx, + InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize())); + unsafe { + let debug_loc = llvm::LLVMGetCurrentDebugLocation(bx.llbuilder); + let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd( + DIB(cx), + alloca, + metadata, + address_operations.as_ptr(), + address_operations.len() as c_uint, + debug_loc, + bx.llbb()); + + llvm::LLVMSetInstDebugLocation(bx.llbuilder, instr); + } + } + } + + match variable_kind { + ArgumentVariable(_) | CapturedVariable => { + assert!(!dbg_context.get_ref(span).source_locations_enabled.get()); + source_loc::set_debug_location(bx, UnknownLocation); + } + _ => { /* nothing to do */ } + } +} diff --git a/src/librustc_codegen_llvm/debuginfo/namespace.rs b/src/librustc_codegen_llvm/debuginfo/namespace.rs new file mode 100644 index 00000000000..51c45de9dc2 --- /dev/null +++ b/src/librustc_codegen_llvm/debuginfo/namespace.rs @@ -0,0 +1,66 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Namespace Handling. + +use super::metadata::{unknown_file_metadata, UNKNOWN_LINE_NUMBER}; +use super::utils::{DIB, debug_context}; +use monomorphize::Instance; +use rustc::ty; + +use llvm; +use llvm::debuginfo::DIScope; +use rustc::hir::def_id::DefId; +use rustc::hir::map::DefPathData; +use common::CodegenCx; + +use std::ffi::CString; +use std::ptr; + +pub fn mangled_name_of_instance<'a, 'tcx>( + cx: &CodegenCx<'a, 'tcx>, + instance: Instance<'tcx>, +) -> ty::SymbolName { + let tcx = cx.tcx; + tcx.symbol_name(instance) +} + +pub fn item_namespace(cx: &CodegenCx, def_id: DefId) -> DIScope { + if let Some(&scope) = debug_context(cx).namespace_map.borrow().get(&def_id) { + return scope; + } + + let def_key = cx.tcx.def_key(def_id); + let parent_scope = def_key.parent.map_or(ptr::null_mut(), |parent| { + item_namespace(cx, DefId { + krate: def_id.krate, + index: parent + }) + }); + + let namespace_name = match def_key.disambiguated_data.data { + DefPathData::CrateRoot => cx.tcx.crate_name(def_id.krate).as_str(), + data => data.as_interned_str().as_str() + }; + + let namespace_name = CString::new(namespace_name.as_bytes()).unwrap(); + + let scope = unsafe { + llvm::LLVMRustDIBuilderCreateNameSpace( + DIB(cx), + parent_scope, + namespace_name.as_ptr(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER) + }; + + debug_context(cx).namespace_map.borrow_mut().insert(def_id, scope); + scope +} diff --git a/src/librustc_codegen_llvm/debuginfo/source_loc.rs b/src/librustc_codegen_llvm/debuginfo/source_loc.rs new file mode 100644 index 00000000000..eb37e7f931c --- /dev/null +++ b/src/librustc_codegen_llvm/debuginfo/source_loc.rs @@ -0,0 +1,107 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use self::InternalDebugLocation::*; + +use super::utils::{debug_context, span_start}; +use super::metadata::UNKNOWN_COLUMN_NUMBER; +use super::FunctionDebugContext; + +use llvm; +use llvm::debuginfo::DIScope; +use builder::Builder; + +use libc::c_uint; +use std::ptr; +use syntax_pos::{Span, Pos}; + +/// Sets the current debug location at the beginning of the span. +/// +/// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...). +pub fn set_source_location( + debug_context: &FunctionDebugContext, bx: &Builder, scope: DIScope, span: Span +) { + let function_debug_context = match *debug_context { + FunctionDebugContext::DebugInfoDisabled => return, + FunctionDebugContext::FunctionWithoutDebugInfo => { + set_debug_location(bx, UnknownLocation); + return; + } + FunctionDebugContext::RegularContext(ref data) => data + }; + + let dbg_loc = if function_debug_context.source_locations_enabled.get() { + debug!("set_source_location: {}", bx.sess().codemap().span_to_string(span)); + let loc = span_start(bx.cx, span); + InternalDebugLocation::new(scope, loc.line, loc.col.to_usize()) + } else { + UnknownLocation + }; + set_debug_location(bx, dbg_loc); +} + +/// Enables emitting source locations for the given functions. +/// +/// Since we don't want source locations to be emitted for the function prelude, +/// they are disabled when beginning to codegen a new function. This functions +/// switches source location emitting on and must therefore be called before the +/// first real statement/expression of the function is codegened. +pub fn start_emitting_source_locations(dbg_context: &FunctionDebugContext) { + match *dbg_context { + FunctionDebugContext::RegularContext(ref data) => { + data.source_locations_enabled.set(true) + }, + _ => { /* safe to ignore */ } + } +} + + +#[derive(Copy, Clone, PartialEq)] +pub enum InternalDebugLocation { + KnownLocation { scope: DIScope, line: usize, col: usize }, + UnknownLocation +} + +impl InternalDebugLocation { + pub fn new(scope: DIScope, line: usize, col: usize) -> InternalDebugLocation { + KnownLocation { + scope, + line, + col, + } + } +} + +pub fn set_debug_location(bx: &Builder, debug_location: InternalDebugLocation) { + let metadata_node = match debug_location { + KnownLocation { scope, line, .. } => { + // Always set the column to zero like Clang and GCC + let col = UNKNOWN_COLUMN_NUMBER; + debug!("setting debug location to {} {}", line, col); + + unsafe { + llvm::LLVMRustDIBuilderCreateDebugLocation( + debug_context(bx.cx).llcontext, + line as c_uint, + col as c_uint, + scope, + ptr::null_mut()) + } + } + UnknownLocation => { + debug!("clearing debug location "); + ptr::null_mut() + } + }; + + unsafe { + llvm::LLVMSetCurrentDebugLocation(bx.llbuilder, metadata_node); + } +} diff --git a/src/librustc_codegen_llvm/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs new file mode 100644 index 00000000000..05a74db3a6c --- /dev/null +++ b/src/librustc_codegen_llvm/debuginfo/type_names.rs @@ -0,0 +1,224 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Type Names for Debug Info. + +use common::CodegenCx; +use rustc::hir::def_id::DefId; +use rustc::ty::subst::Substs; +use rustc::ty::{self, Ty}; + +use rustc::hir; + +// Compute the name of the type as it should be stored in debuginfo. Does not do +// any caching, i.e. calling the function twice with the same type will also do +// the work twice. The `qualified` parameter only affects the first level of the +// type name, further levels (i.e. type parameters) are always fully qualified. +pub fn compute_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + t: Ty<'tcx>, + qualified: bool) + -> String { + let mut result = String::with_capacity(64); + push_debuginfo_type_name(cx, t, qualified, &mut result); + result +} + +// Pushes the name of the type as it should be stored in debuginfo on the +// `output` String. See also compute_debuginfo_type_name(). +pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + t: Ty<'tcx>, + qualified: bool, + output: &mut String) { + // When targeting MSVC, emit C++ style type names for compatibility with + // .natvis visualizers (and perhaps other existing native debuggers?) + let cpp_like_names = cx.sess().target.target.options.is_like_msvc; + + match t.sty { + ty::TyBool => output.push_str("bool"), + ty::TyChar => output.push_str("char"), + ty::TyStr => output.push_str("str"), + ty::TyNever => output.push_str("!"), + ty::TyInt(int_ty) => output.push_str(int_ty.ty_to_string()), + ty::TyUint(uint_ty) => output.push_str(uint_ty.ty_to_string()), + ty::TyFloat(float_ty) => output.push_str(float_ty.ty_to_string()), + ty::TyForeign(def_id) => push_item_name(cx, def_id, qualified, output), + ty::TyAdt(def, substs) => { + push_item_name(cx, def.did, qualified, output); + push_type_params(cx, substs, output); + }, + ty::TyTuple(component_types) => { + output.push('('); + for &component_type in component_types { + push_debuginfo_type_name(cx, component_type, true, output); + output.push_str(", "); + } + if !component_types.is_empty() { + output.pop(); + output.pop(); + } + output.push(')'); + }, + ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { + if !cpp_like_names { + output.push('*'); + } + match mutbl { + hir::MutImmutable => output.push_str("const "), + hir::MutMutable => output.push_str("mut "), + } + + push_debuginfo_type_name(cx, inner_type, true, output); + + if cpp_like_names { + output.push('*'); + } + }, + ty::TyRef(_, inner_type, mutbl) => { + if !cpp_like_names { + output.push('&'); + } + if mutbl == hir::MutMutable { + output.push_str("mut "); + } + + push_debuginfo_type_name(cx, inner_type, true, output); + + if cpp_like_names { + output.push('*'); + } + }, + ty::TyArray(inner_type, len) => { + output.push('['); + push_debuginfo_type_name(cx, inner_type, true, output); + output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx))); + output.push(']'); + }, + ty::TySlice(inner_type) => { + if cpp_like_names { + output.push_str("slice<"); + } else { + output.push('['); + } + + push_debuginfo_type_name(cx, inner_type, true, output); + + if cpp_like_names { + output.push('>'); + } else { + output.push(']'); + } + }, + ty::TyDynamic(ref trait_data, ..) => { + if let Some(principal) = trait_data.principal() { + let principal = cx.tcx.normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &principal, + ); + push_item_name(cx, principal.def_id, false, output); + push_type_params(cx, principal.substs, output); + } + }, + ty::TyFnDef(..) | ty::TyFnPtr(_) => { + let sig = t.fn_sig(cx.tcx); + if sig.unsafety() == hir::Unsafety::Unsafe { + output.push_str("unsafe "); + } + + let abi = sig.abi(); + if abi != ::abi::Abi::Rust { + output.push_str("extern \""); + output.push_str(abi.name()); + output.push_str("\" "); + } + + output.push_str("fn("); + + let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + if !sig.inputs().is_empty() { + for ¶meter_type in sig.inputs() { + push_debuginfo_type_name(cx, parameter_type, true, output); + output.push_str(", "); + } + output.pop(); + output.pop(); + } + + if sig.variadic { + if !sig.inputs().is_empty() { + output.push_str(", ..."); + } else { + output.push_str("..."); + } + } + + output.push(')'); + + if !sig.output().is_nil() { + output.push_str(" -> "); + push_debuginfo_type_name(cx, sig.output(), true, output); + } + }, + ty::TyClosure(..) => { + output.push_str("closure"); + } + ty::TyGenerator(..) => { + output.push_str("generator"); + } + ty::TyError | + ty::TyInfer(_) | + ty::TyProjection(..) | + ty::TyAnon(..) | + ty::TyGeneratorWitness(..) | + ty::TyParam(_) => { + bug!("debuginfo: Trying to create type name for \ + unexpected type: {:?}", t); + } + } + + fn push_item_name(cx: &CodegenCx, + def_id: DefId, + qualified: bool, + output: &mut String) { + if qualified { + output.push_str(&cx.tcx.crate_name(def_id.krate).as_str()); + for path_element in cx.tcx.def_path(def_id).data { + output.push_str("::"); + output.push_str(&path_element.data.as_interned_str().as_str()); + } + } else { + output.push_str(&cx.tcx.item_name(def_id).as_str()); + } + } + + // Pushes the type parameters in the given `Substs` to the output string. + // This ignores region parameters, since they can't reliably be + // reconstructed for items from non-local crates. For local crates, this + // would be possible but with inlining and LTO we have to use the least + // common denominator - otherwise we would run into conflicts. + fn push_type_params<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + substs: &Substs<'tcx>, + output: &mut String) { + if substs.types().next().is_none() { + return; + } + + output.push('<'); + + for type_parameter in substs.types() { + push_debuginfo_type_name(cx, type_parameter, true, output); + output.push_str(", "); + } + + output.pop(); + output.pop(); + + output.push('>'); + } +} diff --git a/src/librustc_codegen_llvm/debuginfo/utils.rs b/src/librustc_codegen_llvm/debuginfo/utils.rs new file mode 100644 index 00000000000..9d37f99cb2a --- /dev/null +++ b/src/librustc_codegen_llvm/debuginfo/utils.rs @@ -0,0 +1,65 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Utility Functions. + +use super::{CrateDebugContext}; +use super::namespace::item_namespace; + +use rustc::hir::def_id::DefId; +use rustc::ty::DefIdTree; + +use llvm; +use llvm::debuginfo::{DIScope, DIBuilderRef, DIDescriptor, DIArray}; +use common::{CodegenCx}; + +use syntax_pos::{self, Span}; + +pub fn is_node_local_to_unit(cx: &CodegenCx, def_id: DefId) -> bool +{ + // The is_local_to_unit flag indicates whether a function is local to the + // current compilation unit (i.e. if it is *static* in the C-sense). The + // *reachable* set should provide a good approximation of this, as it + // contains everything that might leak out of the current crate (by being + // externally visible or by being inlined into something externally + // visible). It might better to use the `exported_items` set from + // `driver::CrateAnalysis` in the future, but (atm) this set is not + // available in the codegen pass. + !cx.tcx.is_reachable_non_generic(def_id) +} + +#[allow(non_snake_case)] +pub fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray { + return unsafe { + llvm::LLVMRustDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32) + }; +} + +/// Return syntax_pos::Loc corresponding to the beginning of the span +pub fn span_start(cx: &CodegenCx, span: Span) -> syntax_pos::Loc { + cx.sess().codemap().lookup_char_pos(span.lo()) +} + +#[inline] +pub fn debug_context<'a, 'tcx>(cx: &'a CodegenCx<'a, 'tcx>) + -> &'a CrateDebugContext<'tcx> { + cx.dbg_cx.as_ref().unwrap() +} + +#[inline] +#[allow(non_snake_case)] +pub fn DIB(cx: &CodegenCx) -> DIBuilderRef { + cx.dbg_cx.as_ref().unwrap().builder +} + +pub fn get_namespace_for_item(cx: &CodegenCx, def_id: DefId) -> DIScope { + item_namespace(cx, cx.tcx.parent(def_id) + .expect("get_namespace_for_item: missing parent?")) +} diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs new file mode 100644 index 00000000000..fdc84f914f5 --- /dev/null +++ b/src/librustc_codegen_llvm/declare.rs @@ -0,0 +1,223 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! Declare various LLVM values. +//! +//! Prefer using functions and methods from this module rather than calling LLVM +//! functions directly. These functions do some additional work to ensure we do +//! the right thing given the preconceptions of codegen. +//! +//! Some useful guidelines: +//! +//! * Use declare_* family of methods if you are declaring, but are not +//! interested in defining the ValueRef they return. +//! * Use define_* family of methods when you might be defining the ValueRef. +//! * When in doubt, define. + +use llvm::{self, ValueRef}; +use llvm::AttributePlace::Function; +use rustc::ty::{self, Ty}; +use rustc::ty::layout::{self, LayoutOf}; +use rustc::session::config::Sanitizer; +use rustc_target::spec::PanicStrategy; +use abi::{Abi, FnType, FnTypeExt}; +use attributes; +use context::CodegenCx; +use common; +use type_::Type; +use value::Value; + +use std::ffi::CString; + + +/// Declare a global value. +/// +/// If there’s a value with the same name already declared, the function will +/// return its ValueRef instead. +pub fn declare_global(cx: &CodegenCx, name: &str, ty: Type) -> llvm::ValueRef { + debug!("declare_global(name={:?})", name); + let namebuf = CString::new(name).unwrap_or_else(|_|{ + bug!("name {:?} contains an interior null byte", name) + }); + unsafe { + llvm::LLVMRustGetOrInsertGlobal(cx.llmod, namebuf.as_ptr(), ty.to_ref()) + } +} + + +/// Declare a function. +/// +/// If there’s a value with the same name already declared, the function will +/// update the declaration and return existing ValueRef instead. +fn declare_raw_fn(cx: &CodegenCx, name: &str, callconv: llvm::CallConv, ty: Type) -> ValueRef { + debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty); + let namebuf = CString::new(name).unwrap_or_else(|_|{ + bug!("name {:?} contains an interior null byte", name) + }); + let llfn = unsafe { + llvm::LLVMRustGetOrInsertFunction(cx.llmod, namebuf.as_ptr(), ty.to_ref()) + }; + + llvm::SetFunctionCallConv(llfn, callconv); + // Function addresses in Rust are never significant, allowing functions to + // be merged. + llvm::SetUnnamedAddr(llfn, true); + + if cx.tcx.sess.opts.cg.no_redzone + .unwrap_or(cx.tcx.sess.target.target.options.disable_redzone) { + llvm::Attribute::NoRedZone.apply_llfn(Function, llfn); + } + + if let Some(ref sanitizer) = cx.tcx.sess.opts.debugging_opts.sanitizer { + match *sanitizer { + Sanitizer::Address => { + llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn); + }, + Sanitizer::Memory => { + llvm::Attribute::SanitizeMemory.apply_llfn(Function, llfn); + }, + Sanitizer::Thread => { + llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn); + }, + _ => {} + } + } + + match cx.tcx.sess.opts.cg.opt_level.as_ref().map(String::as_ref) { + Some("s") => { + llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); + }, + Some("z") => { + llvm::Attribute::MinSize.apply_llfn(Function, llfn); + llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); + }, + _ => {}, + } + + if cx.tcx.sess.panic_strategy() != PanicStrategy::Unwind { + attributes::unwind(llfn, false); + } + + llfn +} + + +/// Declare a C ABI function. +/// +/// Only use this for foreign function ABIs and glue. For Rust functions use +/// `declare_fn` instead. +/// +/// If there’s a value with the same name already declared, the function will +/// update the declaration and return existing ValueRef instead. +pub fn declare_cfn(cx: &CodegenCx, name: &str, fn_type: Type) -> ValueRef { + declare_raw_fn(cx, name, llvm::CCallConv, fn_type) +} + + +/// Declare a Rust function. +/// +/// If there’s a value with the same name already declared, the function will +/// update the declaration and return existing ValueRef instead. +pub fn declare_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, name: &str, + fn_type: Ty<'tcx>) -> ValueRef { + debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type); + let sig = common::ty_fn_sig(cx, fn_type); + let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + debug!("declare_rust_fn (after region erasure) sig={:?}", sig); + + let fty = FnType::new(cx, sig, &[]); + let llfn = declare_raw_fn(cx, name, fty.llvm_cconv(), fty.llvm_type(cx)); + + if cx.layout_of(sig.output()).abi == layout::Abi::Uninhabited { + llvm::Attribute::NoReturn.apply_llfn(Function, llfn); + } + + if sig.abi != Abi::Rust && sig.abi != Abi::RustCall { + attributes::unwind(llfn, false); + } + + fty.apply_attrs_llfn(llfn); + + llfn +} + + +/// Declare a global with an intention to define it. +/// +/// Use this function when you intend to define a global. This function will +/// return None if the name already has a definition associated with it. In that +/// case an error should be reported to the user, because it usually happens due +/// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes). +pub fn define_global(cx: &CodegenCx, name: &str, ty: Type) -> Option { + if get_defined_value(cx, name).is_some() { + None + } else { + Some(declare_global(cx, name, ty)) + } +} + +/// Declare a Rust function with an intention to define it. +/// +/// Use this function when you intend to define a function. This function will +/// return panic if the name already has a definition associated with it. This +/// can happen with #[no_mangle] or #[export_name], for example. +pub fn define_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + name: &str, + fn_type: Ty<'tcx>) -> ValueRef { + if get_defined_value(cx, name).is_some() { + cx.sess().fatal(&format!("symbol `{}` already defined", name)) + } else { + declare_fn(cx, name, fn_type) + } +} + +/// Declare a Rust function with an intention to define it. +/// +/// Use this function when you intend to define a function. This function will +/// return panic if the name already has a definition associated with it. This +/// can happen with #[no_mangle] or #[export_name], for example. +pub fn define_internal_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + name: &str, + fn_type: Ty<'tcx>) -> ValueRef { + let llfn = define_fn(cx, name, fn_type); + unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) }; + llfn +} + + +/// Get declared value by name. +pub fn get_declared_value(cx: &CodegenCx, name: &str) -> Option { + debug!("get_declared_value(name={:?})", name); + let namebuf = CString::new(name).unwrap_or_else(|_|{ + bug!("name {:?} contains an interior null byte", name) + }); + let val = unsafe { llvm::LLVMRustGetNamedValue(cx.llmod, namebuf.as_ptr()) }; + if val.is_null() { + debug!("get_declared_value: {:?} value is null", name); + None + } else { + debug!("get_declared_value: {:?} => {:?}", name, Value(val)); + Some(val) + } +} + +/// Get defined or externally defined (AvailableExternally linkage) value by +/// name. +pub fn get_defined_value(cx: &CodegenCx, name: &str) -> Option { + get_declared_value(cx, name).and_then(|val|{ + let declaration = unsafe { + llvm::LLVMIsDeclaration(val) != 0 + }; + if !declaration { + Some(val) + } else { + None + } + }) +} diff --git a/src/librustc_codegen_llvm/diagnostics.rs b/src/librustc_codegen_llvm/diagnostics.rs new file mode 100644 index 00000000000..57cc33d09bb --- /dev/null +++ b/src/librustc_codegen_llvm/diagnostics.rs @@ -0,0 +1,55 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_snake_case)] + +register_long_diagnostics! { + +E0511: r##" +Invalid monomorphization of an intrinsic function was used. Erroneous code +example: + +```ignore (error-emitted-at-codegen-which-cannot-be-handled-by-compile_fail) +#![feature(platform_intrinsics)] + +extern "platform-intrinsic" { + fn simd_add(a: T, b: T) -> T; +} + +fn main() { + unsafe { simd_add(0, 1); } + // error: invalid monomorphization of `simd_add` intrinsic +} +``` + +The generic type has to be a SIMD type. Example: + +``` +#![feature(repr_simd)] +#![feature(platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +struct i32x2(i32, i32); + +extern "platform-intrinsic" { + fn simd_add(a: T, b: T) -> T; +} + +unsafe { simd_add(i32x2(0, 0), i32x2(1, 2)); } // ok! +``` +"##, + +} + + +register_diagnostics! { + E0558 +} diff --git a/src/librustc_codegen_llvm/glue.rs b/src/librustc_codegen_llvm/glue.rs new file mode 100644 index 00000000000..c7275d09401 --- /dev/null +++ b/src/librustc_codegen_llvm/glue.rs @@ -0,0 +1,122 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! +// +// Code relating to drop glue. + +use std; + +use builder::Builder; +use common::*; +use llvm::{ValueRef}; +use llvm; +use meth; +use rustc::ty::layout::LayoutOf; +use rustc::ty::{self, Ty}; +use value::Value; + +pub fn size_and_align_of_dst<'a, 'tcx>(bx: &Builder<'a, 'tcx>, t: Ty<'tcx>, info: ValueRef) + -> (ValueRef, ValueRef) { + debug!("calculate size of DST: {}; with lost info: {:?}", + t, Value(info)); + if bx.cx.type_is_sized(t) { + let (size, align) = bx.cx.size_and_align_of(t); + debug!("size_and_align_of_dst t={} info={:?} size: {:?} align: {:?}", + t, Value(info), size, align); + let size = C_usize(bx.cx, size.bytes()); + let align = C_usize(bx.cx, align.abi()); + return (size, align); + } + assert!(!info.is_null()); + match t.sty { + ty::TyDynamic(..) => { + // load size/align from vtable + (meth::SIZE.get_usize(bx, info), meth::ALIGN.get_usize(bx, info)) + } + ty::TySlice(_) | ty::TyStr => { + let unit = t.sequence_element_type(bx.tcx()); + // The info in this case is the length of the str, so the size is that + // times the unit size. + let (size, align) = bx.cx.size_and_align_of(unit); + (bx.mul(info, C_usize(bx.cx, size.bytes())), + C_usize(bx.cx, align.abi())) + } + _ => { + let cx = bx.cx; + // First get the size of all statically known fields. + // Don't use size_of because it also rounds up to alignment, which we + // want to avoid, as the unsized field's alignment could be smaller. + assert!(!t.is_simd()); + let layout = cx.layout_of(t); + debug!("DST {} layout: {:?}", t, layout); + + let i = layout.fields.count() - 1; + let sized_size = layout.fields.offset(i).bytes(); + let sized_align = layout.align.abi(); + debug!("DST {} statically sized prefix size: {} align: {}", + t, sized_size, sized_align); + let sized_size = C_usize(cx, sized_size); + let sized_align = C_usize(cx, sized_align); + + // Recurse to get the size of the dynamically sized field (must be + // the last field). + let field_ty = layout.field(cx, i).ty; + let (unsized_size, mut unsized_align) = size_and_align_of_dst(bx, field_ty, info); + + // FIXME (#26403, #27023): We should be adding padding + // to `sized_size` (to accommodate the `unsized_align` + // required of the unsized field that follows) before + // summing it with `sized_size`. (Note that since #26403 + // is unfixed, we do not yet add the necessary padding + // here. But this is where the add would go.) + + // Return the sum of sizes and max of aligns. + let size = bx.add(sized_size, unsized_size); + + // Packed types ignore the alignment of their fields. + if let ty::TyAdt(def, _) = t.sty { + if def.repr.packed() { + unsized_align = sized_align; + } + } + + // Choose max of two known alignments (combined value must + // be aligned according to more restrictive of the two). + let align = match (const_to_opt_u128(sized_align, false), + const_to_opt_u128(unsized_align, false)) { + (Some(sized_align), Some(unsized_align)) => { + // If both alignments are constant, (the sized_align should always be), then + // pick the correct alignment statically. + C_usize(cx, std::cmp::max(sized_align, unsized_align) as u64) + } + _ => bx.select(bx.icmp(llvm::IntUGT, sized_align, unsized_align), + sized_align, + unsized_align) + }; + + // Issue #27023: must add any necessary padding to `size` + // (to make it a multiple of `align`) before returning it. + // + // Namely, the returned size should be, in C notation: + // + // `size + ((size & (align-1)) ? align : 0)` + // + // emulated via the semi-standard fast bit trick: + // + // `(size + (align-1)) & -align` + + let addend = bx.sub(align, C_usize(bx.cx, 1)); + let size = bx.and(bx.add(size, addend), bx.neg(align)); + + (size, align) + } + } +} diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs new file mode 100644 index 00000000000..ba04cc7fad5 --- /dev/null +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -0,0 +1,1465 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_upper_case_globals)] + +use intrinsics::{self, Intrinsic}; +use llvm; +use llvm::{ValueRef}; +use abi::{Abi, FnType, LlvmType, PassMode}; +use mir::place::PlaceRef; +use mir::operand::{OperandRef, OperandValue}; +use base::*; +use common::*; +use declare; +use glue; +use type_::Type; +use type_of::LayoutLlvmExt; +use rustc::ty::{self, Ty}; +use rustc::ty::layout::{HasDataLayout, LayoutOf}; +use rustc::hir; +use syntax::ast; +use syntax::symbol::Symbol; +use builder::Builder; + +use rustc::session::Session; +use syntax_pos::Span; + +use std::cmp::Ordering; +use std::iter; + +fn get_simple_intrinsic(cx: &CodegenCx, name: &str) -> Option { + let llvm_name = match name { + "sqrtf32" => "llvm.sqrt.f32", + "sqrtf64" => "llvm.sqrt.f64", + "powif32" => "llvm.powi.f32", + "powif64" => "llvm.powi.f64", + "sinf32" => "llvm.sin.f32", + "sinf64" => "llvm.sin.f64", + "cosf32" => "llvm.cos.f32", + "cosf64" => "llvm.cos.f64", + "powf32" => "llvm.pow.f32", + "powf64" => "llvm.pow.f64", + "expf32" => "llvm.exp.f32", + "expf64" => "llvm.exp.f64", + "exp2f32" => "llvm.exp2.f32", + "exp2f64" => "llvm.exp2.f64", + "logf32" => "llvm.log.f32", + "logf64" => "llvm.log.f64", + "log10f32" => "llvm.log10.f32", + "log10f64" => "llvm.log10.f64", + "log2f32" => "llvm.log2.f32", + "log2f64" => "llvm.log2.f64", + "fmaf32" => "llvm.fma.f32", + "fmaf64" => "llvm.fma.f64", + "fabsf32" => "llvm.fabs.f32", + "fabsf64" => "llvm.fabs.f64", + "copysignf32" => "llvm.copysign.f32", + "copysignf64" => "llvm.copysign.f64", + "floorf32" => "llvm.floor.f32", + "floorf64" => "llvm.floor.f64", + "ceilf32" => "llvm.ceil.f32", + "ceilf64" => "llvm.ceil.f64", + "truncf32" => "llvm.trunc.f32", + "truncf64" => "llvm.trunc.f64", + "rintf32" => "llvm.rint.f32", + "rintf64" => "llvm.rint.f64", + "nearbyintf32" => "llvm.nearbyint.f32", + "nearbyintf64" => "llvm.nearbyint.f64", + "roundf32" => "llvm.round.f32", + "roundf64" => "llvm.round.f64", + "assume" => "llvm.assume", + "abort" => "llvm.trap", + _ => return None + }; + Some(cx.get_intrinsic(&llvm_name)) +} + +/// Remember to add all intrinsics here, in librustc_typeck/check/mod.rs, +/// and in libcore/intrinsics.rs; if you need access to any llvm intrinsics, +/// add them to librustc_codegen_llvm/context.rs +pub fn codegen_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, + callee_ty: Ty<'tcx>, + fn_ty: &FnType<'tcx, Ty<'tcx>>, + args: &[OperandRef<'tcx>], + llresult: ValueRef, + span: Span) { + let cx = bx.cx; + let tcx = cx.tcx; + + let (def_id, substs) = match callee_ty.sty { + ty::TyFnDef(def_id, substs) => (def_id, substs), + _ => bug!("expected fn item type, found {}", callee_ty) + }; + + let sig = callee_ty.fn_sig(tcx); + let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + let arg_tys = sig.inputs(); + let ret_ty = sig.output(); + let name = &*tcx.item_name(def_id).as_str(); + + let llret_ty = cx.layout_of(ret_ty).llvm_type(cx); + let result = PlaceRef::new_sized(llresult, fn_ty.ret.layout, fn_ty.ret.layout.align); + + let simple = get_simple_intrinsic(cx, name); + let llval = match name { + _ if simple.is_some() => { + bx.call(simple.unwrap(), + &args.iter().map(|arg| arg.immediate()).collect::>(), + None) + } + "unreachable" => { + return; + }, + "likely" => { + let expect = cx.get_intrinsic(&("llvm.expect.i1")); + bx.call(expect, &[args[0].immediate(), C_bool(cx, true)], None) + } + "unlikely" => { + let expect = cx.get_intrinsic(&("llvm.expect.i1")); + bx.call(expect, &[args[0].immediate(), C_bool(cx, false)], None) + } + "try" => { + try_intrinsic(bx, cx, + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + llresult); + return; + } + "breakpoint" => { + let llfn = cx.get_intrinsic(&("llvm.debugtrap")); + bx.call(llfn, &[], None) + } + "size_of" => { + let tp_ty = substs.type_at(0); + C_usize(cx, cx.size_of(tp_ty).bytes()) + } + "size_of_val" => { + let tp_ty = substs.type_at(0); + if let OperandValue::Pair(_, meta) = args[0].val { + let (llsize, _) = + glue::size_and_align_of_dst(bx, tp_ty, meta); + llsize + } else { + C_usize(cx, cx.size_of(tp_ty).bytes()) + } + } + "min_align_of" => { + let tp_ty = substs.type_at(0); + C_usize(cx, cx.align_of(tp_ty).abi()) + } + "min_align_of_val" => { + let tp_ty = substs.type_at(0); + if let OperandValue::Pair(_, meta) = args[0].val { + let (_, llalign) = + glue::size_and_align_of_dst(bx, tp_ty, meta); + llalign + } else { + C_usize(cx, cx.align_of(tp_ty).abi()) + } + } + "pref_align_of" => { + let tp_ty = substs.type_at(0); + C_usize(cx, cx.align_of(tp_ty).pref()) + } + "type_name" => { + let tp_ty = substs.type_at(0); + let ty_name = Symbol::intern(&tp_ty.to_string()).as_str(); + C_str_slice(cx, ty_name) + } + "type_id" => { + C_u64(cx, cx.tcx.type_id_hash(substs.type_at(0))) + } + "init" => { + let ty = substs.type_at(0); + if !cx.layout_of(ty).is_zst() { + // Just zero out the stack slot. + // If we store a zero constant, LLVM will drown in vreg allocation for large data + // structures, and the generated code will be awful. (A telltale sign of this is + // large quantities of `mov [byte ptr foo],0` in the generated code.) + memset_intrinsic(bx, false, ty, llresult, C_u8(cx, 0), C_usize(cx, 1)); + } + return; + } + // Effectively no-ops + "uninit" => { + return; + } + "needs_drop" => { + let tp_ty = substs.type_at(0); + + C_bool(cx, bx.cx.type_needs_drop(tp_ty)) + } + "offset" => { + let ptr = args[0].immediate(); + let offset = args[1].immediate(); + bx.inbounds_gep(ptr, &[offset]) + } + "arith_offset" => { + let ptr = args[0].immediate(); + let offset = args[1].immediate(); + bx.gep(ptr, &[offset]) + } + + "copy_nonoverlapping" => { + copy_intrinsic(bx, false, false, substs.type_at(0), + args[1].immediate(), args[0].immediate(), args[2].immediate()) + } + "copy" => { + copy_intrinsic(bx, true, false, substs.type_at(0), + args[1].immediate(), args[0].immediate(), args[2].immediate()) + } + "write_bytes" => { + memset_intrinsic(bx, false, substs.type_at(0), + args[0].immediate(), args[1].immediate(), args[2].immediate()) + } + + "volatile_copy_nonoverlapping_memory" => { + copy_intrinsic(bx, false, true, substs.type_at(0), + args[0].immediate(), args[1].immediate(), args[2].immediate()) + } + "volatile_copy_memory" => { + copy_intrinsic(bx, true, true, substs.type_at(0), + args[0].immediate(), args[1].immediate(), args[2].immediate()) + } + "volatile_set_memory" => { + memset_intrinsic(bx, true, substs.type_at(0), + args[0].immediate(), args[1].immediate(), args[2].immediate()) + } + "volatile_load" => { + let tp_ty = substs.type_at(0); + let mut ptr = args[0].immediate(); + if let PassMode::Cast(ty) = fn_ty.ret.mode { + ptr = bx.pointercast(ptr, ty.llvm_type(cx).ptr_to()); + } + let load = bx.volatile_load(ptr); + unsafe { + llvm::LLVMSetAlignment(load, cx.align_of(tp_ty).abi() as u32); + } + to_immediate(bx, load, cx.layout_of(tp_ty)) + }, + "volatile_store" => { + let dst = args[0].deref(bx.cx); + args[1].val.volatile_store(bx, dst); + return; + }, + "prefetch_read_data" | "prefetch_write_data" | + "prefetch_read_instruction" | "prefetch_write_instruction" => { + let expect = cx.get_intrinsic(&("llvm.prefetch")); + let (rw, cache_type) = match name { + "prefetch_read_data" => (0, 1), + "prefetch_write_data" => (1, 1), + "prefetch_read_instruction" => (0, 0), + "prefetch_write_instruction" => (1, 0), + _ => bug!() + }; + bx.call(expect, &[ + args[0].immediate(), + C_i32(cx, rw), + args[1].immediate(), + C_i32(cx, cache_type) + ], None) + }, + "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" | + "bitreverse" | "add_with_overflow" | "sub_with_overflow" | + "mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" | + "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" => { + let ty = arg_tys[0]; + match int_type_width_signed(ty, cx) { + Some((width, signed)) => + match name { + "ctlz" | "cttz" => { + let y = C_bool(bx.cx, false); + let llfn = cx.get_intrinsic(&format!("llvm.{}.i{}", name, width)); + bx.call(llfn, &[args[0].immediate(), y], None) + } + "ctlz_nonzero" | "cttz_nonzero" => { + let y = C_bool(bx.cx, true); + let llvm_name = &format!("llvm.{}.i{}", &name[..4], width); + let llfn = cx.get_intrinsic(llvm_name); + bx.call(llfn, &[args[0].immediate(), y], None) + } + "ctpop" => bx.call(cx.get_intrinsic(&format!("llvm.ctpop.i{}", width)), + &[args[0].immediate()], None), + "bswap" => { + if width == 8 { + args[0].immediate() // byte swap a u8/i8 is just a no-op + } else { + bx.call(cx.get_intrinsic(&format!("llvm.bswap.i{}", width)), + &[args[0].immediate()], None) + } + } + "bitreverse" => { + bx.call(cx.get_intrinsic(&format!("llvm.bitreverse.i{}", width)), + &[args[0].immediate()], None) + } + "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => { + let intrinsic = format!("llvm.{}{}.with.overflow.i{}", + if signed { 's' } else { 'u' }, + &name[..3], width); + let llfn = bx.cx.get_intrinsic(&intrinsic); + + // Convert `i1` to a `bool`, and write it to the out parameter + let pair = bx.call(llfn, &[ + args[0].immediate(), + args[1].immediate() + ], None); + let val = bx.extract_value(pair, 0); + let overflow = bx.zext(bx.extract_value(pair, 1), Type::bool(cx)); + + let dest = result.project_field(bx, 0); + bx.store(val, dest.llval, dest.align); + let dest = result.project_field(bx, 1); + bx.store(overflow, dest.llval, dest.align); + + return; + }, + "overflowing_add" => bx.add(args[0].immediate(), args[1].immediate()), + "overflowing_sub" => bx.sub(args[0].immediate(), args[1].immediate()), + "overflowing_mul" => bx.mul(args[0].immediate(), args[1].immediate()), + "exact_div" => + if signed { + bx.exactsdiv(args[0].immediate(), args[1].immediate()) + } else { + bx.exactudiv(args[0].immediate(), args[1].immediate()) + }, + "unchecked_div" => + if signed { + bx.sdiv(args[0].immediate(), args[1].immediate()) + } else { + bx.udiv(args[0].immediate(), args[1].immediate()) + }, + "unchecked_rem" => + if signed { + bx.srem(args[0].immediate(), args[1].immediate()) + } else { + bx.urem(args[0].immediate(), args[1].immediate()) + }, + "unchecked_shl" => bx.shl(args[0].immediate(), args[1].immediate()), + "unchecked_shr" => + if signed { + bx.ashr(args[0].immediate(), args[1].immediate()) + } else { + bx.lshr(args[0].immediate(), args[1].immediate()) + }, + _ => bug!(), + }, + None => { + span_invalid_monomorphization_error( + tcx.sess, span, + &format!("invalid monomorphization of `{}` intrinsic: \ + expected basic integer type, found `{}`", name, ty)); + return; + } + } + + }, + "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { + let sty = &arg_tys[0].sty; + match float_type_width(sty) { + Some(_width) => + match name { + "fadd_fast" => bx.fadd_fast(args[0].immediate(), args[1].immediate()), + "fsub_fast" => bx.fsub_fast(args[0].immediate(), args[1].immediate()), + "fmul_fast" => bx.fmul_fast(args[0].immediate(), args[1].immediate()), + "fdiv_fast" => bx.fdiv_fast(args[0].immediate(), args[1].immediate()), + "frem_fast" => bx.frem_fast(args[0].immediate(), args[1].immediate()), + _ => bug!(), + }, + None => { + span_invalid_monomorphization_error( + tcx.sess, span, + &format!("invalid monomorphization of `{}` intrinsic: \ + expected basic float type, found `{}`", name, sty)); + return; + } + } + + }, + + "discriminant_value" => { + args[0].deref(bx.cx).codegen_get_discr(bx, ret_ty) + } + + "align_offset" => { + // `ptr as usize` + let ptr_val = bx.ptrtoint(args[0].immediate(), bx.cx.isize_ty); + // `ptr_val % align` + let align = args[1].immediate(); + let offset = bx.urem(ptr_val, align); + let zero = C_null(bx.cx.isize_ty); + // `offset == 0` + let is_zero = bx.icmp(llvm::IntPredicate::IntEQ, offset, zero); + // `if offset == 0 { 0 } else { align - offset }` + bx.select(is_zero, zero, bx.sub(align, offset)) + } + name if name.starts_with("simd_") => { + match generic_simd_intrinsic(bx, name, + callee_ty, + args, + ret_ty, llret_ty, + span) { + Ok(llval) => llval, + Err(()) => return + } + } + // This requires that atomic intrinsics follow a specific naming pattern: + // "atomic_[_]", and no ordering means SeqCst + name if name.starts_with("atomic_") => { + use llvm::AtomicOrdering::*; + + let split: Vec<&str> = name.split('_').collect(); + + let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak"; + let (order, failorder) = match split.len() { + 2 => (SequentiallyConsistent, SequentiallyConsistent), + 3 => match split[2] { + "unordered" => (Unordered, Unordered), + "relaxed" => (Monotonic, Monotonic), + "acq" => (Acquire, Acquire), + "rel" => (Release, Monotonic), + "acqrel" => (AcquireRelease, Acquire), + "failrelaxed" if is_cxchg => + (SequentiallyConsistent, Monotonic), + "failacq" if is_cxchg => + (SequentiallyConsistent, Acquire), + _ => cx.sess().fatal("unknown ordering in atomic intrinsic") + }, + 4 => match (split[2], split[3]) { + ("acq", "failrelaxed") if is_cxchg => + (Acquire, Monotonic), + ("acqrel", "failrelaxed") if is_cxchg => + (AcquireRelease, Monotonic), + _ => cx.sess().fatal("unknown ordering in atomic intrinsic") + }, + _ => cx.sess().fatal("Atomic intrinsic not in correct format"), + }; + + let invalid_monomorphization = |ty| { + span_invalid_monomorphization_error(tcx.sess, span, + &format!("invalid monomorphization of `{}` intrinsic: \ + expected basic integer type, found `{}`", name, ty)); + }; + + match split[1] { + "cxchg" | "cxchgweak" => { + let ty = substs.type_at(0); + if int_type_width_signed(ty, cx).is_some() { + let weak = if split[1] == "cxchgweak" { llvm::True } else { llvm::False }; + let pair = bx.atomic_cmpxchg( + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + order, + failorder, + weak); + let val = bx.extract_value(pair, 0); + let success = bx.zext(bx.extract_value(pair, 1), Type::bool(bx.cx)); + + let dest = result.project_field(bx, 0); + bx.store(val, dest.llval, dest.align); + let dest = result.project_field(bx, 1); + bx.store(success, dest.llval, dest.align); + return; + } else { + return invalid_monomorphization(ty); + } + } + + "load" => { + let ty = substs.type_at(0); + if int_type_width_signed(ty, cx).is_some() { + let align = cx.align_of(ty); + bx.atomic_load(args[0].immediate(), order, align) + } else { + return invalid_monomorphization(ty); + } + } + + "store" => { + let ty = substs.type_at(0); + if int_type_width_signed(ty, cx).is_some() { + let align = cx.align_of(ty); + bx.atomic_store(args[1].immediate(), args[0].immediate(), order, align); + return; + } else { + return invalid_monomorphization(ty); + } + } + + "fence" => { + bx.atomic_fence(order, llvm::SynchronizationScope::CrossThread); + return; + } + + "singlethreadfence" => { + bx.atomic_fence(order, llvm::SynchronizationScope::SingleThread); + return; + } + + // These are all AtomicRMW ops + op => { + let atom_op = match op { + "xchg" => llvm::AtomicXchg, + "xadd" => llvm::AtomicAdd, + "xsub" => llvm::AtomicSub, + "and" => llvm::AtomicAnd, + "nand" => llvm::AtomicNand, + "or" => llvm::AtomicOr, + "xor" => llvm::AtomicXor, + "max" => llvm::AtomicMax, + "min" => llvm::AtomicMin, + "umax" => llvm::AtomicUMax, + "umin" => llvm::AtomicUMin, + _ => cx.sess().fatal("unknown atomic operation") + }; + + let ty = substs.type_at(0); + if int_type_width_signed(ty, cx).is_some() { + bx.atomic_rmw(atom_op, args[0].immediate(), args[1].immediate(), order) + } else { + return invalid_monomorphization(ty); + } + } + } + } + + "nontemporal_store" => { + let dst = args[0].deref(bx.cx); + args[1].val.nontemporal_store(bx, dst); + return; + } + + _ => { + let intr = match Intrinsic::find(&name) { + Some(intr) => intr, + None => bug!("unknown intrinsic '{}'", name), + }; + fn one(x: Vec) -> T { + assert_eq!(x.len(), 1); + x.into_iter().next().unwrap() + } + fn ty_to_type(cx: &CodegenCx, t: &intrinsics::Type) -> Vec { + use intrinsics::Type::*; + match *t { + Void => vec![Type::void(cx)], + Integer(_signed, _width, llvm_width) => { + vec![Type::ix(cx, llvm_width as u64)] + } + Float(x) => { + match x { + 32 => vec![Type::f32(cx)], + 64 => vec![Type::f64(cx)], + _ => bug!() + } + } + Pointer(ref t, ref llvm_elem, _const) => { + let t = llvm_elem.as_ref().unwrap_or(t); + let elem = one(ty_to_type(cx, t)); + vec![elem.ptr_to()] + } + Vector(ref t, ref llvm_elem, length) => { + let t = llvm_elem.as_ref().unwrap_or(t); + let elem = one(ty_to_type(cx, t)); + vec![Type::vector(&elem, length as u64)] + } + Aggregate(false, ref contents) => { + let elems = contents.iter() + .map(|t| one(ty_to_type(cx, t))) + .collect::>(); + vec![Type::struct_(cx, &elems, false)] + } + Aggregate(true, ref contents) => { + contents.iter() + .flat_map(|t| ty_to_type(cx, t)) + .collect() + } + } + } + + // This allows an argument list like `foo, (bar, baz), + // qux` to be converted into `foo, bar, baz, qux`, integer + // arguments to be truncated as needed and pointers to be + // cast. + fn modify_as_needed<'a, 'tcx>(bx: &Builder<'a, 'tcx>, + t: &intrinsics::Type, + arg: &OperandRef<'tcx>) + -> Vec + { + match *t { + intrinsics::Type::Aggregate(true, ref contents) => { + // We found a tuple that needs squishing! So + // run over the tuple and load each field. + // + // This assumes the type is "simple", i.e. no + // destructors, and the contents are SIMD + // etc. + assert!(!bx.cx.type_needs_drop(arg.layout.ty)); + let (ptr, align) = match arg.val { + OperandValue::Ref(ptr, align) => (ptr, align), + _ => bug!() + }; + let arg = PlaceRef::new_sized(ptr, arg.layout, align); + (0..contents.len()).map(|i| { + arg.project_field(bx, i).load(bx).immediate() + }).collect() + } + intrinsics::Type::Pointer(_, Some(ref llvm_elem), _) => { + let llvm_elem = one(ty_to_type(bx.cx, llvm_elem)); + vec![bx.pointercast(arg.immediate(), llvm_elem.ptr_to())] + } + intrinsics::Type::Vector(_, Some(ref llvm_elem), length) => { + let llvm_elem = one(ty_to_type(bx.cx, llvm_elem)); + vec![bx.bitcast(arg.immediate(), Type::vector(&llvm_elem, length as u64))] + } + intrinsics::Type::Integer(_, width, llvm_width) if width != llvm_width => { + // the LLVM intrinsic uses a smaller integer + // size than the C intrinsic's signature, so + // we have to trim it down here. + vec![bx.trunc(arg.immediate(), Type::ix(bx.cx, llvm_width as u64))] + } + _ => vec![arg.immediate()], + } + } + + + let inputs = intr.inputs.iter() + .flat_map(|t| ty_to_type(cx, t)) + .collect::>(); + + let outputs = one(ty_to_type(cx, &intr.output)); + + let llargs: Vec<_> = intr.inputs.iter().zip(args).flat_map(|(t, arg)| { + modify_as_needed(bx, t, arg) + }).collect(); + assert_eq!(inputs.len(), llargs.len()); + + let val = match intr.definition { + intrinsics::IntrinsicDef::Named(name) => { + let f = declare::declare_cfn(cx, + name, + Type::func(&inputs, &outputs)); + bx.call(f, &llargs, None) + } + }; + + match *intr.output { + intrinsics::Type::Aggregate(flatten, ref elems) => { + // the output is a tuple so we need to munge it properly + assert!(!flatten); + + for i in 0..elems.len() { + let dest = result.project_field(bx, i); + let val = bx.extract_value(val, i as u64); + bx.store(val, dest.llval, dest.align); + } + return; + } + _ => val, + } + } + }; + + if !fn_ty.ret.is_ignore() { + if let PassMode::Cast(ty) = fn_ty.ret.mode { + let ptr = bx.pointercast(result.llval, ty.llvm_type(cx).ptr_to()); + bx.store(llval, ptr, result.align); + } else { + OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout) + .val.store(bx, result); + } + } +} + +fn copy_intrinsic<'a, 'tcx>(bx: &Builder<'a, 'tcx>, + allow_overlap: bool, + volatile: bool, + ty: Ty<'tcx>, + dst: ValueRef, + src: ValueRef, + count: ValueRef) + -> ValueRef { + let cx = bx.cx; + let (size, align) = cx.size_and_align_of(ty); + let size = C_usize(cx, size.bytes()); + let align = C_i32(cx, align.abi() as i32); + + let operation = if allow_overlap { + "memmove" + } else { + "memcpy" + }; + + let name = format!("llvm.{}.p0i8.p0i8.i{}", operation, + cx.data_layout().pointer_size.bits()); + + let dst_ptr = bx.pointercast(dst, Type::i8p(cx)); + let src_ptr = bx.pointercast(src, Type::i8p(cx)); + let llfn = cx.get_intrinsic(&name); + + bx.call(llfn, + &[dst_ptr, + src_ptr, + bx.mul(size, count), + align, + C_bool(cx, volatile)], + None) +} + +fn memset_intrinsic<'a, 'tcx>( + bx: &Builder<'a, 'tcx>, + volatile: bool, + ty: Ty<'tcx>, + dst: ValueRef, + val: ValueRef, + count: ValueRef +) -> ValueRef { + let cx = bx.cx; + let (size, align) = cx.size_and_align_of(ty); + let size = C_usize(cx, size.bytes()); + let align = C_i32(cx, align.abi() as i32); + let dst = bx.pointercast(dst, Type::i8p(cx)); + call_memset(bx, dst, val, bx.mul(size, count), align, volatile) +} + +fn try_intrinsic<'a, 'tcx>( + bx: &Builder<'a, 'tcx>, + cx: &CodegenCx, + func: ValueRef, + data: ValueRef, + local_ptr: ValueRef, + dest: ValueRef, +) { + if bx.sess().no_landing_pads() { + bx.call(func, &[data], None); + let ptr_align = bx.tcx().data_layout.pointer_align; + bx.store(C_null(Type::i8p(&bx.cx)), dest, ptr_align); + } else if wants_msvc_seh(bx.sess()) { + codegen_msvc_try(bx, cx, func, data, local_ptr, dest); + } else { + codegen_gnu_try(bx, cx, func, data, local_ptr, dest); + } +} + +// MSVC's definition of the `rust_try` function. +// +// This implementation uses the new exception handling instructions in LLVM +// which have support in LLVM for SEH on MSVC targets. Although these +// instructions are meant to work for all targets, as of the time of this +// writing, however, LLVM does not recommend the usage of these new instructions +// as the old ones are still more optimized. +fn codegen_msvc_try<'a, 'tcx>(bx: &Builder<'a, 'tcx>, + cx: &CodegenCx, + func: ValueRef, + data: ValueRef, + local_ptr: ValueRef, + dest: ValueRef) { + let llfn = get_rust_try_fn(cx, &mut |bx| { + let cx = bx.cx; + + bx.set_personality_fn(bx.cx.eh_personality()); + + let normal = bx.build_sibling_block("normal"); + let catchswitch = bx.build_sibling_block("catchswitch"); + let catchpad = bx.build_sibling_block("catchpad"); + let caught = bx.build_sibling_block("caught"); + + let func = llvm::get_param(bx.llfn(), 0); + let data = llvm::get_param(bx.llfn(), 1); + let local_ptr = llvm::get_param(bx.llfn(), 2); + + // We're generating an IR snippet that looks like: + // + // declare i32 @rust_try(%func, %data, %ptr) { + // %slot = alloca i64* + // invoke %func(%data) to label %normal unwind label %catchswitch + // + // normal: + // ret i32 0 + // + // catchswitch: + // %cs = catchswitch within none [%catchpad] unwind to caller + // + // catchpad: + // %tok = catchpad within %cs [%type_descriptor, 0, %slot] + // %ptr[0] = %slot[0] + // %ptr[1] = %slot[1] + // catchret from %tok to label %caught + // + // caught: + // ret i32 1 + // } + // + // This structure follows the basic usage of throw/try/catch in LLVM. + // For example, compile this C++ snippet to see what LLVM generates: + // + // #include + // + // int bar(void (*foo)(void), uint64_t *ret) { + // try { + // foo(); + // return 0; + // } catch(uint64_t a[2]) { + // ret[0] = a[0]; + // ret[1] = a[1]; + // return 1; + // } + // } + // + // More information can be found in libstd's seh.rs implementation. + let i64p = Type::i64(cx).ptr_to(); + let ptr_align = bx.tcx().data_layout.pointer_align; + let slot = bx.alloca(i64p, "slot", ptr_align); + bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), + None); + + normal.ret(C_i32(cx, 0)); + + let cs = catchswitch.catch_switch(None, None, 1); + catchswitch.add_handler(cs, catchpad.llbb()); + + let tcx = cx.tcx; + let tydesc = match tcx.lang_items().msvc_try_filter() { + Some(did) => ::consts::get_static(cx, did), + None => bug!("msvc_try_filter not defined"), + }; + let tok = catchpad.catch_pad(cs, &[tydesc, C_i32(cx, 0), slot]); + let addr = catchpad.load(slot, ptr_align); + + let i64_align = bx.tcx().data_layout.i64_align; + let arg1 = catchpad.load(addr, i64_align); + let val1 = C_i32(cx, 1); + let arg2 = catchpad.load(catchpad.inbounds_gep(addr, &[val1]), i64_align); + let local_ptr = catchpad.bitcast(local_ptr, i64p); + catchpad.store(arg1, local_ptr, i64_align); + catchpad.store(arg2, catchpad.inbounds_gep(local_ptr, &[val1]), i64_align); + catchpad.catch_ret(tok, caught.llbb()); + + caught.ret(C_i32(cx, 1)); + }); + + // Note that no invoke is used here because by definition this function + // can't panic (that's what it's catching). + let ret = bx.call(llfn, &[func, data, local_ptr], None); + let i32_align = bx.tcx().data_layout.i32_align; + bx.store(ret, dest, i32_align); +} + +// Definition of the standard "try" function for Rust using the GNU-like model +// of exceptions (e.g. the normal semantics of LLVM's landingpad and invoke +// instructions). +// +// This codegen is a little surprising because we always call a shim +// function instead of inlining the call to `invoke` manually here. This is done +// because in LLVM we're only allowed to have one personality per function +// definition. The call to the `try` intrinsic is being inlined into the +// function calling it, and that function may already have other personality +// functions in play. By calling a shim we're guaranteed that our shim will have +// the right personality function. +fn codegen_gnu_try<'a, 'tcx>(bx: &Builder<'a, 'tcx>, + cx: &CodegenCx, + func: ValueRef, + data: ValueRef, + local_ptr: ValueRef, + dest: ValueRef) { + let llfn = get_rust_try_fn(cx, &mut |bx| { + let cx = bx.cx; + + // Codegens the shims described above: + // + // bx: + // invoke %func(%args...) normal %normal unwind %catch + // + // normal: + // ret 0 + // + // catch: + // (ptr, _) = landingpad + // store ptr, %local_ptr + // ret 1 + // + // Note that the `local_ptr` data passed into the `try` intrinsic is + // expected to be `*mut *mut u8` for this to actually work, but that's + // managed by the standard library. + + let then = bx.build_sibling_block("then"); + let catch = bx.build_sibling_block("catch"); + + let func = llvm::get_param(bx.llfn(), 0); + let data = llvm::get_param(bx.llfn(), 1); + let local_ptr = llvm::get_param(bx.llfn(), 2); + bx.invoke(func, &[data], then.llbb(), catch.llbb(), None); + then.ret(C_i32(cx, 0)); + + // Type indicator for the exception being thrown. + // + // The first value in this tuple is a pointer to the exception object + // being thrown. The second value is a "selector" indicating which of + // the landing pad clauses the exception's type had been matched to. + // rust_try ignores the selector. + let lpad_ty = Type::struct_(cx, &[Type::i8p(cx), Type::i32(cx)], + false); + let vals = catch.landing_pad(lpad_ty, bx.cx.eh_personality(), 1); + catch.add_clause(vals, C_null(Type::i8p(cx))); + let ptr = catch.extract_value(vals, 0); + let ptr_align = bx.tcx().data_layout.pointer_align; + catch.store(ptr, catch.bitcast(local_ptr, Type::i8p(cx).ptr_to()), ptr_align); + catch.ret(C_i32(cx, 1)); + }); + + // Note that no invoke is used here because by definition this function + // can't panic (that's what it's catching). + let ret = bx.call(llfn, &[func, data, local_ptr], None); + let i32_align = bx.tcx().data_layout.i32_align; + bx.store(ret, dest, i32_align); +} + +// Helper function to give a Block to a closure to codegen a shim function. +// This is currently primarily used for the `try` intrinsic functions above. +fn gen_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + name: &str, + inputs: Vec>, + output: Ty<'tcx>, + codegen: &mut for<'b> FnMut(Builder<'b, 'tcx>)) + -> ValueRef { + let rust_fn_ty = cx.tcx.mk_fn_ptr(ty::Binder::bind(cx.tcx.mk_fn_sig( + inputs.into_iter(), + output, + false, + hir::Unsafety::Unsafe, + Abi::Rust + ))); + let llfn = declare::define_internal_fn(cx, name, rust_fn_ty); + let bx = Builder::new_block(cx, llfn, "entry-block"); + codegen(bx); + llfn +} + +// Helper function used to get a handle to the `__rust_try` function used to +// catch exceptions. +// +// This function is only generated once and is then cached. +fn get_rust_try_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + codegen: &mut for<'b> FnMut(Builder<'b, 'tcx>)) + -> ValueRef { + if let Some(llfn) = cx.rust_try_fn.get() { + return llfn; + } + + // Define the type up front for the signature of the rust_try function. + let tcx = cx.tcx; + let i8p = tcx.mk_mut_ptr(tcx.types.i8); + let fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( + iter::once(i8p), + tcx.mk_nil(), + false, + hir::Unsafety::Unsafe, + Abi::Rust + ))); + let output = tcx.types.i32; + let rust_try = gen_fn(cx, "__rust_try", vec![fn_ty, i8p, i8p], output, codegen); + cx.rust_try_fn.set(Some(rust_try)); + return rust_try +} + +fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) { + span_err!(a, b, E0511, "{}", c); +} + +fn generic_simd_intrinsic<'a, 'tcx>( + bx: &Builder<'a, 'tcx>, + name: &str, + callee_ty: Ty<'tcx>, + args: &[OperandRef<'tcx>], + ret_ty: Ty<'tcx>, + llret_ty: Type, + span: Span +) -> Result { + // macros for error handling: + macro_rules! emit_error { + ($msg: tt) => { + emit_error!($msg, ) + }; + ($msg: tt, $($fmt: tt)*) => { + span_invalid_monomorphization_error( + bx.sess(), span, + &format!(concat!("invalid monomorphization of `{}` intrinsic: ", + $msg), + name, $($fmt)*)); + } + } + macro_rules! return_error { + ($($fmt: tt)*) => { + { + emit_error!($($fmt)*); + return Err(()); + } + } + } + + macro_rules! require { + ($cond: expr, $($fmt: tt)*) => { + if !$cond { + return_error!($($fmt)*); + } + }; + } + macro_rules! require_simd { + ($ty: expr, $position: expr) => { + require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty) + } + } + + + + let tcx = bx.tcx(); + let sig = tcx.normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &callee_ty.fn_sig(tcx), + ); + let arg_tys = sig.inputs(); + + // every intrinsic takes a SIMD vector as its first argument + require_simd!(arg_tys[0], "input"); + let in_ty = arg_tys[0]; + let in_elem = arg_tys[0].simd_type(tcx); + let in_len = arg_tys[0].simd_size(tcx); + + let comparison = match name { + "simd_eq" => Some(hir::BiEq), + "simd_ne" => Some(hir::BiNe), + "simd_lt" => Some(hir::BiLt), + "simd_le" => Some(hir::BiLe), + "simd_gt" => Some(hir::BiGt), + "simd_ge" => Some(hir::BiGe), + _ => None + }; + + if let Some(cmp_op) = comparison { + require_simd!(ret_ty, "return"); + + let out_len = ret_ty.simd_size(tcx); + require!(in_len == out_len, + "expected return type with length {} (same as input type `{}`), \ + found `{}` with length {}", + in_len, in_ty, + ret_ty, out_len); + require!(llret_ty.element_type().kind() == llvm::Integer, + "expected return type with integer elements, found `{}` with non-integer `{}`", + ret_ty, + ret_ty.simd_type(tcx)); + + return Ok(compare_simd_types(bx, + args[0].immediate(), + args[1].immediate(), + in_elem, + llret_ty, + cmp_op)) + } + + if name.starts_with("simd_shuffle") { + let n: usize = match name["simd_shuffle".len()..].parse() { + Ok(n) => n, + Err(_) => span_bug!(span, + "bad `simd_shuffle` instruction only caught in codegen?") + }; + + require_simd!(ret_ty, "return"); + + let out_len = ret_ty.simd_size(tcx); + require!(out_len == n, + "expected return type of length {}, found `{}` with length {}", + n, ret_ty, out_len); + require!(in_elem == ret_ty.simd_type(tcx), + "expected return element type `{}` (element of input `{}`), \ + found `{}` with element type `{}`", + in_elem, in_ty, + ret_ty, ret_ty.simd_type(tcx)); + + let total_len = in_len as u128 * 2; + + let vector = args[2].immediate(); + + let indices: Option> = (0..n) + .map(|i| { + let arg_idx = i; + let val = const_get_elt(vector, i as u64); + match const_to_opt_u128(val, true) { + None => { + emit_error!("shuffle index #{} is not a constant", arg_idx); + None + } + Some(idx) if idx >= total_len => { + emit_error!("shuffle index #{} is out of bounds (limit {})", + arg_idx, total_len); + None + } + Some(idx) => Some(C_i32(bx.cx, idx as i32)), + } + }) + .collect(); + let indices = match indices { + Some(i) => i, + None => return Ok(C_null(llret_ty)) + }; + + return Ok(bx.shuffle_vector(args[0].immediate(), + args[1].immediate(), + C_vector(&indices))) + } + + if name == "simd_insert" { + require!(in_elem == arg_tys[2], + "expected inserted type `{}` (element of input `{}`), found `{}`", + in_elem, in_ty, arg_tys[2]); + return Ok(bx.insert_element(args[0].immediate(), + args[2].immediate(), + args[1].immediate())) + } + if name == "simd_extract" { + require!(ret_ty == in_elem, + "expected return type `{}` (element of input `{}`), found `{}`", + in_elem, in_ty, ret_ty); + return Ok(bx.extract_element(args[0].immediate(), args[1].immediate())) + } + + if name == "simd_select" { + let m_elem_ty = in_elem; + let m_len = in_len; + let v_len = arg_tys[1].simd_size(tcx); + require!(m_len == v_len, + "mismatched lengths: mask length `{}` != other vector length `{}`", + m_len, v_len + ); + match m_elem_ty.sty { + ty::TyInt(_) => {}, + _ => { + return_error!("mask element type is `{}`, expected `i_`", m_elem_ty); + } + } + // truncate the mask to a vector of i1s + let i1 = Type::i1(bx.cx); + let i1xn = Type::vector(&i1, m_len as u64); + let m_i1s = bx.trunc(args[0].immediate(), i1xn); + return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); + } + + macro_rules! arith_red { + ($name:tt : $integer_reduce:ident, $float_reduce:ident, $ordered:expr) => { + if name == $name { + require!(ret_ty == in_elem, + "expected return type `{}` (element of input `{}`), found `{}`", + in_elem, in_ty, ret_ty); + return match in_elem.sty { + ty::TyInt(_) | ty::TyUint(_) => { + let r = bx.$integer_reduce(args[0].immediate()); + if $ordered { + // if overflow occurs, the result is the + // mathematical result modulo 2^n: + if name.contains("mul") { + Ok(bx.mul(args[1].immediate(), r)) + } else { + Ok(bx.add(args[1].immediate(), r)) + } + } else { + Ok(bx.$integer_reduce(args[0].immediate())) + } + }, + ty::TyFloat(f) => { + // ordered arithmetic reductions take an accumulator + let acc = if $ordered { + let acc = args[1].immediate(); + // FIXME: https://bugs.llvm.org/show_bug.cgi?id=36734 + // * if the accumulator of the fadd isn't 0, incorrect + // code is generated + // * if the accumulator of the fmul isn't 1, incorrect + // code is generated + match const_get_real(acc) { + None => return_error!("accumulator of {} is not a constant", $name), + Some((v, loses_info)) => { + if $name.contains("mul") && v != 1.0_f64 { + return_error!("accumulator of {} is not 1.0", $name); + } else if $name.contains("add") && v != 0.0_f64 { + return_error!("accumulator of {} is not 0.0", $name); + } else if loses_info { + return_error!("accumulator of {} loses information", $name); + } + } + } + acc + } else { + // unordered arithmetic reductions do not: + match f.bit_width() { + 32 => C_undef(Type::f32(bx.cx)), + 64 => C_undef(Type::f64(bx.cx)), + v => { + return_error!(r#" +unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, + $name, in_ty, in_elem, v, ret_ty + ) + } + } + + }; + Ok(bx.$float_reduce(acc, args[0].immediate())) + } + _ => { + return_error!( + "unsupported {} from `{}` with element `{}` to `{}`", + $name, in_ty, in_elem, ret_ty + ) + }, + } + } + } + } + + arith_red!("simd_reduce_add_ordered": vector_reduce_add, vector_reduce_fadd_fast, true); + arith_red!("simd_reduce_mul_ordered": vector_reduce_mul, vector_reduce_fmul_fast, true); + arith_red!("simd_reduce_add_unordered": vector_reduce_add, vector_reduce_fadd_fast, false); + arith_red!("simd_reduce_mul_unordered": vector_reduce_mul, vector_reduce_fmul_fast, false); + + macro_rules! minmax_red { + ($name:tt: $int_red:ident, $float_red:ident) => { + if name == $name { + require!(ret_ty == in_elem, + "expected return type `{}` (element of input `{}`), found `{}`", + in_elem, in_ty, ret_ty); + return match in_elem.sty { + ty::TyInt(_i) => { + Ok(bx.$int_red(args[0].immediate(), true)) + }, + ty::TyUint(_u) => { + Ok(bx.$int_red(args[0].immediate(), false)) + }, + ty::TyFloat(_f) => { + Ok(bx.$float_red(args[0].immediate())) + } + _ => { + return_error!("unsupported {} from `{}` with element `{}` to `{}`", + $name, in_ty, in_elem, ret_ty) + }, + } + } + + } + } + + minmax_red!("simd_reduce_min": vector_reduce_min, vector_reduce_fmin); + minmax_red!("simd_reduce_max": vector_reduce_max, vector_reduce_fmax); + + minmax_red!("simd_reduce_min_nanless": vector_reduce_min, vector_reduce_fmin_fast); + minmax_red!("simd_reduce_max_nanless": vector_reduce_max, vector_reduce_fmax_fast); + + macro_rules! bitwise_red { + ($name:tt : $red:ident, $boolean:expr) => { + if name == $name { + let input = if !$boolean { + require!(ret_ty == in_elem, + "expected return type `{}` (element of input `{}`), found `{}`", + in_elem, in_ty, ret_ty); + args[0].immediate() + } else { + match in_elem.sty { + ty::TyInt(_) | ty::TyUint(_) => {}, + _ => { + return_error!("unsupported {} from `{}` with element `{}` to `{}`", + $name, in_ty, in_elem, ret_ty) + } + } + + // boolean reductions operate on vectors of i1s: + let i1 = Type::i1(bx.cx); + let i1xn = Type::vector(&i1, in_len as u64); + bx.trunc(args[0].immediate(), i1xn) + }; + return match in_elem.sty { + ty::TyInt(_) | ty::TyUint(_) => { + let r = bx.$red(input); + Ok( + if !$boolean { + r + } else { + bx.zext(r, Type::bool(bx.cx)) + } + ) + }, + _ => { + return_error!("unsupported {} from `{}` with element `{}` to `{}`", + $name, in_ty, in_elem, ret_ty) + }, + } + } + } + } + + bitwise_red!("simd_reduce_and": vector_reduce_and, false); + bitwise_red!("simd_reduce_or": vector_reduce_or, false); + bitwise_red!("simd_reduce_xor": vector_reduce_xor, false); + bitwise_red!("simd_reduce_all": vector_reduce_and, true); + bitwise_red!("simd_reduce_any": vector_reduce_or, true); + + if name == "simd_cast" { + require_simd!(ret_ty, "return"); + let out_len = ret_ty.simd_size(tcx); + require!(in_len == out_len, + "expected return type with length {} (same as input type `{}`), \ + found `{}` with length {}", + in_len, in_ty, + ret_ty, out_len); + // casting cares about nominal type, not just structural type + let out_elem = ret_ty.simd_type(tcx); + + if in_elem == out_elem { return Ok(args[0].immediate()); } + + enum Style { Float, Int(/* is signed? */ bool), Unsupported } + + let (in_style, in_width) = match in_elem.sty { + // vectors of pointer-sized integers should've been + // disallowed before here, so this unwrap is safe. + ty::TyInt(i) => (Style::Int(true), i.bit_width().unwrap()), + ty::TyUint(u) => (Style::Int(false), u.bit_width().unwrap()), + ty::TyFloat(f) => (Style::Float, f.bit_width()), + _ => (Style::Unsupported, 0) + }; + let (out_style, out_width) = match out_elem.sty { + ty::TyInt(i) => (Style::Int(true), i.bit_width().unwrap()), + ty::TyUint(u) => (Style::Int(false), u.bit_width().unwrap()), + ty::TyFloat(f) => (Style::Float, f.bit_width()), + _ => (Style::Unsupported, 0) + }; + + match (in_style, out_style) { + (Style::Int(in_is_signed), Style::Int(_)) => { + return Ok(match in_width.cmp(&out_width) { + Ordering::Greater => bx.trunc(args[0].immediate(), llret_ty), + Ordering::Equal => args[0].immediate(), + Ordering::Less => if in_is_signed { + bx.sext(args[0].immediate(), llret_ty) + } else { + bx.zext(args[0].immediate(), llret_ty) + } + }) + } + (Style::Int(in_is_signed), Style::Float) => { + return Ok(if in_is_signed { + bx.sitofp(args[0].immediate(), llret_ty) + } else { + bx.uitofp(args[0].immediate(), llret_ty) + }) + } + (Style::Float, Style::Int(out_is_signed)) => { + return Ok(if out_is_signed { + bx.fptosi(args[0].immediate(), llret_ty) + } else { + bx.fptoui(args[0].immediate(), llret_ty) + }) + } + (Style::Float, Style::Float) => { + return Ok(match in_width.cmp(&out_width) { + Ordering::Greater => bx.fptrunc(args[0].immediate(), llret_ty), + Ordering::Equal => args[0].immediate(), + Ordering::Less => bx.fpext(args[0].immediate(), llret_ty) + }) + } + _ => {/* Unsupported. Fallthrough. */} + } + require!(false, + "unsupported cast from `{}` with element `{}` to `{}` with element `{}`", + in_ty, in_elem, + ret_ty, out_elem); + } + macro_rules! arith { + ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => { + $(if name == stringify!($name) { + match in_elem.sty { + $($(ty::$p(_))|* => { + return Ok(bx.$call(args[0].immediate(), args[1].immediate())) + })* + _ => {}, + } + require!(false, + "unsupported operation on `{}` with element `{}`", + in_ty, + in_elem) + })* + } + } + arith! { + simd_add: TyUint, TyInt => add, TyFloat => fadd; + simd_sub: TyUint, TyInt => sub, TyFloat => fsub; + simd_mul: TyUint, TyInt => mul, TyFloat => fmul; + simd_div: TyUint => udiv, TyInt => sdiv, TyFloat => fdiv; + simd_rem: TyUint => urem, TyInt => srem, TyFloat => frem; + simd_shl: TyUint, TyInt => shl; + simd_shr: TyUint => lshr, TyInt => ashr; + simd_and: TyUint, TyInt => and; + simd_or: TyUint, TyInt => or; + simd_xor: TyUint, TyInt => xor; + simd_fmax: TyFloat => maxnum; + simd_fmin: TyFloat => minnum; + } + span_bug!(span, "unknown SIMD intrinsic"); +} + +// Returns the width of an int Ty, and if it's signed or not +// Returns None if the type is not an integer +// FIXME: there’s multiple of this functions, investigate using some of the already existing +// stuffs. +fn int_type_width_signed(ty: Ty, cx: &CodegenCx) -> Option<(u64, bool)> { + match ty.sty { + ty::TyInt(t) => Some((match t { + ast::IntTy::Isize => { + match &cx.tcx.sess.target.target.target_pointer_width[..] { + "16" => 16, + "32" => 32, + "64" => 64, + tws => bug!("Unsupported target word size for isize: {}", tws), + } + }, + ast::IntTy::I8 => 8, + ast::IntTy::I16 => 16, + ast::IntTy::I32 => 32, + ast::IntTy::I64 => 64, + ast::IntTy::I128 => 128, + }, true)), + ty::TyUint(t) => Some((match t { + ast::UintTy::Usize => { + match &cx.tcx.sess.target.target.target_pointer_width[..] { + "16" => 16, + "32" => 32, + "64" => 64, + tws => bug!("Unsupported target word size for usize: {}", tws), + } + }, + ast::UintTy::U8 => 8, + ast::UintTy::U16 => 16, + ast::UintTy::U32 => 32, + ast::UintTy::U64 => 64, + ast::UintTy::U128 => 128, + }, false)), + _ => None, + } +} + +// Returns the width of a float TypeVariant +// Returns None if the type is not a float +fn float_type_width<'tcx>(sty: &ty::TypeVariants<'tcx>) + -> Option { + use rustc::ty::TyFloat; + match *sty { + TyFloat(t) => Some(match t { + ast::FloatTy::F32 => 32, + ast::FloatTy::F64 => 64, + }), + _ => None, + } +} diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs new file mode 100644 index 00000000000..bd053da4bd3 --- /dev/null +++ b/src/librustc_codegen_llvm/lib.rs @@ -0,0 +1,392 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Rust compiler. +//! +//! # Note +//! +//! This API is completely unstable and subject to change. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/")] + +#![feature(box_patterns)] +#![feature(box_syntax)] +#![feature(custom_attribute)] +#![feature(fs_read_write)] +#![allow(unused_attributes)] +#![feature(libc)] +#![feature(quote)] +#![feature(range_contains)] +#![feature(rustc_diagnostic_macros)] +#![feature(slice_sort_by_cached_key)] +#![feature(optin_builtin_traits)] +#![feature(inclusive_range_methods)] + +use rustc::dep_graph::WorkProduct; +use syntax_pos::symbol::Symbol; + +#[macro_use] extern crate bitflags; +extern crate flate2; +extern crate libc; +#[macro_use] extern crate rustc; +extern crate jobserver; +extern crate num_cpus; +extern crate rustc_mir; +extern crate rustc_allocator; +extern crate rustc_apfloat; +extern crate rustc_target; +#[macro_use] extern crate rustc_data_structures; +extern crate rustc_demangle; +extern crate rustc_incremental; +extern crate rustc_llvm as llvm; +extern crate rustc_platform_intrinsics as intrinsics; +extern crate rustc_codegen_utils; + +#[macro_use] extern crate log; +#[macro_use] extern crate syntax; +extern crate syntax_pos; +extern crate rustc_errors as errors; +extern crate serialize; +extern crate cc; // Used to locate MSVC +extern crate tempdir; + +use back::bytecode::RLIB_BYTECODE_EXTENSION; + +pub use llvm_util::target_features; + +use std::any::Any; +use std::path::PathBuf; +use std::sync::mpsc; +use std::collections::BTreeMap; +use rustc_data_structures::sync::Lrc; + +use rustc::dep_graph::DepGraph; +use rustc::hir::def_id::CrateNum; +use rustc::middle::cstore::MetadataLoader; +use rustc::middle::cstore::{NativeLibrary, CrateSource, LibSource}; +use rustc::middle::lang_items::LangItem; +use rustc::session::{Session, CompileIncomplete}; +use rustc::session::config::{OutputFilenames, OutputType, PrintRequest}; +use rustc::ty::{self, TyCtxt}; +use rustc::util::nodemap::{FxHashSet, FxHashMap}; +use rustc_mir::monomorphize; +use rustc_codegen_utils::codegen_backend::CodegenBackend; + +mod diagnostics; + +mod back { + pub use rustc_codegen_utils::symbol_names; + mod archive; + pub mod bytecode; + mod command; + pub mod linker; + pub mod link; + mod lto; + pub mod symbol_export; + pub mod write; + mod rpath; + mod wasm; +} + +mod abi; +mod allocator; +mod asm; +mod attributes; +mod base; +mod builder; +mod callee; +mod common; +mod consts; +mod context; +mod debuginfo; +mod declare; +mod glue; +mod intrinsic; +mod llvm_util; +mod metadata; +mod meth; +mod mir; +mod time_graph; +mod mono_item; +mod type_; +mod type_of; +mod value; + +pub struct LlvmCodegenBackend(()); + +impl !Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis +impl !Sync for LlvmCodegenBackend {} + +impl LlvmCodegenBackend { + pub fn new() -> Box { + box LlvmCodegenBackend(()) + } +} + +impl CodegenBackend for LlvmCodegenBackend { + fn init(&self, sess: &Session) { + llvm_util::init(sess); // Make sure llvm is inited + } + + fn print(&self, req: PrintRequest, sess: &Session) { + match req { + PrintRequest::RelocationModels => { + println!("Available relocation models:"); + for &(name, _) in back::write::RELOC_MODEL_ARGS.iter() { + println!(" {}", name); + } + println!(""); + } + PrintRequest::CodeModels => { + println!("Available code models:"); + for &(name, _) in back::write::CODE_GEN_MODEL_ARGS.iter(){ + println!(" {}", name); + } + println!(""); + } + PrintRequest::TlsModels => { + println!("Available TLS models:"); + for &(name, _) in back::write::TLS_MODEL_ARGS.iter(){ + println!(" {}", name); + } + println!(""); + } + req => llvm_util::print(req, sess), + } + } + + fn print_passes(&self) { + llvm_util::print_passes(); + } + + fn print_version(&self) { + llvm_util::print_version(); + } + + fn diagnostics(&self) -> &[(&'static str, &'static str)] { + &DIAGNOSTICS + } + + fn target_features(&self, sess: &Session) -> Vec { + target_features(sess) + } + + fn metadata_loader(&self) -> Box { + box metadata::LlvmMetadataLoader + } + + fn provide(&self, providers: &mut ty::maps::Providers) { + back::symbol_names::provide(providers); + back::symbol_export::provide(providers); + base::provide(providers); + attributes::provide(providers); + } + + fn provide_extern(&self, providers: &mut ty::maps::Providers) { + back::symbol_export::provide_extern(providers); + base::provide_extern(providers); + attributes::provide_extern(providers); + } + + fn codegen_crate<'a, 'tcx>( + &self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + rx: mpsc::Receiver> + ) -> Box { + box base::codegen_crate(tcx, rx) + } + + fn join_codegen_and_link( + &self, + ongoing_codegen: Box, + sess: &Session, + dep_graph: &DepGraph, + outputs: &OutputFilenames, + ) -> Result<(), CompileIncomplete>{ + use rustc::util::common::time; + let (ongoing_codegen, work_products) = + ongoing_codegen.downcast::<::back::write::OngoingCodegen>() + .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box") + .join(sess); + if sess.opts.debugging_opts.incremental_info { + back::write::dump_incremental_data(&ongoing_codegen); + } + + time(sess, + "serialize work products", + move || rustc_incremental::save_work_product_index(sess, &dep_graph, work_products)); + + sess.compile_status()?; + + if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe || + i == OutputType::Metadata) { + return Ok(()); + } + + // Run the linker on any artifacts that resulted from the LLVM run. + // This should produce either a finished executable or library. + time(sess, "linking", || { + back::link::link_binary(sess, &ongoing_codegen, + outputs, &ongoing_codegen.crate_name.as_str()); + }); + + // Now that we won't touch anything in the incremental compilation directory + // any more, we can finalize it (which involves renaming it) + rustc_incremental::finalize_session_directory(sess, ongoing_codegen.link.crate_hash); + + Ok(()) + } +} + +/// This is the entrypoint for a hot plugged rustc_codegen_llvm +#[no_mangle] +pub fn __rustc_codegen_backend() -> Box { + LlvmCodegenBackend::new() +} + +struct ModuleCodegen { + /// The name of the module. When the crate may be saved between + /// compilations, incremental compilation requires that name be + /// unique amongst **all** crates. Therefore, it should contain + /// something unique to this crate (e.g., a module path) as well + /// as the crate name and disambiguator. + name: String, + llmod_id: String, + source: ModuleSource, + kind: ModuleKind, +} + +#[derive(Copy, Clone, Debug, PartialEq)] +enum ModuleKind { + Regular, + Metadata, + Allocator, +} + +impl ModuleCodegen { + fn llvm(&self) -> Option<&ModuleLlvm> { + match self.source { + ModuleSource::Codegened(ref llvm) => Some(llvm), + ModuleSource::Preexisting(_) => None, + } + } + + fn into_compiled_module(self, + emit_obj: bool, + emit_bc: bool, + emit_bc_compressed: bool, + outputs: &OutputFilenames) -> CompiledModule { + let pre_existing = match self.source { + ModuleSource::Preexisting(_) => true, + ModuleSource::Codegened(_) => false, + }; + let object = if emit_obj { + Some(outputs.temp_path(OutputType::Object, Some(&self.name))) + } else { + None + }; + let bytecode = if emit_bc { + Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name))) + } else { + None + }; + let bytecode_compressed = if emit_bc_compressed { + Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name)) + .with_extension(RLIB_BYTECODE_EXTENSION)) + } else { + None + }; + + CompiledModule { + llmod_id: self.llmod_id, + name: self.name.clone(), + kind: self.kind, + pre_existing, + object, + bytecode, + bytecode_compressed, + } + } +} + +#[derive(Debug)] +struct CompiledModule { + name: String, + llmod_id: String, + kind: ModuleKind, + pre_existing: bool, + object: Option, + bytecode: Option, + bytecode_compressed: Option, +} + +enum ModuleSource { + /// Copy the `.o` files or whatever from the incr. comp. directory. + Preexisting(WorkProduct), + + /// Rebuild from this LLVM module. + Codegened(ModuleLlvm), +} + +#[derive(Debug)] +struct ModuleLlvm { + llcx: llvm::ContextRef, + llmod: llvm::ModuleRef, + tm: llvm::TargetMachineRef, +} + +unsafe impl Send for ModuleLlvm { } +unsafe impl Sync for ModuleLlvm { } + +impl Drop for ModuleLlvm { + fn drop(&mut self) { + unsafe { + llvm::LLVMDisposeModule(self.llmod); + llvm::LLVMContextDispose(self.llcx); + llvm::LLVMRustDisposeTargetMachine(self.tm); + } + } +} + +struct CodegenResults { + crate_name: Symbol, + modules: Vec, + allocator_module: Option, + metadata_module: CompiledModule, + link: rustc::middle::cstore::LinkMeta, + metadata: rustc::middle::cstore::EncodedMetadata, + windows_subsystem: Option, + linker_info: back::linker::LinkerInfo, + crate_info: CrateInfo, +} + +// Misc info we load from metadata to persist beyond the tcx +struct CrateInfo { + panic_runtime: Option, + compiler_builtins: Option, + profiler_runtime: Option, + sanitizer_runtime: Option, + is_no_builtins: FxHashSet, + native_libraries: FxHashMap>>, + crate_name: FxHashMap, + used_libraries: Lrc>, + link_args: Lrc>, + used_crate_source: FxHashMap>, + used_crates_static: Vec<(CrateNum, LibSource)>, + used_crates_dynamic: Vec<(CrateNum, LibSource)>, + wasm_custom_sections: BTreeMap>, + wasm_imports: FxHashMap, + lang_item_to_crate: FxHashMap, + missing_lang_items: FxHashMap>, +} + +__build_diagnostic_array! { librustc_codegen_llvm, DIAGNOSTICS } diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs new file mode 100644 index 00000000000..357b639e788 --- /dev/null +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -0,0 +1,255 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax_pos::symbol::Symbol; +use back::write::create_target_machine; +use llvm; +use rustc::session::Session; +use rustc::session::config::PrintRequest; +use libc::c_int; +use std::ffi::CString; +use syntax::feature_gate::UnstableFeatures; + +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Once; + +static POISONED: AtomicBool = AtomicBool::new(false); +static INIT: Once = Once::new(); + +pub(crate) fn init(sess: &Session) { + unsafe { + // Before we touch LLVM, make sure that multithreading is enabled. + INIT.call_once(|| { + if llvm::LLVMStartMultithreaded() != 1 { + // use an extra bool to make sure that all future usage of LLVM + // cannot proceed despite the Once not running more than once. + POISONED.store(true, Ordering::SeqCst); + } + + configure_llvm(sess); + }); + + if POISONED.load(Ordering::SeqCst) { + bug!("couldn't enable multi-threaded LLVM"); + } + } +} + +fn require_inited() { + INIT.call_once(|| bug!("llvm is not initialized")); + if POISONED.load(Ordering::SeqCst) { + bug!("couldn't enable multi-threaded LLVM"); + } +} + +unsafe fn configure_llvm(sess: &Session) { + let mut llvm_c_strs = Vec::new(); + let mut llvm_args = Vec::new(); + + { + let mut add = |arg: &str| { + let s = CString::new(arg).unwrap(); + llvm_args.push(s.as_ptr()); + llvm_c_strs.push(s); + }; + add("rustc"); // fake program name + if sess.time_llvm_passes() { add("-time-passes"); } + if sess.print_llvm_passes() { add("-debug-pass=Structure"); } + if sess.opts.debugging_opts.disable_instrumentation_preinliner { + add("-disable-preinline"); + } + + for arg in &sess.opts.cg.llvm_args { + add(&(*arg)); + } + } + + llvm::LLVMInitializePasses(); + + llvm::initialize_available_targets(); + + llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, + llvm_args.as_ptr()); +} + +// WARNING: the features after applying `to_llvm_feature` must be known +// to LLVM or the feature detection code will walk past the end of the feature +// array, leading to crashes. + +const ARM_WHITELIST: &[(&str, Option<&str>)] = &[ + ("neon", Some("arm_target_feature")), + ("v7", Some("arm_target_feature")), + ("vfp2", Some("arm_target_feature")), + ("vfp3", Some("arm_target_feature")), + ("vfp4", Some("arm_target_feature")), +]; + +const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[ + ("fp", Some("aarch64_target_feature")), + ("neon", Some("aarch64_target_feature")), + ("sve", Some("aarch64_target_feature")), + ("crc", Some("aarch64_target_feature")), + ("crypto", Some("aarch64_target_feature")), + ("ras", Some("aarch64_target_feature")), + ("lse", Some("aarch64_target_feature")), + ("rdm", Some("aarch64_target_feature")), + ("fp16", Some("aarch64_target_feature")), + ("rcpc", Some("aarch64_target_feature")), + ("dotprod", Some("aarch64_target_feature")), + ("v8.1a", Some("aarch64_target_feature")), + ("v8.2a", Some("aarch64_target_feature")), + ("v8.3a", Some("aarch64_target_feature")), +]; + +const X86_WHITELIST: &[(&str, Option<&str>)] = &[ + ("aes", None), + ("avx", None), + ("avx2", None), + ("avx512bw", Some("avx512_target_feature")), + ("avx512cd", Some("avx512_target_feature")), + ("avx512dq", Some("avx512_target_feature")), + ("avx512er", Some("avx512_target_feature")), + ("avx512f", Some("avx512_target_feature")), + ("avx512ifma", Some("avx512_target_feature")), + ("avx512pf", Some("avx512_target_feature")), + ("avx512vbmi", Some("avx512_target_feature")), + ("avx512vl", Some("avx512_target_feature")), + ("avx512vpopcntdq", Some("avx512_target_feature")), + ("bmi1", None), + ("bmi2", None), + ("fma", None), + ("fxsr", None), + ("lzcnt", None), + ("mmx", Some("mmx_target_feature")), + ("pclmulqdq", None), + ("popcnt", None), + ("rdrand", None), + ("rdseed", None), + ("sha", None), + ("sse", None), + ("sse2", None), + ("sse3", None), + ("sse4.1", None), + ("sse4.2", None), + ("sse4a", Some("sse4a_target_feature")), + ("ssse3", None), + ("tbm", Some("tbm_target_feature")), + ("xsave", None), + ("xsavec", None), + ("xsaveopt", None), + ("xsaves", None), +]; + +const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[ + ("hvx", Some("hexagon_target_feature")), + ("hvx-double", Some("hexagon_target_feature")), +]; + +const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[ + ("altivec", Some("powerpc_target_feature")), + ("power8-altivec", Some("powerpc_target_feature")), + ("power9-altivec", Some("powerpc_target_feature")), + ("power8-vector", Some("powerpc_target_feature")), + ("power9-vector", Some("powerpc_target_feature")), + ("vsx", Some("powerpc_target_feature")), +]; + +const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[ + ("fp64", Some("mips_target_feature")), + ("msa", Some("mips_target_feature")), +]; + +/// When rustdoc is running, provide a list of all known features so that all their respective +/// primtives may be documented. +/// +/// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this +/// iterator! +pub fn all_known_features() -> impl Iterator)> { + ARM_WHITELIST.iter().cloned() + .chain(AARCH64_WHITELIST.iter().cloned()) + .chain(X86_WHITELIST.iter().cloned()) + .chain(HEXAGON_WHITELIST.iter().cloned()) + .chain(POWERPC_WHITELIST.iter().cloned()) + .chain(MIPS_WHITELIST.iter().cloned()) +} + +pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { + let arch = if sess.target.target.arch == "x86_64" { + "x86" + } else { + &*sess.target.target.arch + }; + match (arch, s) { + ("x86", "pclmulqdq") => "pclmul", + ("x86", "rdrand") => "rdrnd", + ("x86", "bmi1") => "bmi", + ("aarch64", "fp") => "fp-armv8", + ("aarch64", "fp16") => "fullfp16", + (_, s) => s, + } +} + +pub fn target_features(sess: &Session) -> Vec { + let target_machine = create_target_machine(sess, true); + target_feature_whitelist(sess) + .iter() + .filter_map(|&(feature, gate)| { + if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() { + Some(feature) + } else { + None + } + }) + .filter(|feature| { + let llvm_feature = to_llvm_feature(sess, feature); + let cstr = CString::new(llvm_feature).unwrap(); + unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } + }) + .map(|feature| Symbol::intern(feature)).collect() +} + +pub fn target_feature_whitelist(sess: &Session) + -> &'static [(&'static str, Option<&'static str>)] +{ + match &*sess.target.target.arch { + "arm" => ARM_WHITELIST, + "aarch64" => AARCH64_WHITELIST, + "x86" | "x86_64" => X86_WHITELIST, + "hexagon" => HEXAGON_WHITELIST, + "mips" | "mips64" => MIPS_WHITELIST, + "powerpc" | "powerpc64" => POWERPC_WHITELIST, + _ => &[], + } +} + +pub fn print_version() { + // Can be called without initializing LLVM + unsafe { + println!("LLVM version: {}.{}", + llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor()); + } +} + +pub fn print_passes() { + // Can be called without initializing LLVM + unsafe { llvm::LLVMRustPrintPasses(); } +} + +pub(crate) fn print(req: PrintRequest, sess: &Session) { + require_inited(); + let tm = create_target_machine(sess, true); + unsafe { + match req { + PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm), + PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm), + _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req), + } + } +} diff --git a/src/librustc_codegen_llvm/metadata.rs b/src/librustc_codegen_llvm/metadata.rs new file mode 100644 index 00000000000..144baa65c1b --- /dev/null +++ b/src/librustc_codegen_llvm/metadata.rs @@ -0,0 +1,124 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::util::common; +use rustc::middle::cstore::MetadataLoader; +use rustc_target::spec::Target; +use llvm; +use llvm::{False, ObjectFile, mk_section_iter}; +use llvm::archive_ro::ArchiveRO; + +use rustc_data_structures::owning_ref::OwningRef; +use std::path::Path; +use std::ptr; +use std::slice; + +pub use rustc_data_structures::sync::MetadataRef; + +pub const METADATA_FILENAME: &str = "rust.metadata.bin"; + +pub struct LlvmMetadataLoader; + +impl MetadataLoader for LlvmMetadataLoader { + fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result { + // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap + // internally to read the file. We also avoid even using a memcpy by + // just keeping the archive along while the metadata is in use. + let archive = ArchiveRO::open(filename) + .map(|ar| OwningRef::new(box ar)) + .map_err(|e| { + debug!("llvm didn't like `{}`: {}", filename.display(), e); + format!("failed to read rlib metadata in '{}': {}", filename.display(), e) + })?; + let buf: OwningRef<_, [u8]> = archive + .try_map(|ar| { + ar.iter() + .filter_map(|s| s.ok()) + .find(|sect| sect.name() == Some(METADATA_FILENAME)) + .map(|s| s.data()) + .ok_or_else(|| { + debug!("didn't find '{}' in the archive", METADATA_FILENAME); + format!("failed to read rlib metadata: '{}'", + filename.display()) + }) + })?; + Ok(rustc_erase_owner!(buf)) + } + + fn get_dylib_metadata(&self, + target: &Target, + filename: &Path) + -> Result { + unsafe { + let buf = common::path2cstr(filename); + let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr()); + if mb as isize == 0 { + return Err(format!("error reading library: '{}'", filename.display())); + } + let of = ObjectFile::new(mb) + .map(|of| OwningRef::new(box of)) + .ok_or_else(|| format!("provided path not an object file: '{}'", + filename.display()))?; + let buf = of.try_map(|of| search_meta_section(of, target, filename))?; + Ok(rustc_erase_owner!(buf)) + } + } +} + +fn search_meta_section<'a>(of: &'a ObjectFile, + target: &Target, + filename: &Path) + -> Result<&'a [u8], String> { + unsafe { + let si = mk_section_iter(of.llof); + while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { + let mut name_buf = ptr::null(); + let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf); + let name = slice::from_raw_parts(name_buf as *const u8, name_len as usize).to_vec(); + let name = String::from_utf8(name).unwrap(); + debug!("get_metadata_section: name {}", name); + if read_metadata_section_name(target) == name { + let cbuf = llvm::LLVMGetSectionContents(si.llsi); + let csz = llvm::LLVMGetSectionSize(si.llsi) as usize; + // The buffer is valid while the object file is around + let buf: &'a [u8] = slice::from_raw_parts(cbuf as *const u8, csz); + return Ok(buf); + } + llvm::LLVMMoveToNextSection(si.llsi); + } + } + Err(format!("metadata not found: '{}'", filename.display())) +} + +pub fn metadata_section_name(target: &Target) -> &'static str { + // Historical note: + // + // When using link.exe it was seen that the section name `.note.rustc` + // was getting shortened to `.note.ru`, and according to the PE and COFF + // specification: + // + // > Executable images do not use a string table and do not support + // > section names longer than 8 characters + // + // https://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx + // + // As a result, we choose a slightly shorter name! As to why + // `.note.rustc` works on MinGW, that's another good question... + + if target.options.is_like_osx { + "__DATA,.rustc" + } else { + ".rustc" + } +} + +fn read_metadata_section_name(_target: &Target) -> &'static str { + ".rustc" +} diff --git a/src/librustc_codegen_llvm/meth.rs b/src/librustc_codegen_llvm/meth.rs new file mode 100644 index 00000000000..21bbdf31dcb --- /dev/null +++ b/src/librustc_codegen_llvm/meth.rs @@ -0,0 +1,115 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use llvm::ValueRef; +use abi::{FnType, FnTypeExt}; +use callee; +use common::*; +use builder::Builder; +use consts; +use monomorphize; +use type_::Type; +use value::Value; +use rustc::ty::{self, Ty}; +use rustc::ty::layout::HasDataLayout; +use debuginfo; + +#[derive(Copy, Clone, Debug)] +pub struct VirtualIndex(u64); + +pub const DESTRUCTOR: VirtualIndex = VirtualIndex(0); +pub const SIZE: VirtualIndex = VirtualIndex(1); +pub const ALIGN: VirtualIndex = VirtualIndex(2); + +impl<'a, 'tcx> VirtualIndex { + pub fn from_index(index: usize) -> Self { + VirtualIndex(index as u64 + 3) + } + + pub fn get_fn(self, bx: &Builder<'a, 'tcx>, + llvtable: ValueRef, + fn_ty: &FnType<'tcx, Ty<'tcx>>) -> ValueRef { + // Load the data pointer from the object. + debug!("get_fn({:?}, {:?})", Value(llvtable), self); + + let llvtable = bx.pointercast(llvtable, fn_ty.llvm_type(bx.cx).ptr_to().ptr_to()); + let ptr_align = bx.tcx().data_layout.pointer_align; + let ptr = bx.load(bx.inbounds_gep(llvtable, &[C_usize(bx.cx, self.0)]), ptr_align); + bx.nonnull_metadata(ptr); + // Vtable loads are invariant + bx.set_invariant_load(ptr); + ptr + } + + pub fn get_usize(self, bx: &Builder<'a, 'tcx>, llvtable: ValueRef) -> ValueRef { + // Load the data pointer from the object. + debug!("get_int({:?}, {:?})", Value(llvtable), self); + + let llvtable = bx.pointercast(llvtable, Type::isize(bx.cx).ptr_to()); + let usize_align = bx.tcx().data_layout.pointer_align; + let ptr = bx.load(bx.inbounds_gep(llvtable, &[C_usize(bx.cx, self.0)]), usize_align); + // Vtable loads are invariant + bx.set_invariant_load(ptr); + ptr + } +} + +/// Creates a dynamic vtable for the given type and vtable origin. +/// This is used only for objects. +/// +/// The vtables are cached instead of created on every call. +/// +/// The `trait_ref` encodes the erased self type. Hence if we are +/// making an object `Foo` from a value of type `Foo`, then +/// `trait_ref` would map `T:Trait`. +pub fn get_vtable<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + ty: Ty<'tcx>, + trait_ref: Option>) + -> ValueRef +{ + let tcx = cx.tcx; + + debug!("get_vtable(ty={:?}, trait_ref={:?})", ty, trait_ref); + + // Check the cache. + if let Some(&val) = cx.vtables.borrow().get(&(ty, trait_ref)) { + return val; + } + + // Not in the cache. Build it. + let nullptr = C_null(Type::i8p(cx)); + + let (size, align) = cx.size_and_align_of(ty); + let mut components: Vec<_> = [ + callee::get_fn(cx, monomorphize::resolve_drop_in_place(cx.tcx, ty)), + C_usize(cx, size.bytes()), + C_usize(cx, align.abi()) + ].iter().cloned().collect(); + + if let Some(trait_ref) = trait_ref { + let trait_ref = trait_ref.with_self_ty(tcx, ty); + let methods = tcx.vtable_methods(trait_ref); + let methods = methods.iter().cloned().map(|opt_mth| { + opt_mth.map_or(nullptr, |(def_id, substs)| { + callee::resolve_and_get_fn(cx, def_id, substs) + }) + }); + components.extend(methods); + } + + let vtable_const = C_struct(cx, &components, false); + let align = cx.data_layout().pointer_align; + let vtable = consts::addr_of(cx, vtable_const, align, "vtable"); + + debuginfo::create_vtable_metadata(cx, ty, vtable); + + cx.vtables.borrow_mut().insert((ty, trait_ref), vtable); + vtable +} diff --git a/src/librustc_codegen_llvm/mir/analyze.rs b/src/librustc_codegen_llvm/mir/analyze.rs new file mode 100644 index 00000000000..9e5298eb736 --- /dev/null +++ b/src/librustc_codegen_llvm/mir/analyze.rs @@ -0,0 +1,361 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! An analysis to determine which locals require allocas and +//! which do not. + +use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::control_flow_graph::dominators::Dominators; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc::mir::{self, Location, TerminatorKind}; +use rustc::mir::visit::{Visitor, PlaceContext}; +use rustc::mir::traversal; +use rustc::ty; +use rustc::ty::layout::LayoutOf; +use type_of::LayoutLlvmExt; +use super::FunctionCx; + +pub fn non_ssa_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector { + let mir = fx.mir; + let mut analyzer = LocalAnalyzer::new(fx); + + analyzer.visit_mir(mir); + + for (index, ty) in mir.local_decls.iter().map(|l| l.ty).enumerate() { + let ty = fx.monomorphize(&ty); + debug!("local {} has type {:?}", index, ty); + let layout = fx.cx.layout_of(ty); + if layout.is_llvm_immediate() { + // These sorts of types are immediates that we can store + // in an ValueRef without an alloca. + } else if layout.is_llvm_scalar_pair() { + // We allow pairs and uses of any of their 2 fields. + } else { + // These sorts of types require an alloca. Note that + // is_llvm_immediate() may *still* be true, particularly + // for newtypes, but we currently force some types + // (e.g. structs) into an alloca unconditionally, just so + // that we don't have to deal with having two pathways + // (gep vs extractvalue etc). + analyzer.not_ssa(mir::Local::new(index)); + } + } + + analyzer.non_ssa_locals +} + +struct LocalAnalyzer<'mir, 'a: 'mir, 'tcx: 'a> { + fx: &'mir FunctionCx<'a, 'tcx>, + dominators: Dominators, + non_ssa_locals: BitVector, + // The location of the first visited direct assignment to each + // local, or an invalid location (out of bounds `block` index). + first_assignment: IndexVec +} + +impl<'mir, 'a, 'tcx> LocalAnalyzer<'mir, 'a, 'tcx> { + fn new(fx: &'mir FunctionCx<'a, 'tcx>) -> LocalAnalyzer<'mir, 'a, 'tcx> { + let invalid_location = + mir::BasicBlock::new(fx.mir.basic_blocks().len()).start_location(); + let mut analyzer = LocalAnalyzer { + fx, + dominators: fx.mir.dominators(), + non_ssa_locals: BitVector::new(fx.mir.local_decls.len()), + first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls) + }; + + // Arguments get assigned to by means of the function being called + for arg in fx.mir.args_iter() { + analyzer.first_assignment[arg] = mir::START_BLOCK.start_location(); + } + + analyzer + } + + fn first_assignment(&self, local: mir::Local) -> Option { + let location = self.first_assignment[local]; + if location.block.index() < self.fx.mir.basic_blocks().len() { + Some(location) + } else { + None + } + } + + fn not_ssa(&mut self, local: mir::Local) { + debug!("marking {:?} as non-SSA", local); + self.non_ssa_locals.insert(local.index()); + } + + fn assign(&mut self, local: mir::Local, location: Location) { + if self.first_assignment(local).is_some() { + self.not_ssa(local); + } else { + self.first_assignment[local] = location; + } + } +} + +impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { + fn visit_assign(&mut self, + block: mir::BasicBlock, + place: &mir::Place<'tcx>, + rvalue: &mir::Rvalue<'tcx>, + location: Location) { + debug!("visit_assign(block={:?}, place={:?}, rvalue={:?})", block, place, rvalue); + + if let mir::Place::Local(index) = *place { + self.assign(index, location); + if !self.fx.rvalue_creates_operand(rvalue) { + self.not_ssa(index); + } + } else { + self.visit_place(place, PlaceContext::Store, location); + } + + self.visit_rvalue(rvalue, location); + } + + fn visit_terminator_kind(&mut self, + block: mir::BasicBlock, + kind: &mir::TerminatorKind<'tcx>, + location: Location) { + let check = match *kind { + mir::TerminatorKind::Call { + func: mir::Operand::Constant(ref c), + ref args, .. + } => match c.ty.sty { + ty::TyFnDef(did, _) => Some((did, args)), + _ => None, + }, + _ => None, + }; + if let Some((def_id, args)) = check { + if Some(def_id) == self.fx.cx.tcx.lang_items().box_free_fn() { + // box_free(x) shares with `drop x` the property that it + // is not guaranteed to be statically dominated by the + // definition of x, so x must always be in an alloca. + if let mir::Operand::Move(ref place) = args[0] { + self.visit_place(place, PlaceContext::Drop, location); + } + } + } + + self.super_terminator_kind(block, kind, location); + } + + fn visit_place(&mut self, + place: &mir::Place<'tcx>, + context: PlaceContext<'tcx>, + location: Location) { + debug!("visit_place(place={:?}, context={:?})", place, context); + let cx = self.fx.cx; + + if let mir::Place::Projection(ref proj) = *place { + // Allow uses of projections that are ZSTs or from scalar fields. + let is_consume = match context { + PlaceContext::Copy | PlaceContext::Move => true, + _ => false + }; + if is_consume { + let base_ty = proj.base.ty(self.fx.mir, cx.tcx); + let base_ty = self.fx.monomorphize(&base_ty); + + // ZSTs don't require any actual memory access. + let elem_ty = base_ty.projection_ty(cx.tcx, &proj.elem).to_ty(cx.tcx); + let elem_ty = self.fx.monomorphize(&elem_ty); + if cx.layout_of(elem_ty).is_zst() { + return; + } + + if let mir::ProjectionElem::Field(..) = proj.elem { + let layout = cx.layout_of(base_ty.to_ty(cx.tcx)); + if layout.is_llvm_immediate() || layout.is_llvm_scalar_pair() { + // Recurse with the same context, instead of `Projection`, + // potentially stopping at non-operand projections, + // which would trigger `not_ssa` on locals. + self.visit_place(&proj.base, context, location); + return; + } + } + } + + // A deref projection only reads the pointer, never needs the place. + if let mir::ProjectionElem::Deref = proj.elem { + return self.visit_place(&proj.base, PlaceContext::Copy, location); + } + } + + self.super_place(place, context, location); + } + + fn visit_local(&mut self, + &local: &mir::Local, + context: PlaceContext<'tcx>, + location: Location) { + match context { + PlaceContext::Call => { + self.assign(local, location); + } + + PlaceContext::StorageLive | + PlaceContext::StorageDead | + PlaceContext::Validate => {} + + PlaceContext::Copy | + PlaceContext::Move => { + // Reads from uninitialized variables (e.g. in dead code, after + // optimizations) require locals to be in (uninitialized) memory. + // NB: there can be uninitialized reads of a local visited after + // an assignment to that local, if they happen on disjoint paths. + let ssa_read = match self.first_assignment(local) { + Some(assignment_location) => { + assignment_location.dominates(location, &self.dominators) + } + None => false + }; + if !ssa_read { + self.not_ssa(local); + } + } + + PlaceContext::Inspect | + PlaceContext::Store | + PlaceContext::AsmOutput | + PlaceContext::Borrow { .. } | + PlaceContext::Projection(..) => { + self.not_ssa(local); + } + + PlaceContext::Drop => { + let ty = mir::Place::Local(local).ty(self.fx.mir, self.fx.cx.tcx); + let ty = self.fx.monomorphize(&ty.to_ty(self.fx.cx.tcx)); + + // Only need the place if we're actually dropping it. + if self.fx.cx.type_needs_drop(ty) { + self.not_ssa(local); + } + } + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum CleanupKind { + NotCleanup, + Funclet, + Internal { funclet: mir::BasicBlock } +} + +impl CleanupKind { + pub fn funclet_bb(self, for_bb: mir::BasicBlock) -> Option { + match self { + CleanupKind::NotCleanup => None, + CleanupKind::Funclet => Some(for_bb), + CleanupKind::Internal { funclet } => Some(funclet), + } + } +} + +pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec { + fn discover_masters<'tcx>(result: &mut IndexVec, + mir: &mir::Mir<'tcx>) { + for (bb, data) in mir.basic_blocks().iter_enumerated() { + match data.terminator().kind { + TerminatorKind::Goto { .. } | + TerminatorKind::Resume | + TerminatorKind::Abort | + TerminatorKind::Return | + TerminatorKind::GeneratorDrop | + TerminatorKind::Unreachable | + TerminatorKind::SwitchInt { .. } | + TerminatorKind::Yield { .. } | + TerminatorKind::FalseEdges { .. } | + TerminatorKind::FalseUnwind { .. } => { + /* nothing to do */ + } + TerminatorKind::Call { cleanup: unwind, .. } | + TerminatorKind::Assert { cleanup: unwind, .. } | + TerminatorKind::DropAndReplace { unwind, .. } | + TerminatorKind::Drop { unwind, .. } => { + if let Some(unwind) = unwind { + debug!("cleanup_kinds: {:?}/{:?} registering {:?} as funclet", + bb, data, unwind); + result[unwind] = CleanupKind::Funclet; + } + } + } + } + } + + fn propagate<'tcx>(result: &mut IndexVec, + mir: &mir::Mir<'tcx>) { + let mut funclet_succs = IndexVec::from_elem(None, mir.basic_blocks()); + + let mut set_successor = |funclet: mir::BasicBlock, succ| { + match funclet_succs[funclet] { + ref mut s @ None => { + debug!("set_successor: updating successor of {:?} to {:?}", + funclet, succ); + *s = Some(succ); + }, + Some(s) => if s != succ { + span_bug!(mir.span, "funclet {:?} has 2 parents - {:?} and {:?}", + funclet, s, succ); + } + } + }; + + for (bb, data) in traversal::reverse_postorder(mir) { + let funclet = match result[bb] { + CleanupKind::NotCleanup => continue, + CleanupKind::Funclet => bb, + CleanupKind::Internal { funclet } => funclet, + }; + + debug!("cleanup_kinds: {:?}/{:?}/{:?} propagating funclet {:?}", + bb, data, result[bb], funclet); + + for &succ in data.terminator().successors() { + let kind = result[succ]; + debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}", + funclet, succ, kind); + match kind { + CleanupKind::NotCleanup => { + result[succ] = CleanupKind::Internal { funclet: funclet }; + } + CleanupKind::Funclet => { + if funclet != succ { + set_successor(funclet, succ); + } + } + CleanupKind::Internal { funclet: succ_funclet } => { + if funclet != succ_funclet { + // `succ` has 2 different funclet going into it, so it must + // be a funclet by itself. + + debug!("promoting {:?} to a funclet and updating {:?}", succ, + succ_funclet); + result[succ] = CleanupKind::Funclet; + set_successor(succ_funclet, succ); + set_successor(funclet, succ); + } + } + } + } + } + } + + let mut result = IndexVec::from_elem(CleanupKind::NotCleanup, mir.basic_blocks()); + + discover_masters(&mut result, mir); + propagate(&mut result, mir); + debug!("cleanup_kinds: result={:?}", result); + result +} diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs new file mode 100644 index 00000000000..556baeba39e --- /dev/null +++ b/src/librustc_codegen_llvm/mir/block.rs @@ -0,0 +1,895 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use llvm::{self, ValueRef, BasicBlockRef}; +use rustc::middle::lang_items; +use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::layout::{self, LayoutOf}; +use rustc::mir; +use rustc::mir::interpret::EvalErrorKind; +use abi::{Abi, ArgType, ArgTypeExt, FnType, FnTypeExt, LlvmType, PassMode}; +use base; +use callee; +use builder::{Builder, MemFlags}; +use common::{self, C_bool, C_str_slice, C_struct, C_u32, C_uint_big, C_undef}; +use consts; +use meth; +use monomorphize; +use type_of::LayoutLlvmExt; +use type_::Type; + +use syntax::symbol::Symbol; +use syntax_pos::Pos; + +use super::{FunctionCx, LocalRef}; +use super::place::PlaceRef; +use super::operand::OperandRef; +use super::operand::OperandValue::{Pair, Ref, Immediate}; + +impl<'a, 'tcx> FunctionCx<'a, 'tcx> { + pub fn codegen_block(&mut self, bb: mir::BasicBlock) { + let mut bx = self.build_block(bb); + let data = &self.mir[bb]; + + debug!("codegen_block({:?}={:?})", bb, data); + + for statement in &data.statements { + bx = self.codegen_statement(bx, statement); + } + + self.codegen_terminator(bx, bb, data.terminator()); + } + + fn codegen_terminator(&mut self, + mut bx: Builder<'a, 'tcx>, + bb: mir::BasicBlock, + terminator: &mir::Terminator<'tcx>) + { + debug!("codegen_terminator: {:?}", terminator); + + // Create the cleanup bundle, if needed. + let tcx = bx.tcx(); + let span = terminator.source_info.span; + let funclet_bb = self.cleanup_kinds[bb].funclet_bb(bb); + let funclet = funclet_bb.and_then(|funclet_bb| self.funclets[funclet_bb].as_ref()); + + let cleanup_pad = funclet.map(|lp| lp.cleanuppad()); + let cleanup_bundle = funclet.map(|l| l.bundle()); + + let lltarget = |this: &mut Self, target: mir::BasicBlock| { + let lltarget = this.blocks[target]; + let target_funclet = this.cleanup_kinds[target].funclet_bb(target); + match (funclet_bb, target_funclet) { + (None, None) => (lltarget, false), + (Some(f), Some(t_f)) + if f == t_f || !base::wants_msvc_seh(tcx.sess) + => (lltarget, false), + (None, Some(_)) => { + // jump *into* cleanup - need a landing pad if GNU + (this.landing_pad_to(target), false) + } + (Some(_), None) => span_bug!(span, "{:?} - jump out of cleanup?", terminator), + (Some(_), Some(_)) => { + (this.landing_pad_to(target), true) + } + } + }; + + let llblock = |this: &mut Self, target: mir::BasicBlock| { + let (lltarget, is_cleanupret) = lltarget(this, target); + if is_cleanupret { + // MSVC cross-funclet jump - need a trampoline + + debug!("llblock: creating cleanup trampoline for {:?}", target); + let name = &format!("{:?}_cleanup_trampoline_{:?}", bb, target); + let trampoline = this.new_block(name); + trampoline.cleanup_ret(cleanup_pad.unwrap(), Some(lltarget)); + trampoline.llbb() + } else { + lltarget + } + }; + + let funclet_br = |this: &mut Self, bx: Builder, target: mir::BasicBlock| { + let (lltarget, is_cleanupret) = lltarget(this, target); + if is_cleanupret { + // micro-optimization: generate a `ret` rather than a jump + // to a trampoline. + bx.cleanup_ret(cleanup_pad.unwrap(), Some(lltarget)); + } else { + bx.br(lltarget); + } + }; + + let do_call = | + this: &mut Self, + bx: Builder<'a, 'tcx>, + fn_ty: FnType<'tcx, Ty<'tcx>>, + fn_ptr: ValueRef, + llargs: &[ValueRef], + destination: Option<(ReturnDest<'tcx>, mir::BasicBlock)>, + cleanup: Option + | { + if let Some(cleanup) = cleanup { + let ret_bx = if let Some((_, target)) = destination { + this.blocks[target] + } else { + this.unreachable_block() + }; + let invokeret = bx.invoke(fn_ptr, + &llargs, + ret_bx, + llblock(this, cleanup), + cleanup_bundle); + fn_ty.apply_attrs_callsite(&bx, invokeret); + + if let Some((ret_dest, target)) = destination { + let ret_bx = this.build_block(target); + this.set_debug_loc(&ret_bx, terminator.source_info); + this.store_return(&ret_bx, ret_dest, &fn_ty.ret, invokeret); + } + } else { + let llret = bx.call(fn_ptr, &llargs, cleanup_bundle); + fn_ty.apply_attrs_callsite(&bx, llret); + if this.mir[bb].is_cleanup { + // Cleanup is always the cold path. Don't inline + // drop glue. Also, when there is a deeply-nested + // struct, there are "symmetry" issues that cause + // exponential inlining - see issue #41696. + llvm::Attribute::NoInline.apply_callsite(llvm::AttributePlace::Function, llret); + } + + if let Some((ret_dest, target)) = destination { + this.store_return(&bx, ret_dest, &fn_ty.ret, llret); + funclet_br(this, bx, target); + } else { + bx.unreachable(); + } + } + }; + + self.set_debug_loc(&bx, terminator.source_info); + match terminator.kind { + mir::TerminatorKind::Resume => { + if let Some(cleanup_pad) = cleanup_pad { + bx.cleanup_ret(cleanup_pad, None); + } else { + let slot = self.get_personality_slot(&bx); + let lp0 = slot.project_field(&bx, 0).load(&bx).immediate(); + let lp1 = slot.project_field(&bx, 1).load(&bx).immediate(); + slot.storage_dead(&bx); + + if !bx.sess().target.target.options.custom_unwind_resume { + let mut lp = C_undef(self.landing_pad_type()); + lp = bx.insert_value(lp, lp0, 0); + lp = bx.insert_value(lp, lp1, 1); + bx.resume(lp); + } else { + bx.call(bx.cx.eh_unwind_resume(), &[lp0], cleanup_bundle); + bx.unreachable(); + } + } + } + + mir::TerminatorKind::Abort => { + // Call core::intrinsics::abort() + let fnname = bx.cx.get_intrinsic(&("llvm.trap")); + bx.call(fnname, &[], None); + bx.unreachable(); + } + + mir::TerminatorKind::Goto { target } => { + funclet_br(self, bx, target); + } + + mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => { + let discr = self.codegen_operand(&bx, discr); + if switch_ty == bx.tcx().types.bool { + let lltrue = llblock(self, targets[0]); + let llfalse = llblock(self, targets[1]); + if let [0] = values[..] { + bx.cond_br(discr.immediate(), llfalse, lltrue); + } else { + assert_eq!(&values[..], &[1]); + bx.cond_br(discr.immediate(), lltrue, llfalse); + } + } else { + let (otherwise, targets) = targets.split_last().unwrap(); + let switch = bx.switch(discr.immediate(), + llblock(self, *otherwise), values.len()); + let switch_llty = bx.cx.layout_of(switch_ty).immediate_llvm_type(bx.cx); + for (&value, target) in values.iter().zip(targets) { + let llval = C_uint_big(switch_llty, value); + let llbb = llblock(self, *target); + bx.add_case(switch, llval, llbb) + } + } + } + + mir::TerminatorKind::Return => { + let llval = match self.fn_ty.ret.mode { + PassMode::Ignore | PassMode::Indirect(_) => { + bx.ret_void(); + return; + } + + PassMode::Direct(_) | PassMode::Pair(..) => { + let op = self.codegen_consume(&bx, &mir::Place::Local(mir::RETURN_PLACE)); + if let Ref(llval, align) = op.val { + bx.load(llval, align) + } else { + op.immediate_or_packed_pair(&bx) + } + } + + PassMode::Cast(cast_ty) => { + let op = match self.locals[mir::RETURN_PLACE] { + LocalRef::Operand(Some(op)) => op, + LocalRef::Operand(None) => bug!("use of return before def"), + LocalRef::Place(cg_place) => { + OperandRef { + val: Ref(cg_place.llval, cg_place.align), + layout: cg_place.layout + } + } + }; + let llslot = match op.val { + Immediate(_) | Pair(..) => { + let scratch = PlaceRef::alloca(&bx, self.fn_ty.ret.layout, "ret"); + op.val.store(&bx, scratch); + scratch.llval + } + Ref(llval, align) => { + assert_eq!(align.abi(), op.layout.align.abi(), + "return place is unaligned!"); + llval + } + }; + bx.load( + bx.pointercast(llslot, cast_ty.llvm_type(bx.cx).ptr_to()), + self.fn_ty.ret.layout.align) + } + }; + bx.ret(llval); + } + + mir::TerminatorKind::Unreachable => { + bx.unreachable(); + } + + mir::TerminatorKind::Drop { ref location, target, unwind } => { + let ty = location.ty(self.mir, bx.tcx()).to_ty(bx.tcx()); + let ty = self.monomorphize(&ty); + let drop_fn = monomorphize::resolve_drop_in_place(bx.cx.tcx, ty); + + if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { + // we don't actually need to drop anything. + funclet_br(self, bx, target); + return + } + + let place = self.codegen_place(&bx, location); + let mut args: &[_] = &[place.llval, place.llextra]; + args = &args[..1 + place.has_extra() as usize]; + let (drop_fn, fn_ty) = match ty.sty { + ty::TyDynamic(..) => { + let fn_ty = drop_fn.ty(bx.cx.tcx); + let sig = common::ty_fn_sig(bx.cx, fn_ty); + let sig = bx.tcx().normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &sig, + ); + let fn_ty = FnType::new_vtable(bx.cx, sig, &[]); + args = &args[..1]; + (meth::DESTRUCTOR.get_fn(&bx, place.llextra, &fn_ty), fn_ty) + } + _ => { + (callee::get_fn(bx.cx, drop_fn), + FnType::of_instance(bx.cx, &drop_fn)) + } + }; + do_call(self, bx, fn_ty, drop_fn, args, + Some((ReturnDest::Nothing, target)), + unwind); + } + + mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => { + let cond = self.codegen_operand(&bx, cond).immediate(); + let mut const_cond = common::const_to_opt_u128(cond, false).map(|c| c == 1); + + // This case can currently arise only from functions marked + // with #[rustc_inherit_overflow_checks] and inlined from + // another crate (mostly core::num generic/#[inline] fns), + // while the current crate doesn't use overflow checks. + // NOTE: Unlike binops, negation doesn't have its own + // checked operation, just a comparison with the minimum + // value, so we have to check for the assert message. + if !bx.cx.check_overflow { + if let mir::interpret::EvalErrorKind::OverflowNeg = *msg { + const_cond = Some(expected); + } + } + + // Don't codegen the panic block if success if known. + if const_cond == Some(expected) { + funclet_br(self, bx, target); + return; + } + + // Pass the condition through llvm.expect for branch hinting. + let expect = bx.cx.get_intrinsic(&"llvm.expect.i1"); + let cond = bx.call(expect, &[cond, C_bool(bx.cx, expected)], None); + + // Create the failure block and the conditional branch to it. + let lltarget = llblock(self, target); + let panic_block = self.new_block("panic"); + if expected { + bx.cond_br(cond, lltarget, panic_block.llbb()); + } else { + bx.cond_br(cond, panic_block.llbb(), lltarget); + } + + // After this point, bx is the block for the call to panic. + bx = panic_block; + self.set_debug_loc(&bx, terminator.source_info); + + // Get the location information. + let loc = bx.sess().codemap().lookup_char_pos(span.lo()); + let filename = Symbol::intern(&loc.file.name.to_string()).as_str(); + let filename = C_str_slice(bx.cx, filename); + let line = C_u32(bx.cx, loc.line as u32); + let col = C_u32(bx.cx, loc.col.to_usize() as u32 + 1); + let align = tcx.data_layout.aggregate_align + .max(tcx.data_layout.i32_align) + .max(tcx.data_layout.pointer_align); + + // Put together the arguments to the panic entry point. + let (lang_item, args) = match *msg { + EvalErrorKind::BoundsCheck { ref len, ref index } => { + let len = self.codegen_operand(&mut bx, len).immediate(); + let index = self.codegen_operand(&mut bx, index).immediate(); + + let file_line_col = C_struct(bx.cx, &[filename, line, col], false); + let file_line_col = consts::addr_of(bx.cx, + file_line_col, + align, + "panic_bounds_check_loc"); + (lang_items::PanicBoundsCheckFnLangItem, + vec![file_line_col, index, len]) + } + _ => { + let str = msg.description(); + let msg_str = Symbol::intern(str).as_str(); + let msg_str = C_str_slice(bx.cx, msg_str); + let msg_file_line_col = C_struct(bx.cx, + &[msg_str, filename, line, col], + false); + let msg_file_line_col = consts::addr_of(bx.cx, + msg_file_line_col, + align, + "panic_loc"); + (lang_items::PanicFnLangItem, + vec![msg_file_line_col]) + } + }; + + // Obtain the panic entry point. + let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item); + let instance = ty::Instance::mono(bx.tcx(), def_id); + let fn_ty = FnType::of_instance(bx.cx, &instance); + let llfn = callee::get_fn(bx.cx, instance); + + // Codegen the actual panic invoke/call. + do_call(self, bx, fn_ty, llfn, &args, None, cleanup); + } + + mir::TerminatorKind::DropAndReplace { .. } => { + bug!("undesugared DropAndReplace in codegen: {:?}", terminator); + } + + mir::TerminatorKind::Call { ref func, ref args, ref destination, cleanup } => { + // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. + let callee = self.codegen_operand(&bx, func); + + let (instance, mut llfn) = match callee.layout.ty.sty { + ty::TyFnDef(def_id, substs) => { + (Some(ty::Instance::resolve(bx.cx.tcx, + ty::ParamEnv::reveal_all(), + def_id, + substs).unwrap()), + None) + } + ty::TyFnPtr(_) => { + (None, Some(callee.immediate())) + } + _ => bug!("{} is not callable", callee.layout.ty) + }; + let def = instance.map(|i| i.def); + let sig = callee.layout.ty.fn_sig(bx.tcx()); + let sig = bx.tcx().normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &sig, + ); + let abi = sig.abi; + + // Handle intrinsics old codegen wants Expr's for, ourselves. + let intrinsic = match def { + Some(ty::InstanceDef::Intrinsic(def_id)) + => Some(bx.tcx().item_name(def_id).as_str()), + _ => None + }; + let intrinsic = intrinsic.as_ref().map(|s| &s[..]); + + if intrinsic == Some("transmute") { + let &(ref dest, target) = destination.as_ref().unwrap(); + self.codegen_transmute(&bx, &args[0], dest); + funclet_br(self, bx, target); + return; + } + + let extra_args = &args[sig.inputs().len()..]; + let extra_args = extra_args.iter().map(|op_arg| { + let op_ty = op_arg.ty(self.mir, bx.tcx()); + self.monomorphize(&op_ty) + }).collect::>(); + + let fn_ty = match def { + Some(ty::InstanceDef::Virtual(..)) => { + FnType::new_vtable(bx.cx, sig, &extra_args) + } + Some(ty::InstanceDef::DropGlue(_, None)) => { + // empty drop glue - a nop. + let &(_, target) = destination.as_ref().unwrap(); + funclet_br(self, bx, target); + return; + } + _ => FnType::new(bx.cx, sig, &extra_args) + }; + + // The arguments we'll be passing. Plus one to account for outptr, if used. + let arg_count = fn_ty.args.len() + fn_ty.ret.is_indirect() as usize; + let mut llargs = Vec::with_capacity(arg_count); + + // Prepare the return value destination + let ret_dest = if let Some((ref dest, _)) = *destination { + let is_intrinsic = intrinsic.is_some(); + self.make_return_dest(&bx, dest, &fn_ty.ret, &mut llargs, + is_intrinsic) + } else { + ReturnDest::Nothing + }; + + if intrinsic.is_some() && intrinsic != Some("drop_in_place") { + use intrinsic::codegen_intrinsic_call; + + let dest = match ret_dest { + _ if fn_ty.ret.is_indirect() => llargs[0], + ReturnDest::Nothing => { + C_undef(fn_ty.ret.memory_ty(bx.cx).ptr_to()) + } + ReturnDest::IndirectOperand(dst, _) | + ReturnDest::Store(dst) => dst.llval, + ReturnDest::DirectOperand(_) => + bug!("Cannot use direct operand with an intrinsic call") + }; + + let args: Vec<_> = args.iter().enumerate().map(|(i, arg)| { + // The indices passed to simd_shuffle* in the + // third argument must be constant. This is + // checked by const-qualification, which also + // promotes any complex rvalues to constants. + if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") { + match *arg { + mir::Operand::Copy(_) | + mir::Operand::Move(_) => { + span_bug!(span, "shuffle indices must be constant"); + } + mir::Operand::Constant(ref constant) => { + let (llval, ty) = self.simd_shuffle_indices( + &bx, + constant, + ); + return OperandRef { + val: Immediate(llval), + layout: bx.cx.layout_of(ty) + }; + } + } + } + + self.codegen_operand(&bx, arg) + }).collect(); + + + let callee_ty = instance.as_ref().unwrap().ty(bx.cx.tcx); + codegen_intrinsic_call(&bx, callee_ty, &fn_ty, &args, dest, + terminator.source_info.span); + + if let ReturnDest::IndirectOperand(dst, _) = ret_dest { + self.store_return(&bx, ret_dest, &fn_ty.ret, dst.llval); + } + + if let Some((_, target)) = *destination { + funclet_br(self, bx, target); + } else { + bx.unreachable(); + } + + return; + } + + // Split the rust-call tupled arguments off. + let (first_args, untuple) = if abi == Abi::RustCall && !args.is_empty() { + let (tup, args) = args.split_last().unwrap(); + (args, Some(tup)) + } else { + (&args[..], None) + }; + + for (i, arg) in first_args.iter().enumerate() { + let mut op = self.codegen_operand(&bx, arg); + if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) { + if let Pair(data_ptr, meta) = op.val { + llfn = Some(meth::VirtualIndex::from_index(idx) + .get_fn(&bx, meta, &fn_ty)); + llargs.push(data_ptr); + continue; + } + } + + // The callee needs to own the argument memory if we pass it + // by-ref, so make a local copy of non-immediate constants. + match (arg, op.val) { + (&mir::Operand::Copy(_), Ref(..)) | + (&mir::Operand::Constant(_), Ref(..)) => { + let tmp = PlaceRef::alloca(&bx, op.layout, "const"); + op.val.store(&bx, tmp); + op.val = Ref(tmp.llval, tmp.align); + } + _ => {} + } + + self.codegen_argument(&bx, op, &mut llargs, &fn_ty.args[i]); + } + if let Some(tup) = untuple { + self.codegen_arguments_untupled(&bx, tup, &mut llargs, + &fn_ty.args[first_args.len()..]) + } + + let fn_ptr = match (llfn, instance) { + (Some(llfn), _) => llfn, + (None, Some(instance)) => callee::get_fn(bx.cx, instance), + _ => span_bug!(span, "no llfn for call"), + }; + + do_call(self, bx, fn_ty, fn_ptr, &llargs, + destination.as_ref().map(|&(_, target)| (ret_dest, target)), + cleanup); + } + mir::TerminatorKind::GeneratorDrop | + mir::TerminatorKind::Yield { .. } => bug!("generator ops in codegen"), + mir::TerminatorKind::FalseEdges { .. } | + mir::TerminatorKind::FalseUnwind { .. } => bug!("borrowck false edges in codegen"), + } + } + + fn codegen_argument(&mut self, + bx: &Builder<'a, 'tcx>, + op: OperandRef<'tcx>, + llargs: &mut Vec, + arg: &ArgType<'tcx, Ty<'tcx>>) { + // Fill padding with undef value, where applicable. + if let Some(ty) = arg.pad { + llargs.push(C_undef(ty.llvm_type(bx.cx))); + } + + if arg.is_ignore() { + return; + } + + if let PassMode::Pair(..) = arg.mode { + match op.val { + Pair(a, b) => { + llargs.push(a); + llargs.push(b); + return; + } + _ => bug!("codegen_argument: {:?} invalid for pair arugment", op) + } + } + + // Force by-ref if we have to load through a cast pointer. + let (mut llval, align, by_ref) = match op.val { + Immediate(_) | Pair(..) => { + match arg.mode { + PassMode::Indirect(_) | PassMode::Cast(_) => { + let scratch = PlaceRef::alloca(bx, arg.layout, "arg"); + op.val.store(bx, scratch); + (scratch.llval, scratch.align, true) + } + _ => { + (op.immediate_or_packed_pair(bx), arg.layout.align, false) + } + } + } + Ref(llval, align) => { + if arg.is_indirect() && align.abi() < arg.layout.align.abi() { + // `foo(packed.large_field)`. We can't pass the (unaligned) field directly. I + // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't + // have scary latent bugs around. + + let scratch = PlaceRef::alloca(bx, arg.layout, "arg"); + base::memcpy_ty(bx, scratch.llval, llval, op.layout, align, MemFlags::empty()); + (scratch.llval, scratch.align, true) + } else { + (llval, align, true) + } + } + }; + + if by_ref && !arg.is_indirect() { + // Have to load the argument, maybe while casting it. + if let PassMode::Cast(ty) = arg.mode { + llval = bx.load(bx.pointercast(llval, ty.llvm_type(bx.cx).ptr_to()), + align.min(arg.layout.align)); + } else { + // We can't use `PlaceRef::load` here because the argument + // may have a type we don't treat as immediate, but the ABI + // used for this call is passing it by-value. In that case, + // the load would just produce `OperandValue::Ref` instead + // of the `OperandValue::Immediate` we need for the call. + llval = bx.load(llval, align); + if let layout::Abi::Scalar(ref scalar) = arg.layout.abi { + if scalar.is_bool() { + bx.range_metadata(llval, 0..2); + } + } + // We store bools as i8 so we need to truncate to i1. + llval = base::to_immediate(bx, llval, arg.layout); + } + } + + llargs.push(llval); + } + + fn codegen_arguments_untupled(&mut self, + bx: &Builder<'a, 'tcx>, + operand: &mir::Operand<'tcx>, + llargs: &mut Vec, + args: &[ArgType<'tcx, Ty<'tcx>>]) { + let tuple = self.codegen_operand(bx, operand); + + // Handle both by-ref and immediate tuples. + if let Ref(llval, align) = tuple.val { + let tuple_ptr = PlaceRef::new_sized(llval, tuple.layout, align); + for i in 0..tuple.layout.fields.count() { + let field_ptr = tuple_ptr.project_field(bx, i); + self.codegen_argument(bx, field_ptr.load(bx), llargs, &args[i]); + } + } else { + // If the tuple is immediate, the elements are as well. + for i in 0..tuple.layout.fields.count() { + let op = tuple.extract_field(bx, i); + self.codegen_argument(bx, op, llargs, &args[i]); + } + } + } + + fn get_personality_slot(&mut self, bx: &Builder<'a, 'tcx>) -> PlaceRef<'tcx> { + let cx = bx.cx; + if let Some(slot) = self.personality_slot { + slot + } else { + let layout = cx.layout_of(cx.tcx.intern_tup(&[ + cx.tcx.mk_mut_ptr(cx.tcx.types.u8), + cx.tcx.types.i32 + ])); + let slot = PlaceRef::alloca(bx, layout, "personalityslot"); + self.personality_slot = Some(slot); + slot + } + } + + /// Return the landingpad wrapper around the given basic block + /// + /// No-op in MSVC SEH scheme. + fn landing_pad_to(&mut self, target_bb: mir::BasicBlock) -> BasicBlockRef { + if let Some(block) = self.landing_pads[target_bb] { + return block; + } + + let block = self.blocks[target_bb]; + let landing_pad = self.landing_pad_uncached(block); + self.landing_pads[target_bb] = Some(landing_pad); + landing_pad + } + + fn landing_pad_uncached(&mut self, target_bb: BasicBlockRef) -> BasicBlockRef { + if base::wants_msvc_seh(self.cx.sess()) { + span_bug!(self.mir.span, "landing pad was not inserted?") + } + + let bx = self.new_block("cleanup"); + + let llpersonality = self.cx.eh_personality(); + let llretty = self.landing_pad_type(); + let lp = bx.landing_pad(llretty, llpersonality, 1); + bx.set_cleanup(lp); + + let slot = self.get_personality_slot(&bx); + slot.storage_live(&bx); + Pair(bx.extract_value(lp, 0), bx.extract_value(lp, 1)).store(&bx, slot); + + bx.br(target_bb); + bx.llbb() + } + + fn landing_pad_type(&self) -> Type { + let cx = self.cx; + Type::struct_(cx, &[Type::i8p(cx), Type::i32(cx)], false) + } + + fn unreachable_block(&mut self) -> BasicBlockRef { + self.unreachable_block.unwrap_or_else(|| { + let bl = self.new_block("unreachable"); + bl.unreachable(); + self.unreachable_block = Some(bl.llbb()); + bl.llbb() + }) + } + + pub fn new_block(&self, name: &str) -> Builder<'a, 'tcx> { + Builder::new_block(self.cx, self.llfn, name) + } + + pub fn build_block(&self, bb: mir::BasicBlock) -> Builder<'a, 'tcx> { + let bx = Builder::with_cx(self.cx); + bx.position_at_end(self.blocks[bb]); + bx + } + + fn make_return_dest(&mut self, bx: &Builder<'a, 'tcx>, + dest: &mir::Place<'tcx>, fn_ret: &ArgType<'tcx, Ty<'tcx>>, + llargs: &mut Vec, is_intrinsic: bool) + -> ReturnDest<'tcx> { + // If the return is ignored, we can just return a do-nothing ReturnDest + if fn_ret.is_ignore() { + return ReturnDest::Nothing; + } + let dest = if let mir::Place::Local(index) = *dest { + match self.locals[index] { + LocalRef::Place(dest) => dest, + LocalRef::Operand(None) => { + // Handle temporary places, specifically Operand ones, as + // they don't have allocas + return if fn_ret.is_indirect() { + // Odd, but possible, case, we have an operand temporary, + // but the calling convention has an indirect return. + let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret"); + tmp.storage_live(bx); + llargs.push(tmp.llval); + ReturnDest::IndirectOperand(tmp, index) + } else if is_intrinsic { + // Currently, intrinsics always need a location to store + // the result. so we create a temporary alloca for the + // result + let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret"); + tmp.storage_live(bx); + ReturnDest::IndirectOperand(tmp, index) + } else { + ReturnDest::DirectOperand(index) + }; + } + LocalRef::Operand(Some(_)) => { + bug!("place local already assigned to"); + } + } + } else { + self.codegen_place(bx, dest) + }; + if fn_ret.is_indirect() { + if dest.align.abi() < dest.layout.align.abi() { + // Currently, MIR code generation does not create calls + // that store directly to fields of packed structs (in + // fact, the calls it creates write only to temps), + // + // If someone changes that, please update this code path + // to create a temporary. + span_bug!(self.mir.span, "can't directly store to unaligned value"); + } + llargs.push(dest.llval); + ReturnDest::Nothing + } else { + ReturnDest::Store(dest) + } + } + + fn codegen_transmute(&mut self, bx: &Builder<'a, 'tcx>, + src: &mir::Operand<'tcx>, + dst: &mir::Place<'tcx>) { + if let mir::Place::Local(index) = *dst { + match self.locals[index] { + LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place), + LocalRef::Operand(None) => { + let dst_layout = bx.cx.layout_of(self.monomorphized_place_ty(dst)); + assert!(!dst_layout.ty.has_erasable_regions()); + let place = PlaceRef::alloca(bx, dst_layout, "transmute_temp"); + place.storage_live(bx); + self.codegen_transmute_into(bx, src, place); + let op = place.load(bx); + place.storage_dead(bx); + self.locals[index] = LocalRef::Operand(Some(op)); + } + LocalRef::Operand(Some(op)) => { + assert!(op.layout.is_zst(), + "assigning to initialized SSAtemp"); + } + } + } else { + let dst = self.codegen_place(bx, dst); + self.codegen_transmute_into(bx, src, dst); + } + } + + fn codegen_transmute_into(&mut self, bx: &Builder<'a, 'tcx>, + src: &mir::Operand<'tcx>, + dst: PlaceRef<'tcx>) { + let src = self.codegen_operand(bx, src); + let llty = src.layout.llvm_type(bx.cx); + let cast_ptr = bx.pointercast(dst.llval, llty.ptr_to()); + let align = src.layout.align.min(dst.layout.align); + src.val.store(bx, PlaceRef::new_sized(cast_ptr, src.layout, align)); + } + + + // Stores the return value of a function call into it's final location. + fn store_return(&mut self, + bx: &Builder<'a, 'tcx>, + dest: ReturnDest<'tcx>, + ret_ty: &ArgType<'tcx, Ty<'tcx>>, + llval: ValueRef) { + use self::ReturnDest::*; + + match dest { + Nothing => (), + Store(dst) => ret_ty.store(bx, llval, dst), + IndirectOperand(tmp, index) => { + let op = tmp.load(bx); + tmp.storage_dead(bx); + self.locals[index] = LocalRef::Operand(Some(op)); + } + DirectOperand(index) => { + // If there is a cast, we have to store and reload. + let op = if let PassMode::Cast(_) = ret_ty.mode { + let tmp = PlaceRef::alloca(bx, ret_ty.layout, "tmp_ret"); + tmp.storage_live(bx); + ret_ty.store(bx, llval, tmp); + let op = tmp.load(bx); + tmp.storage_dead(bx); + op + } else { + OperandRef::from_immediate_or_packed_pair(bx, llval, ret_ty.layout) + }; + self.locals[index] = LocalRef::Operand(Some(op)); + } + } + } +} + +enum ReturnDest<'tcx> { + // Do nothing, the return value is indirect or ignored + Nothing, + // Store the return value to the pointer + Store(PlaceRef<'tcx>), + // Stores an indirect return value to an operand local place + IndirectOperand(PlaceRef<'tcx>, mir::Local), + // Stores a direct return value to an operand local place + DirectOperand(mir::Local) +} diff --git a/src/librustc_codegen_llvm/mir/constant.rs b/src/librustc_codegen_llvm/mir/constant.rs new file mode 100644 index 00000000000..c2638d2d410 --- /dev/null +++ b/src/librustc_codegen_llvm/mir/constant.rs @@ -0,0 +1,271 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use llvm::{self, ValueRef}; +use rustc::middle::const_val::{ConstVal, ConstEvalErr}; +use rustc_mir::interpret::{read_target_uint, const_val_field}; +use rustc::hir::def_id::DefId; +use rustc::mir; +use rustc_data_structures::indexed_vec::Idx; +use rustc::mir::interpret::{GlobalId, MemoryPointer, PrimVal, Allocation, ConstValue}; +use rustc::ty::{self, Ty}; +use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar}; +use builder::Builder; +use common::{CodegenCx}; +use common::{C_bytes, C_struct, C_uint_big, C_undef, C_usize}; +use consts; +use type_of::LayoutLlvmExt; +use type_::Type; +use syntax::ast::Mutability; + +use super::super::callee; +use super::FunctionCx; + +pub fn primval_to_llvm(cx: &CodegenCx, + cv: PrimVal, + scalar: &Scalar, + llty: Type) -> ValueRef { + let bits = if scalar.is_bool() { 1 } else { scalar.value.size(cx).bits() }; + match cv { + PrimVal::Undef => C_undef(Type::ix(cx, bits)), + PrimVal::Bytes(b) => { + let llval = C_uint_big(Type::ix(cx, bits), b); + if scalar.value == layout::Pointer { + unsafe { llvm::LLVMConstIntToPtr(llval, llty.to_ref()) } + } else { + consts::bitcast(llval, llty) + } + }, + PrimVal::Ptr(ptr) => { + if let Some(fn_instance) = cx.tcx.interpret_interner.get_fn(ptr.alloc_id) { + callee::get_fn(cx, fn_instance) + } else { + let static_ = cx + .tcx + .interpret_interner + .get_static(ptr.alloc_id); + let base_addr = if let Some(def_id) = static_ { + assert!(cx.tcx.is_static(def_id).is_some()); + consts::get_static(cx, def_id) + } else if let Some(alloc) = cx.tcx.interpret_interner + .get_alloc(ptr.alloc_id) { + let init = const_alloc_to_llvm(cx, alloc); + if alloc.runtime_mutability == Mutability::Mutable { + consts::addr_of_mut(cx, init, alloc.align, "byte_str") + } else { + consts::addr_of(cx, init, alloc.align, "byte_str") + } + } else { + bug!("missing allocation {:?}", ptr.alloc_id); + }; + + let llval = unsafe { llvm::LLVMConstInBoundsGEP( + consts::bitcast(base_addr, Type::i8p(cx)), + &C_usize(cx, ptr.offset), + 1, + ) }; + if scalar.value != layout::Pointer { + unsafe { llvm::LLVMConstPtrToInt(llval, llty.to_ref()) } + } else { + consts::bitcast(llval, llty) + } + } + } + } +} + +fn const_value_to_llvm<'tcx>(cx: &CodegenCx<'_, 'tcx>, val: ConstValue, ty: Ty<'tcx>) -> ValueRef { + let layout = cx.layout_of(ty); + + if layout.is_zst() { + return C_undef(layout.immediate_llvm_type(cx)); + } + + match val { + ConstValue::ByVal(x) => { + let scalar = match layout.abi { + layout::Abi::Scalar(ref x) => x, + _ => bug!("const_value_to_llvm: invalid ByVal layout: {:#?}", layout) + }; + primval_to_llvm( + cx, + x, + scalar, + layout.immediate_llvm_type(cx), + ) + }, + ConstValue::ByValPair(a, b) => { + let (a_scalar, b_scalar) = match layout.abi { + layout::Abi::ScalarPair(ref a, ref b) => (a, b), + _ => bug!("const_value_to_llvm: invalid ByValPair layout: {:#?}", layout) + }; + let a_llval = primval_to_llvm( + cx, + a, + a_scalar, + layout.scalar_pair_element_llvm_type(cx, 0), + ); + let b_llval = primval_to_llvm( + cx, + b, + b_scalar, + layout.scalar_pair_element_llvm_type(cx, 1), + ); + C_struct(cx, &[a_llval, b_llval], false) + }, + ConstValue::ByRef(alloc) => const_alloc_to_llvm(cx, alloc), + } +} + +pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef { + let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1); + let layout = cx.data_layout(); + let pointer_size = layout.pointer_size.bytes() as usize; + + let mut next_offset = 0; + for (&offset, &alloc_id) in &alloc.relocations { + assert_eq!(offset as usize as u64, offset); + let offset = offset as usize; + if offset > next_offset { + llvals.push(C_bytes(cx, &alloc.bytes[next_offset..offset])); + } + let ptr_offset = read_target_uint( + layout.endian, + &alloc.bytes[offset..(offset + pointer_size)], + ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64; + llvals.push(primval_to_llvm( + cx, + PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }), + &Scalar { + value: layout::Primitive::Pointer, + valid_range: 0..=!0 + }, + Type::i8p(cx) + )); + next_offset = offset + pointer_size; + } + if alloc.bytes.len() >= next_offset { + llvals.push(C_bytes(cx, &alloc.bytes[next_offset ..])); + } + + C_struct(cx, &llvals, true) +} + +pub fn codegen_static_initializer<'a, 'tcx>( + cx: &CodegenCx<'a, 'tcx>, + def_id: DefId) + -> Result> +{ + let instance = ty::Instance::mono(cx.tcx, def_id); + let cid = GlobalId { + instance, + promoted: None + }; + let param_env = ty::ParamEnv::reveal_all(); + let static_ = cx.tcx.const_eval(param_env.and(cid))?; + + let val = match static_.val { + ConstVal::Value(val) => val, + _ => bug!("static const eval returned {:#?}", static_), + }; + Ok(const_value_to_llvm(cx, val, static_.ty)) +} + +impl<'a, 'tcx> FunctionCx<'a, 'tcx> { + fn const_to_const_value( + &mut self, + bx: &Builder<'a, 'tcx>, + constant: &'tcx ty::Const<'tcx>, + ) -> Result, ConstEvalErr<'tcx>> { + match constant.val { + ConstVal::Unevaluated(def_id, ref substs) => { + let tcx = bx.tcx(); + let param_env = ty::ParamEnv::reveal_all(); + let instance = ty::Instance::resolve(tcx, param_env, def_id, substs).unwrap(); + let cid = GlobalId { + instance, + promoted: None, + }; + let c = tcx.const_eval(param_env.and(cid))?; + self.const_to_const_value(bx, c) + }, + ConstVal::Value(val) => Ok(val), + } + } + + pub fn mir_constant_to_const_value( + &mut self, + bx: &Builder<'a, 'tcx>, + constant: &mir::Constant<'tcx>, + ) -> Result, ConstEvalErr<'tcx>> { + match constant.literal { + mir::Literal::Promoted { index } => { + let param_env = ty::ParamEnv::reveal_all(); + let cid = mir::interpret::GlobalId { + instance: self.instance, + promoted: Some(index), + }; + bx.tcx().const_eval(param_env.and(cid)) + } + mir::Literal::Value { value } => { + Ok(self.monomorphize(&value)) + } + }.and_then(|c| self.const_to_const_value(bx, c)) + } + + /// process constant containing SIMD shuffle indices + pub fn simd_shuffle_indices( + &mut self, + bx: &Builder<'a, 'tcx>, + constant: &mir::Constant<'tcx>, + ) -> (ValueRef, Ty<'tcx>) { + self.mir_constant_to_const_value(bx, constant) + .and_then(|c| { + let field_ty = constant.ty.builtin_index().unwrap(); + let fields = match constant.ty.sty { + ty::TyArray(_, n) => n.unwrap_usize(bx.tcx()), + ref other => bug!("invalid simd shuffle type: {}", other), + }; + let values: Result, _> = (0..fields).map(|field| { + let field = const_val_field( + bx.tcx(), + ty::ParamEnv::reveal_all(), + self.instance, + None, + mir::Field::new(field as usize), + c, + constant.ty, + )?; + if let Some(prim) = field.to_primval() { + let layout = bx.cx.layout_of(field_ty); + let scalar = match layout.abi { + layout::Abi::Scalar(ref x) => x, + _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) + }; + Ok(primval_to_llvm( + bx.cx, prim, scalar, + layout.immediate_llvm_type(bx.cx), + )) + } else { + bug!("simd shuffle field {:?}", field) + } + }).collect(); + let llval = C_struct(bx.cx, &values?, false); + Ok((llval, constant.ty)) + }) + .unwrap_or_else(|e| { + e.report(bx.tcx(), constant.span, "shuffle_indices"); + // We've errored, so we don't have to produce working code. + let ty = self.monomorphize(&constant.ty); + let llty = bx.cx.layout_of(ty).llvm_type(bx.cx); + (C_undef(llty), ty) + }) + } +} diff --git a/src/librustc_codegen_llvm/mir/mod.rs b/src/librustc_codegen_llvm/mir/mod.rs new file mode 100644 index 00000000000..47b15320311 --- /dev/null +++ b/src/librustc_codegen_llvm/mir/mod.rs @@ -0,0 +1,652 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use common::{C_i32, C_null}; +use libc::c_uint; +use llvm::{self, ValueRef, BasicBlockRef}; +use llvm::debuginfo::DIScope; +use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts}; +use rustc::ty::layout::{LayoutOf, TyLayout}; +use rustc::mir::{self, Mir}; +use rustc::ty::subst::Substs; +use rustc::session::config::FullDebugInfo; +use base; +use builder::Builder; +use common::{CodegenCx, Funclet}; +use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext}; +use monomorphize::Instance; +use abi::{ArgAttribute, ArgTypeExt, FnType, FnTypeExt, PassMode}; +use type_::Type; + +use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span}; +use syntax::symbol::keywords; + +use std::iter; + +use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; + +pub use self::constant::codegen_static_initializer; + +use self::analyze::CleanupKind; +use self::place::PlaceRef; +use rustc::mir::traversal; + +use self::operand::{OperandRef, OperandValue}; + +/// Master context for codegenning from MIR. +pub struct FunctionCx<'a, 'tcx:'a> { + instance: Instance<'tcx>, + + mir: &'a mir::Mir<'tcx>, + + debug_context: debuginfo::FunctionDebugContext, + + llfn: ValueRef, + + cx: &'a CodegenCx<'a, 'tcx>, + + fn_ty: FnType<'tcx, Ty<'tcx>>, + + /// When unwinding is initiated, we have to store this personality + /// value somewhere so that we can load it and re-use it in the + /// resume instruction. The personality is (afaik) some kind of + /// value used for C++ unwinding, which must filter by type: we + /// don't really care about it very much. Anyway, this value + /// contains an alloca into which the personality is stored and + /// then later loaded when generating the DIVERGE_BLOCK. + personality_slot: Option>, + + /// A `Block` for each MIR `BasicBlock` + blocks: IndexVec, + + /// The funclet status of each basic block + cleanup_kinds: IndexVec, + + /// When targeting MSVC, this stores the cleanup info for each funclet + /// BB. This is initialized as we compute the funclets' head block in RPO. + funclets: &'a IndexVec>, + + /// This stores the landing-pad block for a given BB, computed lazily on GNU + /// and eagerly on MSVC. + landing_pads: IndexVec>, + + /// Cached unreachable block + unreachable_block: Option, + + /// The location where each MIR arg/var/tmp/ret is stored. This is + /// usually an `PlaceRef` representing an alloca, but not always: + /// sometimes we can skip the alloca and just store the value + /// directly using an `OperandRef`, which makes for tighter LLVM + /// IR. The conditions for using an `OperandRef` are as follows: + /// + /// - the type of the local must be judged "immediate" by `is_llvm_immediate` + /// - the operand must never be referenced indirectly + /// - we should not take its address using the `&` operator + /// - nor should it appear in a place path like `tmp.a` + /// - the operand must be defined by an rvalue that can generate immediate + /// values + /// + /// Avoiding allocs can also be important for certain intrinsics, + /// notably `expect`. + locals: IndexVec>, + + /// Debug information for MIR scopes. + scopes: IndexVec, + + /// If this function is being monomorphized, this contains the type substitutions used. + param_substs: &'tcx Substs<'tcx>, +} + +impl<'a, 'tcx> FunctionCx<'a, 'tcx> { + pub fn monomorphize(&self, value: &T) -> T + where T: TypeFoldable<'tcx> + { + self.cx.tcx.subst_and_normalize_erasing_regions( + self.param_substs, + ty::ParamEnv::reveal_all(), + value, + ) + } + + pub fn set_debug_loc(&mut self, bx: &Builder, source_info: mir::SourceInfo) { + let (scope, span) = self.debug_loc(source_info); + debuginfo::set_source_location(&self.debug_context, bx, scope, span); + } + + pub fn debug_loc(&mut self, source_info: mir::SourceInfo) -> (DIScope, Span) { + // Bail out if debug info emission is not enabled. + match self.debug_context { + FunctionDebugContext::DebugInfoDisabled | + FunctionDebugContext::FunctionWithoutDebugInfo => { + return (self.scopes[source_info.scope].scope_metadata, source_info.span); + } + FunctionDebugContext::RegularContext(_) =>{} + } + + // In order to have a good line stepping behavior in debugger, we overwrite debug + // locations of macro expansions with that of the outermost expansion site + // (unless the crate is being compiled with `-Z debug-macros`). + if source_info.span.ctxt() == NO_EXPANSION || + self.cx.sess().opts.debugging_opts.debug_macros { + let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo()); + (scope, source_info.span) + } else { + // Walk up the macro expansion chain until we reach a non-expanded span. + // We also stop at the function body level because no line stepping can occur + // at the level above that. + let mut span = source_info.span; + while span.ctxt() != NO_EXPANSION && span.ctxt() != self.mir.span.ctxt() { + if let Some(info) = span.ctxt().outer().expn_info() { + span = info.call_site; + } else { + break; + } + } + let scope = self.scope_metadata_for_loc(source_info.scope, span.lo()); + // Use span of the outermost expansion site, while keeping the original lexical scope. + (scope, span) + } + } + + // DILocations inherit source file name from the parent DIScope. Due to macro expansions + // it may so happen that the current span belongs to a different file than the DIScope + // corresponding to span's containing visibility scope. If so, we need to create a DIScope + // "extension" into that file. + fn scope_metadata_for_loc(&self, scope_id: mir::VisibilityScope, pos: BytePos) + -> llvm::debuginfo::DIScope { + let scope_metadata = self.scopes[scope_id].scope_metadata; + if pos < self.scopes[scope_id].file_start_pos || + pos >= self.scopes[scope_id].file_end_pos { + let cm = self.cx.sess().codemap(); + let defining_crate = self.debug_context.get_ref(DUMMY_SP).defining_crate; + debuginfo::extend_scope_to_file(self.cx, + scope_metadata, + &cm.lookup_char_pos(pos).file, + defining_crate) + } else { + scope_metadata + } + } +} + +enum LocalRef<'tcx> { + Place(PlaceRef<'tcx>), + Operand(Option>), +} + +impl<'a, 'tcx> LocalRef<'tcx> { + fn new_operand(cx: &CodegenCx<'a, 'tcx>, layout: TyLayout<'tcx>) -> LocalRef<'tcx> { + if layout.is_zst() { + // Zero-size temporaries aren't always initialized, which + // doesn't matter because they don't contain data, but + // we need something in the operand. + LocalRef::Operand(Some(OperandRef::new_zst(cx, layout))) + } else { + LocalRef::Operand(None) + } + } +} + +/////////////////////////////////////////////////////////////////////////// + +pub fn codegen_mir<'a, 'tcx: 'a>( + cx: &'a CodegenCx<'a, 'tcx>, + llfn: ValueRef, + mir: &'a Mir<'tcx>, + instance: Instance<'tcx>, + sig: ty::FnSig<'tcx>, +) { + let fn_ty = FnType::new(cx, sig, &[]); + debug!("fn_ty: {:?}", fn_ty); + let debug_context = + debuginfo::create_function_debug_context(cx, instance, sig, llfn, mir); + let bx = Builder::new_block(cx, llfn, "start"); + + if mir.basic_blocks().iter().any(|bb| bb.is_cleanup) { + bx.set_personality_fn(cx.eh_personality()); + } + + let cleanup_kinds = analyze::cleanup_kinds(&mir); + // Allocate a `Block` for every basic block, except + // the start block, if nothing loops back to it. + let reentrant_start_block = !mir.predecessors_for(mir::START_BLOCK).is_empty(); + let block_bxs: IndexVec = + mir.basic_blocks().indices().map(|bb| { + if bb == mir::START_BLOCK && !reentrant_start_block { + bx.llbb() + } else { + bx.build_sibling_block(&format!("{:?}", bb)).llbb() + } + }).collect(); + + // Compute debuginfo scopes from MIR scopes. + let scopes = debuginfo::create_mir_scopes(cx, mir, &debug_context); + let (landing_pads, funclets) = create_funclets(mir, &bx, &cleanup_kinds, &block_bxs); + + let mut fx = FunctionCx { + instance, + mir, + llfn, + fn_ty, + cx, + personality_slot: None, + blocks: block_bxs, + unreachable_block: None, + cleanup_kinds, + landing_pads, + funclets: &funclets, + scopes, + locals: IndexVec::new(), + debug_context, + param_substs: { + assert!(!instance.substs.needs_infer()); + instance.substs + }, + }; + + let memory_locals = analyze::non_ssa_locals(&fx); + + // Allocate variable and temp allocas + fx.locals = { + let args = arg_local_refs(&bx, &fx, &fx.scopes, &memory_locals); + + let mut allocate_local = |local| { + let decl = &mir.local_decls[local]; + let layout = bx.cx.layout_of(fx.monomorphize(&decl.ty)); + assert!(!layout.ty.has_erasable_regions()); + + if let Some(name) = decl.name { + // User variable + let debug_scope = fx.scopes[decl.source_info.scope]; + let dbg = debug_scope.is_valid() && bx.sess().opts.debuginfo == FullDebugInfo; + + if !memory_locals.contains(local.index()) && !dbg { + debug!("alloc: {:?} ({}) -> operand", local, name); + return LocalRef::new_operand(bx.cx, layout); + } + + debug!("alloc: {:?} ({}) -> place", local, name); + let place = PlaceRef::alloca(&bx, layout, &name.as_str()); + if dbg { + let (scope, span) = fx.debug_loc(decl.source_info); + declare_local(&bx, &fx.debug_context, name, layout.ty, scope, + VariableAccess::DirectVariable { alloca: place.llval }, + VariableKind::LocalVariable, span); + } + LocalRef::Place(place) + } else { + // Temporary or return place + if local == mir::RETURN_PLACE && fx.fn_ty.ret.is_indirect() { + debug!("alloc: {:?} (return place) -> place", local); + let llretptr = llvm::get_param(llfn, 0); + LocalRef::Place(PlaceRef::new_sized(llretptr, layout, layout.align)) + } else if memory_locals.contains(local.index()) { + debug!("alloc: {:?} -> place", local); + LocalRef::Place(PlaceRef::alloca(&bx, layout, &format!("{:?}", local))) + } else { + // If this is an immediate local, we do not create an + // alloca in advance. Instead we wait until we see the + // definition and update the operand there. + debug!("alloc: {:?} -> operand", local); + LocalRef::new_operand(bx.cx, layout) + } + } + }; + + let retptr = allocate_local(mir::RETURN_PLACE); + iter::once(retptr) + .chain(args.into_iter()) + .chain(mir.vars_and_temps_iter().map(allocate_local)) + .collect() + }; + + // Branch to the START block, if it's not the entry block. + if reentrant_start_block { + bx.br(fx.blocks[mir::START_BLOCK]); + } + + // Up until here, IR instructions for this function have explicitly not been annotated with + // source code location, so we don't step into call setup code. From here on, source location + // emitting should be enabled. + debuginfo::start_emitting_source_locations(&fx.debug_context); + + let rpo = traversal::reverse_postorder(&mir); + let mut visited = BitVector::new(mir.basic_blocks().len()); + + // Codegen the body of each block using reverse postorder + for (bb, _) in rpo { + visited.insert(bb.index()); + fx.codegen_block(bb); + } + + // Remove blocks that haven't been visited, or have no + // predecessors. + for bb in mir.basic_blocks().indices() { + // Unreachable block + if !visited.contains(bb.index()) { + debug!("codegen_mir: block {:?} was not visited", bb); + unsafe { + llvm::LLVMDeleteBasicBlock(fx.blocks[bb]); + } + } + } +} + +fn create_funclets<'a, 'tcx>( + mir: &'a Mir<'tcx>, + bx: &Builder<'a, 'tcx>, + cleanup_kinds: &IndexVec, + block_bxs: &IndexVec) + -> (IndexVec>, + IndexVec>) +{ + block_bxs.iter_enumerated().zip(cleanup_kinds).map(|((bb, &llbb), cleanup_kind)| { + match *cleanup_kind { + CleanupKind::Funclet if base::wants_msvc_seh(bx.sess()) => {} + _ => return (None, None) + } + + let cleanup; + let ret_llbb; + match mir[bb].terminator.as_ref().map(|t| &t.kind) { + // This is a basic block that we're aborting the program for, + // notably in an `extern` function. These basic blocks are inserted + // so that we assert that `extern` functions do indeed not panic, + // and if they do we abort the process. + // + // On MSVC these are tricky though (where we're doing funclets). If + // we were to do a cleanuppad (like below) the normal functions like + // `longjmp` would trigger the abort logic, terminating the + // program. Instead we insert the equivalent of `catch(...)` for C++ + // which magically doesn't trigger when `longjmp` files over this + // frame. + // + // Lots more discussion can be found on #48251 but this codegen is + // modeled after clang's for: + // + // try { + // foo(); + // } catch (...) { + // bar(); + // } + Some(&mir::TerminatorKind::Abort) => { + let cs_bx = bx.build_sibling_block(&format!("cs_funclet{:?}", bb)); + let cp_bx = bx.build_sibling_block(&format!("cp_funclet{:?}", bb)); + ret_llbb = cs_bx.llbb(); + + let cs = cs_bx.catch_switch(None, None, 1); + cs_bx.add_handler(cs, cp_bx.llbb()); + + // The "null" here is actually a RTTI type descriptor for the + // C++ personality function, but `catch (...)` has no type so + // it's null. The 64 here is actually a bitfield which + // represents that this is a catch-all block. + let null = C_null(Type::i8p(bx.cx)); + let sixty_four = C_i32(bx.cx, 64); + cleanup = cp_bx.catch_pad(cs, &[null, sixty_four, null]); + cp_bx.br(llbb); + } + _ => { + let cleanup_bx = bx.build_sibling_block(&format!("funclet_{:?}", bb)); + ret_llbb = cleanup_bx.llbb(); + cleanup = cleanup_bx.cleanup_pad(None, &[]); + cleanup_bx.br(llbb); + } + }; + + (Some(ret_llbb), Some(Funclet::new(cleanup))) + }).unzip() +} + +/// Produce, for each argument, a `ValueRef` pointing at the +/// argument's value. As arguments are places, these are always +/// indirect. +fn arg_local_refs<'a, 'tcx>(bx: &Builder<'a, 'tcx>, + fx: &FunctionCx<'a, 'tcx>, + scopes: &IndexVec, + memory_locals: &BitVector) + -> Vec> { + let mir = fx.mir; + let tcx = bx.tcx(); + let mut idx = 0; + let mut llarg_idx = fx.fn_ty.ret.is_indirect() as usize; + + // Get the argument scope, if it exists and if we need it. + let arg_scope = scopes[mir::ARGUMENT_VISIBILITY_SCOPE]; + let arg_scope = if arg_scope.is_valid() && bx.sess().opts.debuginfo == FullDebugInfo { + Some(arg_scope.scope_metadata) + } else { + None + }; + + let deref_op = unsafe { + [llvm::LLVMRustDIBuilderCreateOpDeref()] + }; + + mir.args_iter().enumerate().map(|(arg_index, local)| { + let arg_decl = &mir.local_decls[local]; + + let name = if let Some(name) = arg_decl.name { + name.as_str().to_string() + } else { + format!("arg{}", arg_index) + }; + + if Some(local) == mir.spread_arg { + // This argument (e.g. the last argument in the "rust-call" ABI) + // is a tuple that was spread at the ABI level and now we have + // to reconstruct it into a tuple local variable, from multiple + // individual LLVM function arguments. + + let arg_ty = fx.monomorphize(&arg_decl.ty); + let tupled_arg_tys = match arg_ty.sty { + ty::TyTuple(ref tys) => tys, + _ => bug!("spread argument isn't a tuple?!") + }; + + let place = PlaceRef::alloca(bx, bx.cx.layout_of(arg_ty), &name); + for i in 0..tupled_arg_tys.len() { + let arg = &fx.fn_ty.args[idx]; + idx += 1; + if arg.pad.is_some() { + llarg_idx += 1; + } + arg.store_fn_arg(bx, &mut llarg_idx, place.project_field(bx, i)); + } + + // Now that we have one alloca that contains the aggregate value, + // we can create one debuginfo entry for the argument. + arg_scope.map(|scope| { + let variable_access = VariableAccess::DirectVariable { + alloca: place.llval + }; + declare_local( + bx, + &fx.debug_context, + arg_decl.name.unwrap_or(keywords::Invalid.name()), + arg_ty, scope, + variable_access, + VariableKind::ArgumentVariable(arg_index + 1), + DUMMY_SP + ); + }); + + return LocalRef::Place(place); + } + + let arg = &fx.fn_ty.args[idx]; + idx += 1; + if arg.pad.is_some() { + llarg_idx += 1; + } + + if arg_scope.is_none() && !memory_locals.contains(local.index()) { + // We don't have to cast or keep the argument in the alloca. + // FIXME(eddyb): We should figure out how to use llvm.dbg.value instead + // of putting everything in allocas just so we can use llvm.dbg.declare. + let local = |op| LocalRef::Operand(Some(op)); + match arg.mode { + PassMode::Ignore => { + return local(OperandRef::new_zst(bx.cx, arg.layout)); + } + PassMode::Direct(_) => { + let llarg = llvm::get_param(bx.llfn(), llarg_idx as c_uint); + bx.set_value_name(llarg, &name); + llarg_idx += 1; + return local( + OperandRef::from_immediate_or_packed_pair(bx, llarg, arg.layout)); + } + PassMode::Pair(..) => { + let a = llvm::get_param(bx.llfn(), llarg_idx as c_uint); + bx.set_value_name(a, &(name.clone() + ".0")); + llarg_idx += 1; + + let b = llvm::get_param(bx.llfn(), llarg_idx as c_uint); + bx.set_value_name(b, &(name + ".1")); + llarg_idx += 1; + + return local(OperandRef { + val: OperandValue::Pair(a, b), + layout: arg.layout + }); + } + _ => {} + } + } + + let place = if arg.is_indirect() { + // Don't copy an indirect argument to an alloca, the caller + // already put it in a temporary alloca and gave it up. + // FIXME: lifetimes + let llarg = llvm::get_param(bx.llfn(), llarg_idx as c_uint); + bx.set_value_name(llarg, &name); + llarg_idx += 1; + PlaceRef::new_sized(llarg, arg.layout, arg.layout.align) + } else { + let tmp = PlaceRef::alloca(bx, arg.layout, &name); + arg.store_fn_arg(bx, &mut llarg_idx, tmp); + tmp + }; + arg_scope.map(|scope| { + // Is this a regular argument? + if arg_index > 0 || mir.upvar_decls.is_empty() { + // The Rust ABI passes indirect variables using a pointer and a manual copy, so we + // need to insert a deref here, but the C ABI uses a pointer and a copy using the + // byval attribute, for which LLVM does the deref itself, so we must not add it. + // Starting with D31439 in LLVM 5, it *always* does the deref itself. + let mut variable_access = VariableAccess::DirectVariable { + alloca: place.llval + }; + if unsafe { llvm::LLVMRustVersionMajor() < 5 } { + if let PassMode::Indirect(ref attrs) = arg.mode { + if !attrs.contains(ArgAttribute::ByVal) { + variable_access = VariableAccess::IndirectVariable { + alloca: place.llval, + address_operations: &deref_op, + }; + } + } + } + + declare_local( + bx, + &fx.debug_context, + arg_decl.name.unwrap_or(keywords::Invalid.name()), + arg.layout.ty, + scope, + variable_access, + VariableKind::ArgumentVariable(arg_index + 1), + DUMMY_SP + ); + return; + } + + // Or is it the closure environment? + let (closure_layout, env_ref) = match arg.layout.ty.sty { + ty::TyRawPtr(ty::TypeAndMut { ty, .. }) | + ty::TyRef(_, ty, _) => (bx.cx.layout_of(ty), true), + _ => (arg.layout, false) + }; + + let (def_id, upvar_substs) = match closure_layout.ty.sty { + ty::TyClosure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)), + ty::TyGenerator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)), + _ => bug!("upvar_decls with non-closure arg0 type `{}`", closure_layout.ty) + }; + let upvar_tys = upvar_substs.upvar_tys(def_id, tcx); + + // Store the pointer to closure data in an alloca for debuginfo + // because that's what the llvm.dbg.declare intrinsic expects. + + // FIXME(eddyb) this shouldn't be necessary but SROA seems to + // mishandle DW_OP_plus not preceded by DW_OP_deref, i.e. it + // doesn't actually strip the offset when splitting the closure + // environment into its components so it ends up out of bounds. + let env_ptr = if !env_ref { + let scratch = PlaceRef::alloca(bx, + bx.cx.layout_of(tcx.mk_mut_ptr(arg.layout.ty)), + "__debuginfo_env_ptr"); + bx.store(place.llval, scratch.llval, scratch.align); + scratch.llval + } else { + place.llval + }; + + for (i, (decl, ty)) in mir.upvar_decls.iter().zip(upvar_tys).enumerate() { + let byte_offset_of_var_in_env = closure_layout.fields.offset(i).bytes(); + + let ops = unsafe { + [llvm::LLVMRustDIBuilderCreateOpDeref(), + llvm::LLVMRustDIBuilderCreateOpPlusUconst(), + byte_offset_of_var_in_env as i64, + llvm::LLVMRustDIBuilderCreateOpDeref()] + }; + + // The environment and the capture can each be indirect. + + // FIXME(eddyb) see above why we have to keep + // a pointer in an alloca for debuginfo atm. + let mut ops = if env_ref || true { &ops[..] } else { &ops[1..] }; + + let ty = if let (true, &ty::TyRef(_, ty, _)) = (decl.by_ref, &ty.sty) { + ty + } else { + ops = &ops[..ops.len() - 1]; + ty + }; + + let variable_access = VariableAccess::IndirectVariable { + alloca: env_ptr, + address_operations: &ops + }; + declare_local( + bx, + &fx.debug_context, + decl.debug_name, + ty, + scope, + variable_access, + VariableKind::CapturedVariable, + DUMMY_SP + ); + } + }); + LocalRef::Place(place) + }).collect() +} + +mod analyze; +mod block; +mod constant; +pub mod place; +pub mod operand; +mod rvalue; +mod statement; diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs new file mode 100644 index 00000000000..62ef58f8255 --- /dev/null +++ b/src/librustc_codegen_llvm/mir/operand.rs @@ -0,0 +1,427 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use llvm::ValueRef; +use rustc::middle::const_val::ConstEvalErr; +use rustc::mir; +use rustc::mir::interpret::ConstValue; +use rustc::ty; +use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; +use rustc_data_structures::indexed_vec::Idx; + +use base; +use common::{self, CodegenCx, C_null, C_undef, C_usize}; +use builder::{Builder, MemFlags}; +use value::Value; +use type_of::LayoutLlvmExt; +use type_::Type; +use consts; + +use std::fmt; +use std::ptr; + +use super::{FunctionCx, LocalRef}; +use super::constant::{primval_to_llvm, const_alloc_to_llvm}; +use super::place::PlaceRef; + +/// The representation of a Rust value. The enum variant is in fact +/// uniquely determined by the value's type, but is kept as a +/// safety check. +#[derive(Copy, Clone)] +pub enum OperandValue { + /// A reference to the actual operand. The data is guaranteed + /// to be valid for the operand's lifetime. + Ref(ValueRef, Align), + /// A single LLVM value. + Immediate(ValueRef), + /// A pair of immediate LLVM values. Used by fat pointers too. + Pair(ValueRef, ValueRef) +} + +impl fmt::Debug for OperandValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + OperandValue::Ref(r, align) => { + write!(f, "Ref({:?}, {:?})", Value(r), align) + } + OperandValue::Immediate(i) => { + write!(f, "Immediate({:?})", Value(i)) + } + OperandValue::Pair(a, b) => { + write!(f, "Pair({:?}, {:?})", Value(a), Value(b)) + } + } + } +} + +/// An `OperandRef` is an "SSA" reference to a Rust value, along with +/// its type. +/// +/// NOTE: unless you know a value's type exactly, you should not +/// generate LLVM opcodes acting on it and instead act via methods, +/// to avoid nasty edge cases. In particular, using `Builder::store` +/// directly is sure to cause problems -- use `OperandRef::store` +/// instead. +#[derive(Copy, Clone)] +pub struct OperandRef<'tcx> { + // The value. + pub val: OperandValue, + + // The layout of value, based on its Rust type. + pub layout: TyLayout<'tcx>, +} + +impl<'tcx> fmt::Debug for OperandRef<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "OperandRef({:?} @ {:?})", self.val, self.layout) + } +} + +impl<'a, 'tcx> OperandRef<'tcx> { + pub fn new_zst(cx: &CodegenCx<'a, 'tcx>, + layout: TyLayout<'tcx>) -> OperandRef<'tcx> { + assert!(layout.is_zst()); + OperandRef { + val: OperandValue::Immediate(C_undef(layout.immediate_llvm_type(cx))), + layout + } + } + + pub fn from_const(bx: &Builder<'a, 'tcx>, + val: ConstValue<'tcx>, + ty: ty::Ty<'tcx>) + -> Result, ConstEvalErr<'tcx>> { + let layout = bx.cx.layout_of(ty); + + if layout.is_zst() { + return Ok(OperandRef::new_zst(bx.cx, layout)); + } + + let val = match val { + ConstValue::ByVal(x) => { + let scalar = match layout.abi { + layout::Abi::Scalar(ref x) => x, + _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) + }; + let llval = primval_to_llvm( + bx.cx, + x, + scalar, + layout.immediate_llvm_type(bx.cx), + ); + OperandValue::Immediate(llval) + }, + ConstValue::ByValPair(a, b) => { + let (a_scalar, b_scalar) = match layout.abi { + layout::Abi::ScalarPair(ref a, ref b) => (a, b), + _ => bug!("from_const: invalid ByValPair layout: {:#?}", layout) + }; + let a_llval = primval_to_llvm( + bx.cx, + a, + a_scalar, + layout.scalar_pair_element_llvm_type(bx.cx, 0), + ); + let b_llval = primval_to_llvm( + bx.cx, + b, + b_scalar, + layout.scalar_pair_element_llvm_type(bx.cx, 1), + ); + OperandValue::Pair(a_llval, b_llval) + }, + ConstValue::ByRef(alloc) => { + let init = const_alloc_to_llvm(bx.cx, alloc); + let llval = consts::addr_of(bx.cx, init, layout.align, "byte_str"); + let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to()); + return Ok(PlaceRef::new_sized(llval, layout, alloc.align).load(bx)); + }, + }; + + Ok(OperandRef { + val, + layout + }) + } + + /// Asserts that this operand refers to a scalar and returns + /// a reference to its value. + pub fn immediate(self) -> ValueRef { + match self.val { + OperandValue::Immediate(s) => s, + _ => bug!("not immediate: {:?}", self) + } + } + + pub fn deref(self, cx: &CodegenCx<'a, 'tcx>) -> PlaceRef<'tcx> { + let projected_ty = self.layout.ty.builtin_deref(true) + .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)).ty; + let (llptr, llextra) = match self.val { + OperandValue::Immediate(llptr) => (llptr, ptr::null_mut()), + OperandValue::Pair(llptr, llextra) => (llptr, llextra), + OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self) + }; + let layout = cx.layout_of(projected_ty); + PlaceRef { + llval: llptr, + llextra, + layout, + align: layout.align, + } + } + + /// If this operand is a `Pair`, we return an aggregate with the two values. + /// For other cases, see `immediate`. + pub fn immediate_or_packed_pair(self, bx: &Builder<'a, 'tcx>) -> ValueRef { + if let OperandValue::Pair(a, b) = self.val { + let llty = self.layout.llvm_type(bx.cx); + debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}", + self, llty); + // Reconstruct the immediate aggregate. + let mut llpair = C_undef(llty); + llpair = bx.insert_value(llpair, a, 0); + llpair = bx.insert_value(llpair, b, 1); + llpair + } else { + self.immediate() + } + } + + /// If the type is a pair, we return a `Pair`, otherwise, an `Immediate`. + pub fn from_immediate_or_packed_pair(bx: &Builder<'a, 'tcx>, + llval: ValueRef, + layout: TyLayout<'tcx>) + -> OperandRef<'tcx> { + let val = if layout.is_llvm_scalar_pair() { + debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", + llval, layout); + + // Deconstruct the immediate aggregate. + OperandValue::Pair(bx.extract_value(llval, 0), + bx.extract_value(llval, 1)) + } else { + OperandValue::Immediate(llval) + }; + OperandRef { val, layout } + } + + pub fn extract_field(&self, bx: &Builder<'a, 'tcx>, i: usize) -> OperandRef<'tcx> { + let field = self.layout.field(bx.cx, i); + let offset = self.layout.fields.offset(i); + + let mut val = match (self.val, &self.layout.abi) { + // If the field is ZST, it has no data. + _ if field.is_zst() => { + return OperandRef::new_zst(bx.cx, field); + } + + // Newtype of a scalar, scalar pair or vector. + (OperandValue::Immediate(_), _) | + (OperandValue::Pair(..), _) if field.size == self.layout.size => { + assert_eq!(offset.bytes(), 0); + self.val + } + + // Extract a scalar component from a pair. + (OperandValue::Pair(a_llval, b_llval), &layout::Abi::ScalarPair(ref a, ref b)) => { + if offset.bytes() == 0 { + assert_eq!(field.size, a.value.size(bx.cx)); + OperandValue::Immediate(a_llval) + } else { + assert_eq!(offset, a.value.size(bx.cx) + .abi_align(b.value.align(bx.cx))); + assert_eq!(field.size, b.value.size(bx.cx)); + OperandValue::Immediate(b_llval) + } + } + + // `#[repr(simd)]` types are also immediate. + (OperandValue::Immediate(llval), &layout::Abi::Vector { .. }) => { + OperandValue::Immediate( + bx.extract_element(llval, C_usize(bx.cx, i as u64))) + } + + _ => bug!("OperandRef::extract_field({:?}): not applicable", self) + }; + + // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. + match val { + OperandValue::Immediate(ref mut llval) => { + *llval = bx.bitcast(*llval, field.immediate_llvm_type(bx.cx)); + } + OperandValue::Pair(ref mut a, ref mut b) => { + *a = bx.bitcast(*a, field.scalar_pair_element_llvm_type(bx.cx, 0)); + *b = bx.bitcast(*b, field.scalar_pair_element_llvm_type(bx.cx, 1)); + } + OperandValue::Ref(..) => bug!() + } + + OperandRef { + val, + layout: field + } + } +} + +impl<'a, 'tcx> OperandValue { + pub fn store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { + self.store_with_flags(bx, dest, MemFlags::empty()); + } + + pub fn volatile_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { + self.store_with_flags(bx, dest, MemFlags::VOLATILE); + } + + pub fn nontemporal_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { + self.store_with_flags(bx, dest, MemFlags::NONTEMPORAL); + } + + fn store_with_flags(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>, flags: MemFlags) { + debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest); + // Avoid generating stores of zero-sized values, because the only way to have a zero-sized + // value is through `undef`, and store itself is useless. + if dest.layout.is_zst() { + return; + } + match self { + OperandValue::Ref(r, source_align) => { + base::memcpy_ty(bx, dest.llval, r, dest.layout, + source_align.min(dest.align), flags) + } + OperandValue::Immediate(s) => { + let val = base::from_immediate(bx, s); + bx.store_with_flags(val, dest.llval, dest.align, flags); + } + OperandValue::Pair(a, b) => { + for (i, &x) in [a, b].iter().enumerate() { + let mut llptr = bx.struct_gep(dest.llval, i as u64); + // Make sure to always store i1 as i8. + if common::val_ty(x) == Type::i1(bx.cx) { + llptr = bx.pointercast(llptr, Type::i8p(bx.cx)); + } + let val = base::from_immediate(bx, x); + bx.store_with_flags(val, llptr, dest.align, flags); + } + } + } + } +} + +impl<'a, 'tcx> FunctionCx<'a, 'tcx> { + fn maybe_codegen_consume_direct(&mut self, + bx: &Builder<'a, 'tcx>, + place: &mir::Place<'tcx>) + -> Option> + { + debug!("maybe_codegen_consume_direct(place={:?})", place); + + // watch out for locals that do not have an + // alloca; they are handled somewhat differently + if let mir::Place::Local(index) = *place { + match self.locals[index] { + LocalRef::Operand(Some(o)) => { + return Some(o); + } + LocalRef::Operand(None) => { + bug!("use of {:?} before def", place); + } + LocalRef::Place(..) => { + // use path below + } + } + } + + // Moves out of scalar and scalar pair fields are trivial. + if let &mir::Place::Projection(ref proj) = place { + if let Some(o) = self.maybe_codegen_consume_direct(bx, &proj.base) { + match proj.elem { + mir::ProjectionElem::Field(ref f, _) => { + return Some(o.extract_field(bx, f.index())); + } + mir::ProjectionElem::Index(_) | + mir::ProjectionElem::ConstantIndex { .. } => { + // ZSTs don't require any actual memory access. + // FIXME(eddyb) deduplicate this with the identical + // checks in `codegen_consume` and `extract_field`. + let elem = o.layout.field(bx.cx, 0); + if elem.is_zst() { + return Some(OperandRef::new_zst(bx.cx, elem)); + } + } + _ => {} + } + } + } + + None + } + + pub fn codegen_consume(&mut self, + bx: &Builder<'a, 'tcx>, + place: &mir::Place<'tcx>) + -> OperandRef<'tcx> + { + debug!("codegen_consume(place={:?})", place); + + let ty = self.monomorphized_place_ty(place); + let layout = bx.cx.layout_of(ty); + + // ZSTs don't require any actual memory access. + if layout.is_zst() { + return OperandRef::new_zst(bx.cx, layout); + } + + if let Some(o) = self.maybe_codegen_consume_direct(bx, place) { + return o; + } + + // for most places, to consume them we just load them + // out from their home + self.codegen_place(bx, place).load(bx) + } + + pub fn codegen_operand(&mut self, + bx: &Builder<'a, 'tcx>, + operand: &mir::Operand<'tcx>) + -> OperandRef<'tcx> + { + debug!("codegen_operand(operand={:?})", operand); + + match *operand { + mir::Operand::Copy(ref place) | + mir::Operand::Move(ref place) => { + self.codegen_consume(bx, place) + } + + mir::Operand::Constant(ref constant) => { + let ty = self.monomorphize(&constant.ty); + self.mir_constant_to_const_value(bx, constant) + .and_then(|c| OperandRef::from_const(bx, c, ty)) + .unwrap_or_else(|err| { + match constant.literal { + mir::Literal::Promoted { .. } => { + // don't report errors inside promoteds, just warnings. + }, + mir::Literal::Value { .. } => { + err.report(bx.tcx(), constant.span, "const operand") + }, + } + // We've errored, so we don't have to produce working code. + let layout = bx.cx.layout_of(ty); + PlaceRef::new_sized( + C_null(layout.llvm_type(bx.cx).ptr_to()), + layout, + layout.align, + ).load(bx) + }) + } + } + } +} diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs new file mode 100644 index 00000000000..bda8c758750 --- /dev/null +++ b/src/librustc_codegen_llvm/mir/place.rs @@ -0,0 +1,498 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use llvm::{self, ValueRef}; +use rustc::ty::{self, Ty}; +use rustc::ty::layout::{self, Align, TyLayout, LayoutOf}; +use rustc::mir; +use rustc::mir::tcx::PlaceTy; +use rustc_data_structures::indexed_vec::Idx; +use base; +use builder::Builder; +use common::{CodegenCx, C_undef, C_usize, C_u8, C_u32, C_uint, C_null, C_uint_big}; +use consts; +use type_of::LayoutLlvmExt; +use type_::Type; +use value::Value; +use glue; + +use std::ptr; + +use super::{FunctionCx, LocalRef}; +use super::operand::{OperandRef, OperandValue}; + +#[derive(Copy, Clone, Debug)] +pub struct PlaceRef<'tcx> { + /// Pointer to the contents of the place + pub llval: ValueRef, + + /// This place's extra data if it is unsized, or null + pub llextra: ValueRef, + + /// Monomorphized type of this place, including variant information + pub layout: TyLayout<'tcx>, + + /// What alignment we know for this place + pub align: Align, +} + +impl<'a, 'tcx> PlaceRef<'tcx> { + pub fn new_sized(llval: ValueRef, + layout: TyLayout<'tcx>, + align: Align) + -> PlaceRef<'tcx> { + PlaceRef { + llval, + llextra: ptr::null_mut(), + layout, + align + } + } + + pub fn alloca(bx: &Builder<'a, 'tcx>, layout: TyLayout<'tcx>, name: &str) + -> PlaceRef<'tcx> { + debug!("alloca({:?}: {:?})", name, layout); + let tmp = bx.alloca(layout.llvm_type(bx.cx), name, layout.align); + Self::new_sized(tmp, layout, layout.align) + } + + pub fn len(&self, cx: &CodegenCx<'a, 'tcx>) -> ValueRef { + if let layout::FieldPlacement::Array { count, .. } = self.layout.fields { + if self.layout.is_unsized() { + assert!(self.has_extra()); + assert_eq!(count, 0); + self.llextra + } else { + C_usize(cx, count) + } + } else { + bug!("unexpected layout `{:#?}` in PlaceRef::len", self.layout) + } + } + + pub fn has_extra(&self) -> bool { + !self.llextra.is_null() + } + + pub fn load(&self, bx: &Builder<'a, 'tcx>) -> OperandRef<'tcx> { + debug!("PlaceRef::load: {:?}", self); + + assert!(!self.has_extra()); + + if self.layout.is_zst() { + return OperandRef::new_zst(bx.cx, self.layout); + } + + let scalar_load_metadata = |load, scalar: &layout::Scalar| { + let vr = scalar.valid_range.clone(); + match scalar.value { + layout::Int(..) => { + let range = scalar.valid_range_exclusive(bx.cx); + if range.start != range.end { + bx.range_metadata(load, range); + } + } + layout::Pointer if vr.start() < vr.end() && !vr.contains(&0) => { + bx.nonnull_metadata(load); + } + _ => {} + } + }; + + let val = if self.layout.is_llvm_immediate() { + let mut const_llval = ptr::null_mut(); + unsafe { + let global = llvm::LLVMIsAGlobalVariable(self.llval); + if !global.is_null() && llvm::LLVMIsGlobalConstant(global) == llvm::True { + const_llval = llvm::LLVMGetInitializer(global); + } + } + + let llval = if !const_llval.is_null() { + const_llval + } else { + let load = bx.load(self.llval, self.align); + if let layout::Abi::Scalar(ref scalar) = self.layout.abi { + scalar_load_metadata(load, scalar); + } + load + }; + OperandValue::Immediate(base::to_immediate(bx, llval, self.layout)) + } else if let layout::Abi::ScalarPair(ref a, ref b) = self.layout.abi { + let load = |i, scalar: &layout::Scalar| { + let mut llptr = bx.struct_gep(self.llval, i as u64); + // Make sure to always load i1 as i8. + if scalar.is_bool() { + llptr = bx.pointercast(llptr, Type::i8p(bx.cx)); + } + let load = bx.load(llptr, self.align); + scalar_load_metadata(load, scalar); + if scalar.is_bool() { + bx.trunc(load, Type::i1(bx.cx)) + } else { + load + } + }; + OperandValue::Pair(load(0, a), load(1, b)) + } else { + OperandValue::Ref(self.llval, self.align) + }; + + OperandRef { val, layout: self.layout } + } + + /// Access a field, at a point when the value's case is known. + pub fn project_field(self, bx: &Builder<'a, 'tcx>, ix: usize) -> PlaceRef<'tcx> { + let cx = bx.cx; + let field = self.layout.field(cx, ix); + let offset = self.layout.fields.offset(ix); + let align = self.align.min(self.layout.align).min(field.align); + + let simple = || { + // Unions and newtypes only use an offset of 0. + let llval = if offset.bytes() == 0 { + self.llval + } else if let layout::Abi::ScalarPair(ref a, ref b) = self.layout.abi { + // Offsets have to match either first or second field. + assert_eq!(offset, a.value.size(cx).abi_align(b.value.align(cx))); + bx.struct_gep(self.llval, 1) + } else { + bx.struct_gep(self.llval, self.layout.llvm_field_index(ix)) + }; + PlaceRef { + // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. + llval: bx.pointercast(llval, field.llvm_type(cx).ptr_to()), + llextra: if cx.type_has_metadata(field.ty) { + self.llextra + } else { + ptr::null_mut() + }, + layout: field, + align, + } + }; + + // Simple cases, which don't need DST adjustment: + // * no metadata available - just log the case + // * known alignment - sized types, [T], str or a foreign type + // * packed struct - there is no alignment padding + match field.ty.sty { + _ if !self.has_extra() => { + debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment", + ix, Value(self.llval)); + return simple(); + } + _ if !field.is_unsized() => return simple(), + ty::TySlice(..) | ty::TyStr | ty::TyForeign(..) => return simple(), + ty::TyAdt(def, _) => { + if def.repr.packed() { + // FIXME(eddyb) generalize the adjustment when we + // start supporting packing to larger alignments. + assert_eq!(self.layout.align.abi(), 1); + return simple(); + } + } + _ => {} + } + + // We need to get the pointer manually now. + // We do this by casting to a *i8, then offsetting it by the appropriate amount. + // We do this instead of, say, simply adjusting the pointer from the result of a GEP + // because the field may have an arbitrary alignment in the LLVM representation + // anyway. + // + // To demonstrate: + // struct Foo { + // x: u16, + // y: T + // } + // + // The type Foo> is represented in LLVM as { u16, { u16, u8 }}, meaning that + // the `y` field has 16-bit alignment. + + let meta = self.llextra; + + let unaligned_offset = C_usize(cx, offset.bytes()); + + // Get the alignment of the field + let (_, unsized_align) = glue::size_and_align_of_dst(bx, field.ty, meta); + + // Bump the unaligned offset up to the appropriate alignment using the + // following expression: + // + // (unaligned offset + (align - 1)) & -align + + // Calculate offset + let align_sub_1 = bx.sub(unsized_align, C_usize(cx, 1u64)); + let offset = bx.and(bx.add(unaligned_offset, align_sub_1), + bx.neg(unsized_align)); + + debug!("struct_field_ptr: DST field offset: {:?}", Value(offset)); + + // Cast and adjust pointer + let byte_ptr = bx.pointercast(self.llval, Type::i8p(cx)); + let byte_ptr = bx.gep(byte_ptr, &[offset]); + + // Finally, cast back to the type expected + let ll_fty = field.llvm_type(cx); + debug!("struct_field_ptr: Field type is {:?}", ll_fty); + + PlaceRef { + llval: bx.pointercast(byte_ptr, ll_fty.ptr_to()), + llextra: self.llextra, + layout: field, + align, + } + } + + /// Obtain the actual discriminant of a value. + pub fn codegen_get_discr(self, bx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> ValueRef { + let cast_to = bx.cx.layout_of(cast_to).immediate_llvm_type(bx.cx); + if self.layout.abi == layout::Abi::Uninhabited { + return C_undef(cast_to); + } + match self.layout.variants { + layout::Variants::Single { index } => { + let discr_val = self.layout.ty.ty_adt_def().map_or( + index as u128, + |def| def.discriminant_for_variant(bx.cx.tcx, index).val); + return C_uint_big(cast_to, discr_val); + } + layout::Variants::Tagged { .. } | + layout::Variants::NicheFilling { .. } => {}, + } + + let discr = self.project_field(bx, 0); + let lldiscr = discr.load(bx).immediate(); + match self.layout.variants { + layout::Variants::Single { .. } => bug!(), + layout::Variants::Tagged { ref tag, .. } => { + let signed = match tag.value { + layout::Int(_, signed) => signed, + _ => false + }; + bx.intcast(lldiscr, cast_to, signed) + } + layout::Variants::NicheFilling { + dataful_variant, + ref niche_variants, + niche_start, + .. + } => { + let niche_llty = discr.layout.immediate_llvm_type(bx.cx); + if niche_variants.start() == niche_variants.end() { + // FIXME(eddyb) Check the actual primitive type here. + let niche_llval = if niche_start == 0 { + // HACK(eddyb) Using `C_null` as it works on all types. + C_null(niche_llty) + } else { + C_uint_big(niche_llty, niche_start) + }; + bx.select(bx.icmp(llvm::IntEQ, lldiscr, niche_llval), + C_uint(cast_to, *niche_variants.start() as u64), + C_uint(cast_to, dataful_variant as u64)) + } else { + // Rebase from niche values to discriminant values. + let delta = niche_start.wrapping_sub(*niche_variants.start() as u128); + let lldiscr = bx.sub(lldiscr, C_uint_big(niche_llty, delta)); + let lldiscr_max = C_uint(niche_llty, *niche_variants.end() as u64); + bx.select(bx.icmp(llvm::IntULE, lldiscr, lldiscr_max), + bx.intcast(lldiscr, cast_to, false), + C_uint(cast_to, dataful_variant as u64)) + } + } + } + } + + /// Set the discriminant for a new value of the given case of the given + /// representation. + pub fn codegen_set_discr(&self, bx: &Builder<'a, 'tcx>, variant_index: usize) { + if self.layout.for_variant(bx.cx, variant_index).abi == layout::Abi::Uninhabited { + return; + } + match self.layout.variants { + layout::Variants::Single { index } => { + assert_eq!(index, variant_index); + } + layout::Variants::Tagged { .. } => { + let ptr = self.project_field(bx, 0); + let to = self.layout.ty.ty_adt_def().unwrap() + .discriminant_for_variant(bx.tcx(), variant_index) + .val; + bx.store( + C_uint_big(ptr.layout.llvm_type(bx.cx), to), + ptr.llval, + ptr.align); + } + layout::Variants::NicheFilling { + dataful_variant, + ref niche_variants, + niche_start, + .. + } => { + if variant_index != dataful_variant { + if bx.sess().target.target.arch == "arm" || + bx.sess().target.target.arch == "aarch64" { + // Issue #34427: As workaround for LLVM bug on ARM, + // use memset of 0 before assigning niche value. + let llptr = bx.pointercast(self.llval, Type::i8(bx.cx).ptr_to()); + let fill_byte = C_u8(bx.cx, 0); + let (size, align) = self.layout.size_and_align(); + let size = C_usize(bx.cx, size.bytes()); + let align = C_u32(bx.cx, align.abi() as u32); + base::call_memset(bx, llptr, fill_byte, size, align, false); + } + + let niche = self.project_field(bx, 0); + let niche_llty = niche.layout.immediate_llvm_type(bx.cx); + let niche_value = ((variant_index - *niche_variants.start()) as u128) + .wrapping_add(niche_start); + // FIXME(eddyb) Check the actual primitive type here. + let niche_llval = if niche_value == 0 { + // HACK(eddyb) Using `C_null` as it works on all types. + C_null(niche_llty) + } else { + C_uint_big(niche_llty, niche_value) + }; + OperandValue::Immediate(niche_llval).store(bx, niche); + } + } + } + } + + pub fn project_index(&self, bx: &Builder<'a, 'tcx>, llindex: ValueRef) + -> PlaceRef<'tcx> { + PlaceRef { + llval: bx.inbounds_gep(self.llval, &[C_usize(bx.cx, 0), llindex]), + llextra: ptr::null_mut(), + layout: self.layout.field(bx.cx, 0), + align: self.align + } + } + + pub fn project_downcast(&self, bx: &Builder<'a, 'tcx>, variant_index: usize) + -> PlaceRef<'tcx> { + let mut downcast = *self; + downcast.layout = self.layout.for_variant(bx.cx, variant_index); + + // Cast to the appropriate variant struct type. + let variant_ty = downcast.layout.llvm_type(bx.cx); + downcast.llval = bx.pointercast(downcast.llval, variant_ty.ptr_to()); + + downcast + } + + pub fn storage_live(&self, bx: &Builder<'a, 'tcx>) { + bx.lifetime_start(self.llval, self.layout.size); + } + + pub fn storage_dead(&self, bx: &Builder<'a, 'tcx>) { + bx.lifetime_end(self.llval, self.layout.size); + } +} + +impl<'a, 'tcx> FunctionCx<'a, 'tcx> { + pub fn codegen_place(&mut self, + bx: &Builder<'a, 'tcx>, + place: &mir::Place<'tcx>) + -> PlaceRef<'tcx> { + debug!("codegen_place(place={:?})", place); + + let cx = bx.cx; + let tcx = cx.tcx; + + if let mir::Place::Local(index) = *place { + match self.locals[index] { + LocalRef::Place(place) => { + return place; + } + LocalRef::Operand(..) => { + bug!("using operand local {:?} as place", place); + } + } + } + + let result = match *place { + mir::Place::Local(_) => bug!(), // handled above + mir::Place::Static(box mir::Static { def_id, ty }) => { + let layout = cx.layout_of(self.monomorphize(&ty)); + PlaceRef::new_sized(consts::get_static(cx, def_id), layout, layout.align) + }, + mir::Place::Projection(box mir::Projection { + ref base, + elem: mir::ProjectionElem::Deref + }) => { + // Load the pointer from its location. + self.codegen_consume(bx, base).deref(bx.cx) + } + mir::Place::Projection(ref projection) => { + let cg_base = self.codegen_place(bx, &projection.base); + + match projection.elem { + mir::ProjectionElem::Deref => bug!(), + mir::ProjectionElem::Field(ref field, _) => { + cg_base.project_field(bx, field.index()) + } + mir::ProjectionElem::Index(index) => { + let index = &mir::Operand::Copy(mir::Place::Local(index)); + let index = self.codegen_operand(bx, index); + let llindex = index.immediate(); + cg_base.project_index(bx, llindex) + } + mir::ProjectionElem::ConstantIndex { offset, + from_end: false, + min_length: _ } => { + let lloffset = C_usize(bx.cx, offset as u64); + cg_base.project_index(bx, lloffset) + } + mir::ProjectionElem::ConstantIndex { offset, + from_end: true, + min_length: _ } => { + let lloffset = C_usize(bx.cx, offset as u64); + let lllen = cg_base.len(bx.cx); + let llindex = bx.sub(lllen, lloffset); + cg_base.project_index(bx, llindex) + } + mir::ProjectionElem::Subslice { from, to } => { + let mut subslice = cg_base.project_index(bx, + C_usize(bx.cx, from as u64)); + let projected_ty = PlaceTy::Ty { ty: cg_base.layout.ty } + .projection_ty(tcx, &projection.elem).to_ty(bx.tcx()); + subslice.layout = bx.cx.layout_of(self.monomorphize(&projected_ty)); + + if subslice.layout.is_unsized() { + assert!(cg_base.has_extra()); + subslice.llextra = bx.sub(cg_base.llextra, + C_usize(bx.cx, (from as u64) + (to as u64))); + } + + // Cast the place pointer type to the new + // array or slice type (*[%_; new_len]). + subslice.llval = bx.pointercast(subslice.llval, + subslice.layout.llvm_type(bx.cx).ptr_to()); + + subslice + } + mir::ProjectionElem::Downcast(_, v) => { + cg_base.project_downcast(bx, v) + } + } + } + }; + debug!("codegen_place(place={:?}) => {:?}", place, result); + result + } + + pub fn monomorphized_place_ty(&self, place: &mir::Place<'tcx>) -> Ty<'tcx> { + let tcx = self.cx.tcx; + let place_ty = place.ty(self.mir, tcx); + self.monomorphize(&place_ty.to_ty(tcx)) + } +} diff --git a/src/librustc_codegen_llvm/mir/rvalue.rs b/src/librustc_codegen_llvm/mir/rvalue.rs new file mode 100644 index 00000000000..d1b949d4f73 --- /dev/null +++ b/src/librustc_codegen_llvm/mir/rvalue.rs @@ -0,0 +1,952 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use llvm::{self, ValueRef}; +use rustc::ty::{self, Ty}; +use rustc::ty::cast::{CastTy, IntTy}; +use rustc::ty::layout::{self, LayoutOf}; +use rustc::mir; +use rustc::middle::lang_items::ExchangeMallocFnLangItem; +use rustc_apfloat::{ieee, Float, Status, Round}; +use std::{u128, i128}; + +use base; +use builder::Builder; +use callee; +use common::{self, val_ty}; +use common::{C_bool, C_u8, C_i32, C_u32, C_u64, C_undef, C_null, C_usize, C_uint, C_uint_big}; +use consts; +use monomorphize; +use type_::Type; +use type_of::LayoutLlvmExt; +use value::Value; + +use super::{FunctionCx, LocalRef}; +use super::operand::{OperandRef, OperandValue}; +use super::place::PlaceRef; + +impl<'a, 'tcx> FunctionCx<'a, 'tcx> { + pub fn codegen_rvalue(&mut self, + bx: Builder<'a, 'tcx>, + dest: PlaceRef<'tcx>, + rvalue: &mir::Rvalue<'tcx>) + -> Builder<'a, 'tcx> + { + debug!("codegen_rvalue(dest.llval={:?}, rvalue={:?})", + Value(dest.llval), rvalue); + + match *rvalue { + mir::Rvalue::Use(ref operand) => { + let cg_operand = self.codegen_operand(&bx, operand); + // FIXME: consider not copying constants through stack. (fixable by codegenning + // constants into OperandValue::Ref, why don’t we do that yet if we don’t?) + cg_operand.val.store(&bx, dest); + bx + } + + mir::Rvalue::Cast(mir::CastKind::Unsize, ref source, _) => { + // The destination necessarily contains a fat pointer, so if + // it's a scalar pair, it's a fat pointer or newtype thereof. + if dest.layout.is_llvm_scalar_pair() { + // into-coerce of a thin pointer to a fat pointer - just + // use the operand path. + let (bx, temp) = self.codegen_rvalue_operand(bx, rvalue); + temp.val.store(&bx, dest); + return bx; + } + + // Unsize of a nontrivial struct. I would prefer for + // this to be eliminated by MIR building, but + // `CoerceUnsized` can be passed by a where-clause, + // so the (generic) MIR may not be able to expand it. + let operand = self.codegen_operand(&bx, source); + match operand.val { + OperandValue::Pair(..) | + OperandValue::Immediate(_) => { + // unsize from an immediate structure. We don't + // really need a temporary alloca here, but + // avoiding it would require us to have + // `coerce_unsized_into` use extractvalue to + // index into the struct, and this case isn't + // important enough for it. + debug!("codegen_rvalue: creating ugly alloca"); + let scratch = PlaceRef::alloca(&bx, operand.layout, "__unsize_temp"); + scratch.storage_live(&bx); + operand.val.store(&bx, scratch); + base::coerce_unsized_into(&bx, scratch, dest); + scratch.storage_dead(&bx); + } + OperandValue::Ref(llref, align) => { + let source = PlaceRef::new_sized(llref, operand.layout, align); + base::coerce_unsized_into(&bx, source, dest); + } + } + bx + } + + mir::Rvalue::Repeat(ref elem, count) => { + let cg_elem = self.codegen_operand(&bx, elem); + + // Do not generate the loop for zero-sized elements or empty arrays. + if dest.layout.is_zst() { + return bx; + } + + let start = dest.project_index(&bx, C_usize(bx.cx, 0)).llval; + + if let OperandValue::Immediate(v) = cg_elem.val { + let align = C_i32(bx.cx, dest.align.abi() as i32); + let size = C_usize(bx.cx, dest.layout.size.bytes()); + + // Use llvm.memset.p0i8.* to initialize all zero arrays + if common::is_const_integral(v) && common::const_to_uint(v) == 0 { + let fill = C_u8(bx.cx, 0); + base::call_memset(&bx, start, fill, size, align, false); + return bx; + } + + // Use llvm.memset.p0i8.* to initialize byte arrays + let v = base::from_immediate(&bx, v); + if common::val_ty(v) == Type::i8(bx.cx) { + base::call_memset(&bx, start, v, size, align, false); + return bx; + } + } + + let count = C_usize(bx.cx, count); + let end = dest.project_index(&bx, count).llval; + + let header_bx = bx.build_sibling_block("repeat_loop_header"); + let body_bx = bx.build_sibling_block("repeat_loop_body"); + let next_bx = bx.build_sibling_block("repeat_loop_next"); + + bx.br(header_bx.llbb()); + let current = header_bx.phi(common::val_ty(start), &[start], &[bx.llbb()]); + + let keep_going = header_bx.icmp(llvm::IntNE, current, end); + header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb()); + + cg_elem.val.store(&body_bx, + PlaceRef::new_sized(current, cg_elem.layout, dest.align)); + + let next = body_bx.inbounds_gep(current, &[C_usize(bx.cx, 1)]); + body_bx.br(header_bx.llbb()); + header_bx.add_incoming_to_phi(current, next, body_bx.llbb()); + + next_bx + } + + mir::Rvalue::Aggregate(ref kind, ref operands) => { + let (dest, active_field_index) = match **kind { + mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => { + dest.codegen_set_discr(&bx, variant_index); + if adt_def.is_enum() { + (dest.project_downcast(&bx, variant_index), active_field_index) + } else { + (dest, active_field_index) + } + } + _ => (dest, None) + }; + for (i, operand) in operands.iter().enumerate() { + let op = self.codegen_operand(&bx, operand); + // Do not generate stores and GEPis for zero-sized fields. + if !op.layout.is_zst() { + let field_index = active_field_index.unwrap_or(i); + op.val.store(&bx, dest.project_field(&bx, field_index)); + } + } + bx + } + + _ => { + assert!(self.rvalue_creates_operand(rvalue)); + let (bx, temp) = self.codegen_rvalue_operand(bx, rvalue); + temp.val.store(&bx, dest); + bx + } + } + } + + pub fn codegen_rvalue_operand(&mut self, + bx: Builder<'a, 'tcx>, + rvalue: &mir::Rvalue<'tcx>) + -> (Builder<'a, 'tcx>, OperandRef<'tcx>) + { + assert!(self.rvalue_creates_operand(rvalue), "cannot codegen {:?} to operand", rvalue); + + match *rvalue { + mir::Rvalue::Cast(ref kind, ref source, mir_cast_ty) => { + let operand = self.codegen_operand(&bx, source); + debug!("cast operand is {:?}", operand); + let cast = bx.cx.layout_of(self.monomorphize(&mir_cast_ty)); + + let val = match *kind { + mir::CastKind::ReifyFnPointer => { + match operand.layout.ty.sty { + ty::TyFnDef(def_id, substs) => { + if bx.cx.tcx.has_attr(def_id, "rustc_args_required_const") { + bug!("reifying a fn ptr that requires \ + const arguments"); + } + OperandValue::Immediate( + callee::resolve_and_get_fn(bx.cx, def_id, substs)) + } + _ => { + bug!("{} cannot be reified to a fn ptr", operand.layout.ty) + } + } + } + mir::CastKind::ClosureFnPointer => { + match operand.layout.ty.sty { + ty::TyClosure(def_id, substs) => { + let instance = monomorphize::resolve_closure( + bx.cx.tcx, def_id, substs, ty::ClosureKind::FnOnce); + OperandValue::Immediate(callee::get_fn(bx.cx, instance)) + } + _ => { + bug!("{} cannot be cast to a fn ptr", operand.layout.ty) + } + } + } + mir::CastKind::UnsafeFnPointer => { + // this is a no-op at the LLVM level + operand.val + } + mir::CastKind::Unsize => { + assert!(cast.is_llvm_scalar_pair()); + match operand.val { + OperandValue::Pair(lldata, llextra) => { + // unsize from a fat pointer - this is a + // "trait-object-to-supertrait" coercion, for + // example, + // &'a fmt::Debug+Send => &'a fmt::Debug, + + // HACK(eddyb) have to bitcast pointers + // until LLVM removes pointee types. + let lldata = bx.pointercast(lldata, + cast.scalar_pair_element_llvm_type(bx.cx, 0)); + OperandValue::Pair(lldata, llextra) + } + OperandValue::Immediate(lldata) => { + // "standard" unsize + let (lldata, llextra) = base::unsize_thin_ptr(&bx, lldata, + operand.layout.ty, cast.ty); + OperandValue::Pair(lldata, llextra) + } + OperandValue::Ref(..) => { + bug!("by-ref operand {:?} in codegen_rvalue_operand", + operand); + } + } + } + mir::CastKind::Misc if operand.layout.is_llvm_scalar_pair() => { + if let OperandValue::Pair(data_ptr, meta) = operand.val { + if cast.is_llvm_scalar_pair() { + let data_cast = bx.pointercast(data_ptr, + cast.scalar_pair_element_llvm_type(bx.cx, 0)); + OperandValue::Pair(data_cast, meta) + } else { // cast to thin-ptr + // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and + // pointer-cast of that pointer to desired pointer type. + let llcast_ty = cast.immediate_llvm_type(bx.cx); + let llval = bx.pointercast(data_ptr, llcast_ty); + OperandValue::Immediate(llval) + } + } else { + bug!("Unexpected non-Pair operand") + } + } + mir::CastKind::Misc => { + assert!(cast.is_llvm_immediate()); + let ll_t_out = cast.immediate_llvm_type(bx.cx); + if operand.layout.abi == layout::Abi::Uninhabited { + return (bx, OperandRef { + val: OperandValue::Immediate(C_undef(ll_t_out)), + layout: cast, + }); + } + let r_t_in = CastTy::from_ty(operand.layout.ty) + .expect("bad input type for cast"); + let r_t_out = CastTy::from_ty(cast.ty).expect("bad output type for cast"); + let ll_t_in = operand.layout.immediate_llvm_type(bx.cx); + match operand.layout.variants { + layout::Variants::Single { index } => { + if let Some(def) = operand.layout.ty.ty_adt_def() { + let discr_val = def + .discriminant_for_variant(bx.cx.tcx, index) + .val; + let discr = C_uint_big(ll_t_out, discr_val); + return (bx, OperandRef { + val: OperandValue::Immediate(discr), + layout: cast, + }); + } + } + layout::Variants::Tagged { .. } | + layout::Variants::NicheFilling { .. } => {}, + } + let llval = operand.immediate(); + + let mut signed = false; + if let layout::Abi::Scalar(ref scalar) = operand.layout.abi { + if let layout::Int(_, s) = scalar.value { + signed = s; + + if scalar.valid_range.end() > scalar.valid_range.start() { + // We want `table[e as usize]` to not + // have bound checks, and this is the most + // convenient place to put the `assume`. + + base::call_assume(&bx, bx.icmp( + llvm::IntULE, + llval, + C_uint_big(ll_t_in, *scalar.valid_range.end()) + )); + } + } + } + + let newval = match (r_t_in, r_t_out) { + (CastTy::Int(_), CastTy::Int(_)) => { + bx.intcast(llval, ll_t_out, signed) + } + (CastTy::Float, CastTy::Float) => { + let srcsz = ll_t_in.float_width(); + let dstsz = ll_t_out.float_width(); + if dstsz > srcsz { + bx.fpext(llval, ll_t_out) + } else if srcsz > dstsz { + bx.fptrunc(llval, ll_t_out) + } else { + llval + } + } + (CastTy::Ptr(_), CastTy::Ptr(_)) | + (CastTy::FnPtr, CastTy::Ptr(_)) | + (CastTy::RPtr(_), CastTy::Ptr(_)) => + bx.pointercast(llval, ll_t_out), + (CastTy::Ptr(_), CastTy::Int(_)) | + (CastTy::FnPtr, CastTy::Int(_)) => + bx.ptrtoint(llval, ll_t_out), + (CastTy::Int(_), CastTy::Ptr(_)) => { + let usize_llval = bx.intcast(llval, bx.cx.isize_ty, signed); + bx.inttoptr(usize_llval, ll_t_out) + } + (CastTy::Int(_), CastTy::Float) => + cast_int_to_float(&bx, signed, llval, ll_t_in, ll_t_out), + (CastTy::Float, CastTy::Int(IntTy::I)) => + cast_float_to_int(&bx, true, llval, ll_t_in, ll_t_out), + (CastTy::Float, CastTy::Int(_)) => + cast_float_to_int(&bx, false, llval, ll_t_in, ll_t_out), + _ => bug!("unsupported cast: {:?} to {:?}", operand.layout.ty, cast.ty) + }; + OperandValue::Immediate(newval) + } + }; + (bx, OperandRef { + val, + layout: cast + }) + } + + mir::Rvalue::Ref(_, bk, ref place) => { + let cg_place = self.codegen_place(&bx, place); + + let ty = cg_place.layout.ty; + + // Note: places are indirect, so storing the `llval` into the + // destination effectively creates a reference. + let val = if !bx.cx.type_has_metadata(ty) { + OperandValue::Immediate(cg_place.llval) + } else { + OperandValue::Pair(cg_place.llval, cg_place.llextra) + }; + (bx, OperandRef { + val, + layout: self.cx.layout_of(self.cx.tcx.mk_ref( + self.cx.tcx.types.re_erased, + ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() } + )), + }) + } + + mir::Rvalue::Len(ref place) => { + let size = self.evaluate_array_len(&bx, place); + let operand = OperandRef { + val: OperandValue::Immediate(size), + layout: bx.cx.layout_of(bx.tcx().types.usize), + }; + (bx, operand) + } + + mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => { + let lhs = self.codegen_operand(&bx, lhs); + let rhs = self.codegen_operand(&bx, rhs); + let llresult = match (lhs.val, rhs.val) { + (OperandValue::Pair(lhs_addr, lhs_extra), + OperandValue::Pair(rhs_addr, rhs_extra)) => { + self.codegen_fat_ptr_binop(&bx, op, + lhs_addr, lhs_extra, + rhs_addr, rhs_extra, + lhs.layout.ty) + } + + (OperandValue::Immediate(lhs_val), + OperandValue::Immediate(rhs_val)) => { + self.codegen_scalar_binop(&bx, op, lhs_val, rhs_val, lhs.layout.ty) + } + + _ => bug!() + }; + let operand = OperandRef { + val: OperandValue::Immediate(llresult), + layout: bx.cx.layout_of( + op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty)), + }; + (bx, operand) + } + mir::Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => { + let lhs = self.codegen_operand(&bx, lhs); + let rhs = self.codegen_operand(&bx, rhs); + let result = self.codegen_scalar_checked_binop(&bx, op, + lhs.immediate(), rhs.immediate(), + lhs.layout.ty); + let val_ty = op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty); + let operand_ty = bx.tcx().intern_tup(&[val_ty, bx.tcx().types.bool]); + let operand = OperandRef { + val: result, + layout: bx.cx.layout_of(operand_ty) + }; + + (bx, operand) + } + + mir::Rvalue::UnaryOp(op, ref operand) => { + let operand = self.codegen_operand(&bx, operand); + let lloperand = operand.immediate(); + let is_float = operand.layout.ty.is_fp(); + let llval = match op { + mir::UnOp::Not => bx.not(lloperand), + mir::UnOp::Neg => if is_float { + bx.fneg(lloperand) + } else { + bx.neg(lloperand) + } + }; + (bx, OperandRef { + val: OperandValue::Immediate(llval), + layout: operand.layout, + }) + } + + mir::Rvalue::Discriminant(ref place) => { + let discr_ty = rvalue.ty(&*self.mir, bx.tcx()); + let discr = self.codegen_place(&bx, place) + .codegen_get_discr(&bx, discr_ty); + (bx, OperandRef { + val: OperandValue::Immediate(discr), + layout: self.cx.layout_of(discr_ty) + }) + } + + mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => { + assert!(bx.cx.type_is_sized(ty)); + let val = C_usize(bx.cx, bx.cx.size_of(ty).bytes()); + let tcx = bx.tcx(); + (bx, OperandRef { + val: OperandValue::Immediate(val), + layout: self.cx.layout_of(tcx.types.usize), + }) + } + + mir::Rvalue::NullaryOp(mir::NullOp::Box, content_ty) => { + let content_ty: Ty<'tcx> = self.monomorphize(&content_ty); + let (size, align) = bx.cx.size_and_align_of(content_ty); + let llsize = C_usize(bx.cx, size.bytes()); + let llalign = C_usize(bx.cx, align.abi()); + let box_layout = bx.cx.layout_of(bx.tcx().mk_box(content_ty)); + let llty_ptr = box_layout.llvm_type(bx.cx); + + // Allocate space: + let def_id = match bx.tcx().lang_items().require(ExchangeMallocFnLangItem) { + Ok(id) => id, + Err(s) => { + bx.sess().fatal(&format!("allocation of `{}` {}", box_layout.ty, s)); + } + }; + let instance = ty::Instance::mono(bx.tcx(), def_id); + let r = callee::get_fn(bx.cx, instance); + let val = bx.pointercast(bx.call(r, &[llsize, llalign], None), llty_ptr); + + let operand = OperandRef { + val: OperandValue::Immediate(val), + layout: box_layout, + }; + (bx, operand) + } + mir::Rvalue::Use(ref operand) => { + let operand = self.codegen_operand(&bx, operand); + (bx, operand) + } + mir::Rvalue::Repeat(..) | + mir::Rvalue::Aggregate(..) => { + // According to `rvalue_creates_operand`, only ZST + // aggregate rvalues are allowed to be operands. + let ty = rvalue.ty(self.mir, self.cx.tcx); + (bx, OperandRef::new_zst(self.cx, + self.cx.layout_of(self.monomorphize(&ty)))) + } + } + } + + fn evaluate_array_len(&mut self, + bx: &Builder<'a, 'tcx>, + place: &mir::Place<'tcx>) -> ValueRef + { + // ZST are passed as operands and require special handling + // because codegen_place() panics if Local is operand. + if let mir::Place::Local(index) = *place { + if let LocalRef::Operand(Some(op)) = self.locals[index] { + if let ty::TyArray(_, n) = op.layout.ty.sty { + let n = n.unwrap_usize(bx.cx.tcx); + return common::C_usize(bx.cx, n); + } + } + } + // use common size calculation for non zero-sized types + let cg_value = self.codegen_place(&bx, place); + return cg_value.len(bx.cx); + } + + pub fn codegen_scalar_binop(&mut self, + bx: &Builder<'a, 'tcx>, + op: mir::BinOp, + lhs: ValueRef, + rhs: ValueRef, + input_ty: Ty<'tcx>) -> ValueRef { + let is_float = input_ty.is_fp(); + let is_signed = input_ty.is_signed(); + let is_nil = input_ty.is_nil(); + match op { + mir::BinOp::Add => if is_float { + bx.fadd(lhs, rhs) + } else { + bx.add(lhs, rhs) + }, + mir::BinOp::Sub => if is_float { + bx.fsub(lhs, rhs) + } else { + bx.sub(lhs, rhs) + }, + mir::BinOp::Mul => if is_float { + bx.fmul(lhs, rhs) + } else { + bx.mul(lhs, rhs) + }, + mir::BinOp::Div => if is_float { + bx.fdiv(lhs, rhs) + } else if is_signed { + bx.sdiv(lhs, rhs) + } else { + bx.udiv(lhs, rhs) + }, + mir::BinOp::Rem => if is_float { + bx.frem(lhs, rhs) + } else if is_signed { + bx.srem(lhs, rhs) + } else { + bx.urem(lhs, rhs) + }, + mir::BinOp::BitOr => bx.or(lhs, rhs), + mir::BinOp::BitAnd => bx.and(lhs, rhs), + mir::BinOp::BitXor => bx.xor(lhs, rhs), + mir::BinOp::Offset => bx.inbounds_gep(lhs, &[rhs]), + mir::BinOp::Shl => common::build_unchecked_lshift(bx, lhs, rhs), + mir::BinOp::Shr => common::build_unchecked_rshift(bx, input_ty, lhs, rhs), + mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt | + mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => if is_nil { + C_bool(bx.cx, match op { + mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt => false, + mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => true, + _ => unreachable!() + }) + } else if is_float { + bx.fcmp( + base::bin_op_to_fcmp_predicate(op.to_hir_binop()), + lhs, rhs + ) + } else { + bx.icmp( + base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed), + lhs, rhs + ) + } + } + } + + pub fn codegen_fat_ptr_binop(&mut self, + bx: &Builder<'a, 'tcx>, + op: mir::BinOp, + lhs_addr: ValueRef, + lhs_extra: ValueRef, + rhs_addr: ValueRef, + rhs_extra: ValueRef, + _input_ty: Ty<'tcx>) + -> ValueRef { + match op { + mir::BinOp::Eq => { + bx.and( + bx.icmp(llvm::IntEQ, lhs_addr, rhs_addr), + bx.icmp(llvm::IntEQ, lhs_extra, rhs_extra) + ) + } + mir::BinOp::Ne => { + bx.or( + bx.icmp(llvm::IntNE, lhs_addr, rhs_addr), + bx.icmp(llvm::IntNE, lhs_extra, rhs_extra) + ) + } + mir::BinOp::Le | mir::BinOp::Lt | + mir::BinOp::Ge | mir::BinOp::Gt => { + // a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1) + let (op, strict_op) = match op { + mir::BinOp::Lt => (llvm::IntULT, llvm::IntULT), + mir::BinOp::Le => (llvm::IntULE, llvm::IntULT), + mir::BinOp::Gt => (llvm::IntUGT, llvm::IntUGT), + mir::BinOp::Ge => (llvm::IntUGE, llvm::IntUGT), + _ => bug!(), + }; + + bx.or( + bx.icmp(strict_op, lhs_addr, rhs_addr), + bx.and( + bx.icmp(llvm::IntEQ, lhs_addr, rhs_addr), + bx.icmp(op, lhs_extra, rhs_extra) + ) + ) + } + _ => { + bug!("unexpected fat ptr binop"); + } + } + } + + pub fn codegen_scalar_checked_binop(&mut self, + bx: &Builder<'a, 'tcx>, + op: mir::BinOp, + lhs: ValueRef, + rhs: ValueRef, + input_ty: Ty<'tcx>) -> OperandValue { + // This case can currently arise only from functions marked + // with #[rustc_inherit_overflow_checks] and inlined from + // another crate (mostly core::num generic/#[inline] fns), + // while the current crate doesn't use overflow checks. + if !bx.cx.check_overflow { + let val = self.codegen_scalar_binop(bx, op, lhs, rhs, input_ty); + return OperandValue::Pair(val, C_bool(bx.cx, false)); + } + + let (val, of) = match op { + // These are checked using intrinsics + mir::BinOp::Add | mir::BinOp::Sub | mir::BinOp::Mul => { + let oop = match op { + mir::BinOp::Add => OverflowOp::Add, + mir::BinOp::Sub => OverflowOp::Sub, + mir::BinOp::Mul => OverflowOp::Mul, + _ => unreachable!() + }; + let intrinsic = get_overflow_intrinsic(oop, bx, input_ty); + let res = bx.call(intrinsic, &[lhs, rhs], None); + + (bx.extract_value(res, 0), + bx.extract_value(res, 1)) + } + mir::BinOp::Shl | mir::BinOp::Shr => { + let lhs_llty = val_ty(lhs); + let rhs_llty = val_ty(rhs); + let invert_mask = common::shift_mask_val(&bx, lhs_llty, rhs_llty, true); + let outer_bits = bx.and(rhs, invert_mask); + + let of = bx.icmp(llvm::IntNE, outer_bits, C_null(rhs_llty)); + let val = self.codegen_scalar_binop(bx, op, lhs, rhs, input_ty); + + (val, of) + } + _ => { + bug!("Operator `{:?}` is not a checkable operator", op) + } + }; + + OperandValue::Pair(val, of) + } + + pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>) -> bool { + match *rvalue { + mir::Rvalue::Ref(..) | + mir::Rvalue::Len(..) | + mir::Rvalue::Cast(..) | // (*) + mir::Rvalue::BinaryOp(..) | + mir::Rvalue::CheckedBinaryOp(..) | + mir::Rvalue::UnaryOp(..) | + mir::Rvalue::Discriminant(..) | + mir::Rvalue::NullaryOp(..) | + mir::Rvalue::Use(..) => // (*) + true, + mir::Rvalue::Repeat(..) | + mir::Rvalue::Aggregate(..) => { + let ty = rvalue.ty(self.mir, self.cx.tcx); + let ty = self.monomorphize(&ty); + self.cx.layout_of(ty).is_zst() + } + } + + // (*) this is only true if the type is suitable + } +} + +#[derive(Copy, Clone)] +enum OverflowOp { + Add, Sub, Mul +} + +fn get_overflow_intrinsic(oop: OverflowOp, bx: &Builder, ty: Ty) -> ValueRef { + use syntax::ast::IntTy::*; + use syntax::ast::UintTy::*; + use rustc::ty::{TyInt, TyUint}; + + let tcx = bx.tcx(); + + let new_sty = match ty.sty { + TyInt(Isize) => match &tcx.sess.target.target.target_pointer_width[..] { + "16" => TyInt(I16), + "32" => TyInt(I32), + "64" => TyInt(I64), + _ => panic!("unsupported target word size") + }, + TyUint(Usize) => match &tcx.sess.target.target.target_pointer_width[..] { + "16" => TyUint(U16), + "32" => TyUint(U32), + "64" => TyUint(U64), + _ => panic!("unsupported target word size") + }, + ref t @ TyUint(_) | ref t @ TyInt(_) => t.clone(), + _ => panic!("tried to get overflow intrinsic for op applied to non-int type") + }; + + let name = match oop { + OverflowOp::Add => match new_sty { + TyInt(I8) => "llvm.sadd.with.overflow.i8", + TyInt(I16) => "llvm.sadd.with.overflow.i16", + TyInt(I32) => "llvm.sadd.with.overflow.i32", + TyInt(I64) => "llvm.sadd.with.overflow.i64", + TyInt(I128) => "llvm.sadd.with.overflow.i128", + + TyUint(U8) => "llvm.uadd.with.overflow.i8", + TyUint(U16) => "llvm.uadd.with.overflow.i16", + TyUint(U32) => "llvm.uadd.with.overflow.i32", + TyUint(U64) => "llvm.uadd.with.overflow.i64", + TyUint(U128) => "llvm.uadd.with.overflow.i128", + + _ => unreachable!(), + }, + OverflowOp::Sub => match new_sty { + TyInt(I8) => "llvm.ssub.with.overflow.i8", + TyInt(I16) => "llvm.ssub.with.overflow.i16", + TyInt(I32) => "llvm.ssub.with.overflow.i32", + TyInt(I64) => "llvm.ssub.with.overflow.i64", + TyInt(I128) => "llvm.ssub.with.overflow.i128", + + TyUint(U8) => "llvm.usub.with.overflow.i8", + TyUint(U16) => "llvm.usub.with.overflow.i16", + TyUint(U32) => "llvm.usub.with.overflow.i32", + TyUint(U64) => "llvm.usub.with.overflow.i64", + TyUint(U128) => "llvm.usub.with.overflow.i128", + + _ => unreachable!(), + }, + OverflowOp::Mul => match new_sty { + TyInt(I8) => "llvm.smul.with.overflow.i8", + TyInt(I16) => "llvm.smul.with.overflow.i16", + TyInt(I32) => "llvm.smul.with.overflow.i32", + TyInt(I64) => "llvm.smul.with.overflow.i64", + TyInt(I128) => "llvm.smul.with.overflow.i128", + + TyUint(U8) => "llvm.umul.with.overflow.i8", + TyUint(U16) => "llvm.umul.with.overflow.i16", + TyUint(U32) => "llvm.umul.with.overflow.i32", + TyUint(U64) => "llvm.umul.with.overflow.i64", + TyUint(U128) => "llvm.umul.with.overflow.i128", + + _ => unreachable!(), + }, + }; + + bx.cx.get_intrinsic(&name) +} + +fn cast_int_to_float(bx: &Builder, + signed: bool, + x: ValueRef, + int_ty: Type, + float_ty: Type) -> ValueRef { + // Most integer types, even i128, fit into [-f32::MAX, f32::MAX] after rounding. + // It's only u128 -> f32 that can cause overflows (i.e., should yield infinity). + // LLVM's uitofp produces undef in those cases, so we manually check for that case. + let is_u128_to_f32 = !signed && int_ty.int_width() == 128 && float_ty.float_width() == 32; + if is_u128_to_f32 { + // All inputs greater or equal to (f32::MAX + 0.5 ULP) are rounded to infinity, + // and for everything else LLVM's uitofp works just fine. + use rustc_apfloat::ieee::Single; + use rustc_apfloat::Float; + const MAX_F32_PLUS_HALF_ULP: u128 = ((1 << (Single::PRECISION + 1)) - 1) + << (Single::MAX_EXP - Single::PRECISION as i16); + let max = C_uint_big(int_ty, MAX_F32_PLUS_HALF_ULP); + let overflow = bx.icmp(llvm::IntUGE, x, max); + let infinity_bits = C_u32(bx.cx, ieee::Single::INFINITY.to_bits() as u32); + let infinity = consts::bitcast(infinity_bits, float_ty); + bx.select(overflow, infinity, bx.uitofp(x, float_ty)) + } else { + if signed { + bx.sitofp(x, float_ty) + } else { + bx.uitofp(x, float_ty) + } + } +} + +fn cast_float_to_int(bx: &Builder, + signed: bool, + x: ValueRef, + float_ty: Type, + int_ty: Type) -> ValueRef { + let fptosui_result = if signed { + bx.fptosi(x, int_ty) + } else { + bx.fptoui(x, int_ty) + }; + + if !bx.sess().opts.debugging_opts.saturating_float_casts { + return fptosui_result; + } + // LLVM's fpto[su]i returns undef when the input x is infinite, NaN, or does not fit into the + // destination integer type after rounding towards zero. This `undef` value can cause UB in + // safe code (see issue #10184), so we implement a saturating conversion on top of it: + // Semantically, the mathematical value of the input is rounded towards zero to the next + // mathematical integer, and then the result is clamped into the range of the destination + // integer type. Positive and negative infinity are mapped to the maximum and minimum value of + // the destination integer type. NaN is mapped to 0. + // + // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to + // a value representable in int_ty. + // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits. + // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two. + // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly + // representable. Note that this only works if float_ty's exponent range is sufficiently large. + // f16 or 256 bit integers would break this property. Right now the smallest float type is f32 + // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127. + // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because + // we're rounding towards zero, we just get float_ty::MAX (which is always an integer). + // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX. + fn compute_clamp_bounds(signed: bool, int_ty: Type) -> (u128, u128) { + let rounded_min = F::from_i128_r(int_min(signed, int_ty), Round::TowardZero); + assert_eq!(rounded_min.status, Status::OK); + let rounded_max = F::from_u128_r(int_max(signed, int_ty), Round::TowardZero); + assert!(rounded_max.value.is_finite()); + (rounded_min.value.to_bits(), rounded_max.value.to_bits()) + } + fn int_max(signed: bool, int_ty: Type) -> u128 { + let shift_amount = 128 - int_ty.int_width(); + if signed { + i128::MAX as u128 >> shift_amount + } else { + u128::MAX >> shift_amount + } + } + fn int_min(signed: bool, int_ty: Type) -> i128 { + if signed { + i128::MIN >> (128 - int_ty.int_width()) + } else { + 0 + } + } + let float_bits_to_llval = |bits| { + let bits_llval = match float_ty.float_width() { + 32 => C_u32(bx.cx, bits as u32), + 64 => C_u64(bx.cx, bits as u64), + n => bug!("unsupported float width {}", n), + }; + consts::bitcast(bits_llval, float_ty) + }; + let (f_min, f_max) = match float_ty.float_width() { + 32 => compute_clamp_bounds::(signed, int_ty), + 64 => compute_clamp_bounds::(signed, int_ty), + n => bug!("unsupported float width {}", n), + }; + let f_min = float_bits_to_llval(f_min); + let f_max = float_bits_to_llval(f_max); + // To implement saturation, we perform the following steps: + // + // 1. Cast x to an integer with fpto[su]i. This may result in undef. + // 2. Compare x to f_min and f_max, and use the comparison results to select: + // a) int_ty::MIN if x < f_min or x is NaN + // b) int_ty::MAX if x > f_max + // c) the result of fpto[su]i otherwise + // 3. If x is NaN, return 0.0, otherwise return the result of step 2. + // + // This avoids resulting undef because values in range [f_min, f_max] by definition fit into the + // destination type. It creates an undef temporary, but *producing* undef is not UB. Our use of + // undef does not introduce any non-determinism either. + // More importantly, the above procedure correctly implements saturating conversion. + // Proof (sketch): + // If x is NaN, 0 is returned by definition. + // Otherwise, x is finite or infinite and thus can be compared with f_min and f_max. + // This yields three cases to consider: + // (1) if x in [f_min, f_max], the result of fpto[su]i is returned, which agrees with + // saturating conversion for inputs in that range. + // (2) if x > f_max, then x is larger than int_ty::MAX. This holds even if f_max is rounded + // (i.e., if f_max < int_ty::MAX) because in those cases, nextUp(f_max) is already larger + // than int_ty::MAX. Because x is larger than int_ty::MAX, the return value of int_ty::MAX + // is correct. + // (3) if x < f_min, then x is smaller than int_ty::MIN. As shown earlier, f_min exactly equals + // int_ty::MIN and therefore the return value of int_ty::MIN is correct. + // QED. + + // Step 1 was already performed above. + + // Step 2: We use two comparisons and two selects, with %s1 being the result: + // %less_or_nan = fcmp ult %x, %f_min + // %greater = fcmp olt %x, %f_max + // %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result + // %s1 = select %greater, int_ty::MAX, %s0 + // Note that %less_or_nan uses an *unordered* comparison. This comparison is true if the + // operands are not comparable (i.e., if x is NaN). The unordered comparison ensures that s1 + // becomes int_ty::MIN if x is NaN. + // Performance note: Unordered comparison can be lowered to a "flipped" comparison and a + // negation, and the negation can be merged into the select. Therefore, it not necessarily any + // more expensive than a ordered ("normal") comparison. Whether these optimizations will be + // performed is ultimately up to the backend, but at least x86 does perform them. + let less_or_nan = bx.fcmp(llvm::RealULT, x, f_min); + let greater = bx.fcmp(llvm::RealOGT, x, f_max); + let int_max = C_uint_big(int_ty, int_max(signed, int_ty)); + let int_min = C_uint_big(int_ty, int_min(signed, int_ty) as u128); + let s0 = bx.select(less_or_nan, int_min, fptosui_result); + let s1 = bx.select(greater, int_max, s0); + + // Step 3: NaN replacement. + // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN. + // Therefore we only need to execute this step for signed integer types. + if signed { + // LLVM has no isNaN predicate, so we use (x == x) instead + bx.select(bx.fcmp(llvm::RealOEQ, x, x), s1, C_uint(int_ty, 0)) + } else { + s1 + } +} diff --git a/src/librustc_codegen_llvm/mir/statement.rs b/src/librustc_codegen_llvm/mir/statement.rs new file mode 100644 index 00000000000..578481df157 --- /dev/null +++ b/src/librustc_codegen_llvm/mir/statement.rs @@ -0,0 +1,91 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::mir; + +use asm; +use builder::Builder; + +use super::FunctionCx; +use super::LocalRef; + +impl<'a, 'tcx> FunctionCx<'a, 'tcx> { + pub fn codegen_statement(&mut self, + bx: Builder<'a, 'tcx>, + statement: &mir::Statement<'tcx>) + -> Builder<'a, 'tcx> { + debug!("codegen_statement(statement={:?})", statement); + + self.set_debug_loc(&bx, statement.source_info); + match statement.kind { + mir::StatementKind::Assign(ref place, ref rvalue) => { + if let mir::Place::Local(index) = *place { + match self.locals[index] { + LocalRef::Place(cg_dest) => { + self.codegen_rvalue(bx, cg_dest, rvalue) + } + LocalRef::Operand(None) => { + let (bx, operand) = self.codegen_rvalue_operand(bx, rvalue); + self.locals[index] = LocalRef::Operand(Some(operand)); + bx + } + LocalRef::Operand(Some(op)) => { + if !op.layout.is_zst() { + span_bug!(statement.source_info.span, + "operand {:?} already assigned", + rvalue); + } + + // If the type is zero-sized, it's already been set here, + // but we still need to make sure we codegen the operand + self.codegen_rvalue_operand(bx, rvalue).0 + } + } + } else { + let cg_dest = self.codegen_place(&bx, place); + self.codegen_rvalue(bx, cg_dest, rvalue) + } + } + mir::StatementKind::SetDiscriminant{ref place, variant_index} => { + self.codegen_place(&bx, place) + .codegen_set_discr(&bx, variant_index); + bx + } + mir::StatementKind::StorageLive(local) => { + if let LocalRef::Place(cg_place) = self.locals[local] { + cg_place.storage_live(&bx); + } + bx + } + mir::StatementKind::StorageDead(local) => { + if let LocalRef::Place(cg_place) = self.locals[local] { + cg_place.storage_dead(&bx); + } + bx + } + mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => { + let outputs = outputs.iter().map(|output| { + self.codegen_place(&bx, output) + }).collect(); + + let input_vals = inputs.iter().map(|input| { + self.codegen_operand(&bx, input).immediate() + }).collect(); + + asm::codegen_inline_asm(&bx, asm, outputs, input_vals); + bx + } + mir::StatementKind::EndRegion(_) | + mir::StatementKind::Validate(..) | + mir::StatementKind::UserAssertTy(..) | + mir::StatementKind::Nop => bx, + } + } +} diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs new file mode 100644 index 00000000000..6ba3582f014 --- /dev/null +++ b/src/librustc_codegen_llvm/mono_item.rs @@ -0,0 +1,193 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Walks the crate looking for items/impl-items/trait-items that have +//! either a `rustc_symbol_name` or `rustc_item_path` attribute and +//! generates an error giving, respectively, the symbol name or +//! item-path. This is used for unit testing the code that generates +//! paths etc in all kinds of annoying scenarios. + +use asm; +use attributes; +use base; +use consts; +use context::CodegenCx; +use declare; +use llvm; +use monomorphize::Instance; +use type_of::LayoutLlvmExt; +use rustc::hir; +use rustc::hir::def::Def; +use rustc::hir::def_id::DefId; +use rustc::mir::mono::{Linkage, Visibility}; +use rustc::ty::TypeFoldable; +use rustc::ty::layout::LayoutOf; +use syntax::attr; +use std::fmt; + +pub use rustc::mir::mono::MonoItem; + +pub use rustc_mir::monomorphize::item::*; +pub use rustc_mir::monomorphize::item::MonoItemExt as BaseMonoItemExt; + +pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { + fn define(&self, cx: &CodegenCx<'a, 'tcx>) { + debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}", + self.to_string(cx.tcx), + self.to_raw_string(), + cx.codegen_unit.name()); + + match *self.as_mono_item() { + MonoItem::Static(def_id) => { + let tcx = cx.tcx; + let is_mutable = match tcx.describe_def(def_id) { + Some(Def::Static(_, is_mutable)) => is_mutable, + Some(other) => { + bug!("Expected Def::Static, found {:?}", other) + } + None => { + bug!("Expected Def::Static for {:?}, found nothing", def_id) + } + }; + let attrs = tcx.get_attrs(def_id); + + consts::codegen_static(&cx, def_id, is_mutable, &attrs); + } + MonoItem::GlobalAsm(node_id) => { + let item = cx.tcx.hir.expect_item(node_id); + if let hir::ItemGlobalAsm(ref ga) = item.node { + asm::codegen_global_asm(cx, ga); + } else { + span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type") + } + } + MonoItem::Fn(instance) => { + base::codegen_instance(&cx, instance); + } + } + + debug!("END IMPLEMENTING '{} ({})' in cgu {}", + self.to_string(cx.tcx), + self.to_raw_string(), + cx.codegen_unit.name()); + } + + fn predefine(&self, + cx: &CodegenCx<'a, 'tcx>, + linkage: Linkage, + visibility: Visibility) { + debug!("BEGIN PREDEFINING '{} ({})' in cgu {}", + self.to_string(cx.tcx), + self.to_raw_string(), + cx.codegen_unit.name()); + + let symbol_name = self.symbol_name(cx.tcx).as_str(); + + debug!("symbol {}", &symbol_name); + + match *self.as_mono_item() { + MonoItem::Static(def_id) => { + predefine_static(cx, def_id, linkage, visibility, &symbol_name); + } + MonoItem::Fn(instance) => { + predefine_fn(cx, instance, linkage, visibility, &symbol_name); + } + MonoItem::GlobalAsm(..) => {} + } + + debug!("END PREDEFINING '{} ({})' in cgu {}", + self.to_string(cx.tcx), + self.to_raw_string(), + cx.codegen_unit.name()); + } + + fn to_raw_string(&self) -> String { + match *self.as_mono_item() { + MonoItem::Fn(instance) => { + format!("Fn({:?}, {})", + instance.def, + instance.substs.as_ptr() as usize) + } + MonoItem::Static(id) => { + format!("Static({:?})", id) + } + MonoItem::GlobalAsm(id) => { + format!("GlobalAsm({:?})", id) + } + } + } +} + +impl<'a, 'tcx> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {} + +fn predefine_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + def_id: DefId, + linkage: Linkage, + visibility: Visibility, + symbol_name: &str) { + let instance = Instance::mono(cx.tcx, def_id); + let ty = instance.ty(cx.tcx); + let llty = cx.layout_of(ty).llvm_type(cx); + + let g = declare::define_global(cx, symbol_name, llty).unwrap_or_else(|| { + cx.sess().span_fatal(cx.tcx.def_span(def_id), + &format!("symbol `{}` is already defined", symbol_name)) + }); + + unsafe { + llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage)); + llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility)); + } + + cx.instances.borrow_mut().insert(instance, g); + cx.statics.borrow_mut().insert(g, def_id); +} + +fn predefine_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + instance: Instance<'tcx>, + linkage: Linkage, + visibility: Visibility, + symbol_name: &str) { + assert!(!instance.substs.needs_infer() && + !instance.substs.has_param_types()); + + let mono_ty = instance.ty(cx.tcx); + let attrs = instance.def.attrs(cx.tcx); + let lldecl = declare::declare_fn(cx, symbol_name, mono_ty); + unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) }; + base::set_link_section(cx, lldecl, &attrs); + if linkage == Linkage::LinkOnceODR || + linkage == Linkage::WeakODR { + llvm::SetUniqueComdat(cx.llmod, lldecl); + } + + // If we're compiling the compiler-builtins crate, e.g. the equivalent of + // compiler-rt, then we want to implicitly compile everything with hidden + // visibility as we're going to link this object all over the place but + // don't want the symbols to get exported. + if linkage != Linkage::Internal && linkage != Linkage::Private && + attr::contains_name(cx.tcx.hir.krate_attrs(), "compiler_builtins") { + unsafe { + llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden); + } + } else { + unsafe { + llvm::LLVMRustSetVisibility(lldecl, base::visibility_to_llvm(visibility)); + } + } + + debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance); + if instance.def.is_inline(cx.tcx) { + attributes::inline(lldecl, attributes::InlineAttr::Hint); + } + attributes::from_fn_attrs(cx, lldecl, instance.def.def_id()); + + cx.instances.borrow_mut().insert(instance, lldecl); +} diff --git a/src/librustc_codegen_llvm/time_graph.rs b/src/librustc_codegen_llvm/time_graph.rs new file mode 100644 index 00000000000..a8502682a80 --- /dev/null +++ b/src/librustc_codegen_llvm/time_graph.rs @@ -0,0 +1,278 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::HashMap; +use std::fs::File; +use std::io::prelude::*; +use std::marker::PhantomData; +use std::mem; +use std::sync::{Arc, Mutex}; +use std::time::Instant; + +const OUTPUT_WIDTH_IN_PX: u64 = 1000; +const TIME_LINE_HEIGHT_IN_PX: u64 = 20; +const TIME_LINE_HEIGHT_STRIDE_IN_PX: usize = 30; + +#[derive(Clone)] +struct Timing { + start: Instant, + end: Instant, + work_package_kind: WorkPackageKind, + name: String, + events: Vec<(String, Instant)>, +} + +#[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)] +pub struct TimelineId(pub usize); + +#[derive(Clone)] +struct PerThread { + timings: Vec, + open_work_package: Option<(Instant, WorkPackageKind, String)>, +} + +#[derive(Clone)] +pub struct TimeGraph { + data: Arc>>, +} + +#[derive(Clone, Copy)] +pub struct WorkPackageKind(pub &'static [&'static str]); + +pub struct Timeline { + token: Option, +} + +struct RaiiToken { + graph: TimeGraph, + timeline: TimelineId, + events: Vec<(String, Instant)>, + // The token must not be Send: + _marker: PhantomData<*const ()> +} + + +impl Drop for RaiiToken { + fn drop(&mut self) { + self.graph.end(self.timeline, mem::replace(&mut self.events, Vec::new())); + } +} + +impl TimeGraph { + pub fn new() -> TimeGraph { + TimeGraph { + data: Arc::new(Mutex::new(HashMap::new())) + } + } + + pub fn start(&self, + timeline: TimelineId, + work_package_kind: WorkPackageKind, + name: &str) -> Timeline { + { + let mut table = self.data.lock().unwrap(); + + let data = table.entry(timeline).or_insert(PerThread { + timings: Vec::new(), + open_work_package: None, + }); + + assert!(data.open_work_package.is_none()); + data.open_work_package = Some((Instant::now(), work_package_kind, name.to_string())); + } + + Timeline { + token: Some(RaiiToken { + graph: self.clone(), + timeline, + events: Vec::new(), + _marker: PhantomData, + }), + } + } + + fn end(&self, timeline: TimelineId, events: Vec<(String, Instant)>) { + let end = Instant::now(); + + let mut table = self.data.lock().unwrap(); + let data = table.get_mut(&timeline).unwrap(); + + if let Some((start, work_package_kind, name)) = data.open_work_package.take() { + data.timings.push(Timing { + start, + end, + work_package_kind, + name, + events, + }); + } else { + bug!("end timing without start?") + } + } + + pub fn dump(&self, output_filename: &str) { + let table = self.data.lock().unwrap(); + + for data in table.values() { + assert!(data.open_work_package.is_none()); + } + + let mut threads: Vec = + table.values().map(|data| data.clone()).collect(); + + threads.sort_by_key(|timeline| timeline.timings[0].start); + + let earliest_instant = threads[0].timings[0].start; + let latest_instant = threads.iter() + .map(|timeline| timeline.timings + .last() + .unwrap() + .end) + .max() + .unwrap(); + let max_distance = distance(earliest_instant, latest_instant); + + let mut file = File::create(format!("{}.html", output_filename)).unwrap(); + + writeln!(file, " + + + + + +

+ ").unwrap(); + + let mut idx = 0; + for thread in threads.iter() { + for timing in &thread.timings { + let colors = timing.work_package_kind.0; + let height = TIME_LINE_HEIGHT_STRIDE_IN_PX * timing.events.len(); + writeln!(file, "
", + idx, + colors[idx % colors.len()], + height).unwrap(); + idx += 1; + let max = distance(timing.start, timing.end); + for (i, &(ref event, time)) in timing.events.iter().enumerate() { + let i = i as u64; + let time = distance(timing.start, time); + let at = normalize(time, max, OUTPUT_WIDTH_IN_PX); + writeln!(file, "{}", + at, + TIME_LINE_HEIGHT_IN_PX * i, + event).unwrap(); + } + writeln!(file, "
").unwrap(); + } + } + + writeln!(file, " + + + ").unwrap(); + } +} + +impl Timeline { + pub fn noop() -> Timeline { + Timeline { token: None } + } + + /// Record an event which happened at this moment on this timeline. + /// + /// Events are displayed in the eventual HTML output where you can click on + /// a particular timeline and it'll expand to all of the events that + /// happened on that timeline. This can then be used to drill into a + /// particular timeline and see what events are happening and taking the + /// most time. + pub fn record(&mut self, name: &str) { + if let Some(ref mut token) = self.token { + token.events.push((name.to_string(), Instant::now())); + } + } +} + +fn distance(zero: Instant, x: Instant) -> u64 { + + let duration = x.duration_since(zero); + (duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64) // / div +} + +fn normalize(distance: u64, max: u64, max_pixels: u64) -> u64 { + (max_pixels * distance) / max +} + diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs new file mode 100644 index 00000000000..a77acc4f175 --- /dev/null +++ b/src/librustc_codegen_llvm/type_.rs @@ -0,0 +1,300 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_upper_case_globals)] + +use llvm; +use llvm::{ContextRef, TypeRef, Bool, False, True, TypeKind}; +use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128}; + +use context::CodegenCx; + +use syntax::ast; +use rustc::ty::layout::{self, Align, Size}; + +use std::ffi::CString; +use std::fmt; +use std::mem; +use std::ptr; + +use libc::c_uint; + +#[derive(Clone, Copy, PartialEq)] +#[repr(C)] +pub struct Type { + rf: TypeRef +} + +impl fmt::Debug for Type { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&llvm::build_string(|s| unsafe { + llvm::LLVMRustWriteTypeToString(self.to_ref(), s); + }).expect("non-UTF8 type description from LLVM")) + } +} + +macro_rules! ty { + ($e:expr) => ( Type::from_ref(unsafe { $e })) +} + +/// Wrapper for LLVM TypeRef +impl Type { + #[inline(always)] + pub fn from_ref(r: TypeRef) -> Type { + Type { + rf: r + } + } + + #[inline(always)] // So it doesn't kill --opt-level=0 builds of the compiler + pub fn to_ref(&self) -> TypeRef { + self.rf + } + + pub fn to_ref_slice(slice: &[Type]) -> &[TypeRef] { + unsafe { mem::transmute(slice) } + } + + pub fn void(cx: &CodegenCx) -> Type { + ty!(llvm::LLVMVoidTypeInContext(cx.llcx)) + } + + pub fn metadata(cx: &CodegenCx) -> Type { + ty!(llvm::LLVMRustMetadataTypeInContext(cx.llcx)) + } + + pub fn i1(cx: &CodegenCx) -> Type { + ty!(llvm::LLVMInt1TypeInContext(cx.llcx)) + } + + pub fn i8(cx: &CodegenCx) -> Type { + ty!(llvm::LLVMInt8TypeInContext(cx.llcx)) + } + + pub fn i8_llcx(llcx: ContextRef) -> Type { + ty!(llvm::LLVMInt8TypeInContext(llcx)) + } + + pub fn i16(cx: &CodegenCx) -> Type { + ty!(llvm::LLVMInt16TypeInContext(cx.llcx)) + } + + pub fn i32(cx: &CodegenCx) -> Type { + ty!(llvm::LLVMInt32TypeInContext(cx.llcx)) + } + + pub fn i64(cx: &CodegenCx) -> Type { + ty!(llvm::LLVMInt64TypeInContext(cx.llcx)) + } + + pub fn i128(cx: &CodegenCx) -> Type { + ty!(llvm::LLVMIntTypeInContext(cx.llcx, 128)) + } + + // Creates an integer type with the given number of bits, e.g. i24 + pub fn ix(cx: &CodegenCx, num_bits: u64) -> Type { + ty!(llvm::LLVMIntTypeInContext(cx.llcx, num_bits as c_uint)) + } + + pub fn f32(cx: &CodegenCx) -> Type { + ty!(llvm::LLVMFloatTypeInContext(cx.llcx)) + } + + pub fn f64(cx: &CodegenCx) -> Type { + ty!(llvm::LLVMDoubleTypeInContext(cx.llcx)) + } + + pub fn bool(cx: &CodegenCx) -> Type { + Type::i8(cx) + } + + pub fn char(cx: &CodegenCx) -> Type { + Type::i32(cx) + } + + pub fn i8p(cx: &CodegenCx) -> Type { + Type::i8(cx).ptr_to() + } + + pub fn i8p_llcx(llcx: ContextRef) -> Type { + Type::i8_llcx(llcx).ptr_to() + } + + pub fn isize(cx: &CodegenCx) -> Type { + match &cx.tcx.sess.target.target.target_pointer_width[..] { + "16" => Type::i16(cx), + "32" => Type::i32(cx), + "64" => Type::i64(cx), + tws => bug!("Unsupported target word size for int: {}", tws), + } + } + + pub fn c_int(cx: &CodegenCx) -> Type { + match &cx.tcx.sess.target.target.target_c_int_width[..] { + "16" => Type::i16(cx), + "32" => Type::i32(cx), + "64" => Type::i64(cx), + width => bug!("Unsupported target_c_int_width: {}", width), + } + } + + pub fn int_from_ty(cx: &CodegenCx, t: ast::IntTy) -> Type { + match t { + ast::IntTy::Isize => cx.isize_ty, + ast::IntTy::I8 => Type::i8(cx), + ast::IntTy::I16 => Type::i16(cx), + ast::IntTy::I32 => Type::i32(cx), + ast::IntTy::I64 => Type::i64(cx), + ast::IntTy::I128 => Type::i128(cx), + } + } + + pub fn uint_from_ty(cx: &CodegenCx, t: ast::UintTy) -> Type { + match t { + ast::UintTy::Usize => cx.isize_ty, + ast::UintTy::U8 => Type::i8(cx), + ast::UintTy::U16 => Type::i16(cx), + ast::UintTy::U32 => Type::i32(cx), + ast::UintTy::U64 => Type::i64(cx), + ast::UintTy::U128 => Type::i128(cx), + } + } + + pub fn float_from_ty(cx: &CodegenCx, t: ast::FloatTy) -> Type { + match t { + ast::FloatTy::F32 => Type::f32(cx), + ast::FloatTy::F64 => Type::f64(cx), + } + } + + pub fn func(args: &[Type], ret: &Type) -> Type { + let slice: &[TypeRef] = Type::to_ref_slice(args); + ty!(llvm::LLVMFunctionType(ret.to_ref(), slice.as_ptr(), + args.len() as c_uint, False)) + } + + pub fn variadic_func(args: &[Type], ret: &Type) -> Type { + let slice: &[TypeRef] = Type::to_ref_slice(args); + ty!(llvm::LLVMFunctionType(ret.to_ref(), slice.as_ptr(), + args.len() as c_uint, True)) + } + + pub fn struct_(cx: &CodegenCx, els: &[Type], packed: bool) -> Type { + let els: &[TypeRef] = Type::to_ref_slice(els); + ty!(llvm::LLVMStructTypeInContext(cx.llcx, els.as_ptr(), + els.len() as c_uint, + packed as Bool)) + } + + pub fn named_struct(cx: &CodegenCx, name: &str) -> Type { + let name = CString::new(name).unwrap(); + ty!(llvm::LLVMStructCreateNamed(cx.llcx, name.as_ptr())) + } + + + pub fn array(ty: &Type, len: u64) -> Type { + ty!(llvm::LLVMRustArrayType(ty.to_ref(), len)) + } + + pub fn vector(ty: &Type, len: u64) -> Type { + ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint)) + } + + pub fn kind(&self) -> TypeKind { + unsafe { + llvm::LLVMRustGetTypeKind(self.to_ref()) + } + } + + pub fn set_struct_body(&mut self, els: &[Type], packed: bool) { + let slice: &[TypeRef] = Type::to_ref_slice(els); + unsafe { + llvm::LLVMStructSetBody(self.to_ref(), slice.as_ptr(), + els.len() as c_uint, packed as Bool) + } + } + + pub fn ptr_to(&self) -> Type { + ty!(llvm::LLVMPointerType(self.to_ref(), 0)) + } + + pub fn element_type(&self) -> Type { + unsafe { + Type::from_ref(llvm::LLVMGetElementType(self.to_ref())) + } + } + + /// Return the number of elements in `self` if it is a LLVM vector type. + pub fn vector_length(&self) -> usize { + unsafe { + llvm::LLVMGetVectorSize(self.to_ref()) as usize + } + } + + pub fn func_params(&self) -> Vec { + unsafe { + let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as usize; + let mut args = vec![Type { rf: ptr::null_mut() }; n_args]; + llvm::LLVMGetParamTypes(self.to_ref(), + args.as_mut_ptr() as *mut TypeRef); + args + } + } + + pub fn float_width(&self) -> usize { + match self.kind() { + Float => 32, + Double => 64, + X86_FP80 => 80, + FP128 | PPC_FP128 => 128, + _ => bug!("llvm_float_width called on a non-float type") + } + } + + /// Retrieve the bit width of the integer type `self`. + pub fn int_width(&self) -> u64 { + unsafe { + llvm::LLVMGetIntTypeWidth(self.to_ref()) as u64 + } + } + + pub fn from_integer(cx: &CodegenCx, i: layout::Integer) -> Type { + use rustc::ty::layout::Integer::*; + match i { + I8 => Type::i8(cx), + I16 => Type::i16(cx), + I32 => Type::i32(cx), + I64 => Type::i64(cx), + I128 => Type::i128(cx), + } + } + + /// Return a LLVM type that has at most the required alignment, + /// as a conservative approximation for unknown pointee types. + pub fn pointee_for_abi_align(cx: &CodegenCx, align: Align) -> Type { + // FIXME(eddyb) We could find a better approximation if ity.align < align. + let ity = layout::Integer::approximate_abi_align(cx, align); + Type::from_integer(cx, ity) + } + + /// Return a LLVM type that has at most the required alignment, + /// and exactly the required size, as a best-effort padding array. + pub fn padding_filler(cx: &CodegenCx, size: Size, align: Align) -> Type { + let unit = layout::Integer::approximate_abi_align(cx, align); + let size = size.bytes(); + let unit_size = unit.size().bytes(); + assert_eq!(size % unit_size, 0); + Type::array(&Type::from_integer(cx, unit), size / unit_size) + } + + pub fn x86_mmx(cx: &CodegenCx) -> Type { + ty!(llvm::LLVMX86MMXTypeInContext(cx.llcx)) + } +} diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs new file mode 100644 index 00000000000..5f186e7514e --- /dev/null +++ b/src/librustc_codegen_llvm/type_of.rs @@ -0,0 +1,506 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use abi::{FnType, FnTypeExt}; +use common::*; +use rustc::hir; +use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout}; +use rustc_target::spec::PanicStrategy; +use mono_item::DefPathBasedNames; +use type_::Type; + +use std::fmt::Write; + +fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + layout: TyLayout<'tcx>, + defer: &mut Option<(Type, TyLayout<'tcx>)>) + -> Type { + match layout.abi { + layout::Abi::Scalar(_) => bug!("handled elsewhere"), + layout::Abi::Vector { ref element, count } => { + // LLVM has a separate type for 64-bit SIMD vectors on X86 called + // `x86_mmx` which is needed for some SIMD operations. As a bit of a + // hack (all SIMD definitions are super unstable anyway) we + // recognize any one-element SIMD vector as "this should be an + // x86_mmx" type. In general there shouldn't be a need for other + // one-element SIMD vectors, so it's assumed this won't clash with + // much else. + let use_x86_mmx = count == 1 && layout.size.bits() == 64 && + (cx.sess().target.target.arch == "x86" || + cx.sess().target.target.arch == "x86_64"); + if use_x86_mmx { + return Type::x86_mmx(cx) + } else { + let element = layout.scalar_llvm_type_at(cx, element, Size::from_bytes(0)); + return Type::vector(&element, count); + } + } + layout::Abi::ScalarPair(..) => { + return Type::struct_(cx, &[ + layout.scalar_pair_element_llvm_type(cx, 0), + layout.scalar_pair_element_llvm_type(cx, 1), + ], false); + } + layout::Abi::Uninhabited | + layout::Abi::Aggregate { .. } => {} + } + + let name = match layout.ty.sty { + ty::TyClosure(..) | + ty::TyGenerator(..) | + ty::TyAdt(..) | + // FIXME(eddyb) producing readable type names for trait objects can result + // in problematically distinct types due to HRTB and subtyping (see #47638). + // ty::TyDynamic(..) | + ty::TyForeign(..) | + ty::TyStr => { + let mut name = String::with_capacity(32); + let printer = DefPathBasedNames::new(cx.tcx, true, true); + printer.push_type_name(layout.ty, &mut name); + match (&layout.ty.sty, &layout.variants) { + (&ty::TyAdt(def, _), &layout::Variants::Single { index }) => { + if def.is_enum() && !def.variants.is_empty() { + write!(&mut name, "::{}", def.variants[index].name).unwrap(); + } + } + _ => {} + } + Some(name) + } + _ => None + }; + + match layout.fields { + layout::FieldPlacement::Union(_) => { + let fill = Type::padding_filler(cx, layout.size, layout.align); + let packed = false; + match name { + None => { + Type::struct_(cx, &[fill], packed) + } + Some(ref name) => { + let mut llty = Type::named_struct(cx, name); + llty.set_struct_body(&[fill], packed); + llty + } + } + } + layout::FieldPlacement::Array { count, .. } => { + Type::array(&layout.field(cx, 0).llvm_type(cx), count) + } + layout::FieldPlacement::Arbitrary { .. } => { + match name { + None => { + let (llfields, packed) = struct_llfields(cx, layout); + Type::struct_(cx, &llfields, packed) + } + Some(ref name) => { + let llty = Type::named_struct(cx, name); + *defer = Some((llty, layout)); + llty + } + } + } + } +} + +fn struct_llfields<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + layout: TyLayout<'tcx>) + -> (Vec, bool) { + debug!("struct_llfields: {:#?}", layout); + let field_count = layout.fields.count(); + + let mut packed = false; + let mut offset = Size::from_bytes(0); + let mut prev_align = layout.align; + let mut result: Vec = Vec::with_capacity(1 + field_count * 2); + for i in layout.fields.index_by_increasing_offset() { + let field = layout.field(cx, i); + packed |= layout.align.abi() < field.align.abi(); + + let target_offset = layout.fields.offset(i as usize); + debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?}", + i, field, offset, target_offset); + assert!(target_offset >= offset); + let padding = target_offset - offset; + let padding_align = layout.align.min(prev_align).min(field.align); + assert_eq!(offset.abi_align(padding_align) + padding, target_offset); + result.push(Type::padding_filler(cx, padding, padding_align)); + debug!(" padding before: {:?}", padding); + + result.push(field.llvm_type(cx)); + offset = target_offset + field.size; + prev_align = field.align; + } + if !layout.is_unsized() && field_count > 0 { + if offset > layout.size { + bug!("layout: {:#?} stride: {:?} offset: {:?}", + layout, layout.size, offset); + } + let padding = layout.size - offset; + let padding_align = layout.align.min(prev_align); + assert_eq!(offset.abi_align(padding_align) + padding, layout.size); + debug!("struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}", + padding, offset, layout.size); + result.push(Type::padding_filler(cx, padding, padding_align)); + assert!(result.len() == 1 + field_count * 2); + } else { + debug!("struct_llfields: offset: {:?} stride: {:?}", + offset, layout.size); + } + + (result, packed) +} + +impl<'a, 'tcx> CodegenCx<'a, 'tcx> { + pub fn align_of(&self, ty: Ty<'tcx>) -> Align { + self.layout_of(ty).align + } + + pub fn size_of(&self, ty: Ty<'tcx>) -> Size { + self.layout_of(ty).size + } + + pub fn size_and_align_of(&self, ty: Ty<'tcx>) -> (Size, Align) { + self.layout_of(ty).size_and_align() + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum PointerKind { + /// Most general case, we know no restrictions to tell LLVM. + Shared, + + /// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`. + Frozen, + + /// `&mut T`, when we know `noalias` is safe for LLVM. + UniqueBorrowed, + + /// `Box`, unlike `UniqueBorrowed`, it also has `noalias` on returns. + UniqueOwned +} + +#[derive(Copy, Clone)] +pub struct PointeeInfo { + pub size: Size, + pub align: Align, + pub safe: Option, +} + +pub trait LayoutLlvmExt<'tcx> { + fn is_llvm_immediate(&self) -> bool; + fn is_llvm_scalar_pair<'a>(&self) -> bool; + fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Type; + fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Type; + fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, + scalar: &layout::Scalar, offset: Size) -> Type; + fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>, + index: usize) -> Type; + fn llvm_field_index(&self, index: usize) -> u64; + fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) + -> Option; +} + +impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { + fn is_llvm_immediate(&self) -> bool { + match self.abi { + layout::Abi::Scalar(_) | + layout::Abi::Vector { .. } => true, + layout::Abi::ScalarPair(..) => false, + layout::Abi::Uninhabited | + layout::Abi::Aggregate { .. } => self.is_zst() + } + } + + fn is_llvm_scalar_pair<'a>(&self) -> bool { + match self.abi { + layout::Abi::ScalarPair(..) => true, + layout::Abi::Uninhabited | + layout::Abi::Scalar(_) | + layout::Abi::Vector { .. } | + layout::Abi::Aggregate { .. } => false + } + } + + /// Get the LLVM type corresponding to a Rust type, i.e. `rustc::ty::Ty`. + /// The pointee type of the pointer in `PlaceRef` is always this type. + /// For sized types, it is also the right LLVM type for an `alloca` + /// containing a value of that type, and most immediates (except `bool`). + /// Unsized types, however, are represented by a "minimal unit", e.g. + /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this + /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`. + /// If the type is an unsized struct, the regular layout is generated, + /// with the inner-most trailing unsized field using the "minimal unit" + /// of that field's type - this is useful for taking the address of + /// that field and ensuring the struct has the right alignment. + fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { + if let layout::Abi::Scalar(ref scalar) = self.abi { + // Use a different cache for scalars because pointers to DSTs + // can be either fat or thin (data pointers of fat pointers). + if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) { + return llty; + } + let llty = match self.ty.sty { + ty::TyRef(_, ty, _) | + ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => { + cx.layout_of(ty).llvm_type(cx).ptr_to() + } + ty::TyAdt(def, _) if def.is_box() => { + cx.layout_of(self.ty.boxed_ty()).llvm_type(cx).ptr_to() + } + ty::TyFnPtr(sig) => { + let sig = cx.tcx.normalize_erasing_late_bound_regions( + ty::ParamEnv::reveal_all(), + &sig, + ); + FnType::new(cx, sig, &[]).llvm_type(cx).ptr_to() + } + _ => self.scalar_llvm_type_at(cx, scalar, Size::from_bytes(0)) + }; + cx.scalar_lltypes.borrow_mut().insert(self.ty, llty); + return llty; + } + + + // Check the cache. + let variant_index = match self.variants { + layout::Variants::Single { index } => Some(index), + _ => None + }; + if let Some(&llty) = cx.lltypes.borrow().get(&(self.ty, variant_index)) { + return llty; + } + + debug!("llvm_type({:#?})", self); + + assert!(!self.ty.has_escaping_regions(), "{:?} has escaping regions", self.ty); + + // Make sure lifetimes are erased, to avoid generating distinct LLVM + // types for Rust types that only differ in the choice of lifetimes. + let normal_ty = cx.tcx.erase_regions(&self.ty); + + let mut defer = None; + let llty = if self.ty != normal_ty { + let mut layout = cx.layout_of(normal_ty); + if let Some(v) = variant_index { + layout = layout.for_variant(cx, v); + } + layout.llvm_type(cx) + } else { + uncached_llvm_type(cx, *self, &mut defer) + }; + debug!("--> mapped {:#?} to llty={:?}", self, llty); + + cx.lltypes.borrow_mut().insert((self.ty, variant_index), llty); + + if let Some((mut llty, layout)) = defer { + let (llfields, packed) = struct_llfields(cx, layout); + llty.set_struct_body(&llfields, packed) + } + + llty + } + + fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { + if let layout::Abi::Scalar(ref scalar) = self.abi { + if scalar.is_bool() { + return Type::i1(cx); + } + } + self.llvm_type(cx) + } + + fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, + scalar: &layout::Scalar, offset: Size) -> Type { + match scalar.value { + layout::Int(i, _) => Type::from_integer(cx, i), + layout::F32 => Type::f32(cx), + layout::F64 => Type::f64(cx), + layout::Pointer => { + // If we know the alignment, pick something better than i8. + let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) { + Type::pointee_for_abi_align(cx, pointee.align) + } else { + Type::i8(cx) + }; + pointee.ptr_to() + } + } + } + + fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>, + index: usize) -> Type { + // HACK(eddyb) special-case fat pointers until LLVM removes + // pointee types, to avoid bitcasting every `OperandRef::deref`. + match self.ty.sty { + ty::TyRef(..) | + ty::TyRawPtr(_) => { + return self.field(cx, index).llvm_type(cx); + } + ty::TyAdt(def, _) if def.is_box() => { + let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty()); + return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index); + } + _ => {} + } + + let (a, b) = match self.abi { + layout::Abi::ScalarPair(ref a, ref b) => (a, b), + _ => bug!("TyLayout::scalar_pair_element_llty({:?}): not applicable", self) + }; + let scalar = [a, b][index]; + + // Make sure to return the same type `immediate_llvm_type` would, + // to avoid dealing with two types and the associated conversions. + // This means that `(bool, bool)` is represented as `{i1, i1}`, + // both in memory and as an immediate, while `bool` is typically + // `i8` in memory and only `i1` when immediate. While we need to + // load/store `bool` as `i8` to avoid crippling LLVM optimizations, + // `i1` in a LLVM aggregate is valid and mostly equivalent to `i8`. + if scalar.is_bool() { + return Type::i1(cx); + } + + let offset = if index == 0 { + Size::from_bytes(0) + } else { + a.value.size(cx).abi_align(b.value.align(cx)) + }; + self.scalar_llvm_type_at(cx, scalar, offset) + } + + fn llvm_field_index(&self, index: usize) -> u64 { + match self.abi { + layout::Abi::Scalar(_) | + layout::Abi::ScalarPair(..) => { + bug!("TyLayout::llvm_field_index({:?}): not applicable", self) + } + _ => {} + } + match self.fields { + layout::FieldPlacement::Union(_) => { + bug!("TyLayout::llvm_field_index({:?}): not applicable", self) + } + + layout::FieldPlacement::Array { .. } => { + index as u64 + } + + layout::FieldPlacement::Arbitrary { .. } => { + 1 + (self.fields.memory_index(index) as u64) * 2 + } + } + } + + fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) + -> Option { + if let Some(&pointee) = cx.pointee_infos.borrow().get(&(self.ty, offset)) { + return pointee; + } + + let mut result = None; + match self.ty.sty { + ty::TyRawPtr(mt) if offset.bytes() == 0 => { + let (size, align) = cx.size_and_align_of(mt.ty); + result = Some(PointeeInfo { + size, + align, + safe: None + }); + } + + ty::TyRef(_, ty, mt) if offset.bytes() == 0 => { + let (size, align) = cx.size_and_align_of(ty); + + let kind = match mt { + hir::MutImmutable => if cx.type_is_freeze(ty) { + PointerKind::Frozen + } else { + PointerKind::Shared + }, + hir::MutMutable => { + if cx.tcx.sess.opts.debugging_opts.mutable_noalias || + cx.tcx.sess.panic_strategy() == PanicStrategy::Abort { + PointerKind::UniqueBorrowed + } else { + PointerKind::Shared + } + } + }; + + result = Some(PointeeInfo { + size, + align, + safe: Some(kind) + }); + } + + _ => { + let mut data_variant = match self.variants { + layout::Variants::NicheFilling { dataful_variant, .. } => { + // Only the niche itself is always initialized, + // so only check for a pointer at its offset. + // + // If the niche is a pointer, it's either valid + // (according to its type), or null (which the + // niche field's scalar validity range encodes). + // This allows using `dereferenceable_or_null` + // for e.g. `Option<&T>`, and this will continue + // to work as long as we don't start using more + // niches than just null (e.g. the first page + // of the address space, or unaligned pointers). + if self.fields.offset(0) == offset { + Some(self.for_variant(cx, dataful_variant)) + } else { + None + } + } + _ => Some(*self) + }; + + if let Some(variant) = data_variant { + // We're not interested in any unions. + if let layout::FieldPlacement::Union(_) = variant.fields { + data_variant = None; + } + } + + if let Some(variant) = data_variant { + let ptr_end = offset + layout::Pointer.size(cx); + for i in 0..variant.fields.count() { + let field_start = variant.fields.offset(i); + if field_start <= offset { + let field = variant.field(cx, i); + if ptr_end <= field_start + field.size { + // We found the right field, look inside it. + result = field.pointee_info_at(cx, offset - field_start); + break; + } + } + } + } + + // FIXME(eddyb) This should be for `ptr::Unique`, not `Box`. + if let Some(ref mut pointee) = result { + if let ty::TyAdt(def, _) = self.ty.sty { + if def.is_box() && offset.bytes() == 0 { + pointee.safe = Some(PointerKind::UniqueOwned); + } + } + } + } + } + + cx.pointee_infos.borrow_mut().insert((self.ty, offset), result); + result + } +} diff --git a/src/librustc_codegen_llvm/value.rs b/src/librustc_codegen_llvm/value.rs new file mode 100644 index 00000000000..287ad87caac --- /dev/null +++ b/src/librustc_codegen_llvm/value.rs @@ -0,0 +1,24 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use llvm; + +use std::fmt; + +#[derive(Copy, Clone, PartialEq)] +pub struct Value(pub llvm::ValueRef); + +impl fmt::Debug for Value { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&llvm::build_string(|s| unsafe { + llvm::LLVMRustWriteValueToString(self.0, s); + }).expect("nun-UTF8 value description from LLVM")) + } +} diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml new file mode 100644 index 00000000000..690fb260390 --- /dev/null +++ b/src/librustc_codegen_utils/Cargo.toml @@ -0,0 +1,23 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_codegen_utils" +version = "0.0.0" + +[lib] +name = "rustc_codegen_utils" +path = "lib.rs" +crate-type = ["dylib"] +test = false + +[dependencies] +ar = "0.3.0" +flate2 = "1.0" +log = "0.4" + +syntax = { path = "../libsyntax" } +syntax_pos = { path = "../libsyntax_pos" } +rustc = { path = "../librustc" } +rustc_target = { path = "../librustc_target" } +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_mir = { path = "../librustc_mir" } +rustc_incremental = { path = "../librustc_incremental" } diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs new file mode 100644 index 00000000000..15aab680289 --- /dev/null +++ b/src/librustc_codegen_utils/codegen_backend.rs @@ -0,0 +1,296 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Rust compiler. +//! +//! # Note +//! +//! This API is completely unstable and subject to change. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/")] +#![deny(warnings)] + +#![feature(box_syntax)] + +use std::any::Any; +use std::io::prelude::*; +use std::io::{self, Cursor}; +use std::fs::File; +use std::path::Path; +use std::sync::mpsc; + +use rustc_data_structures::owning_ref::OwningRef; +use rustc_data_structures::sync::Lrc; +use ar::{Archive, Builder, Header}; +use flate2::Compression; +use flate2::write::DeflateEncoder; + +use syntax::symbol::Symbol; +use rustc::hir::def_id::LOCAL_CRATE; +use rustc::session::{Session, CompileIncomplete}; +use rustc::session::config::{CrateType, OutputFilenames, PrintRequest}; +use rustc::ty::TyCtxt; +use rustc::ty::maps::Providers; +use rustc::middle::cstore::EncodedMetadata; +use rustc::middle::cstore::MetadataLoader; +use rustc::dep_graph::DepGraph; +use rustc_target::spec::Target; +use rustc_data_structures::fx::FxHashMap; +use rustc_mir::monomorphize::collector; +use link::{build_link_meta, out_filename}; + +pub use rustc_data_structures::sync::MetadataRef; + +pub trait CodegenBackend { + fn init(&self, _sess: &Session) {} + fn print(&self, _req: PrintRequest, _sess: &Session) {} + fn target_features(&self, _sess: &Session) -> Vec { vec![] } + fn print_passes(&self) {} + fn print_version(&self) {} + fn diagnostics(&self) -> &[(&'static str, &'static str)] { &[] } + + fn metadata_loader(&self) -> Box; + fn provide(&self, _providers: &mut Providers); + fn provide_extern(&self, _providers: &mut Providers); + fn codegen_crate<'a, 'tcx>( + &self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + rx: mpsc::Receiver> + ) -> Box; + + /// This is called on the returned `Box` from `codegen_backend` + /// + /// # Panics + /// + /// Panics when the passed `Box` was not returned by `codegen_backend`. + fn join_codegen_and_link( + &self, + ongoing_codegen: Box, + sess: &Session, + dep_graph: &DepGraph, + outputs: &OutputFilenames, + ) -> Result<(), CompileIncomplete>; +} + +pub struct DummyCodegenBackend; + +impl CodegenBackend for DummyCodegenBackend { + fn metadata_loader(&self) -> Box { + box DummyMetadataLoader(()) + } + + fn provide(&self, _providers: &mut Providers) { + bug!("DummyCodegenBackend::provide"); + } + + fn provide_extern(&self, _providers: &mut Providers) { + bug!("DummyCodegenBackend::provide_extern"); + } + + fn codegen_crate<'a, 'tcx>( + &self, + _tcx: TyCtxt<'a, 'tcx, 'tcx>, + _rx: mpsc::Receiver> + ) -> Box { + bug!("DummyCodegenBackend::codegen_backend"); + } + + fn join_codegen_and_link( + &self, + _ongoing_codegen: Box, + _sess: &Session, + _dep_graph: &DepGraph, + _outputs: &OutputFilenames, + ) -> Result<(), CompileIncomplete> { + bug!("DummyCodegenBackend::join_codegen_and_link"); + } +} + +pub struct DummyMetadataLoader(()); + +impl MetadataLoader for DummyMetadataLoader { + fn get_rlib_metadata( + &self, + _target: &Target, + _filename: &Path + ) -> Result { + bug!("DummyMetadataLoader::get_rlib_metadata"); + } + + fn get_dylib_metadata( + &self, + _target: &Target, + _filename: &Path + ) -> Result { + bug!("DummyMetadataLoader::get_dylib_metadata"); + } +} + +pub struct NoLlvmMetadataLoader; + +impl MetadataLoader for NoLlvmMetadataLoader { + fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result { + let file = File::open(filename) + .map_err(|e| format!("metadata file open err: {:?}", e))?; + let mut archive = Archive::new(file); + + while let Some(entry_result) = archive.next_entry() { + let mut entry = entry_result + .map_err(|e| format!("metadata section read err: {:?}", e))?; + if entry.header().identifier() == "rust.metadata.bin" { + let mut buf = Vec::new(); + io::copy(&mut entry, &mut buf).unwrap(); + let buf: OwningRef, [u8]> = OwningRef::new(buf).into(); + return Ok(rustc_erase_owner!(buf.map_owner_box())); + } + } + + Err("Couldn't find metadata section".to_string()) + } + + fn get_dylib_metadata( + &self, + _target: &Target, + _filename: &Path, + ) -> Result { + // FIXME: Support reading dylibs from llvm enabled rustc + self.get_rlib_metadata(_target, _filename) + } +} + +pub struct MetadataOnlyCodegenBackend(()); +pub struct OngoingCodegen { + metadata: EncodedMetadata, + metadata_version: Vec, + crate_name: Symbol, +} + +impl MetadataOnlyCodegenBackend { + pub fn new() -> Box { + box MetadataOnlyCodegenBackend(()) + } +} + +impl CodegenBackend for MetadataOnlyCodegenBackend { + fn init(&self, sess: &Session) { + for cty in sess.opts.crate_types.iter() { + match *cty { + CrateType::CrateTypeRlib | CrateType::CrateTypeDylib | + CrateType::CrateTypeExecutable => {}, + _ => { + sess.parse_sess.span_diagnostic.warn( + &format!("LLVM unsupported, so output type {} is not supported", cty) + ); + }, + } + } + } + + fn metadata_loader(&self) -> Box { + box NoLlvmMetadataLoader + } + + fn provide(&self, providers: &mut Providers) { + ::symbol_names::provide(providers); + + providers.target_features_whitelist = |_tcx, _cnum| { + Lrc::new(FxHashMap()) // Just a dummy + }; + } + fn provide_extern(&self, _providers: &mut Providers) {} + + fn codegen_crate<'a, 'tcx>( + &self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + _rx: mpsc::Receiver> + ) -> Box { + use rustc_mir::monomorphize::item::MonoItem; + + ::check_for_rustc_errors_attr(tcx); + ::symbol_names_test::report_symbol_names(tcx); + ::rustc_incremental::assert_dep_graph(tcx); + ::rustc_incremental::assert_module_sources::assert_module_sources(tcx); + ::rustc_mir::monomorphize::assert_symbols_are_distinct(tcx, + collector::collect_crate_mono_items( + tcx, + collector::MonoItemCollectionMode::Eager + ).0.iter() + ); + ::rustc::middle::dependency_format::calculate(tcx); + let _ = tcx.link_args(LOCAL_CRATE); + let _ = tcx.native_libraries(LOCAL_CRATE); + for mono_item in + collector::collect_crate_mono_items( + tcx, + collector::MonoItemCollectionMode::Eager + ).0 { + match mono_item { + MonoItem::Fn(inst) => { + let def_id = inst.def_id(); + if def_id.is_local() { + let _ = inst.def.is_inline(tcx); + let _ = tcx.codegen_fn_attrs(def_id); + } + } + _ => {} + } + } + tcx.sess.abort_if_errors(); + + let link_meta = build_link_meta(tcx.crate_hash(LOCAL_CRATE)); + let metadata = tcx.encode_metadata(&link_meta); + + box OngoingCodegen { + metadata: metadata, + metadata_version: tcx.metadata_encoding_version().to_vec(), + crate_name: tcx.crate_name(LOCAL_CRATE), + } + } + + fn join_codegen_and_link( + &self, + ongoing_codegen: Box, + sess: &Session, + _dep_graph: &DepGraph, + outputs: &OutputFilenames, + ) -> Result<(), CompileIncomplete> { + let ongoing_codegen = ongoing_codegen.downcast::() + .expect("Expected MetadataOnlyCodegenBackend's OngoingCodegen, found Box"); + for &crate_type in sess.opts.crate_types.iter() { + if crate_type != CrateType::CrateTypeRlib && crate_type != CrateType::CrateTypeDylib { + continue; + } + let output_name = + out_filename(sess, crate_type, &outputs, &ongoing_codegen.crate_name.as_str()); + let mut compressed = ongoing_codegen.metadata_version.clone(); + let metadata = if crate_type == CrateType::CrateTypeDylib { + DeflateEncoder::new(&mut compressed, Compression::fast()) + .write_all(&ongoing_codegen.metadata.raw_data) + .unwrap(); + &compressed + } else { + &ongoing_codegen.metadata.raw_data + }; + let mut builder = Builder::new(File::create(&output_name).unwrap()); + let header = Header::new("rust.metadata.bin".to_string(), metadata.len() as u64); + builder.append(&header, Cursor::new(metadata)).unwrap(); + } + + sess.abort_if_errors(); + if !sess.opts.crate_types.contains(&CrateType::CrateTypeRlib) + && !sess.opts.crate_types.contains(&CrateType::CrateTypeDylib) + { + sess.fatal("Executables are not supported by the metadata-only backend."); + } + Ok(()) + } +} diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs new file mode 100644 index 00000000000..0c18571f4ff --- /dev/null +++ b/src/librustc_codegen_utils/lib.rs @@ -0,0 +1,63 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! # Note +//! +//! This API is completely unstable and subject to change. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/")] + +#![feature(box_patterns)] +#![feature(box_syntax)] +#![feature(custom_attribute)] +#![allow(unused_attributes)] +#![feature(quote)] +#![feature(rustc_diagnostic_macros)] + +extern crate ar; +extern crate flate2; +#[macro_use] +extern crate log; + +#[macro_use] +extern crate rustc; +extern crate rustc_target; +extern crate rustc_mir; +extern crate rustc_incremental; +extern crate syntax; +extern crate syntax_pos; +#[macro_use] extern crate rustc_data_structures; + +pub extern crate rustc as __rustc; + +use rustc::ty::TyCtxt; + +pub mod link; +pub mod codegen_backend; +pub mod symbol_names; +pub mod symbol_names_test; + +/// check for the #[rustc_error] annotation, which forces an +/// error in codegen. This is used to write compile-fail tests +/// that actually test that compilation succeeds without +/// reporting an error. +pub fn check_for_rustc_errors_attr(tcx: TyCtxt) { + if let Some((id, span, _)) = *tcx.sess.entry_fn.borrow() { + let main_def_id = tcx.hir.local_def_id(id); + + if tcx.has_attr(main_def_id, "rustc_error") { + tcx.sess.span_fatal(span, "compilation successful"); + } + } +} + +__build_diagnostic_array! { librustc_codegen_utils, DIAGNOSTICS } diff --git a/src/librustc_codegen_utils/link.rs b/src/librustc_codegen_utils/link.rs new file mode 100644 index 00000000000..aabe931d79c --- /dev/null +++ b/src/librustc_codegen_utils/link.rs @@ -0,0 +1,191 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::session::config::{self, OutputFilenames, Input, OutputType}; +use rustc::session::Session; +use rustc::middle::cstore::{self, LinkMeta}; +use rustc::hir::svh::Svh; +use std::path::{Path, PathBuf}; +use syntax::{ast, attr}; +use syntax_pos::Span; + +pub fn out_filename(sess: &Session, + crate_type: config::CrateType, + outputs: &OutputFilenames, + crate_name: &str) + -> PathBuf { + let default_filename = filename_for_input(sess, crate_type, crate_name, outputs); + let out_filename = outputs.outputs.get(&OutputType::Exe) + .and_then(|s| s.to_owned()) + .or_else(|| outputs.single_output_file.clone()) + .unwrap_or(default_filename); + + check_file_is_writeable(&out_filename, sess); + + out_filename +} + +// Make sure files are writeable. Mac, FreeBSD, and Windows system linkers +// check this already -- however, the Linux linker will happily overwrite a +// read-only file. We should be consistent. +pub fn check_file_is_writeable(file: &Path, sess: &Session) { + if !is_writeable(file) { + sess.fatal(&format!("output file {} is not writeable -- check its \ + permissions", file.display())); + } +} + +fn is_writeable(p: &Path) -> bool { + match p.metadata() { + Err(..) => true, + Ok(m) => !m.permissions().readonly() + } +} + +pub fn build_link_meta(crate_hash: Svh) -> LinkMeta { + let r = LinkMeta { + crate_hash, + }; + info!("{:?}", r); + return r; +} + +pub fn find_crate_name(sess: Option<&Session>, + attrs: &[ast::Attribute], + input: &Input) -> String { + let validate = |s: String, span: Option| { + cstore::validate_crate_name(sess, &s, span); + s + }; + + // Look in attributes 100% of the time to make sure the attribute is marked + // as used. After doing this, however, we still prioritize a crate name from + // the command line over one found in the #[crate_name] attribute. If we + // find both we ensure that they're the same later on as well. + let attr_crate_name = attr::find_by_name(attrs, "crate_name") + .and_then(|at| at.value_str().map(|s| (at, s))); + + if let Some(sess) = sess { + if let Some(ref s) = sess.opts.crate_name { + if let Some((attr, name)) = attr_crate_name { + if name != &**s { + let msg = format!("--crate-name and #[crate_name] are \ + required to match, but `{}` != `{}`", + s, name); + sess.span_err(attr.span, &msg); + } + } + return validate(s.clone(), None); + } + } + + if let Some((attr, s)) = attr_crate_name { + return validate(s.to_string(), Some(attr.span)); + } + if let Input::File(ref path) = *input { + if let Some(s) = path.file_stem().and_then(|s| s.to_str()) { + if s.starts_with("-") { + let msg = format!("crate names cannot start with a `-`, but \ + `{}` has a leading hyphen", s); + if let Some(sess) = sess { + sess.err(&msg); + } + } else { + return validate(s.replace("-", "_"), None); + } + } + } + + "rust_out".to_string() +} + +pub fn filename_for_input(sess: &Session, + crate_type: config::CrateType, + crate_name: &str, + outputs: &OutputFilenames) -> PathBuf { + let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename); + + match crate_type { + config::CrateTypeRlib => { + outputs.out_directory.join(&format!("lib{}.rlib", libname)) + } + config::CrateTypeCdylib | + config::CrateTypeProcMacro | + config::CrateTypeDylib => { + let (prefix, suffix) = (&sess.target.target.options.dll_prefix, + &sess.target.target.options.dll_suffix); + outputs.out_directory.join(&format!("{}{}{}", prefix, libname, + suffix)) + } + config::CrateTypeStaticlib => { + let (prefix, suffix) = (&sess.target.target.options.staticlib_prefix, + &sess.target.target.options.staticlib_suffix); + outputs.out_directory.join(&format!("{}{}{}", prefix, libname, + suffix)) + } + config::CrateTypeExecutable => { + let suffix = &sess.target.target.options.exe_suffix; + let out_filename = outputs.path(OutputType::Exe); + if suffix.is_empty() { + out_filename.to_path_buf() + } else { + out_filename.with_extension(&suffix[1..]) + } + } + } +} + +/// Returns default crate type for target +/// +/// Default crate type is used when crate type isn't provided neither +/// through cmd line arguments nor through crate attributes +/// +/// It is CrateTypeExecutable for all platforms but iOS as there is no +/// way to run iOS binaries anyway without jailbreaking and +/// interaction with Rust code through static library is the only +/// option for now +pub fn default_output_for_target(sess: &Session) -> config::CrateType { + if !sess.target.target.options.executables { + config::CrateTypeStaticlib + } else { + config::CrateTypeExecutable + } +} + +/// Checks if target supports crate_type as output +pub fn invalid_output_for_target(sess: &Session, + crate_type: config::CrateType) -> bool { + match crate_type { + config::CrateTypeCdylib | + config::CrateTypeDylib | + config::CrateTypeProcMacro => { + if !sess.target.target.options.dynamic_linking { + return true + } + if sess.crt_static() && !sess.target.target.options.crt_static_allows_dylibs { + return true + } + } + _ => {} + } + if sess.target.target.options.only_cdylib { + match crate_type { + config::CrateTypeProcMacro | config::CrateTypeDylib => return true, + _ => {} + } + } + if !sess.target.target.options.executables { + if crate_type == config::CrateTypeExecutable { + return true + } + } + + false +} diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs new file mode 100644 index 00000000000..1a62f39ae3d --- /dev/null +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -0,0 +1,435 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Rust Linkage Model and Symbol Names +//! ======================================= +//! +//! The semantic model of Rust linkage is, broadly, that "there's no global +//! namespace" between crates. Our aim is to preserve the illusion of this +//! model despite the fact that it's not *quite* possible to implement on +//! modern linkers. We initially didn't use system linkers at all, but have +//! been convinced of their utility. +//! +//! There are a few issues to handle: +//! +//! - Linkers operate on a flat namespace, so we have to flatten names. +//! We do this using the C++ namespace-mangling technique. Foo::bar +//! symbols and such. +//! +//! - Symbols for distinct items with the same *name* need to get different +//! linkage-names. Examples of this are monomorphizations of functions or +//! items within anonymous scopes that end up having the same path. +//! +//! - Symbols in different crates but with same names "within" the crate need +//! to get different linkage-names. +//! +//! - Symbol names should be deterministic: Two consecutive runs of the +//! compiler over the same code base should produce the same symbol names for +//! the same items. +//! +//! - Symbol names should not depend on any global properties of the code base, +//! so that small modifications to the code base do not result in all symbols +//! changing. In previous versions of the compiler, symbol names incorporated +//! the SVH (Stable Version Hash) of the crate. This scheme turned out to be +//! infeasible when used in conjunction with incremental compilation because +//! small code changes would invalidate all symbols generated previously. +//! +//! - Even symbols from different versions of the same crate should be able to +//! live next to each other without conflict. +//! +//! In order to fulfill the above requirements the following scheme is used by +//! the compiler: +//! +//! The main tool for avoiding naming conflicts is the incorporation of a 64-bit +//! hash value into every exported symbol name. Anything that makes a difference +//! to the symbol being named, but does not show up in the regular path needs to +//! be fed into this hash: +//! +//! - Different monomorphizations of the same item have the same path but differ +//! in their concrete type parameters, so these parameters are part of the +//! data being digested for the symbol hash. +//! +//! - Rust allows items to be defined in anonymous scopes, such as in +//! `fn foo() { { fn bar() {} } { fn bar() {} } }`. Both `bar` functions have +//! the path `foo::bar`, since the anonymous scopes do not contribute to the +//! path of an item. The compiler already handles this case via so-called +//! disambiguating `DefPaths` which use indices to distinguish items with the +//! same name. The DefPaths of the functions above are thus `foo[0]::bar[0]` +//! and `foo[0]::bar[1]`. In order to incorporate this disambiguation +//! information into the symbol name too, these indices are fed into the +//! symbol hash, so that the above two symbols would end up with different +//! hash values. +//! +//! The two measures described above suffice to avoid intra-crate conflicts. In +//! order to also avoid inter-crate conflicts two more measures are taken: +//! +//! - The name of the crate containing the symbol is prepended to the symbol +//! name, i.e. symbols are "crate qualified". For example, a function `foo` in +//! module `bar` in crate `baz` would get a symbol name like +//! `baz::bar::foo::{hash}` instead of just `bar::foo::{hash}`. This avoids +//! simple conflicts between functions from different crates. +//! +//! - In order to be able to also use symbols from two versions of the same +//! crate (which naturally also have the same name), a stronger measure is +//! required: The compiler accepts an arbitrary "disambiguator" value via the +//! `-C metadata` commandline argument. This disambiguator is then fed into +//! the symbol hash of every exported item. Consequently, the symbols in two +//! identical crates but with different disambiguators are not in conflict +//! with each other. This facility is mainly intended to be used by build +//! tools like Cargo. +//! +//! A note on symbol name stability +//! ------------------------------- +//! Previous versions of the compiler resorted to feeding NodeIds into the +//! symbol hash in order to disambiguate between items with the same path. The +//! current version of the name generation algorithm takes great care not to do +//! that, since NodeIds are notoriously unstable: A small change to the +//! code base will offset all NodeIds after the change and thus, much as using +//! the SVH in the hash, invalidate an unbounded number of symbol names. This +//! makes re-using previously compiled code for incremental compilation +//! virtually impossible. Thus, symbol hash generation exclusively relies on +//! DefPaths which are much more robust in the face of changes to the code base. + +use rustc::middle::weak_lang_items; +use rustc_mir::monomorphize::Instance; +use rustc_mir::monomorphize::item::{MonoItem, MonoItemExt, InstantiationMode}; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::hir::map as hir_map; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::fold::TypeVisitor; +use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; +use rustc::ty::maps::Providers; +use rustc::ty::subst::Substs; +use rustc::hir::map::definitions::DefPathData; +use rustc::util::common::record_time; + +use syntax::attr; +use syntax_pos::symbol::Symbol; + +use std::fmt::Write; + +pub fn provide(providers: &mut Providers) { + *providers = Providers { + def_symbol_name, + symbol_name, + + ..*providers + }; +} + +fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + + // the DefId of the item this name is for + def_id: DefId, + + // instance this name will be for + instance: Instance<'tcx>, + + // type of the item, without any generic + // parameters substituted; this is + // included in the hash as a kind of + // safeguard. + item_type: Ty<'tcx>, + + // values for generic type parameters, + // if any. + substs: &'tcx Substs<'tcx>) + -> u64 { + debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs); + + let mut hasher = ty::util::TypeIdHasher::::new(tcx); + + record_time(&tcx.sess.perf_stats.symbol_hash_time, || { + // the main symbol name is not necessarily unique; hash in the + // compiler's internal def-path, guaranteeing each symbol has a + // truly unique path + hasher.hash(tcx.def_path_hash(def_id)); + + // Include the main item-type. Note that, in this case, the + // assertions about `needs_subst` may not hold, but this item-type + // ought to be the same for every reference anyway. + assert!(!item_type.has_erasable_regions()); + hasher.visit_ty(item_type); + + // If this is a function, we hash the signature as well. + // This is not *strictly* needed, but it may help in some + // situations, see the `run-make/a-b-a-linker-guard` test. + if let ty::TyFnDef(..) = item_type.sty { + item_type.fn_sig(tcx).visit_with(&mut hasher); + } + + // also include any type parameters (for generic items) + assert!(!substs.has_erasable_regions()); + assert!(!substs.needs_subst()); + substs.visit_with(&mut hasher); + + let is_generic = substs.types().next().is_some(); + let avoid_cross_crate_conflicts = + // If this is an instance of a generic function, we also hash in + // the ID of the instantiating crate. This avoids symbol conflicts + // in case the same instances is emitted in two crates of the same + // project. + is_generic || + + // If we're dealing with an instance of a function that's inlined from + // another crate but we're marking it as globally shared to our + // compliation (aka we're not making an internal copy in each of our + // codegen units) then this symbol may become an exported (but hidden + // visibility) symbol. This means that multiple crates may do the same + // and we want to be sure to avoid any symbol conflicts here. + match MonoItem::Fn(instance).instantiation_mode(tcx) { + InstantiationMode::GloballyShared { may_conflict: true } => true, + _ => false, + }; + + if avoid_cross_crate_conflicts { + let instantiating_crate = if is_generic { + if !def_id.is_local() && tcx.share_generics() { + // If we are re-using a monomorphization from another crate, + // we have to compute the symbol hash accordingly. + let upstream_monomorphizations = + tcx.upstream_monomorphizations_for(def_id); + + upstream_monomorphizations.and_then(|monos| monos.get(&substs) + .cloned()) + .unwrap_or(LOCAL_CRATE) + } else { + LOCAL_CRATE + } + } else { + LOCAL_CRATE + }; + + hasher.hash(&tcx.original_crate_name(instantiating_crate).as_str()[..]); + hasher.hash(&tcx.crate_disambiguator(instantiating_crate)); + } + }); + + // 64 bits should be enough to avoid collisions. + hasher.finish() +} + +fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) + -> ty::SymbolName +{ + let mut buffer = SymbolPathBuffer::new(); + item_path::with_forced_absolute_paths(|| { + tcx.push_item_path(&mut buffer, def_id); + }); + buffer.into_interned() +} + +fn symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) + -> ty::SymbolName +{ + ty::SymbolName { name: Symbol::intern(&compute_symbol_name(tcx, instance)).as_interned_str() } +} + +fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) + -> String +{ + let def_id = instance.def_id(); + let substs = instance.substs; + + debug!("symbol_name(def_id={:?}, substs={:?})", + def_id, substs); + + let node_id = tcx.hir.as_local_node_id(def_id); + + if let Some(id) = node_id { + if *tcx.sess.plugin_registrar_fn.get() == Some(id) { + let disambiguator = tcx.sess.local_crate_disambiguator(); + return tcx.sess.generate_plugin_registrar_symbol(disambiguator); + } + if *tcx.sess.derive_registrar_fn.get() == Some(id) { + let disambiguator = tcx.sess.local_crate_disambiguator(); + return tcx.sess.generate_derive_registrar_symbol(disambiguator); + } + } + + // FIXME(eddyb) Precompute a custom symbol name based on attributes. + let attrs = tcx.get_attrs(def_id); + let is_foreign = if let Some(id) = node_id { + match tcx.hir.get(id) { + hir_map::NodeForeignItem(_) => true, + _ => false + } + } else { + tcx.is_foreign_item(def_id) + }; + + if let Some(name) = weak_lang_items::link_name(&attrs) { + return name.to_string(); + } + + if is_foreign { + if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "link_name") { + return name.to_string(); + } + // Don't mangle foreign items. + return tcx.item_name(def_id).to_string(); + } + + if let Some(name) = tcx.codegen_fn_attrs(def_id).export_name { + // Use provided name + return name.to_string(); + } + + if attr::contains_name(&attrs, "no_mangle") { + // Don't mangle + return tcx.item_name(def_id).to_string(); + } + + // We want to compute the "type" of this item. Unfortunately, some + // kinds of items (e.g., closures) don't have an entry in the + // item-type array. So walk back up the find the closest parent + // that DOES have an entry. + let mut ty_def_id = def_id; + let instance_ty; + loop { + let key = tcx.def_key(ty_def_id); + match key.disambiguated_data.data { + DefPathData::TypeNs(_) | + DefPathData::ValueNs(_) => { + instance_ty = tcx.type_of(ty_def_id); + break; + } + _ => { + // if we're making a symbol for something, there ought + // to be a value or type-def or something in there + // *somewhere* + ty_def_id.index = key.parent.unwrap_or_else(|| { + bug!("finding type for {:?}, encountered def-id {:?} with no \ + parent", def_id, ty_def_id); + }); + } + } + } + + // Erase regions because they may not be deterministic when hashed + // and should not matter anyhow. + let instance_ty = tcx.erase_regions(&instance_ty); + + let hash = get_symbol_hash(tcx, def_id, instance, instance_ty, substs); + + SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)).finish(hash) +} + +// Follow C++ namespace-mangling style, see +// http://en.wikipedia.org/wiki/Name_mangling for more info. +// +// It turns out that on macOS you can actually have arbitrary symbols in +// function names (at least when given to LLVM), but this is not possible +// when using unix's linker. Perhaps one day when we just use a linker from LLVM +// we won't need to do this name mangling. The problem with name mangling is +// that it seriously limits the available characters. For example we can't +// have things like &T in symbol names when one would theoretically +// want them for things like impls of traits on that type. +// +// To be able to work on all platforms and get *some* reasonable output, we +// use C++ name-mangling. +struct SymbolPathBuffer { + result: String, + temp_buf: String +} + +impl SymbolPathBuffer { + fn new() -> Self { + let mut result = SymbolPathBuffer { + result: String::with_capacity(64), + temp_buf: String::with_capacity(16) + }; + result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested + result + } + + fn from_interned(symbol: ty::SymbolName) -> Self { + let mut result = SymbolPathBuffer { + result: String::with_capacity(64), + temp_buf: String::with_capacity(16) + }; + result.result.push_str(&symbol.name.as_str()); + result + } + + fn into_interned(self) -> ty::SymbolName { + ty::SymbolName { name: Symbol::intern(&self.result).as_interned_str() } + } + + fn finish(mut self, hash: u64) -> String { + // E = end name-sequence + let _ = write!(self.result, "17h{:016x}E", hash); + self.result + } +} + +impl ItemPathBuffer for SymbolPathBuffer { + fn root_mode(&self) -> &RootMode { + const ABSOLUTE: &'static RootMode = &RootMode::Absolute; + ABSOLUTE + } + + fn push(&mut self, text: &str) { + self.temp_buf.clear(); + let need_underscore = sanitize(&mut self.temp_buf, text); + let _ = write!(self.result, "{}", self.temp_buf.len() + (need_underscore as usize)); + if need_underscore { + self.result.push('_'); + } + self.result.push_str(&self.temp_buf); + } +} + +// Name sanitation. LLVM will happily accept identifiers with weird names, but +// gas doesn't! +// gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $ +// +// returns true if an underscore must be added at the start +pub fn sanitize(result: &mut String, s: &str) -> bool { + for c in s.chars() { + match c { + // Escape these with $ sequences + '@' => result.push_str("$SP$"), + '*' => result.push_str("$BP$"), + '&' => result.push_str("$RF$"), + '<' => result.push_str("$LT$"), + '>' => result.push_str("$GT$"), + '(' => result.push_str("$LP$"), + ')' => result.push_str("$RP$"), + ',' => result.push_str("$C$"), + + // '.' doesn't occur in types and functions, so reuse it + // for ':' and '-' + '-' | ':' => result.push('.'), + + // These are legal symbols + 'a' ... 'z' + | 'A' ... 'Z' + | '0' ... '9' + | '_' | '.' | '$' => result.push(c), + + _ => { + result.push('$'); + for c in c.escape_unicode().skip(1) { + match c { + '{' => {}, + '}' => result.push('$'), + c => result.push(c), + } + } + } + } + } + + // Underscore-qualify anything that didn't start as an ident. + !result.is_empty() && + result.as_bytes()[0] != '_' as u8 && + ! (result.as_bytes()[0] as char).is_xid_start() +} diff --git a/src/librustc_codegen_utils/symbol_names_test.rs b/src/librustc_codegen_utils/symbol_names_test.rs new file mode 100644 index 00000000000..47bbd67fb5c --- /dev/null +++ b/src/librustc_codegen_utils/symbol_names_test.rs @@ -0,0 +1,79 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Walks the crate looking for items/impl-items/trait-items that have +//! either a `rustc_symbol_name` or `rustc_item_path` attribute and +//! generates an error giving, respectively, the symbol name or +//! item-path. This is used for unit testing the code that generates +//! paths etc in all kinds of annoying scenarios. + +use rustc::hir; +use rustc::ty::TyCtxt; +use syntax::ast; + +use rustc_mir::monomorphize::Instance; + +const SYMBOL_NAME: &'static str = "rustc_symbol_name"; +const ITEM_PATH: &'static str = "rustc_item_path"; + +pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + // if the `rustc_attrs` feature is not enabled, then the + // attributes we are interested in cannot be present anyway, so + // skip the walk. + if !tcx.features().rustc_attrs { + return; + } + + tcx.dep_graph.with_ignore(|| { + let mut visitor = SymbolNamesTest { tcx: tcx }; + tcx.hir.krate().visit_all_item_likes(&mut visitor); + }) +} + +struct SymbolNamesTest<'a, 'tcx:'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, +} + +impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { + fn process_attrs(&mut self, + node_id: ast::NodeId) { + let tcx = self.tcx; + let def_id = tcx.hir.local_def_id(node_id); + for attr in tcx.get_attrs(def_id).iter() { + if attr.check_name(SYMBOL_NAME) { + // for now, can only use on monomorphic names + let instance = Instance::mono(tcx, def_id); + let name = self.tcx.symbol_name(instance); + tcx.sess.span_err(attr.span, &format!("symbol-name({})", name)); + } else if attr.check_name(ITEM_PATH) { + let path = tcx.item_path_str(def_id); + tcx.sess.span_err(attr.span, &format!("item-path({})", path)); + } + + // (*) The formatting of `tag({})` is chosen so that tests can elect + // to test the entirety of the string, if they choose, or else just + // some subset. + } + } +} + +impl<'a, 'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for SymbolNamesTest<'a, 'tcx> { + fn visit_item(&mut self, item: &'tcx hir::Item) { + self.process_attrs(item.id); + } + + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { + self.process_attrs(trait_item.id); + } + + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { + self.process_attrs(impl_item.id); + } +} diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index 1827533f0ac..24bf07d793f 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -31,7 +31,7 @@ rustc_privacy = { path = "../librustc_privacy" } rustc_resolve = { path = "../librustc_resolve" } rustc_save_analysis = { path = "../librustc_save_analysis" } rustc_traits = { path = "../librustc_traits" } -rustc_trans_utils = { path = "../librustc_trans_utils" } +rustc_codegen_utils = { path = "../librustc_codegen_utils" } rustc_typeck = { path = "../librustc_typeck" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 62b3accc46f..ed28b05c125 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -32,7 +32,7 @@ use rustc_resolve::{MakeGlobMap, Resolver, ResolverArenas}; use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::{self, CStore}; use rustc_traits; -use rustc_trans_utils::trans_crate::TransCrate; +use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_typeck as typeck; use rustc_privacy; use rustc_plugin::registry::Registry; @@ -110,7 +110,7 @@ pub fn spawn_thread_pool R + sync::Send, R: sync:: } pub fn compile_input( - trans: Box, + codegen_backend: Box, sess: &Session, cstore: &CStore, input_path: &Option, @@ -143,7 +143,7 @@ pub fn compile_input( // We need nested scopes here, because the intermediate results can keep // large chunks of memory alive and we want to free them as soon as // possible to keep the peak memory usage low - let (outputs, ongoing_trans, dep_graph) = { + let (outputs, ongoing_codegen, dep_graph) = { let krate = match phase_1_parse_input(control, sess, input) { Ok(krate) => krate, Err(mut parse_error) => { @@ -162,7 +162,7 @@ pub fn compile_input( let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess); let crate_name = - ::rustc_trans_utils::link::find_crate_name(Some(sess), &krate.attrs, input); + ::rustc_codegen_utils::link::find_crate_name(Some(sess), &krate.attrs, input); install_panic_hook(); let ExpansionResult { @@ -274,7 +274,7 @@ pub fn compile_input( }; phase_3_run_analysis_passes( - &*trans, + &*codegen_backend, control, sess, cstore, @@ -310,14 +310,14 @@ pub fn compile_input( result?; if log_enabled!(::log::Level::Info) { - println!("Pre-trans"); + println!("Pre-codegen"); tcx.print_debug_stats(); } - let ongoing_trans = phase_4_translate_to_llvm(&*trans, tcx, rx); + let ongoing_codegen = phase_4_codegen(&*codegen_backend, tcx, rx); if log_enabled!(::log::Level::Info) { - println!("Post-trans"); + println!("Post-codegen"); tcx.print_debug_stats(); } @@ -328,7 +328,7 @@ pub fn compile_input( } } - Ok((outputs.clone(), ongoing_trans, tcx.dep_graph.clone())) + Ok((outputs.clone(), ongoing_codegen, tcx.dep_graph.clone())) }, )?? }; @@ -337,7 +337,7 @@ pub fn compile_input( sess.code_stats.borrow().print_type_sizes(); } - trans.join_trans_and_link(ongoing_trans, sess, &dep_graph, &outputs)?; + codegen_backend.join_codegen_and_link(ongoing_codegen, sess, &dep_graph, &outputs)?; if sess.opts.debugging_opts.perf_stats { sess.print_perf_stats(); @@ -1089,7 +1089,7 @@ pub fn default_provide_extern(providers: &mut ty::maps::Providers) { /// miscellaneous analysis passes on the crate. Return various /// structures carrying the results of the analysis. pub fn phase_3_run_analysis_passes<'tcx, F, R>( - trans: &TransCrate, + codegen_backend: &CodegenBackend, control: &CompileController, sess: &'tcx Session, cstore: &'tcx CrateStoreDyn, @@ -1128,12 +1128,12 @@ where let mut local_providers = ty::maps::Providers::default(); default_provide(&mut local_providers); - trans.provide(&mut local_providers); + codegen_backend.provide(&mut local_providers); (control.provide)(&mut local_providers); let mut extern_providers = local_providers; default_provide_extern(&mut extern_providers); - trans.provide_extern(&mut extern_providers); + codegen_backend.provide_extern(&mut extern_providers); (control.provide_extern)(&mut extern_providers); let (tx, rx) = mpsc::channel(); @@ -1233,10 +1233,10 @@ where ) } -/// Run the translation phase to LLVM, after which the AST and analysis can +/// Run the codegen backend, after which the AST and analysis can /// be discarded. -pub fn phase_4_translate_to_llvm<'a, 'tcx>( - trans: &TransCrate, +pub fn phase_4_codegen<'a, 'tcx>( + codegen_backend: &CodegenBackend, tcx: TyCtxt<'a, 'tcx, 'tcx>, rx: mpsc::Receiver>, ) -> Box { @@ -1244,12 +1244,12 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>( ::rustc::middle::dependency_format::calculate(tcx) }); - let translation = time(tcx.sess, "translation", move || trans.trans_crate(tcx, rx)); + let codegen = time(tcx.sess, "codegen", move || codegen_backend.codegen_crate(tcx, rx)); if tcx.sess.profile_queries() { profile::dump(&tcx.sess, "profile_queries".to_string()) } - translation + codegen } fn escape_dep_filename(filename: &FileName) -> String { @@ -1272,7 +1272,7 @@ fn generated_output_paths( // If the filename has been overridden using `-o`, it will not be modified // by appending `.rlib`, `.exe`, etc., so we can skip this transformation. OutputType::Exe if !exact_name => for crate_type in sess.crate_types.borrow().iter() { - let p = ::rustc_trans_utils::link::filename_for_input( + let p = ::rustc_codegen_utils::link::filename_for_input( sess, *crate_type, crate_name, @@ -1424,7 +1424,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec Vec(run_compiler: F) -> isize 0 } -fn load_backend_from_dylib(path: &Path) -> fn() -> Box { +fn load_backend_from_dylib(path: &Path) -> fn() -> Box { // Note that we're specifically using `open_global_now` here rather than // `open`, namely we want the behavior on Unix of RTLD_GLOBAL and RTLD_NOW, // where NOW means "bind everything right now" because we don't want @@ -233,24 +235,24 @@ fn load_backend_from_dylib(path: &Path) -> fn() -> Box { } } -pub fn get_trans(sess: &Session) -> Box { +pub fn get_codegen_backend(sess: &Session) -> Box { static INIT: Once = ONCE_INIT; #[allow(deprecated)] #[no_debug] - static mut LOAD: fn() -> Box = || unreachable!(); + static mut LOAD: fn() -> Box = || unreachable!(); INIT.call_once(|| { - let trans_name = sess.opts.debugging_opts.codegen_backend.as_ref() + let codegen_name = sess.opts.debugging_opts.codegen_backend.as_ref() .unwrap_or(&sess.target.target.options.codegen_backend); - let backend = match &trans_name[..] { + let backend = match &codegen_name[..] { "metadata_only" => { - rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new + rustc_codegen_utils::codegen_backend::MetadataOnlyCodegenBackend::new } filename if filename.contains(".") => { load_backend_from_dylib(filename.as_ref()) } - trans_name => get_trans_sysroot(trans_name), + codegen_name => get_codegen_sysroot(codegen_name), }; unsafe { @@ -262,15 +264,15 @@ pub fn get_trans(sess: &Session) -> Box { backend } -fn get_trans_sysroot(backend_name: &str) -> fn() -> Box { +fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box { // For now we only allow this function to be called once as it'll dlopen a // few things, which seems to work best if we only do that once. In - // general this assertion never trips due to the once guard in `get_trans`, + // general this assertion never trips due to the once guard in `get_codegen_backend`, // but there's a few manual calls to this function in this file we protect // against. static LOADED: AtomicBool = ATOMIC_BOOL_INIT; assert!(!LOADED.fetch_or(true, Ordering::SeqCst), - "cannot load the default trans backend twice"); + "cannot load the default codegen backend twice"); // When we're compiling this library with `--test` it'll run as a binary but // not actually exercise much functionality. As a result most of the logic @@ -278,7 +280,7 @@ fn get_trans_sysroot(backend_name: &str) -> fn() -> Box { // let's just return a dummy creation function which won't be used in // general anyway. if cfg!(test) { - return rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new + return rustc_codegen_utils::codegen_backend::MetadataOnlyCodegenBackend::new } let target = session::config::host_triple(); @@ -346,7 +348,7 @@ fn get_trans_sysroot(backend_name: &str) -> fn() -> Box { let mut file: Option = None; - let expected_name = format!("rustc_trans-{}", backend_name); + let expected_name = format!("rustc_codegen_llvm-{}", backend_name); for entry in d.filter_map(|e| e.ok()) { let path = entry.path(); let filename = match path.file_name().and_then(|s| s.to_str()) { @@ -520,20 +522,20 @@ fn run_compiler_with_pool<'a>( return (Err(CompileIncomplete::Stopped), Some(sess)); } - let trans = get_trans(&sess); + let codegen_backend = get_codegen_backend(&sess); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let mut cfg = config::build_configuration(&sess, cfg); - target_features::add_configuration(&mut cfg, &sess, &*trans); + target_features::add_configuration(&mut cfg, &sess, &*codegen_backend); sess.parse_sess.config = cfg; let result = { let plugins = sess.opts.debugging_opts.extra_plugins.clone(); - let cstore = CStore::new(trans.metadata_loader()); + let cstore = CStore::new(codegen_backend.metadata_loader()); - do_or_return!(callbacks.late_callback(&*trans, + do_or_return!(callbacks.late_callback(&*codegen_backend, &matches, &sess, &cstore, @@ -545,7 +547,7 @@ fn run_compiler_with_pool<'a>( let control = callbacks.build_controller(&sess, &matches); - driver::compile_input(trans, + driver::compile_input(codegen_backend, &sess, &cstore, &input_file_path, @@ -659,7 +661,7 @@ pub trait CompilerCalls<'a> { // be called just before actual compilation starts (and before build_controller // is called), after all arguments etc. have been completely handled. fn late_callback(&mut self, - _: &TransCrate, + _: &CodegenBackend, _: &getopts::Matches, _: &Session, _: &CrateStore, @@ -841,11 +843,11 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { } rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let mut cfg = config::build_configuration(&sess, cfg.clone()); - let trans = get_trans(&sess); - target_features::add_configuration(&mut cfg, &sess, &*trans); + let codegen_backend = get_codegen_backend(&sess); + target_features::add_configuration(&mut cfg, &sess, &*codegen_backend); sess.parse_sess.config = cfg; let should_stop = RustcDefaultCalls::print_crate_info( - &*trans, + &*codegen_backend, &sess, None, odir, @@ -863,7 +865,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { } fn late_callback(&mut self, - trans: &TransCrate, + codegen_backend: &CodegenBackend, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, @@ -871,7 +873,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { odir: &Option, ofile: &Option) -> Compilation { - RustcDefaultCalls::print_crate_info(trans, sess, Some(input), odir, ofile) + RustcDefaultCalls::print_crate_info(codegen_backend, sess, Some(input), odir, ofile) .and_then(|| RustcDefaultCalls::list_metadata(sess, cstore, matches, input)) } @@ -1000,7 +1002,7 @@ impl RustcDefaultCalls { } - fn print_crate_info(trans: &TransCrate, + fn print_crate_info(codegen_backend: &CodegenBackend, sess: &Session, input: Option<&Input>, odir: &Option, @@ -1042,14 +1044,14 @@ impl RustcDefaultCalls { }; let attrs = attrs.as_ref().unwrap(); let t_outputs = driver::build_output_filenames(input, odir, ofile, attrs, sess); - let id = rustc_trans_utils::link::find_crate_name(Some(sess), attrs, input); + let id = rustc_codegen_utils::link::find_crate_name(Some(sess), attrs, input); if *req == PrintRequest::CrateName { println!("{}", id); continue; } let crate_types = driver::collect_crate_types(sess, attrs); for &style in &crate_types { - let fname = rustc_trans_utils::link::filename_for_input( + let fname = rustc_codegen_utils::link::filename_for_input( sess, style, &id, @@ -1102,7 +1104,7 @@ impl RustcDefaultCalls { } } RelocationModels | CodeModels | TlsModels | TargetCPUs | TargetFeatures => { - trans.print(*req, sess); + codegen_backend.print(*req, sess); } // Any output here interferes with Cargo's parsing of other printed output PrintRequest::NativeStaticLibs => {} @@ -1143,7 +1145,7 @@ pub fn version(binary: &str, matches: &getopts::Matches) { println!("commit-date: {}", unw(commit_date_str())); println!("host: {}", config::host_triple()); println!("release: {}", unw(release_str())); - get_trans_sysroot("llvm")().print_version(); + get_codegen_sysroot("llvm")().print_version(); } } @@ -1451,7 +1453,7 @@ pub fn handle_options(args: &[String]) -> Option { } if cg_flags.contains(&"passes=list".to_string()) { - get_trans_sysroot("llvm")().print_passes(); + get_codegen_sysroot("llvm")().print_passes(); return None; } @@ -1663,8 +1665,8 @@ pub fn diagnostics_registry() -> errors::registry::Registry { all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS); // FIXME: need to figure out a way to get these back in here - // all_errors.extend_from_slice(get_trans(sess).diagnostics()); - all_errors.extend_from_slice(&rustc_trans_utils::DIAGNOSTICS); + // all_errors.extend_from_slice(get_codegen_backend(sess).diagnostics()); + all_errors.extend_from_slice(&rustc_codegen_utils::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS); diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 108b4762338..f1ad14237ee 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -228,8 +228,8 @@ impl PpSourceMode { } PpmTyped => { let control = &driver::CompileController::basic(); - let trans = ::get_trans(sess); - abort_on_err(driver::phase_3_run_analysis_passes(&*trans, + let codegen_backend = ::get_codegen_backend(sess); + abort_on_err(driver::phase_3_run_analysis_passes(&*codegen_backend, control, sess, cstore, @@ -1089,8 +1089,8 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, let mut out = Vec::new(); let control = &driver::CompileController::basic(); - let trans = ::get_trans(sess); - abort_on_err(driver::phase_3_run_analysis_passes(&*trans, + let codegen_backend = ::get_codegen_backend(sess); + abort_on_err(driver::phase_3_run_analysis_passes(&*codegen_backend, control, sess, cstore, diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 78c95a5ce05..46f552ed28d 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -122,7 +122,7 @@ fn test_env_with_pool( None, diagnostic_handler, Lrc::new(CodeMap::new(FilePathMapping::empty()))); - let cstore = CStore::new(::get_trans(&sess).metadata_loader()); + let cstore = CStore::new(::get_codegen_backend(&sess).metadata_loader()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let input = config::Input::Str { name: FileName::Anon, diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 38e891008f7..c317d31b95a 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -13,7 +13,7 @@ //! will dump graphs in graphviz form to disk, and it searches for //! `#[rustc_if_this_changed]` and `#[rustc_then_this_would_need]` //! annotations. These annotations can be used to test whether paths -//! exist in the graph. These checks run after trans, so they view the +//! exist in the graph. These checks run after codegen, so they view the //! the final state of the dependency graph. Note that there are //! similar assertions found in `persist::dirty_clean` which check the //! **initial** state of the dependency graph, just after it has been @@ -36,10 +36,10 @@ //! #[rustc_if_this_changed(Hir)] //! fn foo() { } //! -//! #[rustc_then_this_would_need(trans)] //~ ERROR no path from `foo` +//! #[rustc_then_this_would_need(codegen)] //~ ERROR no path from `foo` //! fn bar() { } //! -//! #[rustc_then_this_would_need(trans)] //~ ERROR OK +//! #[rustc_then_this_would_need(codegen)] //~ ERROR OK //! fn baz() { foo(); } //! ``` diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs index 6906dacfc5e..df8e0f056af 100644 --- a/src/librustc_incremental/assert_module_sources.rs +++ b/src/librustc_incremental/assert_module_sources.rs @@ -16,7 +16,7 @@ //! //! ``` //! #![rustc_partition_reused(module="spike", cfg="rpass2")] -//! #![rustc_partition_translated(module="spike-x", cfg="rpass2")] +//! #![rustc_partition_codegened(module="spike-x", cfg="rpass2")] //! ``` //! //! The first indicates (in the cfg `rpass2`) that `spike.o` will be @@ -32,13 +32,13 @@ use rustc::mir::mono::CodegenUnit; use rustc::ty::TyCtxt; use syntax::ast; use syntax_pos::symbol::Symbol; -use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_TRANSLATED}; +use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_CODEGENED}; const MODULE: &'static str = "module"; const CFG: &'static str = "cfg"; #[derive(Debug, PartialEq, Clone, Copy)] -enum Disposition { Reused, Translated } +enum Disposition { Reused, Codegened } pub fn assert_module_sources<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { tcx.dep_graph.with_ignore(|| { @@ -61,8 +61,8 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { fn check_attr(&self, attr: &ast::Attribute) { let disposition = if attr.check_name(ATTR_PARTITION_REUSED) { Disposition::Reused - } else if attr.check_name(ATTR_PARTITION_TRANSLATED) { - Disposition::Translated + } else if attr.check_name(ATTR_PARTITION_CODEGENED) { + Disposition::Codegened } else { return; }; @@ -84,17 +84,17 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { (Disposition::Reused, false) => { self.tcx.sess.span_err( attr.span, - &format!("expected module named `{}` to be Reused but is Translated", + &format!("expected module named `{}` to be Reused but is Codegened", mname)); } - (Disposition::Translated, true) => { + (Disposition::Codegened, true) => { self.tcx.sess.span_err( attr.span, - &format!("expected module named `{}` to be Translated but is Reused", + &format!("expected module named `{}` to be Codegened but is Reused", mname)); } (Disposition::Reused, true) | - (Disposition::Translated, false) => { + (Disposition::Codegened, false) => { // These are what we would expect. } } diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index e114606a631..8f406161831 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -239,8 +239,8 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { intravisit::walk_crate(&mut all_attrs, krate); // Note that we cannot use the existing "unused attribute"-infrastructure - // here, since that is running before trans. This is also the reason why - // all trans-specific attributes are `Whitelisted` in syntax::feature_gate. + // here, since that is running before codegen. This is also the reason why + // all codegen-specific attributes are `Whitelisted` in syntax::feature_gate. all_attrs.report_unchecked_attrs(&dirty_clean_visitor.checked_attrs); }) } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 32963146893..2abe361233f 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -432,7 +432,7 @@ enum FfiResult<'tcx> { /// "nullable pointer optimization". Currently restricted /// to function pointers and references, but could be /// expanded to cover NonZero raw pointers and newtypes. -/// FIXME: This duplicates code in trans. +/// FIXME: This duplicates code in codegen. fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def: &'tcx ty::AdtDef, substs: &Substs<'tcx>) diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index c1e32c7c022..0497de940ca 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -515,7 +515,7 @@ pub enum ModuleBuffer {} // dllimport/dllexport are applied and need to be correct for everything to // link successfully. The #[link] annotation here says "these symbols are // included statically" which means that they're all exported with dllexport -// and from the rustc_llvm dynamic library. Otherwise the rustc_trans dynamic +// and from the rustc_llvm dynamic library. Otherwise the rustc_codegen_llvm dynamic // library would not be able to access these symbols. #[link(name = "rustllvm", kind = "static")] extern "C" { diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index bf8a087ab55..07830d54d0c 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -138,7 +138,7 @@ pub fn SetFunctionCallConv(fn_: ValueRef, cc: CallConv) { } } -// Externally visible symbols that might appear in multiple translation units need to appear in +// Externally visible symbols that might appear in multiple codegen units need to appear in // their own comdat section so that the duplicates can be discarded at link time. This can for // example happen for generics when using multiple codegen units. This function simply uses the // value's name as the comdat value to make sure that it is in a 1-to-1 relationship to the diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index 0a1662dd42d..b38c1235573 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -14,7 +14,7 @@ register_long_diagnostics! { E0454: r##" A link name was given with an empty name. Erroneous code example: -```ignore (cannot-test-this-because-rustdoc-stops-compile-fail-before-trans) +```ignore (cannot-test-this-because-rustdoc-stops-compile-fail-before-codegen) #[link(name = "")] extern {} // error: #[link(name = "")] given with empty name ``` @@ -51,7 +51,7 @@ https://doc.rust-lang.org/book/first-edition/conditional-compilation.html E0458: r##" An unknown "kind" was specified for a link attribute. Erroneous code example: -```ignore (cannot-test-this-because-rustdoc-stops-compile-fail-before-trans) +```ignore (cannot-test-this-because-rustdoc-stops-compile-fail-before-codegen) #[link(kind = "wonderful_unicorn")] extern {} // error: unknown kind: `wonderful_unicorn` ``` @@ -67,7 +67,7 @@ Please specify a valid "kind" value, from one of the following: E0459: r##" A link was used without a name parameter. Erroneous code example: -```ignore (cannot-test-this-because-rustdoc-stops-compile-fail-before-trans) +```ignore (cannot-test-this-because-rustdoc-stops-compile-fail-before-codegen) #[link(kind = "dylib")] extern {} // error: #[link(...)] specified without `name = "foo"` ``` diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 3de90abd966..bbc4120f060 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -868,7 +868,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { fn metadata_output_only(&self) -> bool { // MIR optimisation can be skipped when we're just interested in the metadata. - !self.tcx.sess.opts.output_types.should_trans() + !self.tcx.sess.opts.output_types.should_codegen() } fn const_qualif(&self, mir: u8, body_id: hir::BodyId) -> ConstQualif { @@ -930,7 +930,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { hir::ImplItemKind::Method(ref sig, _) => { let generics = self.tcx.generics_of(def_id); let needs_inline = (generics.requires_monomorphization(self.tcx) || - tcx.trans_fn_attrs(def_id).requests_inline()) && + tcx.codegen_fn_attrs(def_id).requests_inline()) && !self.metadata_output_only(); let is_const_fn = sig.constness == hir::Constness::Const; let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; @@ -1224,8 +1224,9 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { hir::ItemConst(..) => self.encode_optimized_mir(def_id), hir::ItemFn(_, _, constness, _, ref generics, _) => { let has_tps = generics.ty_params().next().is_some(); - let needs_inline = (has_tps || tcx.trans_fn_attrs(def_id).requests_inline()) && - !self.metadata_output_only(); + let needs_inline = + (has_tps || tcx.codegen_fn_attrs(def_id).requests_inline()) && + !self.metadata_output_only(); let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; if needs_inline || constness == hir::Constness::Const || always_encode_mir { self.encode_optimized_mir(def_id) diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 20e11abca9f..4115dbe6274 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -140,7 +140,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block.and(Rvalue::Cast(CastKind::Unsize, source, expr.ty)) } ExprKind::Array { fields } => { - // (*) We would (maybe) be closer to trans if we + // (*) We would (maybe) be closer to codegen if we // handled this and other aggregate cases via // `into()`, not `as_rvalue` -- in that case, instead // of generating diff --git a/src/librustc_mir/build/expr/mod.rs b/src/librustc_mir/build/expr/mod.rs index 025e77343e7..0fd4b8e7e23 100644 --- a/src/librustc_mir/build/expr/mod.rs +++ b/src/librustc_mir/build/expr/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Translates expressions into MIR. As a caller into this module, you +//! Builds MIR from expressions. As a caller into this module, you //! have many options, but the first thing you have to decide is //! whether you are evaluating this expression for its *value*, its //! *location*, or as a *constant*. @@ -41,7 +41,7 @@ //! ### Implementation notes //! //! For any given kind of expression, there is generally one way that -//! can be translated most naturally. This is specified by the +//! can be lowered most naturally. This is specified by the //! `Category::of` function in the `category` module. For example, a //! struct expression (or other expression that creates a new value) //! is typically easiest to write in terms of `as_rvalue` or `into`, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 6946ac4c7b2..f3953d0877c 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -896,7 +896,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode)) .collect(), }; - debug!("Entering guard translation context: {:?}", guard_frame); + debug!("Entering guard building context: {:?}", guard_frame); self.guard_context.push(guard_frame); } else { self.bind_matched_candidate_for_arm_body(block, &candidate.bindings, false); @@ -909,7 +909,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let cond = unpack!(block = self.as_local_operand(block, guard)); if autoref { let guard_frame = self.guard_context.pop().unwrap(); - debug!("Exiting guard translation context with locals: {:?}", guard_frame); + debug!("Exiting guard building context with locals: {:?}", guard_frame); } let false_edge_block = self.cfg.start_new_block(); diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index afbcf100b05..3bbf73ec8b5 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -775,7 +775,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /////////////////////////////////////////////////////////////////////////// // Builder methods are broken up into modules, depending on what kind -// of thing is being translated. Note that they use the `unpack` macro +// of thing is being lowered. Note that they use the `unpack` macro // above extensively. mod block; diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index a631ab27d1c..5dc59ac9f41 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -10,7 +10,7 @@ /*! Managing the scope stack. The scopes are tied to lexical scopes, so as -we descend the HAIR, we push a scope on the stack, translate ite +we descend the HAIR, we push a scope on the stack, build its contents, and then pop it off. Every scope is named by a `region::Scope`. @@ -30,7 +30,7 @@ them. Eventually, when we shift to non-lexical lifetimes, there should be no need to remember this mapping. There is one additional wrinkle, actually, that I wanted to hide from -you but duty compels me to mention. In the course of translating +you but duty compels me to mention. In the course of building matches, it sometimes happen that certain code (namely guards) gets executed multiple times. This means that the scope lexical scope may in fact correspond to multiple, disjoint SEME regions. So in fact our @@ -38,7 +38,7 @@ mapping is from one scope to a vector of SEME regions. ### Drops -The primary purpose for scopes is to insert drops: while translating +The primary purpose for scopes is to insert drops: while building the contents, we also accumulate places that need to be dropped upon exit from each scope. This is done by calling `schedule_drop`. Once a drop is scheduled, whenever we branch out we will insert drops of all diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index 14aa307f0ae..5ef1eef133d 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -20,7 +20,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block { type Output = Block<'tcx>; fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Block<'tcx> { - // We have to eagerly translate the "spine" of the statements + // We have to eagerly lower the "spine" of the statements // in order to get the lexical scoping correctly. let stmts = mirror_stmts(cx, self.hir_id.local_id, &*self.stmts); let opt_destruction_scope = diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 4765a82d85b..b01b3542136 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -77,7 +77,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { // Some functions always have overflow checks enabled, // however, they may not get codegen'd, depending on - // the settings for the crate they are translated in. + // the settings for the crate they are codegened in. let mut check_overflow = attr::contains_name(attrs, "rustc_inherit_overflow_checks"); // Respect -C overflow-checks. diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index c27250267bb..ab9acdc4950 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The MIR is translated from some high-level abstract IR +//! The MIR is built from some high-level abstract IR //! (HAIR). This section defines the HAIR along with a trait for //! accessing it. The intention is to allow MIR construction to be //! unit-tested and separated from the Rust source and compiler data @@ -107,12 +107,12 @@ pub enum StmtKind<'tcx> { }, } -/// The Hair trait implementor translates their expressions (`&'tcx H::Expr`) -/// into instances of this `Expr` enum. This translation can be done +/// The Hair trait implementor lowers their expressions (`&'tcx H::Expr`) +/// into instances of this `Expr` enum. This lowering can be done /// basically as lazily or as eagerly as desired: every recursive /// reference to an expression in this enum is an `ExprRef<'tcx>`, which /// may in turn be another instance of this enum (boxed), or else an -/// untranslated `&'tcx H::Expr`. Note that instances of `Expr` are very +/// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very /// shortlived. They are created by `Hair::to_expr`, analyzed and /// converted into MIR, and then discarded. /// diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index dc2009a0260..c62eb1cf185 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -188,7 +188,7 @@ //! this is not implemented however: a mono item will be produced //! regardless of whether it is actually needed or not. -use rustc::hir::{self, TransFnAttrFlags}; +use rustc::hir::{self, CodegenFnAttrFlags}; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::map as hir_map; @@ -343,9 +343,9 @@ fn collect_roots<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, visitor.push_extra_entry_roots(); } - // We can only translate items that are instantiable - items all of + // We can only codegen items that are instantiable - items all of // whose predicates hold. Luckily, items that aren't instantiable - // can't actually be used, so we can just skip translating them. + // can't actually be used, so we can just skip codegenning them. roots.retain(|root| root.is_instantiable(tcx)); roots @@ -717,7 +717,7 @@ fn visit_instance_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -// Returns true if we should translate an instance in the local crate. +// Returns true if we should codegen an instance in the local crate. // Returns false if we can just link to the upstream crate and therefore don't // need a mono item. fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instance<'tcx>) @@ -734,7 +734,7 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: return match tcx.hir.get_if_local(def_id) { Some(hir_map::NodeForeignItem(..)) => { - false // foreign items are linked against, not translated. + false // foreign items are linked against, not codegened. } Some(_) => true, None => { @@ -1015,8 +1015,8 @@ impl<'b, 'a, 'v> RootCollector<'b, 'a, 'v> { MonoItemCollectionMode::Lazy => { self.entry_fn == Some(def_id) || self.tcx.is_reachable_non_generic(def_id) || - self.tcx.trans_fn_attrs(def_id).flags.contains( - TransFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) + self.tcx.codegen_fn_attrs(def_id).flags.contains( + CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) } } } diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index a569ad00d0c..27f8254bf8a 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -29,7 +29,7 @@ use syntax_pos::symbol::Symbol; use syntax::codemap::Span; pub use rustc::mir::mono::MonoItem; -/// Describes how a translation item will be instantiated in object files. +/// Describes how a monomorphization will be instantiated in object files. #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] pub enum InstantiationMode { /// There will be exactly one instance of the given MonoItem. It will have @@ -37,7 +37,7 @@ pub enum InstantiationMode { GloballyShared { /// In some compilation scenarios we may decide to take functions that /// are typically `LocalCopy` and instead move them to `GloballyShared` - /// to avoid translating them a bunch of times. In this situation, + /// to avoid codegenning them a bunch of times. In this situation, /// however, our local copy may conflict with other crates also /// inlining the same function. /// @@ -114,7 +114,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { // creating one copy of this `#[inline]` function which may // conflict with upstream crates as it could be an exported // symbol. - match tcx.trans_fn_attrs(instance.def_id()).inline { + match tcx.codegen_fn_attrs(instance.def_id()).inline { InlineAttr::Always => InstantiationMode::LocalCopy, _ => { InstantiationMode::GloballyShared { may_conflict: true } @@ -137,19 +137,19 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { MonoItem::GlobalAsm(..) => return None, }; - let trans_fn_attrs = tcx.trans_fn_attrs(def_id); - trans_fn_attrs.linkage + let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); + codegen_fn_attrs.linkage } /// Returns whether this instance is instantiable - whether it has no unsatisfied /// predicates. /// - /// In order to translate an item, all of its predicates must hold, because + /// In order to codegen an item, all of its predicates must hold, because /// otherwise the item does not make sense. Type-checking ensures that /// the predicates of every item that is *used by* a valid item *do* /// hold, so we can rely on that. /// - /// However, we translate collector roots (reachable items) and functions + /// However, we codegen collector roots (reachable items) and functions /// in vtables when they are seen, even if they are not used, and so they /// might not be instantiable. For example, a programmer can define this /// public function: @@ -158,7 +158,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { /// <&mut () as Clone>::clone(&s); /// } /// - /// That function can't be translated, because the method `<&mut () as Clone>::clone` + /// That function can't be codegened, because the method `<&mut () as Clone>::clone` /// does not exist. Luckily for us, that function can't ever be used, /// because that would require for `&'a mut (): Clone` to hold, so we /// can just not emit any code, or even a linker reference for it. @@ -229,7 +229,7 @@ impl<'a, 'tcx> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { // MonoItem String Keys //=----------------------------------------------------------------------------- -// The code below allows for producing a unique string key for a trans item. +// The code below allows for producing a unique string key for a mono item. // These keys are used by the handwritten auto-tests, so they need to be // predictable and human-readable. // diff --git a/src/librustc_mir/monomorphize/mod.rs b/src/librustc_mir/monomorphize/mod.rs index 04d4f7a3968..51793305513 100644 --- a/src/librustc_mir/monomorphize/mod.rs +++ b/src/librustc_mir/monomorphize/mod.rs @@ -23,11 +23,11 @@ pub mod item; pub mod partitioning; #[inline(never)] // give this a place in the profiler -pub fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_items: I) +pub fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mono_items: I) where I: Iterator> { - let mut symbols: Vec<_> = trans_items.map(|trans_item| { - (trans_item, trans_item.symbol_name(tcx)) + let mut symbols: Vec<_> = mono_items.map(|mono_item| { + (mono_item, mono_item.symbol_name(tcx)) }).collect(); (&mut symbols[..]).sort_by(|&(_, ref sym1), &(_, ref sym2)|{ @@ -39,11 +39,11 @@ pub fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tra let sym2 = &pair[1].1; if *sym1 == *sym2 { - let trans_item1 = pair[0].0; - let trans_item2 = pair[1].0; + let mono_item1 = pair[0].0; + let mono_item2 = pair[1].0; - let span1 = trans_item1.local_span(tcx); - let span2 = trans_item2.local_span(tcx); + let span1 = mono_item1.local_span(tcx); + let span2 = mono_item2.local_span(tcx); // Deterministically select one of the spans for error reporting let span = match (span1, span2) { @@ -111,7 +111,7 @@ fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind, } (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { // The closure fn `llfn` is a `fn(&self, ...)`. We want a - // `fn(&mut self, ...)`. In fact, at trans time, these are + // `fn(&mut self, ...)`. In fact, at codegen time, these are // basically the same thing, so we can just return llfn. Ok(false) } @@ -124,7 +124,7 @@ fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind, // fn call_once(self, ...) { call_mut(&self, ...) } // fn call_once(mut self, ...) { call_mut(&mut self, ...) } // - // These are both the same at trans time. + // These are both the same at codegen time. Ok(true) } _ => Err(()), @@ -167,7 +167,7 @@ pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, substs: tcx.mk_substs_trait(source_ty, &[target_ty]) }); - match tcx.trans_fulfill_obligation( (ty::ParamEnv::reveal_all(), trait_ref)) { + match tcx.codegen_fulfill_obligation( (ty::ParamEnv::reveal_all(), trait_ref)) { traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap() } diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index 3a65cd4ea77..9607a84124a 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -11,16 +11,16 @@ //! Partitioning Codegen Units for Incremental Compilation //! ====================================================== //! -//! The task of this module is to take the complete set of translation items of +//! The task of this module is to take the complete set of monomorphizations of //! a crate and produce a set of codegen units from it, where a codegen unit -//! is a named set of (translation-item, linkage) pairs. That is, this module -//! decides which translation item appears in which codegen units with which +//! is a named set of (mono-item, linkage) pairs. That is, this module +//! decides which monomorphization appears in which codegen units with which //! linkage. The following paragraphs describe some of the background on the //! partitioning scheme. //! //! The most important opportunity for saving on compilation time with -//! incremental compilation is to avoid re-translating and re-optimizing code. -//! Since the unit of translation and optimization for LLVM is "modules" or, how +//! incremental compilation is to avoid re-codegenning and re-optimizing code. +//! Since the unit of codegen and optimization for LLVM is "modules" or, how //! we call them "codegen units", the particulars of how much time can be saved //! by incremental compilation are tightly linked to how the output program is //! partitioned into these codegen units prior to passing it to LLVM -- @@ -214,17 +214,17 @@ fn fallback_cgu_name(tcx: TyCtxt) -> InternedString { pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - trans_items: I, + mono_items: I, strategy: PartitioningStrategy, inlining_map: &InliningMap<'tcx>) -> Vec> where I: Iterator> { - // In the first step, we place all regular translation items into their - // respective 'home' codegen unit. Regular translation items are all + // In the first step, we place all regular monomorphizations into their + // respective 'home' codegen unit. Regular monomorphizations are all // functions and statics defined in the local crate. - let mut initial_partitioning = place_root_translation_items(tcx, - trans_items); + let mut initial_partitioning = place_root_mono_items(tcx, + mono_items); initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(&tcx)); @@ -239,10 +239,10 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // In the next step, we use the inlining map to determine which additional - // translation items have to go into each codegen unit. These additional - // translation items can be drop-glue, functions from external crates, and + // monomorphizations have to go into each codegen unit. These additional + // monomorphizations can be drop-glue, functions from external crates, and // local functions the definition of which is marked with #[inline]. - let mut post_inlining = place_inlined_translation_items(initial_partitioning, + let mut post_inlining = place_inlined_mono_items(initial_partitioning, inlining_map); post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(&tcx)); @@ -258,7 +258,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Finally, sort by codegen unit name, so that we get deterministic results let PostInliningPartitioning { codegen_units: mut result, - trans_item_placements: _, + mono_item_placements: _, internalization_candidates: _, } = post_inlining; @@ -275,23 +275,23 @@ struct PreInliningPartitioning<'tcx> { internalization_candidates: FxHashSet>, } -/// For symbol internalization, we need to know whether a symbol/trans-item is +/// For symbol internalization, we need to know whether a symbol/mono-item is /// accessed from outside the codegen unit it is defined in. This type is used /// to keep track of that. #[derive(Clone, PartialEq, Eq, Debug)] -enum TransItemPlacement { +enum MonoItemPlacement { SingleCgu { cgu_name: InternedString }, MultipleCgus, } struct PostInliningPartitioning<'tcx> { codegen_units: Vec>, - trans_item_placements: FxHashMap, TransItemPlacement>, + mono_item_placements: FxHashMap, MonoItemPlacement>, internalization_candidates: FxHashSet>, } -fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - trans_items: I) +fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + mono_items: I) -> PreInliningPartitioning<'tcx> where I: Iterator> { @@ -307,15 +307,15 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let export_generics = tcx.share_generics() && tcx.local_crate_exports_generics(); - for trans_item in trans_items { - match trans_item.instantiation_mode(tcx) { + for mono_item in mono_items { + match mono_item.instantiation_mode(tcx) { InstantiationMode::GloballyShared { .. } => {} InstantiationMode::LocalCopy => continue, } - let characteristic_def_id = characteristic_def_id_of_trans_item(tcx, trans_item); + let characteristic_def_id = characteristic_def_id_of_mono_item(tcx, mono_item); let is_volatile = is_incremental_build && - trans_item.is_generic_fn(); + mono_item.is_generic_fn(); let codegen_unit_name = match characteristic_def_id { Some(def_id) => compute_codegen_unit_name(tcx, def_id, is_volatile), @@ -353,10 +353,10 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Visibility::Hidden } }; - let (linkage, mut visibility) = match trans_item.explicit_linkage(tcx) { + let (linkage, mut visibility) = match mono_item.explicit_linkage(tcx) { Some(explicit_linkage) => (explicit_linkage, Visibility::Default), None => { - match trans_item { + match mono_item { MonoItem::Fn(ref instance) => { let visibility = match instance.def { InstanceDef::Item(def_id) => { @@ -463,11 +463,11 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } }; if visibility == Visibility::Hidden && can_be_internalized { - internalization_candidates.insert(trans_item); + internalization_candidates.insert(mono_item); } - codegen_unit.items_mut().insert(trans_item, (linkage, visibility)); - roots.insert(trans_item); + codegen_unit.items_mut().insert(mono_item, (linkage, visibility)); + roots.insert(mono_item); } // always ensure we have at least one CGU; otherwise, if we have a @@ -522,11 +522,11 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning< } } -fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartitioning<'tcx>, +fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<'tcx>, inlining_map: &InliningMap<'tcx>) -> PostInliningPartitioning<'tcx> { let mut new_partitioning = Vec::new(); - let mut trans_item_placements = FxHashMap(); + let mut mono_item_placements = FxHashMap(); let PreInliningPartitioning { codegen_units: initial_cgus, @@ -545,40 +545,40 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name().clone()); - // Add all translation items that are not already there - for trans_item in reachable { - if let Some(linkage) = old_codegen_unit.items().get(&trans_item) { + // Add all monomorphizations that are not already there + for mono_item in reachable { + if let Some(linkage) = old_codegen_unit.items().get(&mono_item) { // This is a root, just copy it over - new_codegen_unit.items_mut().insert(trans_item, *linkage); + new_codegen_unit.items_mut().insert(mono_item, *linkage); } else { - if roots.contains(&trans_item) { - bug!("GloballyShared trans-item inlined into other CGU: \ - {:?}", trans_item); + if roots.contains(&mono_item) { + bug!("GloballyShared mono-item inlined into other CGU: \ + {:?}", mono_item); } // This is a cgu-private copy new_codegen_unit.items_mut().insert( - trans_item, + mono_item, (Linkage::Internal, Visibility::Default), ); } if !single_codegen_unit { // If there is more than one codegen unit, we need to keep track - // in which codegen units each translation item is placed: - match trans_item_placements.entry(trans_item) { + // in which codegen units each monomorphization is placed: + match mono_item_placements.entry(mono_item) { Entry::Occupied(e) => { let placement = e.into_mut(); debug_assert!(match *placement { - TransItemPlacement::SingleCgu { ref cgu_name } => { + MonoItemPlacement::SingleCgu { ref cgu_name } => { *cgu_name != *new_codegen_unit.name() } - TransItemPlacement::MultipleCgus => true, + MonoItemPlacement::MultipleCgus => true, }); - *placement = TransItemPlacement::MultipleCgus; + *placement = MonoItemPlacement::MultipleCgus; } Entry::Vacant(e) => { - e.insert(TransItemPlacement::SingleCgu { + e.insert(MonoItemPlacement::SingleCgu { cgu_name: new_codegen_unit.name().clone() }); } @@ -591,18 +591,18 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit return PostInliningPartitioning { codegen_units: new_partitioning, - trans_item_placements, + mono_item_placements, internalization_candidates, }; - fn follow_inlining<'tcx>(trans_item: MonoItem<'tcx>, + fn follow_inlining<'tcx>(mono_item: MonoItem<'tcx>, inlining_map: &InliningMap<'tcx>, visited: &mut FxHashSet>) { - if !visited.insert(trans_item) { + if !visited.insert(mono_item) { return; } - inlining_map.with_inlining_candidates(trans_item, |target| { + inlining_map.with_inlining_candidates(mono_item, |target| { follow_inlining(target, inlining_map, visited); }); } @@ -625,7 +625,7 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, return; } - // Build a map from every translation item to all the translation items that + // Build a map from every monomorphization to all the monomorphizations that // reference it. let mut accessor_map: FxHashMap, Vec>> = FxHashMap(); inlining_map.iter_accesses(|accessor, accessees| { @@ -636,12 +636,12 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, } }); - let trans_item_placements = &partitioning.trans_item_placements; + let mono_item_placements = &partitioning.mono_item_placements; // For each internalization candidates in each codegen unit, check if it is // accessed from outside its defining codegen unit. for cgu in &mut partitioning.codegen_units { - let home_cgu = TransItemPlacement::SingleCgu { + let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name().clone() }; @@ -650,14 +650,14 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, // This item is no candidate for internalizing, so skip it. continue } - debug_assert_eq!(trans_item_placements[accessee], home_cgu); + debug_assert_eq!(mono_item_placements[accessee], home_cgu); if let Some(accessors) = accessor_map.get(accessee) { if accessors.iter() .filter_map(|accessor| { // Some accessors might not have been // instantiated. We can safely ignore those. - trans_item_placements.get(accessor) + mono_item_placements.get(accessor) }) .any(|placement| *placement != home_cgu) { // Found an accessor from another CGU, so skip to the next @@ -667,16 +667,16 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, } // If we got here, we did not find any accesses from other CGUs, - // so it's fine to make this translation item internal. + // so it's fine to make this monomorphization internal. *linkage_and_visibility = (Linkage::Internal, Visibility::Default); } } } -fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - trans_item: MonoItem<'tcx>) +fn characteristic_def_id_of_mono_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + mono_item: MonoItem<'tcx>) -> Option { - match trans_item { + match mono_item { MonoItem::Fn(instance) => { let def_id = match instance.def { ty::InstanceDef::Item(def_id) => def_id, @@ -771,14 +771,14 @@ fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, for cgu in cgus { debug!("CodegenUnit {}:", cgu.name()); - for (trans_item, linkage) in cgu.items() { - let symbol_name = trans_item.symbol_name(tcx).name.as_str(); + for (mono_item, linkage) in cgu.items() { + let symbol_name = mono_item.symbol_name(tcx).name.as_str(); let symbol_hash_start = symbol_name.rfind('h'); let symbol_hash = symbol_hash_start.map(|i| &symbol_name[i ..]) .unwrap_or(""); debug!(" - {} [{:?}] [{}]", - trans_item.to_string(tcx), + mono_item.to_string(tcx), linkage, symbol_hash); } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index c79298d8dd2..2d2663bc7c3 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -69,8 +69,8 @@ fn make_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ) } ty::InstanceDef::Virtual(def_id, _) => { - // We are translating a call back to our def-id, which - // trans::mir knows to turn to an actual virtual call. + // We are generating a call back to our def-id, which the + // codegen backend knows to turn to an actual virtual call. build_call_shim( tcx, def_id, diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs index 5be369f85bc..26927904440 100644 --- a/src/librustc_mir/transform/add_call_guards.rs +++ b/src/librustc_mir/transform/add_call_guards.rs @@ -30,7 +30,7 @@ pub use self::AddCallGuards::*; * do at the end of the predecessor block, or at the start of the * successor block. Critical edges have to be broken in order to prevent * "edge actions" from affecting other edges. We need this for calls that are - * translated to LLVM invoke instructions, because invoke is a block terminator + * codegened to LLVM invoke instructions, because invoke is a block terminator * in LLVM so we can't insert any code to handle the call's result into the * block that performs the call. * diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 56050318ca7..15b0c4a8bf7 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -442,7 +442,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } /// Elaborate a MIR `replace` terminator. This instruction - /// is not directly handled by translation, and therefore + /// is not directly handled by codegen, and therefore /// must be desugared. /// /// The desugaring drops the location if needed, and then writes diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index cd5ebae2d9d..c697391d867 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -9,7 +9,7 @@ // except according to those terms. //! This pass erases all early-bound regions from the types occurring in the MIR. -//! We want to do this once just before trans, so trans does not have to take +//! We want to do this once just before codegen, so codegen does not have to take //! care erasing regions all over the place. //! NOTE: We do NOT erase regions of statements that are relevant for //! "types-as-contracts"-validation, namely, AcquireValid, ReleaseValid, and EndRegion. diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index ee6d42b1fe5..5fb9148d49a 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -11,7 +11,7 @@ //! Inlining pass for MIR functions use rustc::hir; -use rustc::hir::TransFnAttrFlags; +use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def_id::DefId; use rustc_data_structures::bitvec::BitVector; @@ -211,16 +211,16 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { return false; } - // Do not inline {u,i}128 lang items, trans const eval depends + // Do not inline {u,i}128 lang items, codegen const eval depends // on detecting calls to these lang items and intercepting them if tcx.is_binop_lang_item(callsite.callee).is_some() { debug!(" not inlining 128bit integer lang item"); return false; } - let trans_fn_attrs = tcx.trans_fn_attrs(callsite.callee); + let codegen_fn_attrs = tcx.codegen_fn_attrs(callsite.callee); - let hinted = match trans_fn_attrs.inline { + let hinted = match codegen_fn_attrs.inline { // Just treat inline(always) as a hint for now, // there are cases that prevent inlining that we // need to check for first. @@ -250,7 +250,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { }; // Significantly lower the threshold for inlining cold functions - if trans_fn_attrs.flags.contains(TransFnAttrFlags::COLD) { + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) { threshold /= 5; } @@ -355,7 +355,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } } - if let attr::InlineAttr::Always = trans_fn_attrs.inline { + if let attr::InlineAttr::Always = codegen_fn_attrs.inline { debug!("INLINING {:?} because inline(always) [cost={}]", callsite, cost); true } else { @@ -515,8 +515,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // Fn::call(closure_ref, tuple_tmp) // // meanwhile the closure body expects the arguments (here, `a`, `b`, and `c`) - // as distinct arguments. (This is the "rust-call" ABI hack.) Normally, trans has - // the job of unpacking this tuple. But here, we are trans. =) So we want to create + // as distinct arguments. (This is the "rust-call" ABI hack.) Normally, codegen has + // the job of unpacking this tuple. But here, we are codegen. =) So we want to create // a vector like // // [closure_ref, tuple_tmp.0, tuple_tmp.1, tuple_tmp.2] diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 63ca35aa0e7..e2f2312dbd2 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -277,7 +277,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx simplify::SimplifyLocals, add_call_guards::CriticalCallEdges, - dump_mir::Marker("PreTrans"), + dump_mir::Marker("PreCodegen"), ]; tcx.alloc_mir(mir) } diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 691fdd130e5..7e23a5cb1a8 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -15,7 +15,7 @@ //! //! The `SimplifyLocals` pass is kinda expensive and therefore not very suitable to be run often. //! Most of the passes should not care or be impacted in meaningful ways due to extra locals -//! either, so running the pass once, right before translation, should suffice. +//! either, so running the pass once, right before codegen, should suffice. //! //! On the other side of the spectrum, the `SimplifyCfg` pass is considerably cheap to run, thus //! one should run it after every pass which may modify CFG in significant ways. This pass must diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml deleted file mode 100644 index 64d3a4f4d53..00000000000 --- a/src/librustc_trans/Cargo.toml +++ /dev/null @@ -1,49 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_trans" -version = "0.0.0" - -[lib] -name = "rustc_trans" -path = "lib.rs" -crate-type = ["dylib"] -test = false - -[dependencies] -bitflags = "1.0.1" -cc = "1.0.1" -flate2 = "1.0" -jobserver = "0.1.5" -libc = "0.2" -log = "0.4" -num_cpus = "1.0" -rustc = { path = "../librustc" } -rustc-demangle = "0.1.4" -rustc_allocator = { path = "../librustc_allocator" } -rustc_apfloat = { path = "../librustc_apfloat" } -rustc_target = { path = "../librustc_target" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_incremental = { path = "../librustc_incremental" } -rustc_llvm = { path = "../librustc_llvm" } -rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } -rustc_trans_utils = { path = "../librustc_trans_utils" } -rustc_mir = { path = "../librustc_mir" } -serialize = { path = "../libserialize" } -syntax = { path = "../libsyntax" } -syntax_pos = { path = "../libsyntax_pos" } -tempdir = "0.3" - -# not actually used but needed to make sure we enable the same feature set as -# winapi used in librustc -env_logger = { version = "0.5", default-features = false } - -[features] -# Used to communicate the feature to `rustc_target` in the same manner that the -# `rustc` driver script communicate this. -jemalloc = ["rustc_target/jemalloc"] - -# This is used to convince Cargo to separately cache builds of `rustc_trans` -# when this option is enabled or not. That way we can build two, cache two -# artifacts, and have nice speedy rebuilds. -emscripten = ["rustc_llvm/emscripten"] diff --git a/src/librustc_trans/README.md b/src/librustc_trans/README.md deleted file mode 100644 index d1868ba2abb..00000000000 --- a/src/librustc_trans/README.md +++ /dev/null @@ -1,7 +0,0 @@ -The `trans` crate contains the code to convert from MIR into LLVM IR, -and then from LLVM IR into machine code. In general it contains code -that runs towards the end of the compilation process. - -For more information about how trans works, see the [rustc guide]. - -[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/trans.html diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs deleted file mode 100644 index 25c598c532c..00000000000 --- a/src/librustc_trans/abi.rs +++ /dev/null @@ -1,696 +0,0 @@ -// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use llvm::{self, ValueRef, AttributePlace}; -use base; -use builder::{Builder, MemFlags}; -use common::{ty_fn_sig, C_usize}; -use context::CodegenCx; -use mir::place::PlaceRef; -use mir::operand::OperandValue; -use type_::Type; -use type_of::{LayoutLlvmExt, PointerKind}; - -use rustc_target::abi::{LayoutOf, Size, TyLayout}; -use rustc::ty::{self, Ty}; -use rustc::ty::layout; - -use libc::c_uint; - -pub use rustc_target::spec::abi::Abi; -pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; -pub use rustc_target::abi::call::*; - -macro_rules! for_each_kind { - ($flags: ident, $f: ident, $($kind: ident),+) => ({ - $(if $flags.contains(ArgAttribute::$kind) { $f(llvm::Attribute::$kind) })+ - }) -} - -trait ArgAttributeExt { - fn for_each_kind(&self, f: F) where F: FnMut(llvm::Attribute); -} - -impl ArgAttributeExt for ArgAttribute { - fn for_each_kind(&self, mut f: F) where F: FnMut(llvm::Attribute) { - for_each_kind!(self, f, - ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg) - } -} - -pub trait ArgAttributesExt { - fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef); - fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef); -} - -impl ArgAttributesExt for ArgAttributes { - fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { - let mut regular = self.regular; - unsafe { - let deref = self.pointee_size.bytes(); - if deref != 0 { - if regular.contains(ArgAttribute::NonNull) { - llvm::LLVMRustAddDereferenceableAttr(llfn, - idx.as_uint(), - deref); - } else { - llvm::LLVMRustAddDereferenceableOrNullAttr(llfn, - idx.as_uint(), - deref); - } - regular -= ArgAttribute::NonNull; - } - if let Some(align) = self.pointee_align { - llvm::LLVMRustAddAlignmentAttr(llfn, - idx.as_uint(), - align.abi() as u32); - } - regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn)); - } - } - - fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) { - let mut regular = self.regular; - unsafe { - let deref = self.pointee_size.bytes(); - if deref != 0 { - if regular.contains(ArgAttribute::NonNull) { - llvm::LLVMRustAddDereferenceableCallSiteAttr(callsite, - idx.as_uint(), - deref); - } else { - llvm::LLVMRustAddDereferenceableOrNullCallSiteAttr(callsite, - idx.as_uint(), - deref); - } - regular -= ArgAttribute::NonNull; - } - if let Some(align) = self.pointee_align { - llvm::LLVMRustAddAlignmentCallSiteAttr(callsite, - idx.as_uint(), - align.abi() as u32); - } - regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite)); - } - } -} - -pub trait LlvmType { - fn llvm_type(&self, cx: &CodegenCx) -> Type; -} - -impl LlvmType for Reg { - fn llvm_type(&self, cx: &CodegenCx) -> Type { - match self.kind { - RegKind::Integer => Type::ix(cx, self.size.bits()), - RegKind::Float => { - match self.size.bits() { - 32 => Type::f32(cx), - 64 => Type::f64(cx), - _ => bug!("unsupported float: {:?}", self) - } - } - RegKind::Vector => { - Type::vector(&Type::i8(cx), self.size.bytes()) - } - } - } -} - -impl LlvmType for CastTarget { - fn llvm_type(&self, cx: &CodegenCx) -> Type { - let rest_ll_unit = self.rest.unit.llvm_type(cx); - let rest_count = self.rest.total.bytes() / self.rest.unit.size.bytes(); - let rem_bytes = self.rest.total.bytes() % self.rest.unit.size.bytes(); - - if self.prefix.iter().all(|x| x.is_none()) { - // Simplify to a single unit when there is no prefix and size <= unit size - if self.rest.total <= self.rest.unit.size { - return rest_ll_unit; - } - - // Simplify to array when all chunks are the same size and type - if rem_bytes == 0 { - return Type::array(&rest_ll_unit, rest_count); - } - } - - // Create list of fields in the main structure - let mut args: Vec<_> = - self.prefix.iter().flat_map(|option_kind| option_kind.map( - |kind| Reg { kind: kind, size: self.prefix_chunk }.llvm_type(cx))) - .chain((0..rest_count).map(|_| rest_ll_unit)) - .collect(); - - // Append final integer - if rem_bytes != 0 { - // Only integers can be really split further. - assert_eq!(self.rest.unit.kind, RegKind::Integer); - args.push(Type::ix(cx, rem_bytes * 8)); - } - - Type::struct_(cx, &args, false) - } -} - -pub trait ArgTypeExt<'a, 'tcx> { - fn memory_ty(&self, cx: &CodegenCx<'a, 'tcx>) -> Type; - fn store(&self, bx: &Builder<'a, 'tcx>, val: ValueRef, dst: PlaceRef<'tcx>); - fn store_fn_arg(&self, bx: &Builder<'a, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx>); -} - -impl<'a, 'tcx> ArgTypeExt<'a, 'tcx> for ArgType<'tcx, Ty<'tcx>> { - /// Get the LLVM type for a place of the original Rust type of - /// this argument/return, i.e. the result of `type_of::type_of`. - fn memory_ty(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { - self.layout.llvm_type(cx) - } - - /// Store a direct/indirect value described by this ArgType into a - /// place for the original Rust type of this argument/return. - /// Can be used for both storing formal arguments into Rust variables - /// or results of call/invoke instructions into their destinations. - fn store(&self, bx: &Builder<'a, 'tcx>, val: ValueRef, dst: PlaceRef<'tcx>) { - if self.is_ignore() { - return; - } - let cx = bx.cx; - if self.is_indirect() { - OperandValue::Ref(val, self.layout.align).store(bx, dst) - } else if let PassMode::Cast(cast) = self.mode { - // FIXME(eddyb): Figure out when the simpler Store is safe, clang - // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. - let can_store_through_cast_ptr = false; - if can_store_through_cast_ptr { - let cast_dst = bx.pointercast(dst.llval, cast.llvm_type(cx).ptr_to()); - bx.store(val, cast_dst, self.layout.align); - } else { - // The actual return type is a struct, but the ABI - // adaptation code has cast it into some scalar type. The - // code that follows is the only reliable way I have - // found to do a transform like i64 -> {i32,i32}. - // Basically we dump the data onto the stack then memcpy it. - // - // Other approaches I tried: - // - Casting rust ret pointer to the foreign type and using Store - // is (a) unsafe if size of foreign type > size of rust type and - // (b) runs afoul of strict aliasing rules, yielding invalid - // assembly under -O (specifically, the store gets removed). - // - Truncating foreign type to correct integral type and then - // bitcasting to the struct type yields invalid cast errors. - - // We instead thus allocate some scratch space... - let scratch_size = cast.size(cx); - let scratch_align = cast.align(cx); - let llscratch = bx.alloca(cast.llvm_type(cx), "abi_cast", scratch_align); - bx.lifetime_start(llscratch, scratch_size); - - // ...where we first store the value... - bx.store(val, llscratch, scratch_align); - - // ...and then memcpy it to the intended destination. - base::call_memcpy(bx, - bx.pointercast(dst.llval, Type::i8p(cx)), - bx.pointercast(llscratch, Type::i8p(cx)), - C_usize(cx, self.layout.size.bytes()), - self.layout.align.min(scratch_align), - MemFlags::empty()); - - bx.lifetime_end(llscratch, scratch_size); - } - } else { - OperandValue::Immediate(val).store(bx, dst); - } - } - - fn store_fn_arg(&self, bx: &Builder<'a, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx>) { - let mut next = || { - let val = llvm::get_param(bx.llfn(), *idx as c_uint); - *idx += 1; - val - }; - match self.mode { - PassMode::Ignore => {}, - PassMode::Pair(..) => { - OperandValue::Pair(next(), next()).store(bx, dst); - } - PassMode::Direct(_) | PassMode::Indirect(_) | PassMode::Cast(_) => { - self.store(bx, next(), dst); - } - } - } -} - -pub trait FnTypeExt<'a, 'tcx> { - fn of_instance(cx: &CodegenCx<'a, 'tcx>, instance: &ty::Instance<'tcx>) - -> Self; - fn new(cx: &CodegenCx<'a, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self; - fn new_vtable(cx: &CodegenCx<'a, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self; - fn unadjusted(cx: &CodegenCx<'a, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self; - fn adjust_for_abi(&mut self, - cx: &CodegenCx<'a, 'tcx>, - abi: Abi); - fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type; - fn llvm_cconv(&self) -> llvm::CallConv; - fn apply_attrs_llfn(&self, llfn: ValueRef); - fn apply_attrs_callsite(&self, bx: &Builder<'a, 'tcx>, callsite: ValueRef); -} - -impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { - fn of_instance(cx: &CodegenCx<'a, 'tcx>, instance: &ty::Instance<'tcx>) - -> Self { - let fn_ty = instance.ty(cx.tcx); - let sig = ty_fn_sig(cx, fn_ty); - let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - FnType::new(cx, sig, &[]) - } - - fn new(cx: &CodegenCx<'a, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self { - let mut fn_ty = FnType::unadjusted(cx, sig, extra_args); - fn_ty.adjust_for_abi(cx, sig.abi); - fn_ty - } - - fn new_vtable(cx: &CodegenCx<'a, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self { - let mut fn_ty = FnType::unadjusted(cx, sig, extra_args); - // Don't pass the vtable, it's not an argument of the virtual fn. - { - let self_arg = &mut fn_ty.args[0]; - match self_arg.mode { - PassMode::Pair(data_ptr, _) => { - self_arg.mode = PassMode::Direct(data_ptr); - } - _ => bug!("FnType::new_vtable: non-pair self {:?}", self_arg) - } - - let pointee = self_arg.layout.ty.builtin_deref(true) - .unwrap_or_else(|| { - bug!("FnType::new_vtable: non-pointer self {:?}", self_arg) - }).ty; - let fat_ptr_ty = cx.tcx.mk_mut_ptr(pointee); - self_arg.layout = cx.layout_of(fat_ptr_ty).field(cx, 0); - } - fn_ty.adjust_for_abi(cx, sig.abi); - fn_ty - } - - fn unadjusted(cx: &CodegenCx<'a, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self { - debug!("FnType::unadjusted({:?}, {:?})", sig, extra_args); - - use self::Abi::*; - let conv = match cx.sess().target.target.adjust_abi(sig.abi) { - RustIntrinsic | PlatformIntrinsic | - Rust | RustCall => Conv::C, - - // It's the ABI's job to select this, not us. - System => bug!("system abi should be selected elsewhere"), - - Stdcall => Conv::X86Stdcall, - Fastcall => Conv::X86Fastcall, - Vectorcall => Conv::X86VectorCall, - Thiscall => Conv::X86ThisCall, - C => Conv::C, - Unadjusted => Conv::C, - Win64 => Conv::X86_64Win64, - SysV64 => Conv::X86_64SysV, - Aapcs => Conv::ArmAapcs, - PtxKernel => Conv::PtxKernel, - Msp430Interrupt => Conv::Msp430Intr, - X86Interrupt => Conv::X86Intr, - - // These API constants ought to be more specific... - Cdecl => Conv::C, - }; - - let mut inputs = sig.inputs(); - let extra_args = if sig.abi == RustCall { - assert!(!sig.variadic && extra_args.is_empty()); - - match sig.inputs().last().unwrap().sty { - ty::TyTuple(ref tupled_arguments) => { - inputs = &sig.inputs()[0..sig.inputs().len() - 1]; - tupled_arguments - } - _ => { - bug!("argument to function with \"rust-call\" ABI \ - is not a tuple"); - } - } - } else { - assert!(sig.variadic || extra_args.is_empty()); - extra_args - }; - - let target = &cx.sess().target.target; - let win_x64_gnu = target.target_os == "windows" - && target.arch == "x86_64" - && target.target_env == "gnu"; - let linux_s390x = target.target_os == "linux" - && target.arch == "s390x" - && target.target_env == "gnu"; - let rust_abi = match sig.abi { - RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true, - _ => false - }; - - // Handle safe Rust thin and fat pointers. - let adjust_for_rust_scalar = |attrs: &mut ArgAttributes, - scalar: &layout::Scalar, - layout: TyLayout<'tcx, Ty<'tcx>>, - offset: Size, - is_return: bool| { - // Booleans are always an i1 that needs to be zero-extended. - if scalar.is_bool() { - attrs.set(ArgAttribute::ZExt); - return; - } - - // Only pointer types handled below. - if scalar.value != layout::Pointer { - return; - } - - if scalar.valid_range.start() < scalar.valid_range.end() { - if *scalar.valid_range.start() > 0 { - attrs.set(ArgAttribute::NonNull); - } - } - - if let Some(pointee) = layout.pointee_info_at(cx, offset) { - if let Some(kind) = pointee.safe { - attrs.pointee_size = pointee.size; - attrs.pointee_align = Some(pointee.align); - - // HACK(eddyb) LLVM inserts `llvm.assume` calls when inlining functions - // with align attributes, and those calls later block optimizations. - if !is_return && !cx.tcx.sess.opts.debugging_opts.arg_align_attributes { - attrs.pointee_align = None; - } - - // `Box` pointer parameters never alias because ownership is transferred - // `&mut` pointer parameters never alias other parameters, - // or mutable global data - // - // `&T` where `T` contains no `UnsafeCell` is immutable, - // and can be marked as both `readonly` and `noalias`, as - // LLVM's definition of `noalias` is based solely on memory - // dependencies rather than pointer equality - let no_alias = match kind { - PointerKind::Shared => false, - PointerKind::UniqueOwned => true, - PointerKind::Frozen | - PointerKind::UniqueBorrowed => !is_return - }; - if no_alias { - attrs.set(ArgAttribute::NoAlias); - } - - if kind == PointerKind::Frozen && !is_return { - attrs.set(ArgAttribute::ReadOnly); - } - } - } - }; - - let arg_of = |ty: Ty<'tcx>, is_return: bool| { - let mut arg = ArgType::new(cx.layout_of(ty)); - if arg.layout.is_zst() { - // For some forsaken reason, x86_64-pc-windows-gnu - // doesn't ignore zero-sized struct arguments. - // The same is true for s390x-unknown-linux-gnu. - if is_return || rust_abi || (!win_x64_gnu && !linux_s390x) { - arg.mode = PassMode::Ignore; - } - } - - // FIXME(eddyb) other ABIs don't have logic for scalar pairs. - if !is_return && rust_abi { - if let layout::Abi::ScalarPair(ref a, ref b) = arg.layout.abi { - let mut a_attrs = ArgAttributes::new(); - let mut b_attrs = ArgAttributes::new(); - adjust_for_rust_scalar(&mut a_attrs, - a, - arg.layout, - Size::from_bytes(0), - false); - adjust_for_rust_scalar(&mut b_attrs, - b, - arg.layout, - a.value.size(cx).abi_align(b.value.align(cx)), - false); - arg.mode = PassMode::Pair(a_attrs, b_attrs); - return arg; - } - } - - if let layout::Abi::Scalar(ref scalar) = arg.layout.abi { - if let PassMode::Direct(ref mut attrs) = arg.mode { - adjust_for_rust_scalar(attrs, - scalar, - arg.layout, - Size::from_bytes(0), - is_return); - } - } - - arg - }; - - FnType { - ret: arg_of(sig.output(), true), - args: inputs.iter().chain(extra_args.iter()).map(|ty| { - arg_of(ty, false) - }).collect(), - variadic: sig.variadic, - conv, - } - } - - fn adjust_for_abi(&mut self, - cx: &CodegenCx<'a, 'tcx>, - abi: Abi) { - if abi == Abi::Unadjusted { return } - - if abi == Abi::Rust || abi == Abi::RustCall || - abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { - let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| { - if arg.is_ignore() { return; } - - match arg.layout.abi { - layout::Abi::Aggregate { .. } => {} - - // This is a fun case! The gist of what this is doing is - // that we want callers and callees to always agree on the - // ABI of how they pass SIMD arguments. If we were to *not* - // make these arguments indirect then they'd be immediates - // in LLVM, which means that they'd used whatever the - // appropriate ABI is for the callee and the caller. That - // means, for example, if the caller doesn't have AVX - // enabled but the callee does, then passing an AVX argument - // across this boundary would cause corrupt data to show up. - // - // This problem is fixed by unconditionally passing SIMD - // arguments through memory between callers and callees - // which should get them all to agree on ABI regardless of - // target feature sets. Some more information about this - // issue can be found in #44367. - // - // Note that the platform intrinsic ABI is exempt here as - // that's how we connect up to LLVM and it's unstable - // anyway, we control all calls to it in libstd. - layout::Abi::Vector { .. } if abi != Abi::PlatformIntrinsic => { - arg.make_indirect(); - return - } - - _ => return - } - - let size = arg.layout.size; - if size > layout::Pointer.size(cx) { - arg.make_indirect(); - } else { - // We want to pass small aggregates as immediates, but using - // a LLVM aggregate type for this leads to bad optimizations, - // so we pick an appropriately sized integer type instead. - arg.cast_to(Reg { - kind: RegKind::Integer, - size - }); - } - }; - fixup(&mut self.ret); - for arg in &mut self.args { - fixup(arg); - } - if let PassMode::Indirect(ref mut attrs) = self.ret.mode { - attrs.set(ArgAttribute::StructRet); - } - return; - } - - if let Err(msg) = self.adjust_for_cabi(cx, abi) { - cx.sess().fatal(&msg); - } - } - - fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { - let mut llargument_tys = Vec::new(); - - let llreturn_ty = match self.ret.mode { - PassMode::Ignore => Type::void(cx), - PassMode::Direct(_) | PassMode::Pair(..) => { - self.ret.layout.immediate_llvm_type(cx) - } - PassMode::Cast(cast) => cast.llvm_type(cx), - PassMode::Indirect(_) => { - llargument_tys.push(self.ret.memory_ty(cx).ptr_to()); - Type::void(cx) - } - }; - - for arg in &self.args { - // add padding - if let Some(ty) = arg.pad { - llargument_tys.push(ty.llvm_type(cx)); - } - - let llarg_ty = match arg.mode { - PassMode::Ignore => continue, - PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx), - PassMode::Pair(..) => { - llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0)); - llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1)); - continue; - } - PassMode::Cast(cast) => cast.llvm_type(cx), - PassMode::Indirect(_) => arg.memory_ty(cx).ptr_to(), - }; - llargument_tys.push(llarg_ty); - } - - if self.variadic { - Type::variadic_func(&llargument_tys, &llreturn_ty) - } else { - Type::func(&llargument_tys, &llreturn_ty) - } - } - - fn llvm_cconv(&self) -> llvm::CallConv { - match self.conv { - Conv::C => llvm::CCallConv, - Conv::ArmAapcs => llvm::ArmAapcsCallConv, - Conv::Msp430Intr => llvm::Msp430Intr, - Conv::PtxKernel => llvm::PtxKernel, - Conv::X86Fastcall => llvm::X86FastcallCallConv, - Conv::X86Intr => llvm::X86_Intr, - Conv::X86Stdcall => llvm::X86StdcallCallConv, - Conv::X86ThisCall => llvm::X86_ThisCall, - Conv::X86VectorCall => llvm::X86_VectorCall, - Conv::X86_64SysV => llvm::X86_64_SysV, - Conv::X86_64Win64 => llvm::X86_64_Win64, - } - } - - fn apply_attrs_llfn(&self, llfn: ValueRef) { - let mut i = 0; - let mut apply = |attrs: &ArgAttributes| { - attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn); - i += 1; - }; - match self.ret.mode { - PassMode::Direct(ref attrs) => { - attrs.apply_llfn(llvm::AttributePlace::ReturnValue, llfn); - } - PassMode::Indirect(ref attrs) => apply(attrs), - _ => {} - } - for arg in &self.args { - if arg.pad.is_some() { - apply(&ArgAttributes::new()); - } - match arg.mode { - PassMode::Ignore => {} - PassMode::Direct(ref attrs) | - PassMode::Indirect(ref attrs) => apply(attrs), - PassMode::Pair(ref a, ref b) => { - apply(a); - apply(b); - } - PassMode::Cast(_) => apply(&ArgAttributes::new()), - } - } - } - - fn apply_attrs_callsite(&self, bx: &Builder<'a, 'tcx>, callsite: ValueRef) { - let mut i = 0; - let mut apply = |attrs: &ArgAttributes| { - attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite); - i += 1; - }; - match self.ret.mode { - PassMode::Direct(ref attrs) => { - attrs.apply_callsite(llvm::AttributePlace::ReturnValue, callsite); - } - PassMode::Indirect(ref attrs) => apply(attrs), - _ => {} - } - if let layout::Abi::Scalar(ref scalar) = self.ret.layout.abi { - // If the value is a boolean, the range is 0..2 and that ultimately - // become 0..0 when the type becomes i1, which would be rejected - // by the LLVM verifier. - match scalar.value { - layout::Int(..) if !scalar.is_bool() => { - let range = scalar.valid_range_exclusive(bx.cx); - if range.start != range.end { - // FIXME(nox): This causes very weird type errors about - // SHL operators in constants in stage 2 with LLVM 3.9. - if unsafe { llvm::LLVMRustVersionMajor() >= 4 } { - bx.range_metadata(callsite, range); - } - } - } - _ => {} - } - } - for arg in &self.args { - if arg.pad.is_some() { - apply(&ArgAttributes::new()); - } - match arg.mode { - PassMode::Ignore => {} - PassMode::Direct(ref attrs) | - PassMode::Indirect(ref attrs) => apply(attrs), - PassMode::Pair(ref a, ref b) => { - apply(a); - apply(b); - } - PassMode::Cast(_) => apply(&ArgAttributes::new()), - } - } - - let cconv = self.llvm_cconv(); - if cconv != llvm::CCallConv { - llvm::SetInstructionCallConv(callsite, cconv); - } - } -} diff --git a/src/librustc_trans/allocator.rs b/src/librustc_trans/allocator.rs deleted file mode 100644 index 871fe98ec01..00000000000 --- a/src/librustc_trans/allocator.rs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::ffi::CString; -use std::ptr; - -use attributes; -use libc::c_uint; -use rustc::middle::allocator::AllocatorKind; -use rustc::ty::TyCtxt; -use rustc_allocator::{ALLOCATOR_METHODS, AllocatorTy}; - -use ModuleLlvm; -use llvm::{self, False, True}; - -pub(crate) unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) { - let llcx = mods.llcx; - let llmod = mods.llmod; - let usize = match &tcx.sess.target.target.target_pointer_width[..] { - "16" => llvm::LLVMInt16TypeInContext(llcx), - "32" => llvm::LLVMInt32TypeInContext(llcx), - "64" => llvm::LLVMInt64TypeInContext(llcx), - tws => bug!("Unsupported target word size for int: {}", tws), - }; - let i8 = llvm::LLVMInt8TypeInContext(llcx); - let i8p = llvm::LLVMPointerType(i8, 0); - let void = llvm::LLVMVoidTypeInContext(llcx); - - for method in ALLOCATOR_METHODS { - let mut args = Vec::new(); - for ty in method.inputs.iter() { - match *ty { - AllocatorTy::Layout => { - args.push(usize); // size - args.push(usize); // align - } - AllocatorTy::Ptr => args.push(i8p), - AllocatorTy::Usize => args.push(usize), - - AllocatorTy::ResultPtr | - AllocatorTy::Unit => panic!("invalid allocator arg"), - } - } - let output = match method.output { - AllocatorTy::ResultPtr => Some(i8p), - AllocatorTy::Unit => None, - - AllocatorTy::Layout | - AllocatorTy::Usize | - AllocatorTy::Ptr => panic!("invalid allocator output"), - }; - let ty = llvm::LLVMFunctionType(output.unwrap_or(void), - args.as_ptr(), - args.len() as c_uint, - False); - let name = CString::new(format!("__rust_{}", method.name)).unwrap(); - let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, - name.as_ptr(), - ty); - - if tcx.sess.target.target.options.default_hidden_visibility { - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); - } - if tcx.sess.target.target.options.requires_uwtable { - attributes::emit_uwtable(llfn, true); - } - - let callee = CString::new(kind.fn_name(method.name)).unwrap(); - let callee = llvm::LLVMRustGetOrInsertFunction(llmod, - callee.as_ptr(), - ty); - - let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, - llfn, - "entry\0".as_ptr() as *const _); - - let llbuilder = llvm::LLVMCreateBuilderInContext(llcx); - llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb); - let args = args.iter().enumerate().map(|(i, _)| { - llvm::LLVMGetParam(llfn, i as c_uint) - }).collect::>(); - let ret = llvm::LLVMRustBuildCall(llbuilder, - callee, - args.as_ptr(), - args.len() as c_uint, - ptr::null_mut(), - "\0".as_ptr() as *const _); - llvm::LLVMSetTailCall(ret, True); - if output.is_some() { - llvm::LLVMBuildRet(llbuilder, ret); - } else { - llvm::LLVMBuildRetVoid(llbuilder); - } - llvm::LLVMDisposeBuilder(llbuilder); - } -} diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs deleted file mode 100644 index 751f8148a2a..00000000000 --- a/src/librustc_trans/asm.rs +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! # Translation of inline assembly. - -use llvm::{self, ValueRef}; -use common::*; -use type_::Type; -use type_of::LayoutLlvmExt; -use builder::Builder; - -use rustc::hir; - -use mir::place::PlaceRef; -use mir::operand::OperandValue; - -use std::ffi::CString; -use syntax::ast::AsmDialect; -use libc::{c_uint, c_char}; - -// Take an inline assembly expression and splat it out via LLVM -pub fn trans_inline_asm<'a, 'tcx>( - bx: &Builder<'a, 'tcx>, - ia: &hir::InlineAsm, - outputs: Vec>, - mut inputs: Vec -) { - let mut ext_constraints = vec![]; - let mut output_types = vec![]; - - // Prepare the output operands - let mut indirect_outputs = vec![]; - for (i, (out, place)) in ia.outputs.iter().zip(&outputs).enumerate() { - if out.is_rw { - inputs.push(place.load(bx).immediate()); - ext_constraints.push(i.to_string()); - } - if out.is_indirect { - indirect_outputs.push(place.load(bx).immediate()); - } else { - output_types.push(place.layout.llvm_type(bx.cx)); - } - } - if !indirect_outputs.is_empty() { - indirect_outputs.extend_from_slice(&inputs); - inputs = indirect_outputs; - } - - let clobbers = ia.clobbers.iter() - .map(|s| format!("~{{{}}}", &s)); - - // Default per-arch clobbers - // Basically what clang does - let arch_clobbers = match &bx.sess().target.target.arch[..] { - "x86" | "x86_64" => vec!["~{dirflag}", "~{fpsr}", "~{flags}"], - "mips" | "mips64" => vec!["~{$1}"], - _ => Vec::new() - }; - - let all_constraints = - ia.outputs.iter().map(|out| out.constraint.to_string()) - .chain(ia.inputs.iter().map(|s| s.to_string())) - .chain(ext_constraints) - .chain(clobbers) - .chain(arch_clobbers.iter().map(|s| s.to_string())) - .collect::>().join(","); - - debug!("Asm Constraints: {}", &all_constraints); - - // Depending on how many outputs we have, the return type is different - let num_outputs = output_types.len(); - let output_type = match num_outputs { - 0 => Type::void(bx.cx), - 1 => output_types[0], - _ => Type::struct_(bx.cx, &output_types, false) - }; - - let dialect = match ia.dialect { - AsmDialect::Att => llvm::AsmDialect::Att, - AsmDialect::Intel => llvm::AsmDialect::Intel, - }; - - let asm = CString::new(ia.asm.as_str().as_bytes()).unwrap(); - let constraint_cstr = CString::new(all_constraints).unwrap(); - let r = bx.inline_asm_call( - asm.as_ptr(), - constraint_cstr.as_ptr(), - &inputs, - output_type, - ia.volatile, - ia.alignstack, - dialect - ); - - // Again, based on how many outputs we have - let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect); - for (i, (_, &place)) in outputs.enumerate() { - let v = if num_outputs == 1 { r } else { bx.extract_value(r, i as u64) }; - OperandValue::Immediate(v).store(bx, place); - } - - // Store mark in a metadata node so we can map LLVM errors - // back to source locations. See #17552. - unsafe { - let key = "srcloc"; - let kind = llvm::LLVMGetMDKindIDInContext(bx.cx.llcx, - key.as_ptr() as *const c_char, key.len() as c_uint); - - let val: llvm::ValueRef = C_i32(bx.cx, ia.ctxt.outer().as_u32() as i32); - - llvm::LLVMSetMetadata(r, kind, - llvm::LLVMMDNodeInContext(bx.cx.llcx, &val, 1)); - } -} - -pub fn trans_global_asm<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - ga: &hir::GlobalAsm) { - let asm = CString::new(ga.asm.as_str().as_bytes()).unwrap(); - unsafe { - llvm::LLVMRustAppendModuleInlineAsm(cx.llmod, asm.as_ptr()); - } -} diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs deleted file mode 100644 index 5baed57092d..00000000000 --- a/src/librustc_trans/attributes.rs +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -//! Set and unset common attributes on LLVM values. - -use std::ffi::{CStr, CString}; - -use rustc::hir::{self, TransFnAttrFlags}; -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; -use rustc::hir::itemlikevisit::ItemLikeVisitor; -use rustc::session::Session; -use rustc::session::config::Sanitizer; -use rustc::ty::TyCtxt; -use rustc::ty::maps::Providers; -use rustc_data_structures::sync::Lrc; -use rustc_data_structures::fx::FxHashMap; - -use llvm::{self, Attribute, ValueRef}; -use llvm::AttributePlace::Function; -use llvm_util; -pub use syntax::attr::{self, InlineAttr}; -use context::CodegenCx; - -/// Mark LLVM function to use provided inline heuristic. -#[inline] -pub fn inline(val: ValueRef, inline: InlineAttr) { - use self::InlineAttr::*; - match inline { - Hint => Attribute::InlineHint.apply_llfn(Function, val), - Always => Attribute::AlwaysInline.apply_llfn(Function, val), - Never => Attribute::NoInline.apply_llfn(Function, val), - None => { - Attribute::InlineHint.unapply_llfn(Function, val); - Attribute::AlwaysInline.unapply_llfn(Function, val); - Attribute::NoInline.unapply_llfn(Function, val); - }, - }; -} - -/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function. -#[inline] -pub fn emit_uwtable(val: ValueRef, emit: bool) { - Attribute::UWTable.toggle_llfn(Function, val, emit); -} - -/// Tell LLVM whether the function can or cannot unwind. -#[inline] -pub fn unwind(val: ValueRef, can_unwind: bool) { - Attribute::NoUnwind.toggle_llfn(Function, val, !can_unwind); -} - -/// Tell LLVM whether it should optimize function for size. -#[inline] -#[allow(dead_code)] // possibly useful function -pub fn set_optimize_for_size(val: ValueRef, optimize: bool) { - Attribute::OptimizeForSize.toggle_llfn(Function, val, optimize); -} - -/// Tell LLVM if this function should be 'naked', i.e. skip the epilogue and prologue. -#[inline] -pub fn naked(val: ValueRef, is_naked: bool) { - Attribute::Naked.toggle_llfn(Function, val, is_naked); -} - -pub fn set_frame_pointer_elimination(cx: &CodegenCx, llfn: ValueRef) { - if cx.sess().must_not_eliminate_frame_pointers() { - llvm::AddFunctionAttrStringValue( - llfn, llvm::AttributePlace::Function, - cstr("no-frame-pointer-elim\0"), cstr("true\0")); - } -} - -pub fn set_probestack(cx: &CodegenCx, llfn: ValueRef) { - // Only use stack probes if the target specification indicates that we - // should be using stack probes - if !cx.sess().target.target.options.stack_probes { - return - } - - // Currently stack probes seem somewhat incompatible with the address - // sanitizer. With asan we're already protected from stack overflow anyway - // so we don't really need stack probes regardless. - match cx.sess().opts.debugging_opts.sanitizer { - Some(Sanitizer::Address) => return, - _ => {} - } - - // probestack doesn't play nice either with pgo-gen. - if cx.sess().opts.debugging_opts.pgo_gen.is_some() { - return; - } - - // Flag our internal `__rust_probestack` function as the stack probe symbol. - // This is defined in the `compiler-builtins` crate for each architecture. - llvm::AddFunctionAttrStringValue( - llfn, llvm::AttributePlace::Function, - cstr("probe-stack\0"), cstr("__rust_probestack\0")); -} - -pub fn llvm_target_features(sess: &Session) -> impl Iterator { - const RUSTC_SPECIFIC_FEATURES: &[&str] = &[ - "crt-static", - ]; - - let cmdline = sess.opts.cg.target_feature.split(',') - .filter(|f| !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s))); - sess.target.target.options.features.split(',') - .chain(cmdline) - .filter(|l| !l.is_empty()) -} - -/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute]) -/// attributes. -pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) { - let trans_fn_attrs = cx.tcx.trans_fn_attrs(id); - - inline(llfn, trans_fn_attrs.inline); - - set_frame_pointer_elimination(cx, llfn); - set_probestack(cx, llfn); - - if trans_fn_attrs.flags.contains(TransFnAttrFlags::COLD) { - Attribute::Cold.apply_llfn(Function, llfn); - } - if trans_fn_attrs.flags.contains(TransFnAttrFlags::NAKED) { - naked(llfn, true); - } - if trans_fn_attrs.flags.contains(TransFnAttrFlags::ALLOCATOR) { - Attribute::NoAlias.apply_llfn( - llvm::AttributePlace::ReturnValue, llfn); - } - if trans_fn_attrs.flags.contains(TransFnAttrFlags::UNWIND) { - unwind(llfn, true); - } - if trans_fn_attrs.flags.contains(TransFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) { - unwind(llfn, false); - } - - let features = llvm_target_features(cx.tcx.sess) - .map(|s| s.to_string()) - .chain( - trans_fn_attrs.target_features - .iter() - .map(|f| { - let feature = &*f.as_str(); - format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature)) - }) - ) - .collect::>() - .join(","); - - if !features.is_empty() { - let val = CString::new(features).unwrap(); - llvm::AddFunctionAttrStringValue( - llfn, llvm::AttributePlace::Function, - cstr("target-features\0"), &val); - } - - // Note that currently the `wasm-import-module` doesn't do anything, but - // eventually LLVM 7 should read this and ferry the appropriate import - // module to the output file. - if cx.tcx.sess.target.target.arch == "wasm32" { - if let Some(module) = wasm_import_module(cx.tcx, id) { - llvm::AddFunctionAttrStringValue( - llfn, - llvm::AttributePlace::Function, - cstr("wasm-import-module\0"), - &module, - ); - } - } -} - -fn cstr(s: &'static str) -> &CStr { - CStr::from_bytes_with_nul(s.as_bytes()).expect("null-terminated string") -} - -pub fn provide(providers: &mut Providers) { - providers.target_features_whitelist = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - if tcx.sess.opts.actually_rustdoc { - // rustdoc needs to be able to document functions that use all the features, so - // whitelist them all - Lrc::new(llvm_util::all_known_features() - .map(|(a, b)| (a.to_string(), b.map(|s| s.to_string()))) - .collect()) - } else { - Lrc::new(llvm_util::target_feature_whitelist(tcx.sess) - .iter() - .map(|&(a, b)| (a.to_string(), b.map(|s| s.to_string()))) - .collect()) - } - }; - - providers.wasm_custom_sections = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - let mut finder = WasmSectionFinder { tcx, list: Vec::new() }; - tcx.hir.krate().visit_all_item_likes(&mut finder); - Lrc::new(finder.list) - }; - - provide_extern(providers); -} - -struct WasmSectionFinder<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - list: Vec, -} - -impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for WasmSectionFinder<'a, 'tcx> { - fn visit_item(&mut self, i: &'tcx hir::Item) { - match i.node { - hir::ItemConst(..) => {} - _ => return, - } - if i.attrs.iter().any(|i| i.check_name("wasm_custom_section")) { - self.list.push(self.tcx.hir.local_def_id(i.id)); - } - } - - fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) {} - - fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {} -} - -pub fn provide_extern(providers: &mut Providers) { - providers.wasm_import_module_map = |tcx, cnum| { - let mut ret = FxHashMap(); - for lib in tcx.foreign_modules(cnum).iter() { - let attrs = tcx.get_attrs(lib.def_id); - let mut module = None; - for attr in attrs.iter().filter(|a| a.check_name("wasm_import_module")) { - module = attr.value_str(); - } - let module = match module { - Some(s) => s, - None => continue, - }; - for id in lib.foreign_items.iter() { - assert_eq!(id.krate, cnum); - ret.insert(*id, module.to_string()); - } - } - - Lrc::new(ret) - } -} - -fn wasm_import_module(tcx: TyCtxt, id: DefId) -> Option { - tcx.wasm_import_module_map(id.krate) - .get(&id) - .map(|s| CString::new(&s[..]).unwrap()) -} diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs deleted file mode 100644 index 609629bffb9..00000000000 --- a/src/librustc_trans/back/archive.rs +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A helper class for dealing with static archives - -use std::ffi::{CString, CStr}; -use std::io; -use std::mem; -use std::path::{Path, PathBuf}; -use std::ptr; -use std::str; - -use back::bytecode::RLIB_BYTECODE_EXTENSION; -use libc; -use llvm::archive_ro::{ArchiveRO, Child}; -use llvm::{self, ArchiveKind}; -use metadata::METADATA_FILENAME; -use rustc::session::Session; - -pub struct ArchiveConfig<'a> { - pub sess: &'a Session, - pub dst: PathBuf, - pub src: Option, - pub lib_search_paths: Vec, -} - -/// Helper for adding many files to an archive. -#[must_use = "must call build() to finish building the archive"] -pub struct ArchiveBuilder<'a> { - config: ArchiveConfig<'a>, - removals: Vec, - additions: Vec, - should_update_symbols: bool, - src_archive: Option>, -} - -enum Addition { - File { - path: PathBuf, - name_in_archive: String, - }, - Archive { - archive: ArchiveRO, - skip: Box bool>, - }, -} - -pub fn find_library(name: &str, search_paths: &[PathBuf], sess: &Session) - -> PathBuf { - // On Windows, static libraries sometimes show up as libfoo.a and other - // times show up as foo.lib - let oslibname = format!("{}{}{}", - sess.target.target.options.staticlib_prefix, - name, - sess.target.target.options.staticlib_suffix); - let unixlibname = format!("lib{}.a", name); - - for path in search_paths { - debug!("looking for {} inside {:?}", name, path); - let test = path.join(&oslibname); - if test.exists() { return test } - if oslibname != unixlibname { - let test = path.join(&unixlibname); - if test.exists() { return test } - } - } - sess.fatal(&format!("could not find native static library `{}`, \ - perhaps an -L flag is missing?", name)); -} - -fn is_relevant_child(c: &Child) -> bool { - match c.name() { - Some(name) => !name.contains("SYMDEF"), - None => false, - } -} - -impl<'a> ArchiveBuilder<'a> { - /// Create a new static archive, ready for modifying the archive specified - /// by `config`. - pub fn new(config: ArchiveConfig<'a>) -> ArchiveBuilder<'a> { - ArchiveBuilder { - config, - removals: Vec::new(), - additions: Vec::new(), - should_update_symbols: false, - src_archive: None, - } - } - - /// Removes a file from this archive - pub fn remove_file(&mut self, file: &str) { - self.removals.push(file.to_string()); - } - - /// Lists all files in an archive - pub fn src_files(&mut self) -> Vec { - if self.src_archive().is_none() { - return Vec::new() - } - let archive = self.src_archive.as_ref().unwrap().as_ref().unwrap(); - let ret = archive.iter() - .filter_map(|child| child.ok()) - .filter(is_relevant_child) - .filter_map(|child| child.name()) - .filter(|name| !self.removals.iter().any(|x| x == name)) - .map(|name| name.to_string()) - .collect(); - return ret; - } - - fn src_archive(&mut self) -> Option<&ArchiveRO> { - if let Some(ref a) = self.src_archive { - return a.as_ref() - } - let src = self.config.src.as_ref()?; - self.src_archive = Some(ArchiveRO::open(src).ok()); - self.src_archive.as_ref().unwrap().as_ref() - } - - /// Adds all of the contents of a native library to this archive. This will - /// search in the relevant locations for a library named `name`. - pub fn add_native_library(&mut self, name: &str) { - let location = find_library(name, &self.config.lib_search_paths, - self.config.sess); - self.add_archive(&location, |_| false).unwrap_or_else(|e| { - self.config.sess.fatal(&format!("failed to add native library {}: {}", - location.to_string_lossy(), e)); - }); - } - - /// Adds all of the contents of the rlib at the specified path to this - /// archive. - /// - /// This ignores adding the bytecode from the rlib, and if LTO is enabled - /// then the object file also isn't added. - pub fn add_rlib(&mut self, - rlib: &Path, - name: &str, - lto: bool, - skip_objects: bool) -> io::Result<()> { - // Ignoring obj file starting with the crate name - // as simple comparison is not enough - there - // might be also an extra name suffix - let obj_start = format!("{}", name); - - self.add_archive(rlib, move |fname: &str| { - // Ignore bytecode/metadata files, no matter the name. - if fname.ends_with(RLIB_BYTECODE_EXTENSION) || fname == METADATA_FILENAME { - return true - } - - // Don't include Rust objects if LTO is enabled - if lto && fname.starts_with(&obj_start) && fname.ends_with(".o") { - return true - } - - // Otherwise if this is *not* a rust object and we're skipping - // objects then skip this file - if skip_objects && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) { - return true - } - - // ok, don't skip this - return false - }) - } - - fn add_archive(&mut self, archive: &Path, skip: F) - -> io::Result<()> - where F: FnMut(&str) -> bool + 'static - { - let archive = match ArchiveRO::open(archive) { - Ok(ar) => ar, - Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)), - }; - self.additions.push(Addition::Archive { - archive, - skip: Box::new(skip), - }); - Ok(()) - } - - /// Adds an arbitrary file to this archive - pub fn add_file(&mut self, file: &Path) { - let name = file.file_name().unwrap().to_str().unwrap(); - self.additions.push(Addition::File { - path: file.to_path_buf(), - name_in_archive: name.to_string(), - }); - } - - /// Indicate that the next call to `build` should update all symbols in - /// the archive (equivalent to running 'ar s' over it). - pub fn update_symbols(&mut self) { - self.should_update_symbols = true; - } - - /// Combine the provided files, rlibs, and native libraries into a single - /// `Archive`. - pub fn build(&mut self) { - let kind = match self.llvm_archive_kind() { - Ok(kind) => kind, - Err(kind) => { - self.config.sess.fatal(&format!("Don't know how to build archive of type: {}", - kind)); - } - }; - - if let Err(e) = self.build_with_llvm(kind) { - self.config.sess.fatal(&format!("failed to build archive: {}", e)); - } - - } - - fn llvm_archive_kind(&self) -> Result { - let kind = &*self.config.sess.target.target.options.archive_format; - kind.parse().map_err(|_| kind) - } - - fn build_with_llvm(&mut self, kind: ArchiveKind) -> io::Result<()> { - let mut archives = Vec::new(); - let mut strings = Vec::new(); - let mut members = Vec::new(); - let removals = mem::replace(&mut self.removals, Vec::new()); - - unsafe { - if let Some(archive) = self.src_archive() { - for child in archive.iter() { - let child = child.map_err(string_to_io_error)?; - let child_name = match child.name() { - Some(s) => s, - None => continue, - }; - if removals.iter().any(|r| r == child_name) { - continue - } - - let name = CString::new(child_name)?; - members.push(llvm::LLVMRustArchiveMemberNew(ptr::null(), - name.as_ptr(), - child.raw())); - strings.push(name); - } - } - for addition in mem::replace(&mut self.additions, Vec::new()) { - match addition { - Addition::File { path, name_in_archive } => { - let path = CString::new(path.to_str().unwrap())?; - let name = CString::new(name_in_archive)?; - members.push(llvm::LLVMRustArchiveMemberNew(path.as_ptr(), - name.as_ptr(), - ptr::null_mut())); - strings.push(path); - strings.push(name); - } - Addition::Archive { archive, mut skip } => { - for child in archive.iter() { - let child = child.map_err(string_to_io_error)?; - if !is_relevant_child(&child) { - continue - } - let child_name = child.name().unwrap(); - if skip(child_name) { - continue - } - - // It appears that LLVM's archive writer is a little - // buggy if the name we pass down isn't just the - // filename component, so chop that off here and - // pass it in. - // - // See LLVM bug 25877 for more info. - let child_name = Path::new(child_name) - .file_name().unwrap() - .to_str().unwrap(); - let name = CString::new(child_name)?; - let m = llvm::LLVMRustArchiveMemberNew(ptr::null(), - name.as_ptr(), - child.raw()); - members.push(m); - strings.push(name); - } - archives.push(archive); - } - } - } - - let dst = self.config.dst.to_str().unwrap().as_bytes(); - let dst = CString::new(dst)?; - let r = llvm::LLVMRustWriteArchive(dst.as_ptr(), - members.len() as libc::size_t, - members.as_ptr(), - self.should_update_symbols, - kind); - let ret = if r.into_result().is_err() { - let err = llvm::LLVMRustGetLastError(); - let msg = if err.is_null() { - "failed to write archive".to_string() - } else { - String::from_utf8_lossy(CStr::from_ptr(err).to_bytes()) - .into_owned() - }; - Err(io::Error::new(io::ErrorKind::Other, msg)) - } else { - Ok(()) - }; - for member in members { - llvm::LLVMRustArchiveMemberFree(member); - } - return ret - } - } -} - -fn string_to_io_error(s: String) -> io::Error { - io::Error::new(io::ErrorKind::Other, format!("bad archive: {}", s)) -} diff --git a/src/librustc_trans/back/bytecode.rs b/src/librustc_trans/back/bytecode.rs deleted file mode 100644 index 212d1aaf055..00000000000 --- a/src/librustc_trans/back/bytecode.rs +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Management of the encoding of LLVM bytecode into rlibs -//! -//! This module contains the management of encoding LLVM bytecode into rlibs, -//! primarily for the usage in LTO situations. Currently the compiler will -//! unconditionally encode LLVM-IR into rlibs regardless of what's happening -//! elsewhere, so we currently compress the bytecode via deflate to avoid taking -//! up too much space on disk. -//! -//! After compressing the bytecode we then have the rest of the format to -//! basically deal with various bugs in various archive implementations. The -//! format currently is: -//! -//! RLIB LLVM-BYTECODE OBJECT LAYOUT -//! Version 2 -//! Bytes Data -//! 0..10 "RUST_OBJECT" encoded in ASCII -//! 11..14 format version as little-endian u32 -//! 15..19 the length of the module identifier string -//! 20..n the module identifier string -//! n..n+8 size in bytes of deflate compressed LLVM bitcode as -//! little-endian u64 -//! n+9.. compressed LLVM bitcode -//! ? maybe a byte to make this whole thing even length - -use std::io::{Read, Write}; -use std::ptr; -use std::str; - -use flate2::Compression; -use flate2::read::DeflateDecoder; -use flate2::write::DeflateEncoder; - -// This is the "magic number" expected at the beginning of a LLVM bytecode -// object in an rlib. -pub const RLIB_BYTECODE_OBJECT_MAGIC: &'static [u8] = b"RUST_OBJECT"; - -// The version number this compiler will write to bytecode objects in rlibs -pub const RLIB_BYTECODE_OBJECT_VERSION: u8 = 2; - -pub const RLIB_BYTECODE_EXTENSION: &str = "bc.z"; - -pub fn encode(identifier: &str, bytecode: &[u8]) -> Vec { - let mut encoded = Vec::new(); - - // Start off with the magic string - encoded.extend_from_slice(RLIB_BYTECODE_OBJECT_MAGIC); - - // Next up is the version - encoded.extend_from_slice(&[RLIB_BYTECODE_OBJECT_VERSION, 0, 0, 0]); - - // Next is the LLVM module identifier length + contents - let identifier_len = identifier.len(); - encoded.extend_from_slice(&[ - (identifier_len >> 0) as u8, - (identifier_len >> 8) as u8, - (identifier_len >> 16) as u8, - (identifier_len >> 24) as u8, - ]); - encoded.extend_from_slice(identifier.as_bytes()); - - // Next is the LLVM module deflate compressed, prefixed with its length. We - // don't know its length yet, so fill in 0s - let deflated_size_pos = encoded.len(); - encoded.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]); - - let before = encoded.len(); - DeflateEncoder::new(&mut encoded, Compression::fast()) - .write_all(bytecode) - .unwrap(); - let after = encoded.len(); - - // Fill in the length we reserved space for before - let bytecode_len = (after - before) as u64; - encoded[deflated_size_pos + 0] = (bytecode_len >> 0) as u8; - encoded[deflated_size_pos + 1] = (bytecode_len >> 8) as u8; - encoded[deflated_size_pos + 2] = (bytecode_len >> 16) as u8; - encoded[deflated_size_pos + 3] = (bytecode_len >> 24) as u8; - encoded[deflated_size_pos + 4] = (bytecode_len >> 32) as u8; - encoded[deflated_size_pos + 5] = (bytecode_len >> 40) as u8; - encoded[deflated_size_pos + 6] = (bytecode_len >> 48) as u8; - encoded[deflated_size_pos + 7] = (bytecode_len >> 56) as u8; - - // If the number of bytes written to the object so far is odd, add a - // padding byte to make it even. This works around a crash bug in LLDB - // (see issue #15950) - if encoded.len() % 2 == 1 { - encoded.push(0); - } - - return encoded -} - -pub struct DecodedBytecode<'a> { - identifier: &'a str, - encoded_bytecode: &'a [u8], -} - -impl<'a> DecodedBytecode<'a> { - pub fn new(data: &'a [u8]) -> Result, String> { - if !data.starts_with(RLIB_BYTECODE_OBJECT_MAGIC) { - return Err(format!("magic bytecode prefix not found")) - } - let data = &data[RLIB_BYTECODE_OBJECT_MAGIC.len()..]; - if !data.starts_with(&[RLIB_BYTECODE_OBJECT_VERSION, 0, 0, 0]) { - return Err(format!("wrong version prefix found in bytecode")) - } - let data = &data[4..]; - if data.len() < 4 { - return Err(format!("bytecode corrupted")) - } - let identifier_len = unsafe { - u32::from_le(ptr::read_unaligned(data.as_ptr() as *const u32)) as usize - }; - let data = &data[4..]; - if data.len() < identifier_len { - return Err(format!("bytecode corrupted")) - } - let identifier = match str::from_utf8(&data[..identifier_len]) { - Ok(s) => s, - Err(_) => return Err(format!("bytecode corrupted")) - }; - let data = &data[identifier_len..]; - if data.len() < 8 { - return Err(format!("bytecode corrupted")) - } - let bytecode_len = unsafe { - u64::from_le(ptr::read_unaligned(data.as_ptr() as *const u64)) as usize - }; - let data = &data[8..]; - if data.len() < bytecode_len { - return Err(format!("bytecode corrupted")) - } - let encoded_bytecode = &data[..bytecode_len]; - - Ok(DecodedBytecode { - identifier, - encoded_bytecode, - }) - } - - pub fn bytecode(&self) -> Vec { - let mut data = Vec::new(); - DeflateDecoder::new(self.encoded_bytecode).read_to_end(&mut data).unwrap(); - return data - } - - pub fn identifier(&self) -> &'a str { - self.identifier - } -} diff --git a/src/librustc_trans/back/command.rs b/src/librustc_trans/back/command.rs deleted file mode 100644 index 9ebbdd7c3c9..00000000000 --- a/src/librustc_trans/back/command.rs +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A thin wrapper around `Command` in the standard library which allows us to -//! read the arguments that are built up. - -use std::ffi::{OsStr, OsString}; -use std::fmt; -use std::io; -use std::mem; -use std::process::{self, Output}; - -use rustc_target::spec::LldFlavor; - -#[derive(Clone)] -pub struct Command { - program: Program, - args: Vec, - env: Vec<(OsString, OsString)>, -} - -#[derive(Clone)] -enum Program { - Normal(OsString), - CmdBatScript(OsString), - Lld(OsString, LldFlavor) -} - -impl Command { - pub fn new>(program: P) -> Command { - Command::_new(Program::Normal(program.as_ref().to_owned())) - } - - pub fn bat_script>(program: P) -> Command { - Command::_new(Program::CmdBatScript(program.as_ref().to_owned())) - } - - pub fn lld>(program: P, flavor: LldFlavor) -> Command { - Command::_new(Program::Lld(program.as_ref().to_owned(), flavor)) - } - - fn _new(program: Program) -> Command { - Command { - program, - args: Vec::new(), - env: Vec::new(), - } - } - - pub fn arg>(&mut self, arg: P) -> &mut Command { - self._arg(arg.as_ref()); - self - } - - pub fn args(&mut self, args: I) -> &mut Command - where I: IntoIterator, - I::Item: AsRef, - { - for arg in args { - self._arg(arg.as_ref()); - } - self - } - - fn _arg(&mut self, arg: &OsStr) { - self.args.push(arg.to_owned()); - } - - pub fn env(&mut self, key: K, value: V) -> &mut Command - where K: AsRef, - V: AsRef - { - self._env(key.as_ref(), value.as_ref()); - self - } - - fn _env(&mut self, key: &OsStr, value: &OsStr) { - self.env.push((key.to_owned(), value.to_owned())); - } - - pub fn output(&mut self) -> io::Result { - self.command().output() - } - - pub fn command(&self) -> process::Command { - let mut ret = match self.program { - Program::Normal(ref p) => process::Command::new(p), - Program::CmdBatScript(ref p) => { - let mut c = process::Command::new("cmd"); - c.arg("/c").arg(p); - c - } - Program::Lld(ref p, flavor) => { - let mut c = process::Command::new(p); - c.arg("-flavor").arg(match flavor { - LldFlavor::Wasm => "wasm", - LldFlavor::Ld => "gnu", - LldFlavor::Link => "link", - LldFlavor::Ld64 => "darwin", - }); - c - } - }; - ret.args(&self.args); - ret.envs(self.env.clone()); - return ret - } - - // extensions - - pub fn get_args(&self) -> &[OsString] { - &self.args - } - - pub fn take_args(&mut self) -> Vec { - mem::replace(&mut self.args, Vec::new()) - } - - /// Returns a `true` if we're pretty sure that this'll blow OS spawn limits, - /// or `false` if we should attempt to spawn and see what the OS says. - pub fn very_likely_to_exceed_some_spawn_limit(&self) -> bool { - // We mostly only care about Windows in this method, on Unix the limits - // can be gargantuan anyway so we're pretty unlikely to hit them - if cfg!(unix) { - return false - } - - // Right now LLD doesn't support the `@` syntax of passing an argument - // through files, so regardless of the platform we try to go to the OS - // on this one. - if let Program::Lld(..) = self.program { - return false - } - - // Ok so on Windows to spawn a process is 32,768 characters in its - // command line [1]. Unfortunately we don't actually have access to that - // as it's calculated just before spawning. Instead we perform a - // poor-man's guess as to how long our command line will be. We're - // assuming here that we don't have to escape every character... - // - // Turns out though that `cmd.exe` has even smaller limits, 8192 - // characters [2]. Linkers can often be batch scripts (for example - // Emscripten, Gecko's current build system) which means that we're - // running through batch scripts. These linkers often just forward - // arguments elsewhere (and maybe tack on more), so if we blow 8192 - // bytes we'll typically cause them to blow as well. - // - // Basically as a result just perform an inflated estimate of what our - // command line will look like and test if it's > 8192 (we actually - // test against 6k to artificially inflate our estimate). If all else - // fails we'll fall back to the normal unix logic of testing the OS - // error code if we fail to spawn and automatically re-spawning the - // linker with smaller arguments. - // - // [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx - // [2]: https://blogs.msdn.microsoft.com/oldnewthing/20031210-00/?p=41553 - - let estimated_command_line_len = - self.args.iter().map(|a| a.len()).sum::(); - estimated_command_line_len > 1024 * 6 - } -} - -impl fmt::Debug for Command { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.command().fmt(f) - } -} diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs deleted file mode 100644 index 299075ed03a..00000000000 --- a/src/librustc_trans/back/link.rs +++ /dev/null @@ -1,1626 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use back::wasm; -use cc::windows_registry; -use super::archive::{ArchiveBuilder, ArchiveConfig}; -use super::bytecode::RLIB_BYTECODE_EXTENSION; -use super::linker::Linker; -use super::command::Command; -use super::rpath::RPathConfig; -use super::rpath; -use metadata::METADATA_FILENAME; -use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType, PrintRequest}; -use rustc::session::config::{RUST_CGU_EXT, Lto}; -use rustc::session::filesearch; -use rustc::session::search_paths::PathKind; -use rustc::session::Session; -use rustc::middle::cstore::{NativeLibrary, LibSource, NativeLibraryKind}; -use rustc::middle::dependency_format::Linkage; -use {CrateTranslation, CrateInfo}; -use rustc::util::common::time; -use rustc::util::fs::fix_windows_verbatim_for_gcc; -use rustc::hir::def_id::CrateNum; -use tempdir::TempDir; -use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor, TargetTriple}; -use rustc_data_structures::fx::FxHashSet; -use context::get_reloc_model; -use llvm; - -use std::ascii; -use std::char; -use std::env; -use std::fmt; -use std::fs; -use std::io; -use std::path::{Path, PathBuf}; -use std::process::{Output, Stdio}; -use std::str; -use syntax::attr; - -/// The LLVM module name containing crate-metadata. This includes a `.` on -/// purpose, so it cannot clash with the name of a user-defined module. -pub const METADATA_MODULE_NAME: &'static str = "crate.metadata"; - -// same as for metadata above, but for allocator shim -pub const ALLOCATOR_MODULE_NAME: &'static str = "crate.allocator"; - -pub use rustc_trans_utils::link::{find_crate_name, filename_for_input, default_output_for_target, - invalid_output_for_target, build_link_meta, out_filename, - check_file_is_writeable}; - -// The third parameter is for env vars, used on windows to set up the -// path for MSVC to find its DLLs, and gcc to find its bundled -// toolchain -pub fn get_linker(sess: &Session) -> (PathBuf, Command) { - // If our linker looks like a batch script on Windows then to execute this - // we'll need to spawn `cmd` explicitly. This is primarily done to handle - // emscripten where the linker is `emcc.bat` and needs to be spawned as - // `cmd /c emcc.bat ...`. - // - // This worked historically but is needed manually since #42436 (regression - // was tagged as #42791) and some more info can be found on #44443 for - // emscripten itself. - let cmd = |linker: &Path| { - if let Some(linker) = linker.to_str() { - if cfg!(windows) && linker.ends_with(".bat") { - return Command::bat_script(linker) - } - } - match sess.linker_flavor() { - LinkerFlavor::Lld(f) => Command::lld(linker, f), - _ => Command::new(linker), - - } - }; - - let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe"); - - let linker_path = sess.opts.cg.linker.as_ref().map(|s| &**s) - .or(sess.target.target.options.linker.as_ref().map(|s| s.as_ref())) - .unwrap_or(match sess.linker_flavor() { - LinkerFlavor::Msvc => { - msvc_tool.as_ref().map(|t| t.path()).unwrap_or("link.exe".as_ref()) - } - LinkerFlavor::Em if cfg!(windows) => "emcc.bat".as_ref(), - LinkerFlavor::Em => "emcc".as_ref(), - LinkerFlavor::Gcc => "cc".as_ref(), - LinkerFlavor::Ld => "ld".as_ref(), - LinkerFlavor::Lld(_) => "lld".as_ref(), - }); - - let mut cmd = cmd(linker_path); - - // The compiler's sysroot often has some bundled tools, so add it to the - // PATH for the child. - let mut new_path = sess.host_filesearch(PathKind::All) - .get_tools_search_paths(); - let mut msvc_changed_path = false; - if sess.target.target.options.is_like_msvc { - if let Some(ref tool) = msvc_tool { - cmd.args(tool.args()); - for &(ref k, ref v) in tool.env() { - if k == "PATH" { - new_path.extend(env::split_paths(v)); - msvc_changed_path = true; - } else { - cmd.env(k, v); - } - } - } - } - - if !msvc_changed_path { - if let Some(path) = env::var_os("PATH") { - new_path.extend(env::split_paths(&path)); - } - } - cmd.env("PATH", env::join_paths(new_path).unwrap()); - - (linker_path.to_path_buf(), cmd) -} - -pub fn remove(sess: &Session, path: &Path) { - match fs::remove_file(path) { - Ok(..) => {} - Err(e) => { - sess.err(&format!("failed to remove {}: {}", - path.display(), - e)); - } - } -} - -/// Perform the linkage portion of the compilation phase. This will generate all -/// of the requested outputs for this compilation session. -pub(crate) fn link_binary(sess: &Session, - trans: &CrateTranslation, - outputs: &OutputFilenames, - crate_name: &str) -> Vec { - let mut out_filenames = Vec::new(); - for &crate_type in sess.crate_types.borrow().iter() { - // Ignore executable crates if we have -Z no-trans, as they will error. - let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); - if (sess.opts.debugging_opts.no_trans || !sess.opts.output_types.should_trans()) && - !output_metadata && - crate_type == config::CrateTypeExecutable { - continue; - } - - if invalid_output_for_target(sess, crate_type) { - bug!("invalid output type `{:?}` for target os `{}`", - crate_type, sess.opts.target_triple); - } - let mut out_files = link_binary_output(sess, - trans, - crate_type, - outputs, - crate_name); - out_filenames.append(&mut out_files); - } - - // Remove the temporary object file and metadata if we aren't saving temps - if !sess.opts.cg.save_temps { - if sess.opts.output_types.should_trans() && - !preserve_objects_for_their_debuginfo(sess) - { - for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) { - remove(sess, obj); - } - } - for obj in trans.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) { - remove(sess, obj); - } - if let Some(ref obj) = trans.metadata_module.object { - remove(sess, obj); - } - if let Some(ref allocator) = trans.allocator_module { - if let Some(ref obj) = allocator.object { - remove(sess, obj); - } - if let Some(ref bc) = allocator.bytecode_compressed { - remove(sess, bc); - } - } - } - - out_filenames -} - -/// Returns a boolean indicating whether we should preserve the object files on -/// the filesystem for their debug information. This is often useful with -/// split-dwarf like schemes. -fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool { - // If the objects don't have debuginfo there's nothing to preserve. - if sess.opts.debuginfo == NoDebugInfo { - return false - } - - // If we're only producing artifacts that are archives, no need to preserve - // the objects as they're losslessly contained inside the archives. - let output_linked = sess.crate_types.borrow() - .iter() - .any(|x| *x != config::CrateTypeRlib && *x != config::CrateTypeStaticlib); - if !output_linked { - return false - } - - // If we're on OSX then the equivalent of split dwarf is turned on by - // default. The final executable won't actually have any debug information - // except it'll have pointers to elsewhere. Historically we've always run - // `dsymutil` to "link all the dwarf together" but this is actually sort of - // a bummer for incremental compilation! (the whole point of split dwarf is - // that you don't do this sort of dwarf link). - // - // Basically as a result this just means that if we're on OSX and we're - // *not* running dsymutil then the object files are the only source of truth - // for debug information, so we must preserve them. - if sess.target.target.options.is_like_osx { - match sess.opts.debugging_opts.run_dsymutil { - // dsymutil is not being run, preserve objects - Some(false) => return true, - - // dsymutil is being run, no need to preserve the objects - Some(true) => return false, - - // The default historical behavior was to always run dsymutil, so - // we're preserving that temporarily, but we're likely to switch the - // default soon. - None => return false, - } - } - - false -} - -fn filename_for_metadata(sess: &Session, crate_name: &str, outputs: &OutputFilenames) -> PathBuf { - let out_filename = outputs.single_output_file.clone() - .unwrap_or(outputs - .out_directory - .join(&format!("lib{}{}.rmeta", crate_name, sess.opts.cg.extra_filename))); - check_file_is_writeable(&out_filename, sess); - out_filename -} - -pub(crate) fn each_linked_rlib(sess: &Session, - info: &CrateInfo, - f: &mut FnMut(CrateNum, &Path)) -> Result<(), String> { - let crates = info.used_crates_static.iter(); - let fmts = sess.dependency_formats.borrow(); - let fmts = fmts.get(&config::CrateTypeExecutable) - .or_else(|| fmts.get(&config::CrateTypeStaticlib)) - .or_else(|| fmts.get(&config::CrateTypeCdylib)) - .or_else(|| fmts.get(&config::CrateTypeProcMacro)); - let fmts = match fmts { - Some(f) => f, - None => return Err(format!("could not find formats for rlibs")) - }; - for &(cnum, ref path) in crates { - match fmts.get(cnum.as_usize() - 1) { - Some(&Linkage::NotLinked) | - Some(&Linkage::IncludedFromDylib) => continue, - Some(_) => {} - None => return Err(format!("could not find formats for rlibs")) - } - let name = &info.crate_name[&cnum]; - let path = match *path { - LibSource::Some(ref p) => p, - LibSource::MetadataOnly => { - return Err(format!("could not find rlib for: `{}`, found rmeta (metadata) file", - name)) - } - LibSource::None => { - return Err(format!("could not find rlib for: `{}`", name)) - } - }; - f(cnum, &path); - } - Ok(()) -} - -/// Returns a boolean indicating whether the specified crate should be ignored -/// during LTO. -/// -/// Crates ignored during LTO are not lumped together in the "massive object -/// file" that we create and are linked in their normal rlib states. See -/// comments below for what crates do not participate in LTO. -/// -/// It's unusual for a crate to not participate in LTO. Typically only -/// compiler-specific and unstable crates have a reason to not participate in -/// LTO. -pub(crate) fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool { - // If our target enables builtin function lowering in LLVM then the - // crates providing these functions don't participate in LTO (e.g. - // no_builtins or compiler builtins crates). - !sess.target.target.options.no_builtins && - (info.is_no_builtins.contains(&cnum) || info.compiler_builtins == Some(cnum)) -} - -fn link_binary_output(sess: &Session, - trans: &CrateTranslation, - crate_type: config::CrateType, - outputs: &OutputFilenames, - crate_name: &str) -> Vec { - for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) { - check_file_is_writeable(obj, sess); - } - - let mut out_filenames = vec![]; - - if outputs.outputs.contains_key(&OutputType::Metadata) { - let out_filename = filename_for_metadata(sess, crate_name, outputs); - // To avoid races with another rustc process scanning the output directory, - // we need to write the file somewhere else and atomically move it to its - // final destination, with a `fs::rename` call. In order for the rename to - // always succeed, the temporary file needs to be on the same filesystem, - // which is why we create it inside the output directory specifically. - let metadata_tmpdir = match TempDir::new_in(out_filename.parent().unwrap(), "rmeta") { - Ok(tmpdir) => tmpdir, - Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)), - }; - let metadata = emit_metadata(sess, trans, &metadata_tmpdir); - if let Err(e) = fs::rename(metadata, &out_filename) { - sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); - } - out_filenames.push(out_filename); - } - - let tmpdir = match TempDir::new("rustc") { - Ok(tmpdir) => tmpdir, - Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)), - }; - - if outputs.outputs.should_trans() { - let out_filename = out_filename(sess, crate_type, outputs, crate_name); - match crate_type { - config::CrateTypeRlib => { - link_rlib(sess, - trans, - RlibFlavor::Normal, - &out_filename, - &tmpdir).build(); - } - config::CrateTypeStaticlib => { - link_staticlib(sess, trans, &out_filename, &tmpdir); - } - _ => { - link_natively(sess, crate_type, &out_filename, trans, tmpdir.path()); - } - } - out_filenames.push(out_filename); - } - - if sess.opts.cg.save_temps { - let _ = tmpdir.into_path(); - } - - out_filenames -} - -fn archive_search_paths(sess: &Session) -> Vec { - let mut search = Vec::new(); - sess.target_filesearch(PathKind::Native).for_each_lib_search_path(|path, _| { - search.push(path.to_path_buf()); - }); - return search; -} - -fn archive_config<'a>(sess: &'a Session, - output: &Path, - input: Option<&Path>) -> ArchiveConfig<'a> { - ArchiveConfig { - sess, - dst: output.to_path_buf(), - src: input.map(|p| p.to_path_buf()), - lib_search_paths: archive_search_paths(sess), - } -} - -/// We use a temp directory here to avoid races between concurrent rustc processes, -/// such as builds in the same directory using the same filename for metadata while -/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a -/// directory being searched for `extern crate` (observing an incomplete file). -/// The returned path is the temporary file containing the complete metadata. -fn emit_metadata<'a>(sess: &'a Session, trans: &CrateTranslation, tmpdir: &TempDir) - -> PathBuf { - let out_filename = tmpdir.path().join(METADATA_FILENAME); - let result = fs::write(&out_filename, &trans.metadata.raw_data); - - if let Err(e) = result { - sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); - } - - out_filename -} - -enum RlibFlavor { - Normal, - StaticlibBase, -} - -// Create an 'rlib' -// -// An rlib in its current incarnation is essentially a renamed .a file. The -// rlib primarily contains the object file of the crate, but it also contains -// all of the object files from native libraries. This is done by unzipping -// native libraries and inserting all of the contents into this archive. -fn link_rlib<'a>(sess: &'a Session, - trans: &CrateTranslation, - flavor: RlibFlavor, - out_filename: &Path, - tmpdir: &TempDir) -> ArchiveBuilder<'a> { - info!("preparing rlib to {:?}", out_filename); - let mut ab = ArchiveBuilder::new(archive_config(sess, out_filename, None)); - - for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) { - ab.add_file(obj); - } - - // Note that in this loop we are ignoring the value of `lib.cfg`. That is, - // we may not be configured to actually include a static library if we're - // adding it here. That's because later when we consume this rlib we'll - // decide whether we actually needed the static library or not. - // - // To do this "correctly" we'd need to keep track of which libraries added - // which object files to the archive. We don't do that here, however. The - // #[link(cfg(..))] feature is unstable, though, and only intended to get - // liblibc working. In that sense the check below just indicates that if - // there are any libraries we want to omit object files for at link time we - // just exclude all custom object files. - // - // Eventually if we want to stabilize or flesh out the #[link(cfg(..))] - // feature then we'll need to figure out how to record what objects were - // loaded from the libraries found here and then encode that into the - // metadata of the rlib we're generating somehow. - for lib in trans.crate_info.used_libraries.iter() { - match lib.kind { - NativeLibraryKind::NativeStatic => {} - NativeLibraryKind::NativeStaticNobundle | - NativeLibraryKind::NativeFramework | - NativeLibraryKind::NativeUnknown => continue, - } - ab.add_native_library(&lib.name.as_str()); - } - - // After adding all files to the archive, we need to update the - // symbol table of the archive. - ab.update_symbols(); - - // Note that it is important that we add all of our non-object "magical - // files" *after* all of the object files in the archive. The reason for - // this is as follows: - // - // * When performing LTO, this archive will be modified to remove - // objects from above. The reason for this is described below. - // - // * When the system linker looks at an archive, it will attempt to - // determine the architecture of the archive in order to see whether its - // linkable. - // - // The algorithm for this detection is: iterate over the files in the - // archive. Skip magical SYMDEF names. Interpret the first file as an - // object file. Read architecture from the object file. - // - // * As one can probably see, if "metadata" and "foo.bc" were placed - // before all of the objects, then the architecture of this archive would - // not be correctly inferred once 'foo.o' is removed. - // - // Basically, all this means is that this code should not move above the - // code above. - match flavor { - RlibFlavor::Normal => { - // Instead of putting the metadata in an object file section, rlibs - // contain the metadata in a separate file. - ab.add_file(&emit_metadata(sess, trans, tmpdir)); - - // For LTO purposes, the bytecode of this library is also inserted - // into the archive. - for bytecode in trans.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) { - ab.add_file(bytecode); - } - - // After adding all files to the archive, we need to update the - // symbol table of the archive. This currently dies on macOS (see - // #11162), and isn't necessary there anyway - if !sess.target.target.options.is_like_osx { - ab.update_symbols(); - } - } - - RlibFlavor::StaticlibBase => { - let obj = trans.allocator_module - .as_ref() - .and_then(|m| m.object.as_ref()); - if let Some(obj) = obj { - ab.add_file(obj); - } - } - } - - ab -} - -// Create a static archive -// -// This is essentially the same thing as an rlib, but it also involves adding -// all of the upstream crates' objects into the archive. This will slurp in -// all of the native libraries of upstream dependencies as well. -// -// Additionally, there's no way for us to link dynamic libraries, so we warn -// about all dynamic library dependencies that they're not linked in. -// -// There's no need to include metadata in a static archive, so ensure to not -// link in the metadata object file (and also don't prepare the archive with a -// metadata file). -fn link_staticlib(sess: &Session, - trans: &CrateTranslation, - out_filename: &Path, - tempdir: &TempDir) { - let mut ab = link_rlib(sess, - trans, - RlibFlavor::StaticlibBase, - out_filename, - tempdir); - let mut all_native_libs = vec![]; - - let res = each_linked_rlib(sess, &trans.crate_info, &mut |cnum, path| { - let name = &trans.crate_info.crate_name[&cnum]; - let native_libs = &trans.crate_info.native_libraries[&cnum]; - - // Here when we include the rlib into our staticlib we need to make a - // decision whether to include the extra object files along the way. - // These extra object files come from statically included native - // libraries, but they may be cfg'd away with #[link(cfg(..))]. - // - // This unstable feature, though, only needs liblibc to work. The only - // use case there is where musl is statically included in liblibc.rlib, - // so if we don't want the included version we just need to skip it. As - // a result the logic here is that if *any* linked library is cfg'd away - // we just skip all object files. - // - // Clearly this is not sufficient for a general purpose feature, and - // we'd want to read from the library's metadata to determine which - // object files come from where and selectively skip them. - let skip_object_files = native_libs.iter().any(|lib| { - lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) - }); - ab.add_rlib(path, - &name.as_str(), - is_full_lto_enabled(sess) && - !ignored_for_lto(sess, &trans.crate_info, cnum), - skip_object_files).unwrap(); - - all_native_libs.extend(trans.crate_info.native_libraries[&cnum].iter().cloned()); - }); - if let Err(e) = res { - sess.fatal(&e); - } - - ab.update_symbols(); - ab.build(); - - if !all_native_libs.is_empty() { - if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) { - print_native_static_libs(sess, &all_native_libs); - } - } -} - -fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) { - let lib_args: Vec<_> = all_native_libs.iter() - .filter(|l| relevant_lib(sess, l)) - .filter_map(|lib| match lib.kind { - NativeLibraryKind::NativeStaticNobundle | - NativeLibraryKind::NativeUnknown => { - if sess.target.target.options.is_like_msvc { - Some(format!("{}.lib", lib.name)) - } else { - Some(format!("-l{}", lib.name)) - } - }, - NativeLibraryKind::NativeFramework => { - // ld-only syntax, since there are no frameworks in MSVC - Some(format!("-framework {}", lib.name)) - }, - // These are included, no need to print them - NativeLibraryKind::NativeStatic => None, - }) - .collect(); - if !lib_args.is_empty() { - sess.note_without_error("Link against the following native artifacts when linking \ - against this static library. The order and any duplication \ - can be significant on some platforms."); - // Prefix for greppability - sess.note_without_error(&format!("native-static-libs: {}", &lib_args.join(" "))); - } -} - -// Create a dynamic library or executable -// -// This will invoke the system linker/cc to create the resulting file. This -// links to all upstream files as well. -fn link_natively(sess: &Session, - crate_type: config::CrateType, - out_filename: &Path, - trans: &CrateTranslation, - tmpdir: &Path) { - info!("preparing {:?} to {:?}", crate_type, out_filename); - let flavor = sess.linker_flavor(); - - // The invocations of cc share some flags across platforms - let (pname, mut cmd) = get_linker(sess); - - let root = sess.target_filesearch(PathKind::Native).get_lib_path(); - if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) { - cmd.args(args); - } - if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) { - if sess.crt_static() { - cmd.args(args); - } - } - if let Some(ref args) = sess.opts.debugging_opts.pre_link_args { - cmd.args(args); - } - cmd.args(&sess.opts.debugging_opts.pre_link_arg); - - let pre_link_objects = if crate_type == config::CrateTypeExecutable { - &sess.target.target.options.pre_link_objects_exe - } else { - &sess.target.target.options.pre_link_objects_dll - }; - for obj in pre_link_objects { - cmd.arg(root.join(obj)); - } - - if crate_type == config::CrateTypeExecutable && sess.crt_static() { - for obj in &sess.target.target.options.pre_link_objects_exe_crt { - cmd.arg(root.join(obj)); - } - - for obj in &sess.target.target.options.pre_link_objects_exe_crt_sys { - if flavor == LinkerFlavor::Gcc { - cmd.arg(format!("-l:{}", obj)); - } - } - } - - if sess.target.target.options.is_like_emscripten { - cmd.arg("-s"); - cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort { - "DISABLE_EXCEPTION_CATCHING=1" - } else { - "DISABLE_EXCEPTION_CATCHING=0" - }); - } - - { - let mut linker = trans.linker_info.to_linker(cmd, &sess); - link_args(&mut *linker, sess, crate_type, tmpdir, - out_filename, trans); - cmd = linker.finalize(); - } - if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { - cmd.args(args); - } - for obj in &sess.target.target.options.post_link_objects { - cmd.arg(root.join(obj)); - } - if sess.crt_static() { - for obj in &sess.target.target.options.post_link_objects_crt_sys { - if flavor == LinkerFlavor::Gcc { - cmd.arg(format!("-l:{}", obj)); - } - } - for obj in &sess.target.target.options.post_link_objects_crt { - cmd.arg(root.join(obj)); - } - } - if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) { - cmd.args(args); - } - for &(ref k, ref v) in &sess.target.target.options.link_env { - cmd.env(k, v); - } - - if sess.opts.debugging_opts.print_link_args { - println!("{:?}", &cmd); - } - - // May have not found libraries in the right formats. - sess.abort_if_errors(); - - // Invoke the system linker - // - // Note that there's a terribly awful hack that really shouldn't be present - // in any compiler. Here an environment variable is supported to - // automatically retry the linker invocation if the linker looks like it - // segfaulted. - // - // Gee that seems odd, normally segfaults are things we want to know about! - // Unfortunately though in rust-lang/rust#38878 we're experiencing the - // linker segfaulting on Travis quite a bit which is causing quite a bit of - // pain to land PRs when they spuriously fail due to a segfault. - // - // The issue #38878 has some more debugging information on it as well, but - // this unfortunately looks like it's just a race condition in macOS's linker - // with some thread pool working in the background. It seems that no one - // currently knows a fix for this so in the meantime we're left with this... - info!("{:?}", &cmd); - let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok(); - let mut prog; - let mut i = 0; - loop { - i += 1; - prog = time(sess, "running linker", || { - exec_linker(sess, &mut cmd, out_filename, tmpdir) - }); - let output = match prog { - Ok(ref output) => output, - Err(_) => break, - }; - if output.status.success() { - break - } - let mut out = output.stderr.clone(); - out.extend(&output.stdout); - let out = String::from_utf8_lossy(&out); - - // Check to see if the link failed with "unrecognized command line option: - // '-no-pie'" for gcc or "unknown argument: '-no-pie'" for clang. If so, - // reperform the link step without the -no-pie option. This is safe because - // if the linker doesn't support -no-pie then it should not default to - // linking executables as pie. Different versions of gcc seem to use - // different quotes in the error message so don't check for them. - if sess.target.target.options.linker_is_gnu && - sess.linker_flavor() != LinkerFlavor::Ld && - (out.contains("unrecognized command line option") || - out.contains("unknown argument")) && - out.contains("-no-pie") && - cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie") { - info!("linker output: {:?}", out); - warn!("Linker does not support -no-pie command line option. Retrying without."); - for arg in cmd.take_args() { - if arg.to_string_lossy() != "-no-pie" { - cmd.arg(arg); - } - } - info!("{:?}", &cmd); - continue; - } - if !retry_on_segfault || i > 3 { - break - } - let msg_segv = "clang: error: unable to execute command: Segmentation fault: 11"; - let msg_bus = "clang: error: unable to execute command: Bus error: 10"; - if !(out.contains(msg_segv) || out.contains(msg_bus)) { - break - } - - warn!( - "looks like the linker segfaulted when we tried to call it, \ - automatically retrying again. cmd = {:?}, out = {}.", - cmd, - out, - ); - } - - match prog { - Ok(prog) => { - fn escape_string(s: &[u8]) -> String { - str::from_utf8(s).map(|s| s.to_owned()) - .unwrap_or_else(|_| { - let mut x = "Non-UTF-8 output: ".to_string(); - x.extend(s.iter() - .flat_map(|&b| ascii::escape_default(b)) - .map(|b| char::from_u32(b as u32).unwrap())); - x - }) - } - if !prog.status.success() { - let mut output = prog.stderr.clone(); - output.extend_from_slice(&prog.stdout); - sess.struct_err(&format!("linking with `{}` failed: {}", - pname.display(), - prog.status)) - .note(&format!("{:?}", &cmd)) - .note(&escape_string(&output)) - .emit(); - sess.abort_if_errors(); - } - info!("linker stderr:\n{}", escape_string(&prog.stderr)); - info!("linker stdout:\n{}", escape_string(&prog.stdout)); - }, - Err(e) => { - let linker_not_found = e.kind() == io::ErrorKind::NotFound; - - let mut linker_error = { - if linker_not_found { - sess.struct_err(&format!("linker `{}` not found", pname.display())) - } else { - sess.struct_err(&format!("could not exec the linker `{}`", pname.display())) - } - }; - - linker_error.note(&format!("{}", e)); - - if !linker_not_found { - linker_error.note(&format!("{:?}", &cmd)); - } - - linker_error.emit(); - - if sess.target.target.options.is_like_msvc && linker_not_found { - sess.note_without_error("the msvc targets depend on the msvc linker \ - but `link.exe` was not found"); - sess.note_without_error("please ensure that VS 2013 or VS 2015 was installed \ - with the Visual C++ option"); - } - sess.abort_if_errors(); - } - } - - - // On macOS, debuggers need this utility to get run to do some munging of - // the symbols. Note, though, that if the object files are being preserved - // for their debug information there's no need for us to run dsymutil. - if sess.target.target.options.is_like_osx && - sess.opts.debuginfo != NoDebugInfo && - !preserve_objects_for_their_debuginfo(sess) - { - match Command::new("dsymutil").arg(out_filename).output() { - Ok(..) => {} - Err(e) => sess.fatal(&format!("failed to run dsymutil: {}", e)), - } - } - - if sess.opts.target_triple == TargetTriple::from_triple("wasm32-unknown-unknown") { - wasm::rewrite_imports(&out_filename, &trans.crate_info.wasm_imports); - wasm::add_custom_sections(&out_filename, - &trans.crate_info.wasm_custom_sections); - } -} - -fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: &Path) - -> io::Result -{ - // When attempting to spawn the linker we run a risk of blowing out the - // size limits for spawning a new process with respect to the arguments - // we pass on the command line. - // - // Here we attempt to handle errors from the OS saying "your list of - // arguments is too big" by reinvoking the linker again with an `@`-file - // that contains all the arguments. The theory is that this is then - // accepted on all linkers and the linker will read all its options out of - // there instead of looking at the command line. - if !cmd.very_likely_to_exceed_some_spawn_limit() { - match cmd.command().stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() { - Ok(child) => { - let output = child.wait_with_output(); - flush_linked_file(&output, out_filename)?; - return output; - } - Err(ref e) if command_line_too_big(e) => { - info!("command line to linker was too big: {}", e); - } - Err(e) => return Err(e) - } - } - - info!("falling back to passing arguments to linker via an @-file"); - let mut cmd2 = cmd.clone(); - let mut args = String::new(); - for arg in cmd2.take_args() { - args.push_str(&Escape { - arg: arg.to_str().unwrap(), - is_like_msvc: sess.target.target.options.is_like_msvc, - }.to_string()); - args.push_str("\n"); - } - let file = tmpdir.join("linker-arguments"); - let bytes = if sess.target.target.options.is_like_msvc { - let mut out = vec![]; - // start the stream with a UTF-16 BOM - for c in vec![0xFEFF].into_iter().chain(args.encode_utf16()) { - // encode in little endian - out.push(c as u8); - out.push((c >> 8) as u8); - } - out - } else { - args.into_bytes() - }; - fs::write(&file, &bytes)?; - cmd2.arg(format!("@{}", file.display())); - info!("invoking linker {:?}", cmd2); - let output = cmd2.output(); - flush_linked_file(&output, out_filename)?; - return output; - - #[cfg(unix)] - fn flush_linked_file(_: &io::Result, _: &Path) -> io::Result<()> { - Ok(()) - } - - #[cfg(windows)] - fn flush_linked_file(command_output: &io::Result, out_filename: &Path) - -> io::Result<()> - { - // On Windows, under high I/O load, output buffers are sometimes not flushed, - // even long after process exit, causing nasty, non-reproducible output bugs. - // - // File::sync_all() calls FlushFileBuffers() down the line, which solves the problem. - // - // А full writeup of the original Chrome bug can be found at - // randomascii.wordpress.com/2018/02/25/compiler-bug-linker-bug-windows-kernel-bug/amp - - if let &Ok(ref out) = command_output { - if out.status.success() { - if let Ok(of) = fs::OpenOptions::new().write(true).open(out_filename) { - of.sync_all()?; - } - } - } - - Ok(()) - } - - #[cfg(unix)] - fn command_line_too_big(err: &io::Error) -> bool { - err.raw_os_error() == Some(::libc::E2BIG) - } - - #[cfg(windows)] - fn command_line_too_big(err: &io::Error) -> bool { - const ERROR_FILENAME_EXCED_RANGE: i32 = 206; - err.raw_os_error() == Some(ERROR_FILENAME_EXCED_RANGE) - } - - struct Escape<'a> { - arg: &'a str, - is_like_msvc: bool, - } - - impl<'a> fmt::Display for Escape<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.is_like_msvc { - // This is "documented" at - // https://msdn.microsoft.com/en-us/library/4xdcbak7.aspx - // - // Unfortunately there's not a great specification of the - // syntax I could find online (at least) but some local - // testing showed that this seemed sufficient-ish to catch - // at least a few edge cases. - write!(f, "\"")?; - for c in self.arg.chars() { - match c { - '"' => write!(f, "\\{}", c)?, - c => write!(f, "{}", c)?, - } - } - write!(f, "\"")?; - } else { - // This is documented at https://linux.die.net/man/1/ld, namely: - // - // > Options in file are separated by whitespace. A whitespace - // > character may be included in an option by surrounding the - // > entire option in either single or double quotes. Any - // > character (including a backslash) may be included by - // > prefixing the character to be included with a backslash. - // - // We put an argument on each line, so all we need to do is - // ensure the line is interpreted as one whole argument. - for c in self.arg.chars() { - match c { - '\\' | - ' ' => write!(f, "\\{}", c)?, - c => write!(f, "{}", c)?, - } - } - } - Ok(()) - } - } -} - -fn link_args(cmd: &mut Linker, - sess: &Session, - crate_type: config::CrateType, - tmpdir: &Path, - out_filename: &Path, - trans: &CrateTranslation) { - - // Linker plugins should be specified early in the list of arguments - cmd.cross_lang_lto(); - - // The default library location, we need this to find the runtime. - // The location of crates will be determined as needed. - let lib_path = sess.target_filesearch(PathKind::All).get_lib_path(); - - // target descriptor - let t = &sess.target.target; - - cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); - for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) { - cmd.add_object(obj); - } - cmd.output_filename(out_filename); - - if crate_type == config::CrateTypeExecutable && - sess.target.target.options.is_like_windows { - if let Some(ref s) = trans.windows_subsystem { - cmd.subsystem(s); - } - } - - // If we're building a dynamic library then some platforms need to make sure - // that all symbols are exported correctly from the dynamic library. - if crate_type != config::CrateTypeExecutable || - sess.target.target.options.is_like_emscripten { - cmd.export_symbols(tmpdir, crate_type); - } - - // When linking a dynamic library, we put the metadata into a section of the - // executable. This metadata is in a separate object file from the main - // object file, so we link that in here. - if crate_type == config::CrateTypeDylib || - crate_type == config::CrateTypeProcMacro { - if let Some(obj) = trans.metadata_module.object.as_ref() { - cmd.add_object(obj); - } - } - - let obj = trans.allocator_module - .as_ref() - .and_then(|m| m.object.as_ref()); - if let Some(obj) = obj { - cmd.add_object(obj); - } - - // Try to strip as much out of the generated object by removing unused - // sections if possible. See more comments in linker.rs - if !sess.opts.cg.link_dead_code { - let keep_metadata = crate_type == config::CrateTypeDylib; - cmd.gc_sections(keep_metadata); - } - - let used_link_args = &trans.crate_info.link_args; - - if crate_type == config::CrateTypeExecutable { - let mut position_independent_executable = false; - - if t.options.position_independent_executables { - let empty_vec = Vec::new(); - let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec); - let more_args = &sess.opts.cg.link_arg; - let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter()); - - if get_reloc_model(sess) == llvm::RelocMode::PIC - && !sess.crt_static() && !args.any(|x| *x == "-static") { - position_independent_executable = true; - } - } - - if position_independent_executable { - cmd.position_independent_executable(); - } else { - // recent versions of gcc can be configured to generate position - // independent executables by default. We have to pass -no-pie to - // explicitly turn that off. Not applicable to ld. - if sess.target.target.options.linker_is_gnu - && sess.linker_flavor() != LinkerFlavor::Ld { - cmd.no_position_independent_executable(); - } - } - } - - let relro_level = match sess.opts.debugging_opts.relro_level { - Some(level) => level, - None => t.options.relro_level, - }; - match relro_level { - RelroLevel::Full => { - cmd.full_relro(); - }, - RelroLevel::Partial => { - cmd.partial_relro(); - }, - RelroLevel::Off => { - cmd.no_relro(); - }, - RelroLevel::None => { - }, - } - - // Pass optimization flags down to the linker. - cmd.optimize(); - - // Pass debuginfo flags down to the linker. - cmd.debuginfo(); - - // We want to prevent the compiler from accidentally leaking in any system - // libraries, so we explicitly ask gcc to not link to any libraries by - // default. Note that this does not happen for windows because windows pulls - // in some large number of libraries and I couldn't quite figure out which - // subset we wanted. - if t.options.no_default_libraries { - cmd.no_default_libraries(); - } - - // Take careful note of the ordering of the arguments we pass to the linker - // here. Linkers will assume that things on the left depend on things to the - // right. Things on the right cannot depend on things on the left. This is - // all formally implemented in terms of resolving symbols (libs on the right - // resolve unknown symbols of libs on the left, but not vice versa). - // - // For this reason, we have organized the arguments we pass to the linker as - // such: - // - // 1. The local object that LLVM just generated - // 2. Local native libraries - // 3. Upstream rust libraries - // 4. Upstream native libraries - // - // The rationale behind this ordering is that those items lower down in the - // list can't depend on items higher up in the list. For example nothing can - // depend on what we just generated (e.g. that'd be a circular dependency). - // Upstream rust libraries are not allowed to depend on our local native - // libraries as that would violate the structure of the DAG, in that - // scenario they are required to link to them as well in a shared fashion. - // - // Note that upstream rust libraries may contain native dependencies as - // well, but they also can't depend on what we just started to add to the - // link line. And finally upstream native libraries can't depend on anything - // in this DAG so far because they're only dylibs and dylibs can only depend - // on other dylibs (e.g. other native deps). - add_local_native_libraries(cmd, sess, trans); - add_upstream_rust_crates(cmd, sess, trans, crate_type, tmpdir); - add_upstream_native_libraries(cmd, sess, trans, crate_type); - - // Tell the linker what we're doing. - if crate_type != config::CrateTypeExecutable { - cmd.build_dylib(out_filename); - } - if crate_type == config::CrateTypeExecutable && sess.crt_static() { - cmd.build_static_executable(); - } - - if sess.opts.debugging_opts.pgo_gen.is_some() { - cmd.pgo_gen(); - } - - // FIXME (#2397): At some point we want to rpath our guesses as to - // where extern libraries might live, based on the - // addl_lib_search_paths - if sess.opts.cg.rpath { - let sysroot = sess.sysroot(); - let target_triple = sess.opts.target_triple.triple(); - let mut get_install_prefix_lib_path = || { - let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX"); - let tlib = filesearch::relative_target_lib_path(sysroot, target_triple); - let mut path = PathBuf::from(install_prefix); - path.push(&tlib); - - path - }; - let mut rpath_config = RPathConfig { - used_crates: &trans.crate_info.used_crates_dynamic, - out_filename: out_filename.to_path_buf(), - has_rpath: sess.target.target.options.has_rpath, - is_like_osx: sess.target.target.options.is_like_osx, - linker_is_gnu: sess.target.target.options.linker_is_gnu, - get_install_prefix_lib_path: &mut get_install_prefix_lib_path, - }; - cmd.args(&rpath::get_rpath_flags(&mut rpath_config)); - } - - // Finally add all the linker arguments provided on the command line along - // with any #[link_args] attributes found inside the crate - if let Some(ref args) = sess.opts.cg.link_args { - cmd.args(args); - } - cmd.args(&sess.opts.cg.link_arg); - cmd.args(&used_link_args); -} - -// # Native library linking -// -// User-supplied library search paths (-L on the command line). These are -// the same paths used to find Rust crates, so some of them may have been -// added already by the previous crate linking code. This only allows them -// to be found at compile time so it is still entirely up to outside -// forces to make sure that library can be found at runtime. -// -// Also note that the native libraries linked here are only the ones located -// in the current crate. Upstream crates with native library dependencies -// may have their native library pulled in above. -fn add_local_native_libraries(cmd: &mut Linker, - sess: &Session, - trans: &CrateTranslation) { - sess.target_filesearch(PathKind::All).for_each_lib_search_path(|path, k| { - match k { - PathKind::Framework => { cmd.framework_path(path); } - _ => { cmd.include_path(&fix_windows_verbatim_for_gcc(path)); } - } - }); - - let relevant_libs = trans.crate_info.used_libraries.iter().filter(|l| { - relevant_lib(sess, l) - }); - - let search_path = archive_search_paths(sess); - for lib in relevant_libs { - match lib.kind { - NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()), - NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()), - NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&lib.name.as_str()), - NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&lib.name.as_str(), - &search_path) - } - } -} - -// # Rust Crate linking -// -// Rust crates are not considered at all when creating an rlib output. All -// dependencies will be linked when producing the final output (instead of -// the intermediate rlib version) -fn add_upstream_rust_crates(cmd: &mut Linker, - sess: &Session, - trans: &CrateTranslation, - crate_type: config::CrateType, - tmpdir: &Path) { - // All of the heavy lifting has previously been accomplished by the - // dependency_format module of the compiler. This is just crawling the - // output of that module, adding crates as necessary. - // - // Linking to a rlib involves just passing it to the linker (the linker - // will slurp up the object files inside), and linking to a dynamic library - // involves just passing the right -l flag. - - let formats = sess.dependency_formats.borrow(); - let data = formats.get(&crate_type).unwrap(); - - // Invoke get_used_crates to ensure that we get a topological sorting of - // crates. - let deps = &trans.crate_info.used_crates_dynamic; - - // There's a few internal crates in the standard library (aka libcore and - // libstd) which actually have a circular dependence upon one another. This - // currently arises through "weak lang items" where libcore requires things - // like `rust_begin_unwind` but libstd ends up defining it. To get this - // circular dependence to work correctly in all situations we'll need to be - // sure to correctly apply the `--start-group` and `--end-group` options to - // GNU linkers, otherwise if we don't use any other symbol from the standard - // library it'll get discarded and the whole application won't link. - // - // In this loop we're calculating the `group_end`, after which crate to - // pass `--end-group` and `group_start`, before which crate to pass - // `--start-group`. We currently do this by passing `--end-group` after - // the first crate (when iterating backwards) that requires a lang item - // defined somewhere else. Once that's set then when we've defined all the - // necessary lang items we'll pass `--start-group`. - // - // Note that this isn't amazing logic for now but it should do the trick - // for the current implementation of the standard library. - let mut group_end = None; - let mut group_start = None; - let mut end_with = FxHashSet(); - let info = &trans.crate_info; - for &(cnum, _) in deps.iter().rev() { - if let Some(missing) = info.missing_lang_items.get(&cnum) { - end_with.extend(missing.iter().cloned()); - if end_with.len() > 0 && group_end.is_none() { - group_end = Some(cnum); - } - } - end_with.retain(|item| info.lang_item_to_crate.get(item) != Some(&cnum)); - if end_with.len() == 0 && group_end.is_some() { - group_start = Some(cnum); - break - } - } - - // If we didn't end up filling in all lang items from upstream crates then - // we'll be filling it in with our crate. This probably means we're the - // standard library itself, so skip this for now. - if group_end.is_some() && group_start.is_none() { - group_end = None; - } - - let mut compiler_builtins = None; - - for &(cnum, _) in deps.iter() { - if group_start == Some(cnum) { - cmd.group_start(); - } - - // We may not pass all crates through to the linker. Some crates may - // appear statically in an existing dylib, meaning we'll pick up all the - // symbols from the dylib. - let src = &trans.crate_info.used_crate_source[&cnum]; - match data[cnum.as_usize() - 1] { - _ if trans.crate_info.profiler_runtime == Some(cnum) => { - add_static_crate(cmd, sess, trans, tmpdir, crate_type, cnum); - } - _ if trans.crate_info.sanitizer_runtime == Some(cnum) => { - link_sanitizer_runtime(cmd, sess, trans, tmpdir, cnum); - } - // compiler-builtins are always placed last to ensure that they're - // linked correctly. - _ if trans.crate_info.compiler_builtins == Some(cnum) => { - assert!(compiler_builtins.is_none()); - compiler_builtins = Some(cnum); - } - Linkage::NotLinked | - Linkage::IncludedFromDylib => {} - Linkage::Static => { - add_static_crate(cmd, sess, trans, tmpdir, crate_type, cnum); - } - Linkage::Dynamic => { - add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0) - } - } - - if group_end == Some(cnum) { - cmd.group_end(); - } - } - - // compiler-builtins are always placed last to ensure that they're - // linked correctly. - // We must always link the `compiler_builtins` crate statically. Even if it - // was already "included" in a dylib (e.g. `libstd` when `-C prefer-dynamic` - // is used) - if let Some(cnum) = compiler_builtins { - add_static_crate(cmd, sess, trans, tmpdir, crate_type, cnum); - } - - // Converts a library file-stem into a cc -l argument - fn unlib<'a>(config: &config::Config, stem: &'a str) -> &'a str { - if stem.starts_with("lib") && !config.target.options.is_like_windows { - &stem[3..] - } else { - stem - } - } - - // We must link the sanitizer runtime using -Wl,--whole-archive but since - // it's packed in a .rlib, it contains stuff that are not objects that will - // make the linker error. So we must remove those bits from the .rlib before - // linking it. - fn link_sanitizer_runtime(cmd: &mut Linker, - sess: &Session, - trans: &CrateTranslation, - tmpdir: &Path, - cnum: CrateNum) { - let src = &trans.crate_info.used_crate_source[&cnum]; - let cratepath = &src.rlib.as_ref().unwrap().0; - - if sess.target.target.options.is_like_osx { - // On Apple platforms, the sanitizer is always built as a dylib, and - // LLVM will link to `@rpath/*.dylib`, so we need to specify an - // rpath to the library as well (the rpath should be absolute, see - // PR #41352 for details). - // - // FIXME: Remove this logic into librustc_*san once Cargo supports it - let rpath = cratepath.parent().unwrap(); - let rpath = rpath.to_str().expect("non-utf8 component in path"); - cmd.args(&["-Wl,-rpath".into(), "-Xlinker".into(), rpath.into()]); - } - - let dst = tmpdir.join(cratepath.file_name().unwrap()); - let cfg = archive_config(sess, &dst, Some(cratepath)); - let mut archive = ArchiveBuilder::new(cfg); - archive.update_symbols(); - - for f in archive.src_files() { - if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME { - archive.remove_file(&f); - continue - } - } - - archive.build(); - - cmd.link_whole_rlib(&dst); - } - - // Adds the static "rlib" versions of all crates to the command line. - // There's a bit of magic which happens here specifically related to LTO and - // dynamic libraries. Specifically: - // - // * For LTO, we remove upstream object files. - // * For dylibs we remove metadata and bytecode from upstream rlibs - // - // When performing LTO, almost(*) all of the bytecode from the upstream - // libraries has already been included in our object file output. As a - // result we need to remove the object files in the upstream libraries so - // the linker doesn't try to include them twice (or whine about duplicate - // symbols). We must continue to include the rest of the rlib, however, as - // it may contain static native libraries which must be linked in. - // - // (*) Crates marked with `#![no_builtins]` don't participate in LTO and - // their bytecode wasn't included. The object files in those libraries must - // still be passed to the linker. - // - // When making a dynamic library, linkers by default don't include any - // object files in an archive if they're not necessary to resolve the link. - // We basically want to convert the archive (rlib) to a dylib, though, so we - // *do* want everything included in the output, regardless of whether the - // linker thinks it's needed or not. As a result we must use the - // --whole-archive option (or the platform equivalent). When using this - // option the linker will fail if there are non-objects in the archive (such - // as our own metadata and/or bytecode). All in all, for rlibs to be - // entirely included in dylibs, we need to remove all non-object files. - // - // Note, however, that if we're not doing LTO or we're not producing a dylib - // (aka we're making an executable), we can just pass the rlib blindly to - // the linker (fast) because it's fine if it's not actually included as - // we're at the end of the dependency chain. - fn add_static_crate(cmd: &mut Linker, - sess: &Session, - trans: &CrateTranslation, - tmpdir: &Path, - crate_type: config::CrateType, - cnum: CrateNum) { - let src = &trans.crate_info.used_crate_source[&cnum]; - let cratepath = &src.rlib.as_ref().unwrap().0; - - // See the comment above in `link_staticlib` and `link_rlib` for why if - // there's a static library that's not relevant we skip all object - // files. - let native_libs = &trans.crate_info.native_libraries[&cnum]; - let skip_native = native_libs.iter().any(|lib| { - lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) - }); - - if (!is_full_lto_enabled(sess) || - ignored_for_lto(sess, &trans.crate_info, cnum)) && - crate_type != config::CrateTypeDylib && - !skip_native { - cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); - return - } - - let dst = tmpdir.join(cratepath.file_name().unwrap()); - let name = cratepath.file_name().unwrap().to_str().unwrap(); - let name = &name[3..name.len() - 5]; // chop off lib/.rlib - - time(sess, &format!("altering {}.rlib", name), || { - let cfg = archive_config(sess, &dst, Some(cratepath)); - let mut archive = ArchiveBuilder::new(cfg); - archive.update_symbols(); - - let mut any_objects = false; - for f in archive.src_files() { - if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME { - archive.remove_file(&f); - continue - } - - let canonical = f.replace("-", "_"); - let canonical_name = name.replace("-", "_"); - - // Look for `.rcgu.o` at the end of the filename to conclude - // that this is a Rust-related object file. - fn looks_like_rust(s: &str) -> bool { - let path = Path::new(s); - let ext = path.extension().and_then(|s| s.to_str()); - if ext != Some(OutputType::Object.extension()) { - return false - } - let ext2 = path.file_stem() - .and_then(|s| Path::new(s).extension()) - .and_then(|s| s.to_str()); - ext2 == Some(RUST_CGU_EXT) - } - - let is_rust_object = - canonical.starts_with(&canonical_name) && - looks_like_rust(&f); - - // If we've been requested to skip all native object files - // (those not generated by the rust compiler) then we can skip - // this file. See above for why we may want to do this. - let skip_because_cfg_say_so = skip_native && !is_rust_object; - - // If we're performing LTO and this is a rust-generated object - // file, then we don't need the object file as it's part of the - // LTO module. Note that `#![no_builtins]` is excluded from LTO, - // though, so we let that object file slide. - let skip_because_lto = is_full_lto_enabled(sess) && - is_rust_object && - (sess.target.target.options.no_builtins || - !trans.crate_info.is_no_builtins.contains(&cnum)); - - if skip_because_cfg_say_so || skip_because_lto { - archive.remove_file(&f); - } else { - any_objects = true; - } - } - - if !any_objects { - return - } - archive.build(); - - // If we're creating a dylib, then we need to include the - // whole of each object in our archive into that artifact. This is - // because a `dylib` can be reused as an intermediate artifact. - // - // Note, though, that we don't want to include the whole of a - // compiler-builtins crate (e.g. compiler-rt) because it'll get - // repeatedly linked anyway. - if crate_type == config::CrateTypeDylib && - trans.crate_info.compiler_builtins != Some(cnum) { - cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst)); - } else { - cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst)); - } - }); - } - - // Same thing as above, but for dynamic crates instead of static crates. - fn add_dynamic_crate(cmd: &mut Linker, sess: &Session, cratepath: &Path) { - // If we're performing LTO, then it should have been previously required - // that all upstream rust dependencies were available in an rlib format. - assert!(!is_full_lto_enabled(sess)); - - // Just need to tell the linker about where the library lives and - // what its name is - let parent = cratepath.parent(); - if let Some(dir) = parent { - cmd.include_path(&fix_windows_verbatim_for_gcc(dir)); - } - let filestem = cratepath.file_stem().unwrap().to_str().unwrap(); - cmd.link_rust_dylib(&unlib(&sess.target, filestem), - parent.unwrap_or(Path::new(""))); - } -} - -// Link in all of our upstream crates' native dependencies. Remember that -// all of these upstream native dependencies are all non-static -// dependencies. We've got two cases then: -// -// 1. The upstream crate is an rlib. In this case we *must* link in the -// native dependency because the rlib is just an archive. -// -// 2. The upstream crate is a dylib. In order to use the dylib, we have to -// have the dependency present on the system somewhere. Thus, we don't -// gain a whole lot from not linking in the dynamic dependency to this -// crate as well. -// -// The use case for this is a little subtle. In theory the native -// dependencies of a crate are purely an implementation detail of the crate -// itself, but the problem arises with generic and inlined functions. If a -// generic function calls a native function, then the generic function must -// be instantiated in the target crate, meaning that the native symbol must -// also be resolved in the target crate. -fn add_upstream_native_libraries(cmd: &mut Linker, - sess: &Session, - trans: &CrateTranslation, - crate_type: config::CrateType) { - // Be sure to use a topological sorting of crates because there may be - // interdependencies between native libraries. When passing -nodefaultlibs, - // for example, almost all native libraries depend on libc, so we have to - // make sure that's all the way at the right (liblibc is near the base of - // the dependency chain). - // - // This passes RequireStatic, but the actual requirement doesn't matter, - // we're just getting an ordering of crate numbers, we're not worried about - // the paths. - let formats = sess.dependency_formats.borrow(); - let data = formats.get(&crate_type).unwrap(); - - let crates = &trans.crate_info.used_crates_static; - for &(cnum, _) in crates { - for lib in trans.crate_info.native_libraries[&cnum].iter() { - if !relevant_lib(sess, &lib) { - continue - } - match lib.kind { - NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()), - NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()), - NativeLibraryKind::NativeStaticNobundle => { - // Link "static-nobundle" native libs only if the crate they originate from - // is being linked statically to the current crate. If it's linked dynamically - // or is an rlib already included via some other dylib crate, the symbols from - // native libs will have already been included in that dylib. - if data[cnum.as_usize() - 1] == Linkage::Static { - cmd.link_staticlib(&lib.name.as_str()) - } - }, - // ignore statically included native libraries here as we've - // already included them when we included the rust library - // previously - NativeLibraryKind::NativeStatic => {} - } - } - } -} - -fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { - match lib.cfg { - Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None), - None => true, - } -} - -fn is_full_lto_enabled(sess: &Session) -> bool { - match sess.lto() { - Lto::Yes | - Lto::Thin | - Lto::Fat => true, - Lto::No | - Lto::ThinLocal => false, - } -} diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs deleted file mode 100644 index 2a84ffe79b2..00000000000 --- a/src/librustc_trans/back/linker.rs +++ /dev/null @@ -1,1037 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::collections::HashMap; -use std::ffi::{OsStr, OsString}; -use std::fs::{self, File}; -use std::io::prelude::*; -use std::io::{self, BufWriter}; -use std::path::{Path, PathBuf}; - -use back::archive; -use back::command::Command; -use back::symbol_export; -use rustc::hir::def_id::{LOCAL_CRATE, CrateNum}; -use rustc::middle::dependency_format::Linkage; -use rustc::session::Session; -use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel, - CrossLangLto}; -use rustc::ty::TyCtxt; -use rustc_target::spec::{LinkerFlavor, LldFlavor}; -use serialize::{json, Encoder}; - -/// For all the linkers we support, and information they might -/// need out of the shared crate context before we get rid of it. -pub struct LinkerInfo { - exports: HashMap>, -} - -impl LinkerInfo { - pub fn new(tcx: TyCtxt) -> LinkerInfo { - LinkerInfo { - exports: tcx.sess.crate_types.borrow().iter().map(|&c| { - (c, exported_symbols(tcx, c)) - }).collect(), - } - } - - pub fn to_linker<'a>(&'a self, - cmd: Command, - sess: &'a Session) -> Box { - match sess.linker_flavor() { - LinkerFlavor::Lld(LldFlavor::Link) | - LinkerFlavor::Msvc => { - Box::new(MsvcLinker { - cmd, - sess, - info: self - }) as Box - } - LinkerFlavor::Em => { - Box::new(EmLinker { - cmd, - sess, - info: self - }) as Box - } - LinkerFlavor::Gcc => { - Box::new(GccLinker { - cmd, - sess, - info: self, - hinted_static: false, - is_ld: false, - }) as Box - } - - LinkerFlavor::Lld(LldFlavor::Ld) | - LinkerFlavor::Lld(LldFlavor::Ld64) | - LinkerFlavor::Ld => { - Box::new(GccLinker { - cmd, - sess, - info: self, - hinted_static: false, - is_ld: true, - }) as Box - } - - LinkerFlavor::Lld(LldFlavor::Wasm) => { - Box::new(WasmLd { - cmd, - }) as Box - } - } - } -} - -/// Linker abstraction used by back::link to build up the command to invoke a -/// linker. -/// -/// This trait is the total list of requirements needed by `back::link` and -/// represents the meaning of each option being passed down. This trait is then -/// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an -/// MSVC linker (e.g. `link.exe`) is being used. -pub trait Linker { - fn link_dylib(&mut self, lib: &str); - fn link_rust_dylib(&mut self, lib: &str, path: &Path); - fn link_framework(&mut self, framework: &str); - fn link_staticlib(&mut self, lib: &str); - fn link_rlib(&mut self, lib: &Path); - fn link_whole_rlib(&mut self, lib: &Path); - fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]); - fn include_path(&mut self, path: &Path); - fn framework_path(&mut self, path: &Path); - fn output_filename(&mut self, path: &Path); - fn add_object(&mut self, path: &Path); - fn gc_sections(&mut self, keep_metadata: bool); - fn position_independent_executable(&mut self); - fn no_position_independent_executable(&mut self); - fn full_relro(&mut self); - fn partial_relro(&mut self); - fn no_relro(&mut self); - fn optimize(&mut self); - fn pgo_gen(&mut self); - fn debuginfo(&mut self); - fn no_default_libraries(&mut self); - fn build_dylib(&mut self, out_filename: &Path); - fn build_static_executable(&mut self); - fn args(&mut self, args: &[String]); - fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType); - fn subsystem(&mut self, subsystem: &str); - fn group_start(&mut self); - fn group_end(&mut self); - fn cross_lang_lto(&mut self); - // Should have been finalize(self), but we don't support self-by-value on trait objects (yet?). - fn finalize(&mut self) -> Command; -} - -pub struct GccLinker<'a> { - cmd: Command, - sess: &'a Session, - info: &'a LinkerInfo, - hinted_static: bool, // Keeps track of the current hinting mode. - // Link as ld - is_ld: bool, -} - -impl<'a> GccLinker<'a> { - /// Argument that must be passed *directly* to the linker - /// - /// These arguments need to be prepended with '-Wl,' when a gcc-style linker is used - fn linker_arg(&mut self, arg: S) -> &mut Self - where S: AsRef - { - if !self.is_ld { - let mut os = OsString::from("-Wl,"); - os.push(arg.as_ref()); - self.cmd.arg(os); - } else { - self.cmd.arg(arg); - } - self - } - - fn takes_hints(&self) -> bool { - !self.sess.target.target.options.is_like_osx - } - - // Some platforms take hints about whether a library is static or dynamic. - // For those that support this, we ensure we pass the option if the library - // was flagged "static" (most defaults are dynamic) to ensure that if - // libfoo.a and libfoo.so both exist that the right one is chosen. - fn hint_static(&mut self) { - if !self.takes_hints() { return } - if !self.hinted_static { - self.linker_arg("-Bstatic"); - self.hinted_static = true; - } - } - - fn hint_dynamic(&mut self) { - if !self.takes_hints() { return } - if self.hinted_static { - self.linker_arg("-Bdynamic"); - self.hinted_static = false; - } - } -} - -impl<'a> Linker for GccLinker<'a> { - fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg("-l").arg(lib); } - fn link_staticlib(&mut self, lib: &str) { self.hint_static(); self.cmd.arg("-l").arg(lib); } - fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); } - fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); } - fn framework_path(&mut self, path: &Path) { self.cmd.arg("-F").arg(path); } - fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); } - fn add_object(&mut self, path: &Path) { self.cmd.arg(path); } - fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); } - fn no_position_independent_executable(&mut self) { self.cmd.arg("-no-pie"); } - fn full_relro(&mut self) { self.linker_arg("-z,relro,-z,now"); } - fn partial_relro(&mut self) { self.linker_arg("-z,relro"); } - fn no_relro(&mut self) { self.linker_arg("-z,norelro"); } - fn build_static_executable(&mut self) { self.cmd.arg("-static"); } - fn args(&mut self, args: &[String]) { self.cmd.args(args); } - - fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { - self.hint_dynamic(); - self.cmd.arg("-l").arg(lib); - } - - fn link_framework(&mut self, framework: &str) { - self.hint_dynamic(); - self.cmd.arg("-framework").arg(framework); - } - - // Here we explicitly ask that the entire archive is included into the - // result artifact. For more details see #15460, but the gist is that - // the linker will strip away any unused objects in the archive if we - // don't otherwise explicitly reference them. This can occur for - // libraries which are just providing bindings, libraries with generic - // functions, etc. - fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]) { - self.hint_static(); - let target = &self.sess.target.target; - if !target.options.is_like_osx { - self.linker_arg("--whole-archive").cmd.arg("-l").arg(lib); - self.linker_arg("--no-whole-archive"); - } else { - // -force_load is the macOS equivalent of --whole-archive, but it - // involves passing the full path to the library to link. - let mut v = OsString::from("-force_load,"); - v.push(&archive::find_library(lib, search_path, &self.sess)); - self.linker_arg(&v); - } - } - - fn link_whole_rlib(&mut self, lib: &Path) { - self.hint_static(); - if self.sess.target.target.options.is_like_osx { - let mut v = OsString::from("-force_load,"); - v.push(lib); - self.linker_arg(&v); - } else { - self.linker_arg("--whole-archive").cmd.arg(lib); - self.linker_arg("--no-whole-archive"); - } - } - - fn gc_sections(&mut self, keep_metadata: bool) { - // The dead_strip option to the linker specifies that functions and data - // unreachable by the entry point will be removed. This is quite useful - // with Rust's compilation model of compiling libraries at a time into - // one object file. For example, this brings hello world from 1.7MB to - // 458K. - // - // Note that this is done for both executables and dynamic libraries. We - // won't get much benefit from dylibs because LLVM will have already - // stripped away as much as it could. This has not been seen to impact - // link times negatively. - // - // -dead_strip can't be part of the pre_link_args because it's also used - // for partial linking when using multiple codegen units (-r). So we - // insert it here. - if self.sess.target.target.options.is_like_osx { - self.linker_arg("-dead_strip"); - } else if self.sess.target.target.options.is_like_solaris { - self.linker_arg("-z"); - self.linker_arg("ignore"); - - // If we're building a dylib, we don't use --gc-sections because LLVM - // has already done the best it can do, and we also don't want to - // eliminate the metadata. If we're building an executable, however, - // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67% - // reduction. - } else if !keep_metadata { - self.linker_arg("--gc-sections"); - } - } - - fn optimize(&mut self) { - if !self.sess.target.target.options.linker_is_gnu { return } - - // GNU-style linkers support optimization with -O. GNU ld doesn't - // need a numeric argument, but other linkers do. - if self.sess.opts.optimize == config::OptLevel::Default || - self.sess.opts.optimize == config::OptLevel::Aggressive { - self.linker_arg("-O1"); - } - } - - fn pgo_gen(&mut self) { - if !self.sess.target.target.options.linker_is_gnu { return } - - // If we're doing PGO generation stuff and on a GNU-like linker, use the - // "-u" flag to properly pull in the profiler runtime bits. - // - // This is because LLVM otherwise won't add the needed initialization - // for us on Linux (though the extra flag should be harmless if it - // does). - // - // See https://reviews.llvm.org/D14033 and https://reviews.llvm.org/D14030. - // - // Though it may be worth to try to revert those changes upstream, since - // the overhead of the initialization should be minor. - self.cmd.arg("-u"); - self.cmd.arg("__llvm_profile_runtime"); - } - - fn debuginfo(&mut self) { - match self.sess.opts.debuginfo { - DebugInfoLevel::NoDebugInfo => { - // If we are building without debuginfo enabled and we were called with - // `-Zstrip-debuginfo-if-disabled=yes`, tell the linker to strip any debuginfo - // found when linking to get rid of symbols from libstd. - match self.sess.opts.debugging_opts.strip_debuginfo_if_disabled { - Some(true) => { self.linker_arg("-S"); }, - _ => {}, - } - }, - _ => {}, - }; - } - - fn no_default_libraries(&mut self) { - if !self.is_ld { - self.cmd.arg("-nodefaultlibs"); - } - } - - fn build_dylib(&mut self, out_filename: &Path) { - // On mac we need to tell the linker to let this library be rpathed - if self.sess.target.target.options.is_like_osx { - self.cmd.arg("-dynamiclib"); - self.linker_arg("-dylib"); - - // Note that the `osx_rpath_install_name` option here is a hack - // purely to support rustbuild right now, we should get a more - // principled solution at some point to force the compiler to pass - // the right `-Wl,-install_name` with an `@rpath` in it. - if self.sess.opts.cg.rpath || - self.sess.opts.debugging_opts.osx_rpath_install_name { - let mut v = OsString::from("-install_name,@rpath/"); - v.push(out_filename.file_name().unwrap()); - self.linker_arg(&v); - } - } else { - self.cmd.arg("-shared"); - } - } - - fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) { - // If we're compiling a dylib, then we let symbol visibility in object - // files to take care of whether they're exported or not. - // - // If we're compiling a cdylib, however, we manually create a list of - // exported symbols to ensure we don't expose any more. The object files - // have far more public symbols than we actually want to export, so we - // hide them all here. - if crate_type == CrateType::CrateTypeDylib || - crate_type == CrateType::CrateTypeProcMacro { - return - } - - let mut arg = OsString::new(); - let path = tmpdir.join("list"); - - debug!("EXPORTED SYMBOLS:"); - - if self.sess.target.target.options.is_like_osx { - // Write a plain, newline-separated list of symbols - let res = (|| -> io::Result<()> { - let mut f = BufWriter::new(File::create(&path)?); - for sym in self.info.exports[&crate_type].iter() { - debug!(" _{}", sym); - writeln!(f, "_{}", sym)?; - } - Ok(()) - })(); - if let Err(e) = res { - self.sess.fatal(&format!("failed to write lib.def file: {}", e)); - } - } else { - // Write an LD version script - let res = (|| -> io::Result<()> { - let mut f = BufWriter::new(File::create(&path)?); - writeln!(f, "{{\n global:")?; - for sym in self.info.exports[&crate_type].iter() { - debug!(" {};", sym); - writeln!(f, " {};", sym)?; - } - writeln!(f, "\n local:\n *;\n}};")?; - Ok(()) - })(); - if let Err(e) = res { - self.sess.fatal(&format!("failed to write version script: {}", e)); - } - } - - if self.sess.target.target.options.is_like_osx { - if !self.is_ld { - arg.push("-Wl,") - } - arg.push("-exported_symbols_list,"); - } else if self.sess.target.target.options.is_like_solaris { - if !self.is_ld { - arg.push("-Wl,") - } - arg.push("-M,"); - } else { - if !self.is_ld { - arg.push("-Wl,") - } - arg.push("--version-script="); - } - - arg.push(&path); - self.cmd.arg(arg); - } - - fn subsystem(&mut self, subsystem: &str) { - self.linker_arg(&format!("--subsystem,{}", subsystem)); - } - - fn finalize(&mut self) -> Command { - self.hint_dynamic(); // Reset to default before returning the composed command line. - let mut cmd = Command::new(""); - ::std::mem::swap(&mut cmd, &mut self.cmd); - cmd - } - - fn group_start(&mut self) { - if !self.sess.target.target.options.is_like_osx { - self.linker_arg("--start-group"); - } - } - - fn group_end(&mut self) { - if !self.sess.target.target.options.is_like_osx { - self.linker_arg("--end-group"); - } - } - - fn cross_lang_lto(&mut self) { - match self.sess.opts.debugging_opts.cross_lang_lto { - CrossLangLto::Disabled | - CrossLangLto::NoLink => { - // Nothing to do - } - CrossLangLto::LinkerPlugin(ref path) => { - self.linker_arg(&format!("-plugin={}", path.display())); - - let opt_level = match self.sess.opts.optimize { - config::OptLevel::No => "O0", - config::OptLevel::Less => "O1", - config::OptLevel::Default => "O2", - config::OptLevel::Aggressive => "O3", - config::OptLevel::Size => "Os", - config::OptLevel::SizeMin => "Oz", - }; - - self.linker_arg(&format!("-plugin-opt={}", opt_level)); - self.linker_arg(&format!("-plugin-opt=mcpu={}", self.sess.target_cpu())); - - match self.sess.opts.cg.lto { - config::Lto::Thin | - config::Lto::ThinLocal => { - self.linker_arg(&format!("-plugin-opt=thin")); - } - config::Lto::Fat | - config::Lto::Yes | - config::Lto::No => { - // default to regular LTO - } - } - } - } - } -} - -pub struct MsvcLinker<'a> { - cmd: Command, - sess: &'a Session, - info: &'a LinkerInfo -} - -impl<'a> Linker for MsvcLinker<'a> { - fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); } - fn add_object(&mut self, path: &Path) { self.cmd.arg(path); } - fn args(&mut self, args: &[String]) { self.cmd.args(args); } - - fn build_dylib(&mut self, out_filename: &Path) { - self.cmd.arg("/DLL"); - let mut arg: OsString = "/IMPLIB:".into(); - arg.push(out_filename.with_extension("dll.lib")); - self.cmd.arg(arg); - } - - fn build_static_executable(&mut self) { - // noop - } - - fn gc_sections(&mut self, _keep_metadata: bool) { - // MSVC's ICF (Identical COMDAT Folding) link optimization is - // slow for Rust and thus we disable it by default when not in - // optimization build. - if self.sess.opts.optimize != config::OptLevel::No { - self.cmd.arg("/OPT:REF,ICF"); - } else { - // It is necessary to specify NOICF here, because /OPT:REF - // implies ICF by default. - self.cmd.arg("/OPT:REF,NOICF"); - } - } - - fn link_dylib(&mut self, lib: &str) { - self.cmd.arg(&format!("{}.lib", lib)); - } - - fn link_rust_dylib(&mut self, lib: &str, path: &Path) { - // When producing a dll, the MSVC linker may not actually emit a - // `foo.lib` file if the dll doesn't actually export any symbols, so we - // check to see if the file is there and just omit linking to it if it's - // not present. - let name = format!("{}.dll.lib", lib); - if fs::metadata(&path.join(&name)).is_ok() { - self.cmd.arg(name); - } - } - - fn link_staticlib(&mut self, lib: &str) { - self.cmd.arg(&format!("{}.lib", lib)); - } - - fn position_independent_executable(&mut self) { - // noop - } - - fn no_position_independent_executable(&mut self) { - // noop - } - - fn full_relro(&mut self) { - // noop - } - - fn partial_relro(&mut self) { - // noop - } - - fn no_relro(&mut self) { - // noop - } - - fn no_default_libraries(&mut self) { - // Currently we don't pass the /NODEFAULTLIB flag to the linker on MSVC - // as there's been trouble in the past of linking the C++ standard - // library required by LLVM. This likely needs to happen one day, but - // in general Windows is also a more controlled environment than - // Unix, so it's not necessarily as critical that this be implemented. - // - // Note that there are also some licensing worries about statically - // linking some libraries which require a specific agreement, so it may - // not ever be possible for us to pass this flag. - } - - fn include_path(&mut self, path: &Path) { - let mut arg = OsString::from("/LIBPATH:"); - arg.push(path); - self.cmd.arg(&arg); - } - - fn output_filename(&mut self, path: &Path) { - let mut arg = OsString::from("/OUT:"); - arg.push(path); - self.cmd.arg(&arg); - } - - fn framework_path(&mut self, _path: &Path) { - bug!("frameworks are not supported on windows") - } - fn link_framework(&mut self, _framework: &str) { - bug!("frameworks are not supported on windows") - } - - fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) { - // not supported? - self.link_staticlib(lib); - } - fn link_whole_rlib(&mut self, path: &Path) { - // not supported? - self.link_rlib(path); - } - fn optimize(&mut self) { - // Needs more investigation of `/OPT` arguments - } - - fn pgo_gen(&mut self) { - // Nothing needed here. - } - - fn debuginfo(&mut self) { - // This will cause the Microsoft linker to generate a PDB file - // from the CodeView line tables in the object files. - self.cmd.arg("/DEBUG"); - - // This will cause the Microsoft linker to embed .natvis info into the the PDB file - let sysroot = self.sess.sysroot(); - let natvis_dir_path = sysroot.join("lib\\rustlib\\etc"); - if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) { - // LLVM 5.0.0's lld-link frontend doesn't yet recognize, and chokes - // on, the /NATVIS:... flags. LLVM 6 (or earlier) should at worst ignore - // them, eventually mooting this workaround, per this landed patch: - // https://github.com/llvm-mirror/lld/commit/27b9c4285364d8d76bb43839daa100 - if let Some(ref linker_path) = self.sess.opts.cg.linker { - if let Some(linker_name) = Path::new(&linker_path).file_stem() { - if linker_name.to_str().unwrap().to_lowercase() == "lld-link" { - self.sess.warn("not embedding natvis: lld-link may not support the flag"); - return; - } - } - } - for entry in natvis_dir { - match entry { - Ok(entry) => { - let path = entry.path(); - if path.extension() == Some("natvis".as_ref()) { - let mut arg = OsString::from("/NATVIS:"); - arg.push(path); - self.cmd.arg(arg); - } - }, - Err(err) => { - self.sess.warn(&format!("error enumerating natvis directory: {}", err)); - }, - } - } - } - } - - // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to - // export symbols from a dynamic library. When building a dynamic library, - // however, we're going to want some symbols exported, so this function - // generates a DEF file which lists all the symbols. - // - // The linker will read this `*.def` file and export all the symbols from - // the dynamic library. Note that this is not as simple as just exporting - // all the symbols in the current crate (as specified by `trans.reachable`) - // but rather we also need to possibly export the symbols of upstream - // crates. Upstream rlibs may be linked statically to this dynamic library, - // in which case they may continue to transitively be used and hence need - // their symbols exported. - fn export_symbols(&mut self, - tmpdir: &Path, - crate_type: CrateType) { - let path = tmpdir.join("lib.def"); - let res = (|| -> io::Result<()> { - let mut f = BufWriter::new(File::create(&path)?); - - // Start off with the standard module name header and then go - // straight to exports. - writeln!(f, "LIBRARY")?; - writeln!(f, "EXPORTS")?; - for symbol in self.info.exports[&crate_type].iter() { - debug!(" _{}", symbol); - writeln!(f, " {}", symbol)?; - } - Ok(()) - })(); - if let Err(e) = res { - self.sess.fatal(&format!("failed to write lib.def file: {}", e)); - } - let mut arg = OsString::from("/DEF:"); - arg.push(path); - self.cmd.arg(&arg); - } - - fn subsystem(&mut self, subsystem: &str) { - // Note that previous passes of the compiler validated this subsystem, - // so we just blindly pass it to the linker. - self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem)); - - // Windows has two subsystems we're interested in right now, the console - // and windows subsystems. These both implicitly have different entry - // points (starting symbols). The console entry point starts with - // `mainCRTStartup` and the windows entry point starts with - // `WinMainCRTStartup`. These entry points, defined in system libraries, - // will then later probe for either `main` or `WinMain`, respectively to - // start the application. - // - // In Rust we just always generate a `main` function so we want control - // to always start there, so we force the entry point on the windows - // subsystem to be `mainCRTStartup` to get everything booted up - // correctly. - // - // For more information see RFC #1665 - if subsystem == "windows" { - self.cmd.arg("/ENTRY:mainCRTStartup"); - } - } - - fn finalize(&mut self) -> Command { - let mut cmd = Command::new(""); - ::std::mem::swap(&mut cmd, &mut self.cmd); - cmd - } - - // MSVC doesn't need group indicators - fn group_start(&mut self) {} - fn group_end(&mut self) {} - - fn cross_lang_lto(&mut self) { - // Do nothing - } -} - -pub struct EmLinker<'a> { - cmd: Command, - sess: &'a Session, - info: &'a LinkerInfo -} - -impl<'a> Linker for EmLinker<'a> { - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn link_staticlib(&mut self, lib: &str) { - self.cmd.arg("-l").arg(lib); - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - - fn link_dylib(&mut self, lib: &str) { - // Emscripten always links statically - self.link_staticlib(lib); - } - - fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) { - // not supported? - self.link_staticlib(lib); - } - - fn link_whole_rlib(&mut self, lib: &Path) { - // not supported? - self.link_rlib(lib); - } - - fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { - self.link_dylib(lib); - } - - fn link_rlib(&mut self, lib: &Path) { - self.add_object(lib); - } - - fn position_independent_executable(&mut self) { - // noop - } - - fn no_position_independent_executable(&mut self) { - // noop - } - - fn full_relro(&mut self) { - // noop - } - - fn partial_relro(&mut self) { - // noop - } - - fn no_relro(&mut self) { - // noop - } - - fn args(&mut self, args: &[String]) { - self.cmd.args(args); - } - - fn framework_path(&mut self, _path: &Path) { - bug!("frameworks are not supported on Emscripten") - } - - fn link_framework(&mut self, _framework: &str) { - bug!("frameworks are not supported on Emscripten") - } - - fn gc_sections(&mut self, _keep_metadata: bool) { - // noop - } - - fn optimize(&mut self) { - // Emscripten performs own optimizations - self.cmd.arg(match self.sess.opts.optimize { - OptLevel::No => "-O0", - OptLevel::Less => "-O1", - OptLevel::Default => "-O2", - OptLevel::Aggressive => "-O3", - OptLevel::Size => "-Os", - OptLevel::SizeMin => "-Oz" - }); - // Unusable until https://github.com/rust-lang/rust/issues/38454 is resolved - self.cmd.args(&["--memory-init-file", "0"]); - } - - fn pgo_gen(&mut self) { - // noop, but maybe we need something like the gnu linker? - } - - fn debuginfo(&mut self) { - // Preserve names or generate source maps depending on debug info - self.cmd.arg(match self.sess.opts.debuginfo { - DebugInfoLevel::NoDebugInfo => "-g0", - DebugInfoLevel::LimitedDebugInfo => "-g3", - DebugInfoLevel::FullDebugInfo => "-g4" - }); - } - - fn no_default_libraries(&mut self) { - self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]); - } - - fn build_dylib(&mut self, _out_filename: &Path) { - bug!("building dynamic library is unsupported on Emscripten") - } - - fn build_static_executable(&mut self) { - // noop - } - - fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) { - let symbols = &self.info.exports[&crate_type]; - - debug!("EXPORTED SYMBOLS:"); - - self.cmd.arg("-s"); - - let mut arg = OsString::from("EXPORTED_FUNCTIONS="); - let mut encoded = String::new(); - - { - let mut encoder = json::Encoder::new(&mut encoded); - let res = encoder.emit_seq(symbols.len(), |encoder| { - for (i, sym) in symbols.iter().enumerate() { - encoder.emit_seq_elt(i, |encoder| { - encoder.emit_str(&("_".to_string() + sym)) - })?; - } - Ok(()) - }); - if let Err(e) = res { - self.sess.fatal(&format!("failed to encode exported symbols: {}", e)); - } - } - debug!("{}", encoded); - arg.push(encoded); - - self.cmd.arg(arg); - } - - fn subsystem(&mut self, _subsystem: &str) { - // noop - } - - fn finalize(&mut self) -> Command { - let mut cmd = Command::new(""); - ::std::mem::swap(&mut cmd, &mut self.cmd); - cmd - } - - // Appears not necessary on Emscripten - fn group_start(&mut self) {} - fn group_end(&mut self) {} - - fn cross_lang_lto(&mut self) { - // Do nothing - } -} - -fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec { - let mut symbols = Vec::new(); - - let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); - for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() { - if level.is_below_threshold(export_threshold) { - symbols.push(symbol.symbol_name(tcx).to_string()); - } - } - - let formats = tcx.sess.dependency_formats.borrow(); - let deps = formats[&crate_type].iter(); - - for (index, dep_format) in deps.enumerate() { - let cnum = CrateNum::new(index + 1); - // For each dependency that we are linking to statically ... - if *dep_format == Linkage::Static { - // ... we add its symbol list to our export list. - for &(symbol, level) in tcx.exported_symbols(cnum).iter() { - if level.is_below_threshold(export_threshold) { - symbols.push(symbol.symbol_name(tcx).to_string()); - } - } - } - } - - symbols -} - -pub struct WasmLd { - cmd: Command, -} - -impl Linker for WasmLd { - fn link_dylib(&mut self, lib: &str) { - self.cmd.arg("-l").arg(lib); - } - - fn link_staticlib(&mut self, lib: &str) { - self.cmd.arg("-l").arg(lib); - } - - fn link_rlib(&mut self, lib: &Path) { - self.cmd.arg(lib); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - - fn position_independent_executable(&mut self) { - } - - fn full_relro(&mut self) { - } - - fn partial_relro(&mut self) { - } - - fn no_relro(&mut self) { - } - - fn build_static_executable(&mut self) { - } - - fn args(&mut self, args: &[String]) { - self.cmd.args(args); - } - - fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { - self.cmd.arg("-l").arg(lib); - } - - fn link_framework(&mut self, _framework: &str) { - panic!("frameworks not supported") - } - - fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) { - self.cmd.arg("-l").arg(lib); - } - - fn link_whole_rlib(&mut self, lib: &Path) { - self.cmd.arg(lib); - } - - fn gc_sections(&mut self, _keep_metadata: bool) { - } - - fn optimize(&mut self) { - } - - fn pgo_gen(&mut self) { - } - - fn debuginfo(&mut self) { - } - - fn no_default_libraries(&mut self) { - } - - fn build_dylib(&mut self, _out_filename: &Path) { - } - - fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) { - } - - fn subsystem(&mut self, _subsystem: &str) { - } - - fn no_position_independent_executable(&mut self) { - } - - fn finalize(&mut self) -> Command { - // There have been reports in the wild (rustwasm/wasm-bindgen#119) of - // using threads causing weird hangs and bugs. Disable it entirely as - // this isn't yet the bottleneck of compilation at all anyway. - self.cmd.arg("--no-threads"); - - self.cmd.arg("-z").arg("stack-size=1048576"); - - // FIXME we probably shouldn't pass this but instead pass an explicit - // whitelist of symbols we'll allow to be undefined. Unfortunately - // though we can't handle symbols like `log10` that LLVM injects at a - // super late date without actually parsing object files. For now let's - // stick to this and hopefully fix it before stabilization happens. - self.cmd.arg("--allow-undefined"); - - // For now we just never have an entry symbol - self.cmd.arg("--no-entry"); - - let mut cmd = Command::new(""); - ::std::mem::swap(&mut cmd, &mut self.cmd); - cmd - } - - // Not needed for now with LLD - fn group_start(&mut self) {} - fn group_end(&mut self) {} - - fn cross_lang_lto(&mut self) { - // Do nothing for now - } -} diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs deleted file mode 100644 index bbb5f7eecc8..00000000000 --- a/src/librustc_trans/back/lto.rs +++ /dev/null @@ -1,773 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION}; -use back::symbol_export; -use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext}; -use back::write; -use errors::{FatalError, Handler}; -use llvm::archive_ro::ArchiveRO; -use llvm::{ModuleRef, TargetMachineRef, True, False}; -use llvm; -use rustc::hir::def_id::LOCAL_CRATE; -use rustc::middle::exported_symbols::SymbolExportLevel; -use rustc::session::config::{self, Lto}; -use rustc::util::common::time_ext; -use time_graph::Timeline; -use {ModuleTranslation, ModuleLlvm, ModuleKind, ModuleSource}; - -use libc; - -use std::ffi::CString; -use std::ptr; -use std::slice; -use std::sync::Arc; - -pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool { - match crate_type { - config::CrateTypeExecutable | - config::CrateTypeStaticlib | - config::CrateTypeCdylib => true, - - config::CrateTypeDylib | - config::CrateTypeRlib | - config::CrateTypeProcMacro => false, - } -} - -pub(crate) enum LtoModuleTranslation { - Fat { - module: Option, - _serialized_bitcode: Vec, - }, - - Thin(ThinModule), -} - -impl LtoModuleTranslation { - pub fn name(&self) -> &str { - match *self { - LtoModuleTranslation::Fat { .. } => "everything", - LtoModuleTranslation::Thin(ref m) => m.name(), - } - } - - /// Optimize this module within the given codegen context. - /// - /// This function is unsafe as it'll return a `ModuleTranslation` still - /// points to LLVM data structures owned by this `LtoModuleTranslation`. - /// It's intended that the module returned is immediately code generated and - /// dropped, and then this LTO module is dropped. - pub(crate) unsafe fn optimize(&mut self, - cgcx: &CodegenContext, - timeline: &mut Timeline) - -> Result - { - match *self { - LtoModuleTranslation::Fat { ref mut module, .. } => { - let trans = module.take().unwrap(); - let config = cgcx.config(trans.kind); - let llmod = trans.llvm().unwrap().llmod; - let tm = trans.llvm().unwrap().tm; - run_pass_manager(cgcx, tm, llmod, config, false); - timeline.record("fat-done"); - Ok(trans) - } - LtoModuleTranslation::Thin(ref mut thin) => thin.optimize(cgcx, timeline), - } - } - - /// A "gauge" of how costly it is to optimize this module, used to sort - /// biggest modules first. - pub fn cost(&self) -> u64 { - match *self { - // Only one module with fat LTO, so the cost doesn't matter. - LtoModuleTranslation::Fat { .. } => 0, - LtoModuleTranslation::Thin(ref m) => m.cost(), - } - } -} - -pub(crate) fn run(cgcx: &CodegenContext, - modules: Vec, - timeline: &mut Timeline) - -> Result, FatalError> -{ - let diag_handler = cgcx.create_diag_handler(); - let export_threshold = match cgcx.lto { - // We're just doing LTO for our one crate - Lto::ThinLocal => SymbolExportLevel::Rust, - - // We're doing LTO for the entire crate graph - Lto::Yes | Lto::Fat | Lto::Thin => { - symbol_export::crates_export_threshold(&cgcx.crate_types) - } - - Lto::No => panic!("didn't request LTO but we're doing LTO"), - }; - - let symbol_filter = &|&(ref name, level): &(String, SymbolExportLevel)| { - if level.is_below_threshold(export_threshold) { - let mut bytes = Vec::with_capacity(name.len() + 1); - bytes.extend(name.bytes()); - Some(CString::new(bytes).unwrap()) - } else { - None - } - }; - let exported_symbols = cgcx.exported_symbols - .as_ref().expect("needs exported symbols for LTO"); - let mut symbol_white_list = exported_symbols[&LOCAL_CRATE] - .iter() - .filter_map(symbol_filter) - .collect::>(); - timeline.record("whitelist"); - info!("{} symbols to preserve in this crate", symbol_white_list.len()); - - // If we're performing LTO for the entire crate graph, then for each of our - // upstream dependencies, find the corresponding rlib and load the bitcode - // from the archive. - // - // We save off all the bytecode and LLVM module ids for later processing - // with either fat or thin LTO - let mut upstream_modules = Vec::new(); - if cgcx.lto != Lto::ThinLocal { - if cgcx.opts.cg.prefer_dynamic { - diag_handler.struct_err("cannot prefer dynamic linking when performing LTO") - .note("only 'staticlib', 'bin', and 'cdylib' outputs are \ - supported with LTO") - .emit(); - return Err(FatalError) - } - - // Make sure we actually can run LTO - for crate_type in cgcx.crate_types.iter() { - if !crate_type_allows_lto(*crate_type) { - let e = diag_handler.fatal("lto can only be run for executables, cdylibs and \ - static library outputs"); - return Err(e) - } - } - - for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() { - let exported_symbols = cgcx.exported_symbols - .as_ref().expect("needs exported symbols for LTO"); - symbol_white_list.extend( - exported_symbols[&cnum] - .iter() - .filter_map(symbol_filter)); - - let archive = ArchiveRO::open(&path).expect("wanted an rlib"); - let bytecodes = archive.iter().filter_map(|child| { - child.ok().and_then(|c| c.name().map(|name| (name, c))) - }).filter(|&(name, _)| name.ends_with(RLIB_BYTECODE_EXTENSION)); - for (name, data) in bytecodes { - info!("adding bytecode {}", name); - let bc_encoded = data.data(); - - let (bc, id) = time_ext(cgcx.time_passes, None, &format!("decode {}", name), || { - match DecodedBytecode::new(bc_encoded) { - Ok(b) => Ok((b.bytecode(), b.identifier().to_string())), - Err(e) => Err(diag_handler.fatal(&e)), - } - })?; - let bc = SerializedModule::FromRlib(bc); - upstream_modules.push((bc, CString::new(id).unwrap())); - } - timeline.record(&format!("load: {}", path.display())); - } - } - - let arr = symbol_white_list.iter().map(|c| c.as_ptr()).collect::>(); - match cgcx.lto { - Lto::Yes | // `-C lto` == fat LTO by default - Lto::Fat => { - fat_lto(cgcx, &diag_handler, modules, upstream_modules, &arr, timeline) - } - Lto::Thin | - Lto::ThinLocal => { - thin_lto(&diag_handler, modules, upstream_modules, &arr, timeline) - } - Lto::No => unreachable!(), - } -} - -fn fat_lto(cgcx: &CodegenContext, - diag_handler: &Handler, - mut modules: Vec, - mut serialized_modules: Vec<(SerializedModule, CString)>, - symbol_white_list: &[*const libc::c_char], - timeline: &mut Timeline) - -> Result, FatalError> -{ - info!("going for a fat lto"); - - // Find the "costliest" module and merge everything into that codegen unit. - // All the other modules will be serialized and reparsed into the new - // context, so this hopefully avoids serializing and parsing the largest - // codegen unit. - // - // Additionally use a regular module as the base here to ensure that various - // file copy operations in the backend work correctly. The only other kind - // of module here should be an allocator one, and if your crate is smaller - // than the allocator module then the size doesn't really matter anyway. - let (_, costliest_module) = modules.iter() - .enumerate() - .filter(|&(_, module)| module.kind == ModuleKind::Regular) - .map(|(i, module)| { - let cost = unsafe { - llvm::LLVMRustModuleCost(module.llvm().unwrap().llmod) - }; - (cost, i) - }) - .max() - .expect("must be trans'ing at least one module"); - let module = modules.remove(costliest_module); - let llmod = module.llvm().expect("can't lto pre-translated modules").llmod; - info!("using {:?} as a base module", module.llmod_id); - - // For all other modules we translated we'll need to link them into our own - // bitcode. All modules were translated in their own LLVM context, however, - // and we want to move everything to the same LLVM context. Currently the - // way we know of to do that is to serialize them to a string and them parse - // them later. Not great but hey, that's why it's "fat" LTO, right? - for module in modules { - let llvm = module.llvm().expect("can't lto pre-translated modules"); - let buffer = ModuleBuffer::new(llvm.llmod); - let llmod_id = CString::new(&module.llmod_id[..]).unwrap(); - serialized_modules.push((SerializedModule::Local(buffer), llmod_id)); - } - - // For all serialized bitcode files we parse them and link them in as we did - // above, this is all mostly handled in C++. Like above, though, we don't - // know much about the memory management here so we err on the side of being - // save and persist everything with the original module. - let mut serialized_bitcode = Vec::new(); - let mut linker = Linker::new(llmod); - for (bc_decoded, name) in serialized_modules { - info!("linking {:?}", name); - time_ext(cgcx.time_passes, None, &format!("ll link {:?}", name), || { - let data = bc_decoded.data(); - linker.add(&data).map_err(|()| { - let msg = format!("failed to load bc of {:?}", name); - write::llvm_err(&diag_handler, msg) - }) - })?; - timeline.record(&format!("link {:?}", name)); - serialized_bitcode.push(bc_decoded); - } - drop(linker); - cgcx.save_temp_bitcode(&module, "lto.input"); - - // Internalize everything that *isn't* in our whitelist to help strip out - // more modules and such - unsafe { - let ptr = symbol_white_list.as_ptr(); - llvm::LLVMRustRunRestrictionPass(llmod, - ptr as *const *const libc::c_char, - symbol_white_list.len() as libc::size_t); - cgcx.save_temp_bitcode(&module, "lto.after-restriction"); - } - - if cgcx.no_landing_pads { - unsafe { - llvm::LLVMRustMarkAllFunctionsNounwind(llmod); - } - cgcx.save_temp_bitcode(&module, "lto.after-nounwind"); - } - timeline.record("passes"); - - Ok(vec![LtoModuleTranslation::Fat { - module: Some(module), - _serialized_bitcode: serialized_bitcode, - }]) -} - -struct Linker(llvm::LinkerRef); - -impl Linker { - fn new(llmod: ModuleRef) -> Linker { - unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) } - } - - fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { - unsafe { - if llvm::LLVMRustLinkerAdd(self.0, - bytecode.as_ptr() as *const libc::c_char, - bytecode.len()) { - Ok(()) - } else { - Err(()) - } - } - } -} - -impl Drop for Linker { - fn drop(&mut self) { - unsafe { llvm::LLVMRustLinkerFree(self.0); } - } -} - -/// Prepare "thin" LTO to get run on these modules. -/// -/// The general structure of ThinLTO is quite different from the structure of -/// "fat" LTO above. With "fat" LTO all LLVM modules in question are merged into -/// one giant LLVM module, and then we run more optimization passes over this -/// big module after internalizing most symbols. Thin LTO, on the other hand, -/// avoid this large bottleneck through more targeted optimization. -/// -/// At a high level Thin LTO looks like: -/// -/// 1. Prepare a "summary" of each LLVM module in question which describes -/// the values inside, cost of the values, etc. -/// 2. Merge the summaries of all modules in question into one "index" -/// 3. Perform some global analysis on this index -/// 4. For each module, use the index and analysis calculated previously to -/// perform local transformations on the module, for example inlining -/// small functions from other modules. -/// 5. Run thin-specific optimization passes over each module, and then code -/// generate everything at the end. -/// -/// The summary for each module is intended to be quite cheap, and the global -/// index is relatively quite cheap to create as well. As a result, the goal of -/// ThinLTO is to reduce the bottleneck on LTO and enable LTO to be used in more -/// situations. For example one cheap optimization is that we can parallelize -/// all codegen modules, easily making use of all the cores on a machine. -/// -/// With all that in mind, the function here is designed at specifically just -/// calculating the *index* for ThinLTO. This index will then be shared amongst -/// all of the `LtoModuleTranslation` units returned below and destroyed once -/// they all go out of scope. -fn thin_lto(diag_handler: &Handler, - modules: Vec, - serialized_modules: Vec<(SerializedModule, CString)>, - symbol_white_list: &[*const libc::c_char], - timeline: &mut Timeline) - -> Result, FatalError> -{ - unsafe { - info!("going for that thin, thin LTO"); - - let mut thin_buffers = Vec::new(); - let mut module_names = Vec::new(); - let mut thin_modules = Vec::new(); - - // FIXME: right now, like with fat LTO, we serialize all in-memory - // modules before working with them and ThinLTO. We really - // shouldn't do this, however, and instead figure out how to - // extract a summary from an in-memory module and then merge that - // into the global index. It turns out that this loop is by far - // the most expensive portion of this small bit of global - // analysis! - for (i, module) in modules.iter().enumerate() { - info!("local module: {} - {}", i, module.llmod_id); - let llvm = module.llvm().expect("can't lto pretranslated module"); - let name = CString::new(module.llmod_id.clone()).unwrap(); - let buffer = ThinBuffer::new(llvm.llmod); - thin_modules.push(llvm::ThinLTOModule { - identifier: name.as_ptr(), - data: buffer.data().as_ptr(), - len: buffer.data().len(), - }); - thin_buffers.push(buffer); - module_names.push(name); - timeline.record(&module.llmod_id); - } - - // FIXME: All upstream crates are deserialized internally in the - // function below to extract their summary and modules. Note that - // unlike the loop above we *must* decode and/or read something - // here as these are all just serialized files on disk. An - // improvement, however, to make here would be to store the - // module summary separately from the actual module itself. Right - // now this is store in one large bitcode file, and the entire - // file is deflate-compressed. We could try to bypass some of the - // decompression by storing the index uncompressed and only - // lazily decompressing the bytecode if necessary. - // - // Note that truly taking advantage of this optimization will - // likely be further down the road. We'd have to implement - // incremental ThinLTO first where we could actually avoid - // looking at upstream modules entirely sometimes (the contents, - // we must always unconditionally look at the index). - let mut serialized = Vec::new(); - for (module, name) in serialized_modules { - info!("foreign module {:?}", name); - thin_modules.push(llvm::ThinLTOModule { - identifier: name.as_ptr(), - data: module.data().as_ptr(), - len: module.data().len(), - }); - serialized.push(module); - module_names.push(name); - } - - // Delegate to the C++ bindings to create some data here. Once this is a - // tried-and-true interface we may wish to try to upstream some of this - // to LLVM itself, right now we reimplement a lot of what they do - // upstream... - let data = llvm::LLVMRustCreateThinLTOData( - thin_modules.as_ptr(), - thin_modules.len() as u32, - symbol_white_list.as_ptr(), - symbol_white_list.len() as u32, - ); - if data.is_null() { - let msg = format!("failed to prepare thin LTO context"); - return Err(write::llvm_err(&diag_handler, msg)) - } - let data = ThinData(data); - info!("thin LTO data created"); - timeline.record("data"); - - // Throw our data in an `Arc` as we'll be sharing it across threads. We - // also put all memory referenced by the C++ data (buffers, ids, etc) - // into the arc as well. After this we'll create a thin module - // translation per module in this data. - let shared = Arc::new(ThinShared { - data, - thin_buffers, - serialized_modules: serialized, - module_names, - }); - Ok((0..shared.module_names.len()).map(|i| { - LtoModuleTranslation::Thin(ThinModule { - shared: shared.clone(), - idx: i, - }) - }).collect()) - } -} - -fn run_pass_manager(cgcx: &CodegenContext, - tm: TargetMachineRef, - llmod: ModuleRef, - config: &ModuleConfig, - thin: bool) { - // Now we have one massive module inside of llmod. Time to run the - // LTO-specific optimization passes that LLVM provides. - // - // This code is based off the code found in llvm's LTO code generator: - // tools/lto/LTOCodeGenerator.cpp - debug!("running the pass manager"); - unsafe { - let pm = llvm::LLVMCreatePassManager(); - llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod); - let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _); - assert!(!pass.is_null()); - llvm::LLVMRustAddPass(pm, pass); - - // When optimizing for LTO we don't actually pass in `-O0`, but we force - // it to always happen at least with `-O1`. - // - // With ThinLTO we mess around a lot with symbol visibility in a way - // that will actually cause linking failures if we optimize at O0 which - // notable is lacking in dead code elimination. To ensure we at least - // get some optimizations and correctly link we forcibly switch to `-O1` - // to get dead code elimination. - // - // Note that in general this shouldn't matter too much as you typically - // only turn on ThinLTO when you're compiling with optimizations - // otherwise. - let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None); - let opt_level = match opt_level { - llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less, - level => level, - }; - with_llvm_pmb(llmod, config, opt_level, false, &mut |b| { - if thin { - if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) { - panic!("this version of LLVM does not support ThinLTO"); - } - } else { - llvm::LLVMPassManagerBuilderPopulateLTOPassManager(b, pm, - /* Internalize = */ False, - /* RunInliner = */ True); - } - }); - - let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _); - assert!(!pass.is_null()); - llvm::LLVMRustAddPass(pm, pass); - - time_ext(cgcx.time_passes, None, "LTO passes", || - llvm::LLVMRunPassManager(pm, llmod)); - - llvm::LLVMDisposePassManager(pm); - } - debug!("lto done"); -} - -pub enum SerializedModule { - Local(ModuleBuffer), - FromRlib(Vec), -} - -impl SerializedModule { - fn data(&self) -> &[u8] { - match *self { - SerializedModule::Local(ref m) => m.data(), - SerializedModule::FromRlib(ref m) => m, - } - } -} - -pub struct ModuleBuffer(*mut llvm::ModuleBuffer); - -unsafe impl Send for ModuleBuffer {} -unsafe impl Sync for ModuleBuffer {} - -impl ModuleBuffer { - pub fn new(m: ModuleRef) -> ModuleBuffer { - ModuleBuffer(unsafe { - llvm::LLVMRustModuleBufferCreate(m) - }) - } - - pub fn data(&self) -> &[u8] { - unsafe { - let ptr = llvm::LLVMRustModuleBufferPtr(self.0); - let len = llvm::LLVMRustModuleBufferLen(self.0); - slice::from_raw_parts(ptr, len) - } - } -} - -impl Drop for ModuleBuffer { - fn drop(&mut self) { - unsafe { llvm::LLVMRustModuleBufferFree(self.0); } - } -} - -pub struct ThinModule { - shared: Arc, - idx: usize, -} - -struct ThinShared { - data: ThinData, - thin_buffers: Vec, - serialized_modules: Vec, - module_names: Vec, -} - -struct ThinData(*mut llvm::ThinLTOData); - -unsafe impl Send for ThinData {} -unsafe impl Sync for ThinData {} - -impl Drop for ThinData { - fn drop(&mut self) { - unsafe { - llvm::LLVMRustFreeThinLTOData(self.0); - } - } -} - -pub struct ThinBuffer(*mut llvm::ThinLTOBuffer); - -unsafe impl Send for ThinBuffer {} -unsafe impl Sync for ThinBuffer {} - -impl ThinBuffer { - pub fn new(m: ModuleRef) -> ThinBuffer { - unsafe { - let buffer = llvm::LLVMRustThinLTOBufferCreate(m); - ThinBuffer(buffer) - } - } - - pub fn data(&self) -> &[u8] { - unsafe { - let ptr = llvm::LLVMRustThinLTOBufferPtr(self.0) as *const _; - let len = llvm::LLVMRustThinLTOBufferLen(self.0); - slice::from_raw_parts(ptr, len) - } - } -} - -impl Drop for ThinBuffer { - fn drop(&mut self) { - unsafe { - llvm::LLVMRustThinLTOBufferFree(self.0); - } - } -} - -impl ThinModule { - fn name(&self) -> &str { - self.shared.module_names[self.idx].to_str().unwrap() - } - - fn cost(&self) -> u64 { - // Yes, that's correct, we're using the size of the bytecode as an - // indicator for how costly this codegen unit is. - self.data().len() as u64 - } - - fn data(&self) -> &[u8] { - let a = self.shared.thin_buffers.get(self.idx).map(|b| b.data()); - a.unwrap_or_else(|| { - let len = self.shared.thin_buffers.len(); - self.shared.serialized_modules[self.idx - len].data() - }) - } - - unsafe fn optimize(&mut self, cgcx: &CodegenContext, timeline: &mut Timeline) - -> Result - { - let diag_handler = cgcx.create_diag_handler(); - let tm = (cgcx.tm_factory)().map_err(|e| { - write::llvm_err(&diag_handler, e) - })?; - - // Right now the implementation we've got only works over serialized - // modules, so we create a fresh new LLVM context and parse the module - // into that context. One day, however, we may do this for upstream - // crates but for locally translated modules we may be able to reuse - // that LLVM Context and Module. - let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); - let llmod = llvm::LLVMRustParseBitcodeForThinLTO( - llcx, - self.data().as_ptr(), - self.data().len(), - self.shared.module_names[self.idx].as_ptr(), - ); - if llmod.is_null() { - let msg = format!("failed to parse bitcode for thin LTO module"); - return Err(write::llvm_err(&diag_handler, msg)); - } - let mtrans = ModuleTranslation { - source: ModuleSource::Translated(ModuleLlvm { - llmod, - llcx, - tm, - }), - llmod_id: self.name().to_string(), - name: self.name().to_string(), - kind: ModuleKind::Regular, - }; - cgcx.save_temp_bitcode(&mtrans, "thin-lto-input"); - - // Before we do much else find the "main" `DICompileUnit` that we'll be - // using below. If we find more than one though then rustc has changed - // in a way we're not ready for, so generate an ICE by returning - // an error. - let mut cu1 = ptr::null_mut(); - let mut cu2 = ptr::null_mut(); - llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2); - if !cu2.is_null() { - let msg = format!("multiple source DICompileUnits found"); - return Err(write::llvm_err(&diag_handler, msg)) - } - - // Like with "fat" LTO, get some better optimizations if landing pads - // are disabled by removing all landing pads. - if cgcx.no_landing_pads { - llvm::LLVMRustMarkAllFunctionsNounwind(llmod); - cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-nounwind"); - timeline.record("nounwind"); - } - - // Up next comes the per-module local analyses that we do for Thin LTO. - // Each of these functions is basically copied from the LLVM - // implementation and then tailored to suit this implementation. Ideally - // each of these would be supported by upstream LLVM but that's perhaps - // a patch for another day! - // - // You can find some more comments about these functions in the LLVM - // bindings we've got (currently `PassWrapper.cpp`) - if !llvm::LLVMRustPrepareThinLTORename(self.shared.data.0, llmod) { - let msg = format!("failed to prepare thin LTO module"); - return Err(write::llvm_err(&diag_handler, msg)) - } - cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-rename"); - timeline.record("rename"); - if !llvm::LLVMRustPrepareThinLTOResolveWeak(self.shared.data.0, llmod) { - let msg = format!("failed to prepare thin LTO module"); - return Err(write::llvm_err(&diag_handler, msg)) - } - cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-resolve"); - timeline.record("resolve"); - if !llvm::LLVMRustPrepareThinLTOInternalize(self.shared.data.0, llmod) { - let msg = format!("failed to prepare thin LTO module"); - return Err(write::llvm_err(&diag_handler, msg)) - } - cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-internalize"); - timeline.record("internalize"); - if !llvm::LLVMRustPrepareThinLTOImport(self.shared.data.0, llmod) { - let msg = format!("failed to prepare thin LTO module"); - return Err(write::llvm_err(&diag_handler, msg)) - } - cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-import"); - timeline.record("import"); - - // Ok now this is a bit unfortunate. This is also something you won't - // find upstream in LLVM's ThinLTO passes! This is a hack for now to - // work around bugs in LLVM. - // - // First discovered in #45511 it was found that as part of ThinLTO - // importing passes LLVM will import `DICompileUnit` metadata - // information across modules. This means that we'll be working with one - // LLVM module that has multiple `DICompileUnit` instances in it (a - // bunch of `llvm.dbg.cu` members). Unfortunately there's a number of - // bugs in LLVM's backend which generates invalid DWARF in a situation - // like this: - // - // https://bugs.llvm.org/show_bug.cgi?id=35212 - // https://bugs.llvm.org/show_bug.cgi?id=35562 - // - // While the first bug there is fixed the second ended up causing #46346 - // which was basically a resurgence of #45511 after LLVM's bug 35212 was - // fixed. - // - // This function below is a huge hack around this problem. The function - // below is defined in `PassWrapper.cpp` and will basically "merge" - // all `DICompileUnit` instances in a module. Basically it'll take all - // the objects, rewrite all pointers of `DISubprogram` to point to the - // first `DICompileUnit`, and then delete all the other units. - // - // This is probably mangling to the debug info slightly (but hopefully - // not too much) but for now at least gets LLVM to emit valid DWARF (or - // so it appears). Hopefully we can remove this once upstream bugs are - // fixed in LLVM. - llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1); - cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-patch"); - timeline.record("patch"); - - // Alright now that we've done everything related to the ThinLTO - // analysis it's time to run some optimizations! Here we use the same - // `run_pass_manager` as the "fat" LTO above except that we tell it to - // populate a thin-specific pass manager, which presumably LLVM treats a - // little differently. - info!("running thin lto passes over {}", mtrans.name); - let config = cgcx.config(mtrans.kind); - run_pass_manager(cgcx, tm, llmod, config, true); - cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-pm"); - timeline.record("thin-done"); - - // FIXME: this is a hack around a bug in LLVM right now. Discovered in - // #46910 it was found out that on 32-bit MSVC LLVM will hit a codegen - // error if there's an available_externally function in the LLVM module. - // Typically we don't actually use these functions but ThinLTO makes - // heavy use of them when inlining across modules. - // - // Tracked upstream at https://bugs.llvm.org/show_bug.cgi?id=35736 this - // function call (and its definition on the C++ side of things) - // shouldn't be necessary eventually and we can safetly delete these few - // lines. - llvm::LLVMRustThinLTORemoveAvailableExternally(llmod); - cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-rm-ae"); - timeline.record("no-ae"); - - Ok(mtrans) - } -} diff --git a/src/librustc_trans/back/rpath.rs b/src/librustc_trans/back/rpath.rs deleted file mode 100644 index 8e5e7d37648..00000000000 --- a/src/librustc_trans/back/rpath.rs +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::collections::HashSet; -use std::env; -use std::path::{Path, PathBuf}; -use std::fs; - -use rustc::hir::def_id::CrateNum; -use rustc::middle::cstore::LibSource; - -pub struct RPathConfig<'a> { - pub used_crates: &'a [(CrateNum, LibSource)], - pub out_filename: PathBuf, - pub is_like_osx: bool, - pub has_rpath: bool, - pub linker_is_gnu: bool, - pub get_install_prefix_lib_path: &'a mut FnMut() -> PathBuf, -} - -pub fn get_rpath_flags(config: &mut RPathConfig) -> Vec { - // No rpath on windows - if !config.has_rpath { - return Vec::new(); - } - - let mut flags = Vec::new(); - - debug!("preparing the RPATH!"); - - let libs = config.used_crates.clone(); - let libs = libs.iter().filter_map(|&(_, ref l)| l.option()).collect::>(); - let rpaths = get_rpaths(config, &libs); - flags.extend_from_slice(&rpaths_to_flags(&rpaths)); - - // Use DT_RUNPATH instead of DT_RPATH if available - if config.linker_is_gnu { - flags.push("-Wl,--enable-new-dtags".to_string()); - } - - flags -} - -fn rpaths_to_flags(rpaths: &[String]) -> Vec { - let mut ret = Vec::new(); - for rpath in rpaths { - if rpath.contains(',') { - ret.push("-Wl,-rpath".into()); - ret.push("-Xlinker".into()); - ret.push(rpath.clone()); - } else { - ret.push(format!("-Wl,-rpath,{}", &(*rpath))); - } - } - return ret; -} - -fn get_rpaths(config: &mut RPathConfig, libs: &[PathBuf]) -> Vec { - debug!("output: {:?}", config.out_filename.display()); - debug!("libs:"); - for libpath in libs { - debug!(" {:?}", libpath.display()); - } - - // Use relative paths to the libraries. Binaries can be moved - // as long as they maintain the relative relationship to the - // crates they depend on. - let rel_rpaths = get_rpaths_relative_to_output(config, libs); - - // And a final backup rpath to the global library location. - let fallback_rpaths = vec![get_install_prefix_rpath(config)]; - - fn log_rpaths(desc: &str, rpaths: &[String]) { - debug!("{} rpaths:", desc); - for rpath in rpaths { - debug!(" {}", *rpath); - } - } - - log_rpaths("relative", &rel_rpaths); - log_rpaths("fallback", &fallback_rpaths); - - let mut rpaths = rel_rpaths; - rpaths.extend_from_slice(&fallback_rpaths); - - // Remove duplicates - let rpaths = minimize_rpaths(&rpaths); - return rpaths; -} - -fn get_rpaths_relative_to_output(config: &mut RPathConfig, - libs: &[PathBuf]) -> Vec { - libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect() -} - -fn get_rpath_relative_to_output(config: &mut RPathConfig, lib: &Path) -> String { - // Mac doesn't appear to support $ORIGIN - let prefix = if config.is_like_osx { - "@loader_path" - } else { - "$ORIGIN" - }; - - let cwd = env::current_dir().unwrap(); - let mut lib = fs::canonicalize(&cwd.join(lib)).unwrap_or(cwd.join(lib)); - lib.pop(); - let mut output = cwd.join(&config.out_filename); - output.pop(); - let output = fs::canonicalize(&output).unwrap_or(output); - let relative = path_relative_from(&lib, &output) - .expect(&format!("couldn't create relative path from {:?} to {:?}", output, lib)); - // FIXME (#9639): This needs to handle non-utf8 paths - format!("{}/{}", prefix, - relative.to_str().expect("non-utf8 component in path")) -} - -// This routine is adapted from the *old* Path's `path_relative_from` -// function, which works differently from the new `relative_from` function. -// In particular, this handles the case on unix where both paths are -// absolute but with only the root as the common directory. -fn path_relative_from(path: &Path, base: &Path) -> Option { - use std::path::Component; - - if path.is_absolute() != base.is_absolute() { - if path.is_absolute() { - Some(PathBuf::from(path)) - } else { - None - } - } else { - let mut ita = path.components(); - let mut itb = base.components(); - let mut comps: Vec = vec![]; - loop { - match (ita.next(), itb.next()) { - (None, None) => break, - (Some(a), None) => { - comps.push(a); - comps.extend(ita.by_ref()); - break; - } - (None, _) => comps.push(Component::ParentDir), - (Some(a), Some(b)) if comps.is_empty() && a == b => (), - (Some(a), Some(b)) if b == Component::CurDir => comps.push(a), - (Some(_), Some(b)) if b == Component::ParentDir => return None, - (Some(a), Some(_)) => { - comps.push(Component::ParentDir); - for _ in itb { - comps.push(Component::ParentDir); - } - comps.push(a); - comps.extend(ita.by_ref()); - break; - } - } - } - Some(comps.iter().map(|c| c.as_os_str()).collect()) - } -} - - -fn get_install_prefix_rpath(config: &mut RPathConfig) -> String { - let path = (config.get_install_prefix_lib_path)(); - let path = env::current_dir().unwrap().join(&path); - // FIXME (#9639): This needs to handle non-utf8 paths - path.to_str().expect("non-utf8 component in rpath").to_string() -} - -fn minimize_rpaths(rpaths: &[String]) -> Vec { - let mut set = HashSet::new(); - let mut minimized = Vec::new(); - for rpath in rpaths { - if set.insert(rpath) { - minimized.push(rpath.clone()); - } - } - minimized -} - -#[cfg(all(unix, test))] -mod tests { - use super::{RPathConfig}; - use super::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output}; - use std::path::{Path, PathBuf}; - - #[test] - fn test_rpaths_to_flags() { - let flags = rpaths_to_flags(&[ - "path1".to_string(), - "path2".to_string() - ]); - assert_eq!(flags, - ["-Wl,-rpath,path1", - "-Wl,-rpath,path2"]); - } - - #[test] - fn test_minimize1() { - let res = minimize_rpaths(&[ - "rpath1".to_string(), - "rpath2".to_string(), - "rpath1".to_string() - ]); - assert!(res == [ - "rpath1", - "rpath2", - ]); - } - - #[test] - fn test_minimize2() { - let res = minimize_rpaths(&[ - "1a".to_string(), - "2".to_string(), - "2".to_string(), - "1a".to_string(), - "4a".to_string(), - "1a".to_string(), - "2".to_string(), - "3".to_string(), - "4a".to_string(), - "3".to_string() - ]); - assert!(res == [ - "1a", - "2", - "4a", - "3", - ]); - } - - #[test] - fn test_rpath_relative() { - if cfg!(target_os = "macos") { - let config = &mut RPathConfig { - used_crates: Vec::new(), - has_rpath: true, - is_like_osx: true, - linker_is_gnu: false, - out_filename: PathBuf::from("bin/rustc"), - get_install_prefix_lib_path: &mut || panic!(), - }; - let res = get_rpath_relative_to_output(config, - Path::new("lib/libstd.so")); - assert_eq!(res, "@loader_path/../lib"); - } else { - let config = &mut RPathConfig { - used_crates: Vec::new(), - out_filename: PathBuf::from("bin/rustc"), - get_install_prefix_lib_path: &mut || panic!(), - has_rpath: true, - is_like_osx: false, - linker_is_gnu: true, - }; - let res = get_rpath_relative_to_output(config, - Path::new("lib/libstd.so")); - assert_eq!(res, "$ORIGIN/../lib"); - } - } - - #[test] - fn test_xlinker() { - let args = rpaths_to_flags(&[ - "a/normal/path".to_string(), - "a,comma,path".to_string() - ]); - - assert_eq!(args, vec![ - "-Wl,-rpath,a/normal/path".to_string(), - "-Wl,-rpath".to_string(), - "-Xlinker".to_string(), - "a,comma,path".to_string() - ]); - } -} diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs deleted file mode 100644 index d7785522069..00000000000 --- a/src/librustc_trans/back/symbol_export.rs +++ /dev/null @@ -1,395 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use rustc_data_structures::sync::Lrc; -use std::sync::Arc; - -use monomorphize::Instance; -use rustc::hir; -use rustc::hir::TransFnAttrFlags; -use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; -use rustc::ich::Fingerprint; -use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name}; -use rustc::session::config; -use rustc::ty::{TyCtxt, SymbolName}; -use rustc::ty::maps::Providers; -use rustc::ty::subst::Substs; -use rustc::util::nodemap::{FxHashMap, DefIdMap}; -use rustc_allocator::ALLOCATOR_METHODS; -use rustc_data_structures::indexed_vec::IndexVec; -use std::collections::hash_map::Entry::*; - -pub type ExportedSymbols = FxHashMap< - CrateNum, - Arc>, ->; - -pub fn threshold(tcx: TyCtxt) -> SymbolExportLevel { - crates_export_threshold(&tcx.sess.crate_types.borrow()) -} - -fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel { - match crate_type { - config::CrateTypeExecutable | - config::CrateTypeStaticlib | - config::CrateTypeProcMacro | - config::CrateTypeCdylib => SymbolExportLevel::C, - config::CrateTypeRlib | - config::CrateTypeDylib => SymbolExportLevel::Rust, - } -} - -pub fn crates_export_threshold(crate_types: &[config::CrateType]) - -> SymbolExportLevel { - if crate_types.iter().any(|&crate_type| { - crate_export_threshold(crate_type) == SymbolExportLevel::Rust - }) { - SymbolExportLevel::Rust - } else { - SymbolExportLevel::C - } -} - -fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - cnum: CrateNum) - -> Lrc> -{ - assert_eq!(cnum, LOCAL_CRATE); - - if !tcx.sess.opts.output_types.should_trans() { - return Lrc::new(DefIdMap()) - } - - // Check to see if this crate is a "special runtime crate". These - // crates, implementation details of the standard library, typically - // have a bunch of `pub extern` and `#[no_mangle]` functions as the - // ABI between them. We don't want their symbols to have a `C` - // export level, however, as they're just implementation details. - // Down below we'll hardwire all of the symbols to the `Rust` export - // level instead. - let special_runtime_crate = tcx.is_panic_runtime(LOCAL_CRATE) || - tcx.is_compiler_builtins(LOCAL_CRATE); - - let mut reachable_non_generics: DefIdMap<_> = tcx.reachable_set(LOCAL_CRATE).0 - .iter() - .filter_map(|&node_id| { - // We want to ignore some FFI functions that are not exposed from - // this crate. Reachable FFI functions can be lumped into two - // categories: - // - // 1. Those that are included statically via a static library - // 2. Those included otherwise (e.g. dynamically or via a framework) - // - // Although our LLVM module is not literally emitting code for the - // statically included symbols, it's an export of our library which - // needs to be passed on to the linker and encoded in the metadata. - // - // As a result, if this id is an FFI item (foreign item) then we only - // let it through if it's included statically. - match tcx.hir.get(node_id) { - hir::map::NodeForeignItem(..) => { - let def_id = tcx.hir.local_def_id(node_id); - if tcx.is_statically_included_foreign_item(def_id) { - Some(def_id) - } else { - None - } - } - - // Only consider nodes that actually have exported symbols. - hir::map::NodeItem(&hir::Item { - node: hir::ItemStatic(..), - .. - }) | - hir::map::NodeItem(&hir::Item { - node: hir::ItemFn(..), .. - }) | - hir::map::NodeImplItem(&hir::ImplItem { - node: hir::ImplItemKind::Method(..), - .. - }) => { - let def_id = tcx.hir.local_def_id(node_id); - let generics = tcx.generics_of(def_id); - if !generics.requires_monomorphization(tcx) && - // Functions marked with #[inline] are only ever translated - // with "internal" linkage and are never exported. - !Instance::mono(tcx, def_id).def.requires_local(tcx) { - Some(def_id) - } else { - None - } - } - - _ => None - } - }) - .map(|def_id| { - let export_level = if special_runtime_crate { - let name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str(); - // We can probably do better here by just ensuring that - // it has hidden visibility rather than public - // visibility, as this is primarily here to ensure it's - // not stripped during LTO. - // - // In general though we won't link right if these - // symbols are stripped, and LTO currently strips them. - if &*name == "rust_eh_personality" || - &*name == "rust_eh_register_frames" || - &*name == "rust_eh_unregister_frames" { - SymbolExportLevel::C - } else { - SymbolExportLevel::Rust - } - } else { - symbol_export_level(tcx, def_id) - }; - debug!("EXPORTED SYMBOL (local): {} ({:?})", - tcx.symbol_name(Instance::mono(tcx, def_id)), - export_level); - (def_id, export_level) - }) - .collect(); - - if let Some(id) = *tcx.sess.derive_registrar_fn.get() { - let def_id = tcx.hir.local_def_id(id); - reachable_non_generics.insert(def_id, SymbolExportLevel::C); - } - - if let Some(id) = *tcx.sess.plugin_registrar_fn.get() { - let def_id = tcx.hir.local_def_id(id); - reachable_non_generics.insert(def_id, SymbolExportLevel::C); - } - - Lrc::new(reachable_non_generics) -} - -fn is_reachable_non_generic_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> bool { - let export_threshold = threshold(tcx); - - if let Some(&level) = tcx.reachable_non_generics(def_id.krate).get(&def_id) { - level.is_below_threshold(export_threshold) - } else { - false - } -} - -fn is_reachable_non_generic_provider_extern<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> bool { - tcx.reachable_non_generics(def_id.krate).contains_key(&def_id) -} - -fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - cnum: CrateNum) - -> Arc, - SymbolExportLevel)>> -{ - assert_eq!(cnum, LOCAL_CRATE); - - if !tcx.sess.opts.output_types.should_trans() { - return Arc::new(vec![]) - } - - let mut symbols: Vec<_> = tcx.reachable_non_generics(LOCAL_CRATE) - .iter() - .map(|(&def_id, &level)| { - (ExportedSymbol::NonGeneric(def_id), level) - }) - .collect(); - - if let Some(_) = *tcx.sess.entry_fn.borrow() { - let symbol_name = "main".to_string(); - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name)); - - symbols.push((exported_symbol, SymbolExportLevel::C)); - } - - if tcx.sess.allocator_kind.get().is_some() { - for method in ALLOCATOR_METHODS { - let symbol_name = format!("__rust_{}", method.name); - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name)); - - symbols.push((exported_symbol, SymbolExportLevel::Rust)); - } - } - - if tcx.sess.opts.debugging_opts.pgo_gen.is_some() { - // These are weak symbols that point to the profile version and the - // profile name, which need to be treated as exported so LTO doesn't nix - // them. - const PROFILER_WEAK_SYMBOLS: [&'static str; 2] = [ - "__llvm_profile_raw_version", - "__llvm_profile_filename", - ]; - for sym in &PROFILER_WEAK_SYMBOLS { - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(sym)); - symbols.push((exported_symbol, SymbolExportLevel::C)); - } - } - - if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) { - let symbol_name = metadata_symbol_name(tcx); - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name)); - - symbols.push((exported_symbol, SymbolExportLevel::Rust)); - } - - if tcx.share_generics() && tcx.local_crate_exports_generics() { - use rustc::mir::mono::{Linkage, Visibility, MonoItem}; - use rustc::ty::InstanceDef; - - // Normally, we require that shared monomorphizations are not hidden, - // because if we want to re-use a monomorphization from a Rust dylib, it - // needs to be exported. - // However, on platforms that don't allow for Rust dylibs, having - // external linkage is enough for monomorphization to be linked to. - let need_visibility = tcx.sess.target.target.options.dynamic_linking && - !tcx.sess.target.target.options.only_cdylib; - - let (_, cgus) = tcx.collect_and_partition_translation_items(LOCAL_CRATE); - - for (mono_item, &(linkage, visibility)) in cgus.iter() - .flat_map(|cgu| cgu.items().iter()) { - if linkage != Linkage::External { - // We can only re-use things with external linkage, otherwise - // we'll get a linker error - continue - } - - if need_visibility && visibility == Visibility::Hidden { - // If we potentially share things from Rust dylibs, they must - // not be hidden - continue - } - - if let &MonoItem::Fn(Instance { - def: InstanceDef::Item(def_id), - substs, - }) = mono_item { - if substs.types().next().is_some() { - symbols.push((ExportedSymbol::Generic(def_id, substs), - SymbolExportLevel::Rust)); - } - } - } - } - - // Sort so we get a stable incr. comp. hash. - symbols.sort_unstable_by(|&(ref symbol1, ..), &(ref symbol2, ..)| { - symbol1.compare_stable(tcx, symbol2) - }); - - Arc::new(symbols) -} - -fn upstream_monomorphizations_provider<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - cnum: CrateNum) - -> Lrc, CrateNum>>>> -{ - debug_assert!(cnum == LOCAL_CRATE); - - let cnums = tcx.all_crate_nums(LOCAL_CRATE); - - let mut instances = DefIdMap(); - - let cnum_stable_ids: IndexVec = { - let mut cnum_stable_ids = IndexVec::from_elem_n(Fingerprint::ZERO, - cnums.len() + 1); - - for &cnum in cnums.iter() { - cnum_stable_ids[cnum] = tcx.def_path_hash(DefId { - krate: cnum, - index: CRATE_DEF_INDEX, - }).0; - } - - cnum_stable_ids - }; - - for &cnum in cnums.iter() { - for &(ref exported_symbol, _) in tcx.exported_symbols(cnum).iter() { - if let &ExportedSymbol::Generic(def_id, substs) = exported_symbol { - let substs_map = instances.entry(def_id) - .or_insert_with(|| FxHashMap()); - - match substs_map.entry(substs) { - Occupied(mut e) => { - // If there are multiple monomorphizations available, - // we select one deterministically. - let other_cnum = *e.get(); - if cnum_stable_ids[other_cnum] > cnum_stable_ids[cnum] { - e.insert(cnum); - } - } - Vacant(e) => { - e.insert(cnum); - } - } - } - } - } - - Lrc::new(instances.into_iter() - .map(|(key, value)| (key, Lrc::new(value))) - .collect()) -} - -fn upstream_monomorphizations_for_provider<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> Option, CrateNum>>> -{ - debug_assert!(!def_id.is_local()); - tcx.upstream_monomorphizations(LOCAL_CRATE) - .get(&def_id) - .cloned() -} - -fn is_unreachable_local_definition_provider(tcx: TyCtxt, def_id: DefId) -> bool { - if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { - !tcx.reachable_set(LOCAL_CRATE).0.contains(&node_id) - } else { - bug!("is_unreachable_local_definition called with non-local DefId: {:?}", - def_id) - } -} - -pub fn provide(providers: &mut Providers) { - providers.reachable_non_generics = reachable_non_generics_provider; - providers.is_reachable_non_generic = is_reachable_non_generic_provider_local; - providers.exported_symbols = exported_symbols_provider_local; - providers.upstream_monomorphizations = upstream_monomorphizations_provider; - providers.is_unreachable_local_definition = is_unreachable_local_definition_provider; -} - -pub fn provide_extern(providers: &mut Providers) { - providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern; - providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider; -} - -fn symbol_export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel { - // We export anything that's not mangled at the "C" layer as it probably has - // to do with ABI concerns. We do not, however, apply such treatment to - // special symbols in the standard library for various plumbing between - // core/std/allocators/etc. For example symbols used to hook up allocation - // are not considered for export - let trans_fn_attrs = tcx.trans_fn_attrs(sym_def_id); - let is_extern = trans_fn_attrs.contains_extern_indicator(); - let std_internal = trans_fn_attrs.flags.contains(TransFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); - - if is_extern && !std_internal { - SymbolExportLevel::C - } else { - SymbolExportLevel::Rust - } -} diff --git a/src/librustc_trans/back/wasm.rs b/src/librustc_trans/back/wasm.rs deleted file mode 100644 index d6d386c9fbe..00000000000 --- a/src/librustc_trans/back/wasm.rs +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::collections::BTreeMap; -use std::fs; -use std::path::Path; -use std::str; - -use rustc_data_structures::fx::FxHashMap; -use serialize::leb128; - -// https://webassembly.github.io/spec/core/binary/modules.html#binary-importsec -const WASM_IMPORT_SECTION_ID: u8 = 2; - -const WASM_EXTERNAL_KIND_FUNCTION: u8 = 0; -const WASM_EXTERNAL_KIND_TABLE: u8 = 1; -const WASM_EXTERNAL_KIND_MEMORY: u8 = 2; -const WASM_EXTERNAL_KIND_GLOBAL: u8 = 3; - -/// Append all the custom sections listed in `sections` to the wasm binary -/// specified at `path`. -/// -/// LLVM 6 which we're using right now doesn't have the ability to create custom -/// sections in wasm files nor does LLD have the ability to merge these sections -/// into one larger section when linking. It's expected that this will -/// eventually get implemented, however! -/// -/// Until that time though this is a custom implementation in rustc to append -/// all sections to a wasm file to the finished product that LLD produces. -/// -/// Support for this is landing in LLVM in https://reviews.llvm.org/D43097, -/// although after that support will need to be in LLD as well. -pub fn add_custom_sections(path: &Path, sections: &BTreeMap>) { - if sections.len() == 0 { - return - } - - let wasm = fs::read(path).expect("failed to read wasm output"); - - // see https://webassembly.github.io/spec/core/binary/modules.html#custom-section - let mut wasm = WasmEncoder { data: wasm }; - for (section, bytes) in sections { - // write the `id` identifier, 0 for a custom section - wasm.byte(0); - - // figure out how long our name descriptor will be - let mut name = WasmEncoder::new(); - name.str(section); - - // write the length of the payload followed by all its contents - wasm.u32((bytes.len() + name.data.len()) as u32); - wasm.data.extend_from_slice(&name.data); - wasm.data.extend_from_slice(bytes); - } - - fs::write(path, &wasm.data).expect("failed to write wasm output"); -} - -/// Rewrite the module imports are listed from in a wasm module given the field -/// name to module name mapping in `import_map`. -/// -/// LLVM 6 which we're using right now doesn't have the ability to configure the -/// module a wasm symbol is import from. Rather all imported symbols come from -/// the bland `"env"` module unconditionally. Furthermore we'd *also* need -/// support in LLD for preserving these import modules, which it unfortunately -/// currently does not. -/// -/// This function is intended as a hack for now where we manually rewrite the -/// wasm output by LLVM to have the correct import modules listed. The -/// `#[wasm_import_module]` attribute in Rust translates to the module that each -/// symbol is imported from, so here we manually go through the wasm file, -/// decode it, rewrite imports, and then rewrite the wasm module. -/// -/// Support for this was added to LLVM in -/// https://github.com/llvm-mirror/llvm/commit/0f32e1365, although support still -/// needs to be added (AFAIK at the time of this writing) to LLD -pub fn rewrite_imports(path: &Path, import_map: &FxHashMap) { - if import_map.len() == 0 { - return - } - - let wasm = fs::read(path).expect("failed to read wasm output"); - let mut ret = WasmEncoder::new(); - ret.data.extend(&wasm[..8]); - - // skip the 8 byte wasm/version header - for (id, raw) in WasmSections(WasmDecoder::new(&wasm[8..])) { - ret.byte(id); - if id == WASM_IMPORT_SECTION_ID { - info!("rewriting import section"); - let data = rewrite_import_section( - &mut WasmDecoder::new(raw), - import_map, - ); - ret.bytes(&data); - } else { - info!("carry forward section {}, {} bytes long", id, raw.len()); - ret.bytes(raw); - } - } - - fs::write(path, &ret.data).expect("failed to write wasm output"); - - fn rewrite_import_section( - wasm: &mut WasmDecoder, - import_map: &FxHashMap, - ) - -> Vec - { - let mut dst = WasmEncoder::new(); - let n = wasm.u32(); - dst.u32(n); - info!("rewriting {} imports", n); - for _ in 0..n { - rewrite_import_entry(wasm, &mut dst, import_map); - } - return dst.data - } - - fn rewrite_import_entry(wasm: &mut WasmDecoder, - dst: &mut WasmEncoder, - import_map: &FxHashMap) { - // More info about the binary format here is available at: - // https://webassembly.github.io/spec/core/binary/modules.html#import-section - // - // Note that you can also find the whole point of existence of this - // function here, where we map the `module` name to a different one if - // we've got one listed. - let module = wasm.str(); - let field = wasm.str(); - let new_module = if module == "env" { - import_map.get(field).map(|s| &**s).unwrap_or(module) - } else { - module - }; - info!("import rewrite ({} => {}) / {}", module, new_module, field); - dst.str(new_module); - dst.str(field); - let kind = wasm.byte(); - dst.byte(kind); - match kind { - WASM_EXTERNAL_KIND_FUNCTION => dst.u32(wasm.u32()), - WASM_EXTERNAL_KIND_TABLE => { - dst.byte(wasm.byte()); // element_type - dst.limits(wasm.limits()); - } - WASM_EXTERNAL_KIND_MEMORY => dst.limits(wasm.limits()), - WASM_EXTERNAL_KIND_GLOBAL => { - dst.byte(wasm.byte()); // content_type - dst.bool(wasm.bool()); // mutable - } - b => panic!("unknown kind: {}", b), - } - } -} - -struct WasmSections<'a>(WasmDecoder<'a>); - -impl<'a> Iterator for WasmSections<'a> { - type Item = (u8, &'a [u8]); - - fn next(&mut self) -> Option<(u8, &'a [u8])> { - if self.0.data.len() == 0 { - return None - } - - // see https://webassembly.github.io/spec/core/binary/modules.html#sections - let id = self.0.byte(); - let section_len = self.0.u32(); - info!("new section {} / {} bytes", id, section_len); - let section = self.0.skip(section_len as usize); - Some((id, section)) - } -} - -struct WasmDecoder<'a> { - data: &'a [u8], -} - -impl<'a> WasmDecoder<'a> { - fn new(data: &'a [u8]) -> WasmDecoder<'a> { - WasmDecoder { data } - } - - fn byte(&mut self) -> u8 { - self.skip(1)[0] - } - - fn u32(&mut self) -> u32 { - let (n, l1) = leb128::read_u32_leb128(self.data); - self.data = &self.data[l1..]; - return n - } - - fn skip(&mut self, amt: usize) -> &'a [u8] { - let (data, rest) = self.data.split_at(amt); - self.data = rest; - data - } - - fn str(&mut self) -> &'a str { - let len = self.u32(); - str::from_utf8(self.skip(len as usize)).unwrap() - } - - fn bool(&mut self) -> bool { - self.byte() == 1 - } - - fn limits(&mut self) -> (u32, Option) { - let has_max = self.bool(); - (self.u32(), if has_max { Some(self.u32()) } else { None }) - } -} - -struct WasmEncoder { - data: Vec, -} - -impl WasmEncoder { - fn new() -> WasmEncoder { - WasmEncoder { data: Vec::new() } - } - - fn u32(&mut self, val: u32) { - let at = self.data.len(); - leb128::write_u32_leb128(&mut self.data, at, val); - } - - fn byte(&mut self, val: u8) { - self.data.push(val); - } - - fn bytes(&mut self, val: &[u8]) { - self.u32(val.len() as u32); - self.data.extend_from_slice(val); - } - - fn str(&mut self, val: &str) { - self.bytes(val.as_bytes()) - } - - fn bool(&mut self, b: bool) { - self.byte(b as u8); - } - - fn limits(&mut self, limits: (u32, Option)) { - self.bool(limits.1.is_some()); - self.u32(limits.0); - if let Some(c) = limits.1 { - self.u32(c); - } - } -} diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs deleted file mode 100644 index acfe7c33028..00000000000 --- a/src/librustc_trans/back/write.rs +++ /dev/null @@ -1,2392 +0,0 @@ -// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use attributes; -use back::bytecode::{self, RLIB_BYTECODE_EXTENSION}; -use back::lto::{self, ModuleBuffer, ThinBuffer}; -use back::link::{self, get_linker, remove}; -use back::command::Command; -use back::linker::LinkerInfo; -use back::symbol_export::ExportedSymbols; -use base; -use consts; -use rustc_incremental::{copy_cgu_workproducts_to_incr_comp_cache_dir, in_incr_comp_dir}; -use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind}; -use rustc::middle::cstore::{LinkMeta, EncodedMetadata}; -use rustc::session::config::{self, OutputFilenames, OutputType, Passes, SomePasses, - AllPasses, Sanitizer, Lto}; -use rustc::session::Session; -use rustc::util::nodemap::FxHashMap; -use time_graph::{self, TimeGraph, Timeline}; -use llvm; -use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef}; -use llvm::{SMDiagnosticRef, ContextRef}; -use {CrateTranslation, ModuleSource, ModuleTranslation, CompiledModule, ModuleKind}; -use CrateInfo; -use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; -use rustc::ty::TyCtxt; -use rustc::util::common::{time_ext, time_depth, set_time_depth, print_time_passes_entry}; -use rustc::util::common::path2cstr; -use rustc::util::fs::{link_or_copy}; -use errors::{self, Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId}; -use errors::emitter::{Emitter}; -use syntax::attr; -use syntax::ext::hygiene::Mark; -use syntax_pos::MultiSpan; -use syntax_pos::symbol::Symbol; -use type_::Type; -use context::{is_pie_binary, get_reloc_model}; -use common::{C_bytes_in_context, val_ty}; -use jobserver::{Client, Acquired}; -use rustc_demangle; - -use std::any::Any; -use std::ffi::{CString, CStr}; -use std::fs; -use std::io::{self, Write}; -use std::mem; -use std::path::{Path, PathBuf}; -use std::str; -use std::sync::Arc; -use std::sync::mpsc::{channel, Sender, Receiver}; -use std::slice; -use std::time::Instant; -use std::thread; -use libc::{c_uint, c_void, c_char, size_t}; - -pub const RELOC_MODEL_ARGS : [(&'static str, llvm::RelocMode); 7] = [ - ("pic", llvm::RelocMode::PIC), - ("static", llvm::RelocMode::Static), - ("default", llvm::RelocMode::Default), - ("dynamic-no-pic", llvm::RelocMode::DynamicNoPic), - ("ropi", llvm::RelocMode::ROPI), - ("rwpi", llvm::RelocMode::RWPI), - ("ropi-rwpi", llvm::RelocMode::ROPI_RWPI), -]; - -pub const CODE_GEN_MODEL_ARGS: &[(&str, llvm::CodeModel)] = &[ - ("small", llvm::CodeModel::Small), - ("kernel", llvm::CodeModel::Kernel), - ("medium", llvm::CodeModel::Medium), - ("large", llvm::CodeModel::Large), -]; - -pub const TLS_MODEL_ARGS : [(&'static str, llvm::ThreadLocalMode); 4] = [ - ("global-dynamic", llvm::ThreadLocalMode::GeneralDynamic), - ("local-dynamic", llvm::ThreadLocalMode::LocalDynamic), - ("initial-exec", llvm::ThreadLocalMode::InitialExec), - ("local-exec", llvm::ThreadLocalMode::LocalExec), -]; - -pub fn llvm_err(handler: &errors::Handler, msg: String) -> FatalError { - match llvm::last_error() { - Some(err) => handler.fatal(&format!("{}: {}", msg, err)), - None => handler.fatal(&msg), - } -} - -pub fn write_output_file( - handler: &errors::Handler, - target: llvm::TargetMachineRef, - pm: llvm::PassManagerRef, - m: ModuleRef, - output: &Path, - file_type: llvm::FileType) -> Result<(), FatalError> { - unsafe { - let output_c = path2cstr(output); - let result = llvm::LLVMRustWriteOutputFile( - target, pm, m, output_c.as_ptr(), file_type); - if result.into_result().is_err() { - let msg = format!("could not write output to {}", output.display()); - Err(llvm_err(handler, msg)) - } else { - Ok(()) - } - } -} - -fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel { - match optimize { - config::OptLevel::No => llvm::CodeGenOptLevel::None, - config::OptLevel::Less => llvm::CodeGenOptLevel::Less, - config::OptLevel::Default => llvm::CodeGenOptLevel::Default, - config::OptLevel::Aggressive => llvm::CodeGenOptLevel::Aggressive, - _ => llvm::CodeGenOptLevel::Default, - } -} - -fn get_llvm_opt_size(optimize: config::OptLevel) -> llvm::CodeGenOptSize { - match optimize { - config::OptLevel::Size => llvm::CodeGenOptSizeDefault, - config::OptLevel::SizeMin => llvm::CodeGenOptSizeAggressive, - _ => llvm::CodeGenOptSizeNone, - } -} - -pub fn create_target_machine(sess: &Session, find_features: bool) -> TargetMachineRef { - target_machine_factory(sess, find_features)().unwrap_or_else(|err| { - llvm_err(sess.diagnostic(), err).raise() - }) -} - -// If find_features is true this won't access `sess.crate_types` by assuming -// that `is_pie_binary` is false. When we discover LLVM target features -// `sess.crate_types` is uninitialized so we cannot access it. -pub fn target_machine_factory(sess: &Session, find_features: bool) - -> Arc Result + Send + Sync> -{ - let reloc_model = get_reloc_model(sess); - - let opt_level = get_llvm_opt_level(sess.opts.optimize); - let use_softfp = sess.opts.cg.soft_float; - - let ffunction_sections = sess.target.target.options.function_sections; - let fdata_sections = ffunction_sections; - - let code_model_arg = sess.opts.cg.code_model.as_ref().or( - sess.target.target.options.code_model.as_ref(), - ); - - let code_model = match code_model_arg { - Some(s) => { - match CODE_GEN_MODEL_ARGS.iter().find(|arg| arg.0 == s) { - Some(x) => x.1, - _ => { - sess.err(&format!("{:?} is not a valid code model", - code_model_arg)); - sess.abort_if_errors(); - bug!(); - } - } - } - None => llvm::CodeModel::None, - }; - - let singlethread = sess.target.target.options.singlethread; - - let triple = &sess.target.target.llvm_target; - - let triple = CString::new(triple.as_bytes()).unwrap(); - let cpu = sess.target_cpu(); - let cpu = CString::new(cpu.as_bytes()).unwrap(); - let features = attributes::llvm_target_features(sess) - .collect::>() - .join(","); - let features = CString::new(features).unwrap(); - let is_pie_binary = !find_features && is_pie_binary(sess); - let trap_unreachable = sess.target.target.options.trap_unreachable; - - Arc::new(move || { - let tm = unsafe { - llvm::LLVMRustCreateTargetMachine( - triple.as_ptr(), cpu.as_ptr(), features.as_ptr(), - code_model, - reloc_model, - opt_level, - use_softfp, - is_pie_binary, - ffunction_sections, - fdata_sections, - trap_unreachable, - singlethread, - ) - }; - - if tm.is_null() { - Err(format!("Could not create LLVM TargetMachine for triple: {}", - triple.to_str().unwrap())) - } else { - Ok(tm) - } - }) -} - -/// Module-specific configuration for `optimize_and_codegen`. -pub struct ModuleConfig { - /// Names of additional optimization passes to run. - passes: Vec, - /// Some(level) to optimize at a certain level, or None to run - /// absolutely no optimizations (used for the metadata module). - pub opt_level: Option, - - /// Some(level) to optimize binary size, or None to not affect program size. - opt_size: Option, - - pgo_gen: Option, - pgo_use: String, - - // Flags indicating which outputs to produce. - emit_no_opt_bc: bool, - emit_bc: bool, - emit_bc_compressed: bool, - emit_lto_bc: bool, - emit_ir: bool, - emit_asm: bool, - emit_obj: bool, - // Miscellaneous flags. These are mostly copied from command-line - // options. - no_verify: bool, - no_prepopulate_passes: bool, - no_builtins: bool, - time_passes: bool, - vectorize_loop: bool, - vectorize_slp: bool, - merge_functions: bool, - inline_threshold: Option, - // Instead of creating an object file by doing LLVM codegen, just - // make the object file bitcode. Provides easy compatibility with - // emscripten's ecc compiler, when used as the linker. - obj_is_bitcode: bool, - no_integrated_as: bool, - embed_bitcode: bool, - embed_bitcode_marker: bool, -} - -impl ModuleConfig { - fn new(passes: Vec) -> ModuleConfig { - ModuleConfig { - passes, - opt_level: None, - opt_size: None, - - pgo_gen: None, - pgo_use: String::new(), - - emit_no_opt_bc: false, - emit_bc: false, - emit_bc_compressed: false, - emit_lto_bc: false, - emit_ir: false, - emit_asm: false, - emit_obj: false, - obj_is_bitcode: false, - embed_bitcode: false, - embed_bitcode_marker: false, - no_integrated_as: false, - - no_verify: false, - no_prepopulate_passes: false, - no_builtins: false, - time_passes: false, - vectorize_loop: false, - vectorize_slp: false, - merge_functions: false, - inline_threshold: None - } - } - - fn set_flags(&mut self, sess: &Session, no_builtins: bool) { - self.no_verify = sess.no_verify(); - self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes; - self.no_builtins = no_builtins || sess.target.target.options.no_builtins; - self.time_passes = sess.time_passes(); - self.inline_threshold = sess.opts.cg.inline_threshold; - self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode; - let embed_bitcode = sess.target.target.options.embed_bitcode || - sess.opts.debugging_opts.embed_bitcode || - sess.opts.debugging_opts.cross_lang_lto.embed_bitcode(); - if embed_bitcode { - match sess.opts.optimize { - config::OptLevel::No | - config::OptLevel::Less => { - self.embed_bitcode_marker = embed_bitcode; - } - _ => self.embed_bitcode = embed_bitcode, - } - } - - // Copy what clang does by turning on loop vectorization at O2 and - // slp vectorization at O3. Otherwise configure other optimization aspects - // of this pass manager builder. - // Turn off vectorization for emscripten, as it's not very well supported. - self.vectorize_loop = !sess.opts.cg.no_vectorize_loops && - (sess.opts.optimize == config::OptLevel::Default || - sess.opts.optimize == config::OptLevel::Aggressive) && - !sess.target.target.options.is_like_emscripten; - - self.vectorize_slp = !sess.opts.cg.no_vectorize_slp && - sess.opts.optimize == config::OptLevel::Aggressive && - !sess.target.target.options.is_like_emscripten; - - self.merge_functions = sess.opts.optimize == config::OptLevel::Default || - sess.opts.optimize == config::OptLevel::Aggressive; - } -} - -/// Assembler name and command used by codegen when no_integrated_as is enabled -struct AssemblerCommand { - name: PathBuf, - cmd: Command, -} - -/// Additional resources used by optimize_and_codegen (not module specific) -#[derive(Clone)] -pub struct CodegenContext { - // Resouces needed when running LTO - pub time_passes: bool, - pub lto: Lto, - pub no_landing_pads: bool, - pub save_temps: bool, - pub fewer_names: bool, - pub exported_symbols: Option>, - pub opts: Arc, - pub crate_types: Vec, - pub each_linked_rlib_for_lto: Vec<(CrateNum, PathBuf)>, - output_filenames: Arc, - regular_module_config: Arc, - metadata_module_config: Arc, - allocator_module_config: Arc, - pub tm_factory: Arc Result + Send + Sync>, - pub msvc_imps_needed: bool, - pub target_pointer_width: String, - debuginfo: config::DebugInfoLevel, - - // Number of cgus excluding the allocator/metadata modules - pub total_cgus: usize, - // Handler to use for diagnostics produced during codegen. - pub diag_emitter: SharedEmitter, - // LLVM passes added by plugins. - pub plugin_passes: Vec, - // LLVM optimizations for which we want to print remarks. - pub remark: Passes, - // Worker thread number - pub worker: usize, - // The incremental compilation session directory, or None if we are not - // compiling incrementally - pub incr_comp_session_dir: Option, - // Channel back to the main control thread to send messages to - coordinator_send: Sender>, - // A reference to the TimeGraph so we can register timings. None means that - // measuring is disabled. - time_graph: Option, - // The assembler command if no_integrated_as option is enabled, None otherwise - assembler_cmd: Option>, -} - -impl CodegenContext { - pub fn create_diag_handler(&self) -> Handler { - Handler::with_emitter(true, false, Box::new(self.diag_emitter.clone())) - } - - pub(crate) fn config(&self, kind: ModuleKind) -> &ModuleConfig { - match kind { - ModuleKind::Regular => &self.regular_module_config, - ModuleKind::Metadata => &self.metadata_module_config, - ModuleKind::Allocator => &self.allocator_module_config, - } - } - - pub(crate) fn save_temp_bitcode(&self, trans: &ModuleTranslation, name: &str) { - if !self.save_temps { - return - } - unsafe { - let ext = format!("{}.bc", name); - let cgu = Some(&trans.name[..]); - let path = self.output_filenames.temp_path_ext(&ext, cgu); - let cstr = path2cstr(&path); - let llmod = trans.llvm().unwrap().llmod; - llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr()); - } - } -} - -struct DiagnosticHandlers<'a> { - inner: Box<(&'a CodegenContext, &'a Handler)>, - llcx: ContextRef, -} - -impl<'a> DiagnosticHandlers<'a> { - fn new(cgcx: &'a CodegenContext, - handler: &'a Handler, - llcx: ContextRef) -> DiagnosticHandlers<'a> { - let data = Box::new((cgcx, handler)); - unsafe { - let arg = &*data as &(_, _) as *const _ as *mut _; - llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, arg); - llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, arg); - } - DiagnosticHandlers { - inner: data, - llcx: llcx, - } - } -} - -impl<'a> Drop for DiagnosticHandlers<'a> { - fn drop(&mut self) { - unsafe { - llvm::LLVMRustSetInlineAsmDiagnosticHandler(self.llcx, inline_asm_handler, 0 as *mut _); - llvm::LLVMContextSetDiagnosticHandler(self.llcx, diagnostic_handler, 0 as *mut _); - } - } -} - -unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext, - msg: &'b str, - cookie: c_uint) { - cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_string()); -} - -unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef, - user: *const c_void, - cookie: c_uint) { - if user.is_null() { - return - } - let (cgcx, _) = *(user as *const (&CodegenContext, &Handler)); - - let msg = llvm::build_string(|s| llvm::LLVMRustWriteSMDiagnosticToString(diag, s)) - .expect("non-UTF8 SMDiagnostic"); - - report_inline_asm(cgcx, &msg, cookie); -} - -unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_void) { - if user.is_null() { - return - } - let (cgcx, diag_handler) = *(user as *const (&CodegenContext, &Handler)); - - match llvm::diagnostic::Diagnostic::unpack(info) { - llvm::diagnostic::InlineAsm(inline) => { - report_inline_asm(cgcx, - &llvm::twine_to_string(inline.message), - inline.cookie); - } - - llvm::diagnostic::Optimization(opt) => { - let enabled = match cgcx.remark { - AllPasses => true, - SomePasses(ref v) => v.iter().any(|s| *s == opt.pass_name), - }; - - if enabled { - diag_handler.note_without_error(&format!("optimization {} for {} at {}:{}:{}: {}", - opt.kind.describe(), - opt.pass_name, - opt.filename, - opt.line, - opt.column, - opt.message)); - } - } - llvm::diagnostic::PGO(diagnostic_ref) => { - let msg = llvm::build_string(|s| { - llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) - }).expect("non-UTF8 PGO diagnostic"); - diag_handler.warn(&msg); - } - llvm::diagnostic::UnknownDiagnostic(..) => {}, - } -} - -// Unsafe due to LLVM calls. -unsafe fn optimize(cgcx: &CodegenContext, - diag_handler: &Handler, - mtrans: &ModuleTranslation, - config: &ModuleConfig, - timeline: &mut Timeline) - -> Result<(), FatalError> -{ - let (llmod, llcx, tm) = match mtrans.source { - ModuleSource::Translated(ref llvm) => (llvm.llmod, llvm.llcx, llvm.tm), - ModuleSource::Preexisting(_) => { - bug!("optimize_and_codegen: called with ModuleSource::Preexisting") - } - }; - - let _handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx); - - let module_name = mtrans.name.clone(); - let module_name = Some(&module_name[..]); - - if config.emit_no_opt_bc { - let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name); - let out = path2cstr(&out); - llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); - } - - if config.opt_level.is_some() { - // Create the two optimizing pass managers. These mirror what clang - // does, and are by populated by LLVM's default PassManagerBuilder. - // Each manager has a different set of passes, but they also share - // some common passes. - let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod); - let mpm = llvm::LLVMCreatePassManager(); - - // If we're verifying or linting, add them to the function pass - // manager. - let addpass = |pass_name: &str| { - let pass_name = CString::new(pass_name).unwrap(); - let pass = llvm::LLVMRustFindAndCreatePass(pass_name.as_ptr()); - if pass.is_null() { - return false; - } - let pass_manager = match llvm::LLVMRustPassKind(pass) { - llvm::PassKind::Function => fpm, - llvm::PassKind::Module => mpm, - llvm::PassKind::Other => { - diag_handler.err("Encountered LLVM pass kind we can't handle"); - return true - }, - }; - llvm::LLVMRustAddPass(pass_manager, pass); - true - }; - - if !config.no_verify { assert!(addpass("verify")); } - if !config.no_prepopulate_passes { - llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod); - llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod); - let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None); - let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal; - with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| { - llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm); - llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm); - }) - } - - for pass in &config.passes { - if !addpass(pass) { - diag_handler.warn(&format!("unknown pass `{}`, ignoring", - pass)); - } - } - - for pass in &cgcx.plugin_passes { - if !addpass(pass) { - diag_handler.err(&format!("a plugin asked for LLVM pass \ - `{}` but LLVM does not \ - recognize it", pass)); - } - } - - diag_handler.abort_if_errors(); - - // Finally, run the actual optimization passes - time_ext(config.time_passes, - None, - &format!("llvm function passes [{}]", module_name.unwrap()), - || { - llvm::LLVMRustRunFunctionPassManager(fpm, llmod) - }); - timeline.record("fpm"); - time_ext(config.time_passes, - None, - &format!("llvm module passes [{}]", module_name.unwrap()), - || { - llvm::LLVMRunPassManager(mpm, llmod) - }); - - // Deallocate managers that we're now done with - llvm::LLVMDisposePassManager(fpm); - llvm::LLVMDisposePassManager(mpm); - } - Ok(()) -} - -fn generate_lto_work(cgcx: &CodegenContext, - modules: Vec) - -> Vec<(WorkItem, u64)> -{ - let mut timeline = cgcx.time_graph.as_ref().map(|tg| { - tg.start(TRANS_WORKER_TIMELINE, - TRANS_WORK_PACKAGE_KIND, - "generate lto") - }).unwrap_or(Timeline::noop()); - let lto_modules = lto::run(cgcx, modules, &mut timeline) - .unwrap_or_else(|e| e.raise()); - - lto_modules.into_iter().map(|module| { - let cost = module.cost(); - (WorkItem::LTO(module), cost) - }).collect() -} - -unsafe fn codegen(cgcx: &CodegenContext, - diag_handler: &Handler, - mtrans: ModuleTranslation, - config: &ModuleConfig, - timeline: &mut Timeline) - -> Result -{ - timeline.record("codegen"); - let (llmod, llcx, tm) = match mtrans.source { - ModuleSource::Translated(ref llvm) => (llvm.llmod, llvm.llcx, llvm.tm), - ModuleSource::Preexisting(_) => { - bug!("codegen: called with ModuleSource::Preexisting") - } - }; - let module_name = mtrans.name.clone(); - let module_name = Some(&module_name[..]); - let handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx); - - if cgcx.msvc_imps_needed { - create_msvc_imps(cgcx, llcx, llmod); - } - - // A codegen-specific pass manager is used to generate object - // files for an LLVM module. - // - // Apparently each of these pass managers is a one-shot kind of - // thing, so we create a new one for each type of output. The - // pass manager passed to the closure should be ensured to not - // escape the closure itself, and the manager should only be - // used once. - unsafe fn with_codegen(tm: TargetMachineRef, - llmod: ModuleRef, - no_builtins: bool, - f: F) -> R - where F: FnOnce(PassManagerRef) -> R, - { - let cpm = llvm::LLVMCreatePassManager(); - llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod); - llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); - f(cpm) - } - - // If we don't have the integrated assembler, then we need to emit asm - // from LLVM and use `gcc` to create the object file. - let asm_to_obj = config.emit_obj && config.no_integrated_as; - - // Change what we write and cleanup based on whether obj files are - // just llvm bitcode. In that case write bitcode, and possibly - // delete the bitcode if it wasn't requested. Don't generate the - // machine code, instead copy the .o file from the .bc - let write_bc = config.emit_bc || config.obj_is_bitcode; - let rm_bc = !config.emit_bc && config.obj_is_bitcode; - let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm_to_obj; - let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode; - - let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); - let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); - - - if write_bc || config.emit_bc_compressed || config.embed_bitcode { - let thin; - let old; - let data = if llvm::LLVMRustThinLTOAvailable() { - thin = ThinBuffer::new(llmod); - thin.data() - } else { - old = ModuleBuffer::new(llmod); - old.data() - }; - timeline.record("make-bc"); - - if write_bc { - if let Err(e) = fs::write(&bc_out, data) { - diag_handler.err(&format!("failed to write bytecode: {}", e)); - } - timeline.record("write-bc"); - } - - if config.embed_bitcode { - embed_bitcode(cgcx, llcx, llmod, Some(data)); - timeline.record("embed-bc"); - } - - if config.emit_bc_compressed { - let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION); - let data = bytecode::encode(&mtrans.llmod_id, data); - if let Err(e) = fs::write(&dst, data) { - diag_handler.err(&format!("failed to write bytecode: {}", e)); - } - timeline.record("compress-bc"); - } - } else if config.embed_bitcode_marker { - embed_bitcode(cgcx, llcx, llmod, None); - } - - time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()), - || -> Result<(), FatalError> { - if config.emit_ir { - let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name); - let out = path2cstr(&out); - - extern "C" fn demangle_callback(input_ptr: *const c_char, - input_len: size_t, - output_ptr: *mut c_char, - output_len: size_t) -> size_t { - let input = unsafe { - slice::from_raw_parts(input_ptr as *const u8, input_len as usize) - }; - - let input = match str::from_utf8(input) { - Ok(s) => s, - Err(_) => return 0, - }; - - let output = unsafe { - slice::from_raw_parts_mut(output_ptr as *mut u8, output_len as usize) - }; - let mut cursor = io::Cursor::new(output); - - let demangled = match rustc_demangle::try_demangle(input) { - Ok(d) => d, - Err(_) => return 0, - }; - - if let Err(_) = write!(cursor, "{:#}", demangled) { - // Possible only if provided buffer is not big enough - return 0; - } - - cursor.position() as size_t - } - - with_codegen(tm, llmod, config.no_builtins, |cpm| { - llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr(), demangle_callback); - llvm::LLVMDisposePassManager(cpm); - }); - timeline.record("ir"); - } - - if config.emit_asm || asm_to_obj { - let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); - - // We can't use the same module for asm and binary output, because that triggers - // various errors like invalid IR or broken binaries, so we might have to clone the - // module to produce the asm output - let llmod = if config.emit_obj { - llvm::LLVMCloneModule(llmod) - } else { - llmod - }; - with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file(diag_handler, tm, cpm, llmod, &path, - llvm::FileType::AssemblyFile) - })?; - if config.emit_obj { - llvm::LLVMDisposeModule(llmod); - } - timeline.record("asm"); - } - - if write_obj { - with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file(diag_handler, tm, cpm, llmod, &obj_out, - llvm::FileType::ObjectFile) - })?; - timeline.record("obj"); - } else if asm_to_obj { - let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); - run_assembler(cgcx, diag_handler, &assembly, &obj_out); - timeline.record("asm_to_obj"); - - if !config.emit_asm && !cgcx.save_temps { - drop(fs::remove_file(&assembly)); - } - } - - Ok(()) - })?; - - if copy_bc_to_obj { - debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out); - if let Err(e) = link_or_copy(&bc_out, &obj_out) { - diag_handler.err(&format!("failed to copy bitcode to object file: {}", e)); - } - } - - if rm_bc { - debug!("removing_bitcode {:?}", bc_out); - if let Err(e) = fs::remove_file(&bc_out) { - diag_handler.err(&format!("failed to remove bitcode: {}", e)); - } - } - - drop(handlers); - Ok(mtrans.into_compiled_module(config.emit_obj, - config.emit_bc, - config.emit_bc_compressed, - &cgcx.output_filenames)) -} - -/// Embed the bitcode of an LLVM module in the LLVM module itself. -/// -/// This is done primarily for iOS where it appears to be standard to compile C -/// code at least with `-fembed-bitcode` which creates two sections in the -/// executable: -/// -/// * __LLVM,__bitcode -/// * __LLVM,__cmdline -/// -/// It appears *both* of these sections are necessary to get the linker to -/// recognize what's going on. For us though we just always throw in an empty -/// cmdline section. -/// -/// Furthermore debug/O1 builds don't actually embed bitcode but rather just -/// embed an empty section. -/// -/// Basically all of this is us attempting to follow in the footsteps of clang -/// on iOS. See #35968 for lots more info. -unsafe fn embed_bitcode(cgcx: &CodegenContext, - llcx: ContextRef, - llmod: ModuleRef, - bitcode: Option<&[u8]>) { - let llconst = C_bytes_in_context(llcx, bitcode.unwrap_or(&[])); - let llglobal = llvm::LLVMAddGlobal( - llmod, - val_ty(llconst).to_ref(), - "rustc.embedded.module\0".as_ptr() as *const _, - ); - llvm::LLVMSetInitializer(llglobal, llconst); - - let is_apple = cgcx.opts.target_triple.triple().contains("-ios") || - cgcx.opts.target_triple.triple().contains("-darwin"); - - let section = if is_apple { - "__LLVM,__bitcode\0" - } else { - ".llvmbc\0" - }; - llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _); - llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); - llvm::LLVMSetGlobalConstant(llglobal, llvm::True); - - let llconst = C_bytes_in_context(llcx, &[]); - let llglobal = llvm::LLVMAddGlobal( - llmod, - val_ty(llconst).to_ref(), - "rustc.embedded.cmdline\0".as_ptr() as *const _, - ); - llvm::LLVMSetInitializer(llglobal, llconst); - let section = if is_apple { - "__LLVM,__cmdline\0" - } else { - ".llvmcmd\0" - }; - llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _); - llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); -} - -pub(crate) struct CompiledModules { - pub modules: Vec, - pub metadata_module: CompiledModule, - pub allocator_module: Option, -} - -fn need_crate_bitcode_for_rlib(sess: &Session) -> bool { - sess.crate_types.borrow().contains(&config::CrateTypeRlib) && - sess.opts.output_types.contains_key(&OutputType::Exe) -} - -pub fn start_async_translation(tcx: TyCtxt, - time_graph: Option, - link: LinkMeta, - metadata: EncodedMetadata, - coordinator_receive: Receiver>, - total_cgus: usize) - -> OngoingCrateTranslation { - let sess = tcx.sess; - let crate_name = tcx.crate_name(LOCAL_CRATE); - let no_builtins = attr::contains_name(&tcx.hir.krate().attrs, "no_builtins"); - let subsystem = attr::first_attr_value_str_by_name(&tcx.hir.krate().attrs, - "windows_subsystem"); - let windows_subsystem = subsystem.map(|subsystem| { - if subsystem != "windows" && subsystem != "console" { - tcx.sess.fatal(&format!("invalid windows subsystem `{}`, only \ - `windows` and `console` are allowed", - subsystem)); - } - subsystem.to_string() - }); - - let linker_info = LinkerInfo::new(tcx); - let crate_info = CrateInfo::new(tcx); - - // Figure out what we actually need to build. - let mut modules_config = ModuleConfig::new(sess.opts.cg.passes.clone()); - let mut metadata_config = ModuleConfig::new(vec![]); - let mut allocator_config = ModuleConfig::new(vec![]); - - if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer { - match *sanitizer { - Sanitizer::Address => { - modules_config.passes.push("asan".to_owned()); - modules_config.passes.push("asan-module".to_owned()); - } - Sanitizer::Memory => { - modules_config.passes.push("msan".to_owned()) - } - Sanitizer::Thread => { - modules_config.passes.push("tsan".to_owned()) - } - _ => {} - } - } - - if sess.opts.debugging_opts.profile { - modules_config.passes.push("insert-gcov-profiling".to_owned()) - } - - modules_config.pgo_gen = sess.opts.debugging_opts.pgo_gen.clone(); - modules_config.pgo_use = sess.opts.debugging_opts.pgo_use.clone(); - - modules_config.opt_level = Some(get_llvm_opt_level(sess.opts.optimize)); - modules_config.opt_size = Some(get_llvm_opt_size(sess.opts.optimize)); - - // Save all versions of the bytecode if we're saving our temporaries. - if sess.opts.cg.save_temps { - modules_config.emit_no_opt_bc = true; - modules_config.emit_bc = true; - modules_config.emit_lto_bc = true; - metadata_config.emit_bc = true; - allocator_config.emit_bc = true; - } - - // Emit compressed bitcode files for the crate if we're emitting an rlib. - // Whenever an rlib is created, the bitcode is inserted into the archive in - // order to allow LTO against it. - if need_crate_bitcode_for_rlib(sess) { - modules_config.emit_bc_compressed = true; - allocator_config.emit_bc_compressed = true; - } - - modules_config.no_integrated_as = tcx.sess.opts.cg.no_integrated_as || - tcx.sess.target.target.options.no_integrated_as; - - for output_type in sess.opts.output_types.keys() { - match *output_type { - OutputType::Bitcode => { modules_config.emit_bc = true; } - OutputType::LlvmAssembly => { modules_config.emit_ir = true; } - OutputType::Assembly => { - modules_config.emit_asm = true; - // If we're not using the LLVM assembler, this function - // could be invoked specially with output_type_assembly, so - // in this case we still want the metadata object file. - if !sess.opts.output_types.contains_key(&OutputType::Assembly) { - metadata_config.emit_obj = true; - allocator_config.emit_obj = true; - } - } - OutputType::Object => { modules_config.emit_obj = true; } - OutputType::Metadata => { metadata_config.emit_obj = true; } - OutputType::Exe => { - modules_config.emit_obj = true; - metadata_config.emit_obj = true; - allocator_config.emit_obj = true; - }, - OutputType::Mir => {} - OutputType::DepInfo => {} - } - } - - modules_config.set_flags(sess, no_builtins); - metadata_config.set_flags(sess, no_builtins); - allocator_config.set_flags(sess, no_builtins); - - // Exclude metadata and allocator modules from time_passes output, since - // they throw off the "LLVM passes" measurement. - metadata_config.time_passes = false; - allocator_config.time_passes = false; - - let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); - let (trans_worker_send, trans_worker_receive) = channel(); - - let coordinator_thread = start_executing_work(tcx, - &crate_info, - shared_emitter, - trans_worker_send, - coordinator_receive, - total_cgus, - sess.jobserver.clone(), - time_graph.clone(), - Arc::new(modules_config), - Arc::new(metadata_config), - Arc::new(allocator_config)); - - OngoingCrateTranslation { - crate_name, - link, - metadata, - windows_subsystem, - linker_info, - crate_info, - - time_graph, - coordinator_send: tcx.tx_to_llvm_workers.lock().clone(), - trans_worker_receive, - shared_emitter_main, - future: coordinator_thread, - output_filenames: tcx.output_filenames(LOCAL_CRATE), - } -} - -fn copy_all_cgu_workproducts_to_incr_comp_cache_dir( - sess: &Session, - compiled_modules: &CompiledModules -) -> FxHashMap { - let mut work_products = FxHashMap::default(); - - if sess.opts.incremental.is_none() { - return work_products; - } - - for module in compiled_modules.modules.iter() { - let mut files = vec![]; - - if let Some(ref path) = module.object { - files.push((WorkProductFileKind::Object, path.clone())); - } - if let Some(ref path) = module.bytecode { - files.push((WorkProductFileKind::Bytecode, path.clone())); - } - if let Some(ref path) = module.bytecode_compressed { - files.push((WorkProductFileKind::BytecodeCompressed, path.clone())); - } - - if let Some((id, product)) = - copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files) { - work_products.insert(id, product); - } - } - - work_products -} - -fn produce_final_output_artifacts(sess: &Session, - compiled_modules: &CompiledModules, - crate_output: &OutputFilenames) { - let mut user_wants_bitcode = false; - let mut user_wants_objects = false; - - // Produce final compile outputs. - let copy_gracefully = |from: &Path, to: &Path| { - if let Err(e) = fs::copy(from, to) { - sess.err(&format!("could not copy {:?} to {:?}: {}", from, to, e)); - } - }; - - let copy_if_one_unit = |output_type: OutputType, - keep_numbered: bool| { - if compiled_modules.modules.len() == 1 { - // 1) Only one codegen unit. In this case it's no difficulty - // to copy `foo.0.x` to `foo.x`. - let module_name = Some(&compiled_modules.modules[0].name[..]); - let path = crate_output.temp_path(output_type, module_name); - copy_gracefully(&path, - &crate_output.path(output_type)); - if !sess.opts.cg.save_temps && !keep_numbered { - // The user just wants `foo.x`, not `foo.#module-name#.x`. - remove(sess, &path); - } - } else { - let ext = crate_output.temp_path(output_type, None) - .extension() - .unwrap() - .to_str() - .unwrap() - .to_owned(); - - if crate_output.outputs.contains_key(&output_type) { - // 2) Multiple codegen units, with `--emit foo=some_name`. We have - // no good solution for this case, so warn the user. - sess.warn(&format!("ignoring emit path because multiple .{} files \ - were produced", ext)); - } else if crate_output.single_output_file.is_some() { - // 3) Multiple codegen units, with `-o some_name`. We have - // no good solution for this case, so warn the user. - sess.warn(&format!("ignoring -o because multiple .{} files \ - were produced", ext)); - } else { - // 4) Multiple codegen units, but no explicit name. We - // just leave the `foo.0.x` files in place. - // (We don't have to do any work in this case.) - } - } - }; - - // Flag to indicate whether the user explicitly requested bitcode. - // Otherwise, we produced it only as a temporary output, and will need - // to get rid of it. - for output_type in crate_output.outputs.keys() { - match *output_type { - OutputType::Bitcode => { - user_wants_bitcode = true; - // Copy to .bc, but always keep the .0.bc. There is a later - // check to figure out if we should delete .0.bc files, or keep - // them for making an rlib. - copy_if_one_unit(OutputType::Bitcode, true); - } - OutputType::LlvmAssembly => { - copy_if_one_unit(OutputType::LlvmAssembly, false); - } - OutputType::Assembly => { - copy_if_one_unit(OutputType::Assembly, false); - } - OutputType::Object => { - user_wants_objects = true; - copy_if_one_unit(OutputType::Object, true); - } - OutputType::Mir | - OutputType::Metadata | - OutputType::Exe | - OutputType::DepInfo => {} - } - } - - // Clean up unwanted temporary files. - - // We create the following files by default: - // - #crate#.#module-name#.bc - // - #crate#.#module-name#.o - // - #crate#.crate.metadata.bc - // - #crate#.crate.metadata.o - // - #crate#.o (linked from crate.##.o) - // - #crate#.bc (copied from crate.##.bc) - // We may create additional files if requested by the user (through - // `-C save-temps` or `--emit=` flags). - - if !sess.opts.cg.save_temps { - // Remove the temporary .#module-name#.o objects. If the user didn't - // explicitly request bitcode (with --emit=bc), and the bitcode is not - // needed for building an rlib, then we must remove .#module-name#.bc as - // well. - - // Specific rules for keeping .#module-name#.bc: - // - If the user requested bitcode (`user_wants_bitcode`), and - // codegen_units > 1, then keep it. - // - If the user requested bitcode but codegen_units == 1, then we - // can toss .#module-name#.bc because we copied it to .bc earlier. - // - If we're not building an rlib and the user didn't request - // bitcode, then delete .#module-name#.bc. - // If you change how this works, also update back::link::link_rlib, - // where .#module-name#.bc files are (maybe) deleted after making an - // rlib. - let needs_crate_object = crate_output.outputs.contains_key(&OutputType::Exe); - - let keep_numbered_bitcode = user_wants_bitcode && sess.codegen_units() > 1; - - let keep_numbered_objects = needs_crate_object || - (user_wants_objects && sess.codegen_units() > 1); - - for module in compiled_modules.modules.iter() { - if let Some(ref path) = module.object { - if !keep_numbered_objects { - remove(sess, path); - } - } - - if let Some(ref path) = module.bytecode { - if !keep_numbered_bitcode { - remove(sess, path); - } - } - } - - if !user_wants_bitcode { - if let Some(ref path) = compiled_modules.metadata_module.bytecode { - remove(sess, &path); - } - - if let Some(ref allocator_module) = compiled_modules.allocator_module { - if let Some(ref path) = allocator_module.bytecode { - remove(sess, path); - } - } - } - } - - // We leave the following files around by default: - // - #crate#.o - // - #crate#.crate.metadata.o - // - #crate#.bc - // These are used in linking steps and will be cleaned up afterward. -} - -pub(crate) fn dump_incremental_data(trans: &CrateTranslation) { - println!("[incremental] Re-using {} out of {} modules", - trans.modules.iter().filter(|m| m.pre_existing).count(), - trans.modules.len()); -} - -enum WorkItem { - Optimize(ModuleTranslation), - LTO(lto::LtoModuleTranslation), -} - -impl WorkItem { - fn kind(&self) -> ModuleKind { - match *self { - WorkItem::Optimize(ref m) => m.kind, - WorkItem::LTO(_) => ModuleKind::Regular, - } - } - - fn name(&self) -> String { - match *self { - WorkItem::Optimize(ref m) => format!("optimize: {}", m.name), - WorkItem::LTO(ref m) => format!("lto: {}", m.name()), - } - } -} - -enum WorkItemResult { - Compiled(CompiledModule), - NeedsLTO(ModuleTranslation), -} - -fn execute_work_item(cgcx: &CodegenContext, - work_item: WorkItem, - timeline: &mut Timeline) - -> Result -{ - let diag_handler = cgcx.create_diag_handler(); - let config = cgcx.config(work_item.kind()); - let mtrans = match work_item { - WorkItem::Optimize(mtrans) => mtrans, - WorkItem::LTO(mut lto) => { - unsafe { - let module = lto.optimize(cgcx, timeline)?; - let module = codegen(cgcx, &diag_handler, module, config, timeline)?; - return Ok(WorkItemResult::Compiled(module)) - } - } - }; - let module_name = mtrans.name.clone(); - - let pre_existing = match mtrans.source { - ModuleSource::Translated(_) => None, - ModuleSource::Preexisting(ref wp) => Some(wp.clone()), - }; - - if let Some(wp) = pre_existing { - let incr_comp_session_dir = cgcx.incr_comp_session_dir - .as_ref() - .unwrap(); - let name = &mtrans.name; - let mut object = None; - let mut bytecode = None; - let mut bytecode_compressed = None; - for (kind, saved_file) in wp.saved_files { - let obj_out = match kind { - WorkProductFileKind::Object => { - let path = cgcx.output_filenames.temp_path(OutputType::Object, Some(name)); - object = Some(path.clone()); - path - } - WorkProductFileKind::Bytecode => { - let path = cgcx.output_filenames.temp_path(OutputType::Bitcode, Some(name)); - bytecode = Some(path.clone()); - path - } - WorkProductFileKind::BytecodeCompressed => { - let path = cgcx.output_filenames.temp_path(OutputType::Bitcode, Some(name)) - .with_extension(RLIB_BYTECODE_EXTENSION); - bytecode_compressed = Some(path.clone()); - path - } - }; - let source_file = in_incr_comp_dir(&incr_comp_session_dir, - &saved_file); - debug!("copying pre-existing module `{}` from {:?} to {}", - mtrans.name, - source_file, - obj_out.display()); - match link_or_copy(&source_file, &obj_out) { - Ok(_) => { } - Err(err) => { - diag_handler.err(&format!("unable to copy {} to {}: {}", - source_file.display(), - obj_out.display(), - err)); - } - } - } - assert_eq!(object.is_some(), config.emit_obj); - assert_eq!(bytecode.is_some(), config.emit_bc); - assert_eq!(bytecode_compressed.is_some(), config.emit_bc_compressed); - - Ok(WorkItemResult::Compiled(CompiledModule { - llmod_id: mtrans.llmod_id.clone(), - name: module_name, - kind: ModuleKind::Regular, - pre_existing: true, - object, - bytecode, - bytecode_compressed, - })) - } else { - debug!("llvm-optimizing {:?}", module_name); - - unsafe { - optimize(cgcx, &diag_handler, &mtrans, config, timeline)?; - - // After we've done the initial round of optimizations we need to - // decide whether to synchronously codegen this module or ship it - // back to the coordinator thread for further LTO processing (which - // has to wait for all the initial modules to be optimized). - // - // Here we dispatch based on the `cgcx.lto` and kind of module we're - // translating... - let needs_lto = match cgcx.lto { - Lto::No => false, - - // Here we've got a full crate graph LTO requested. We ignore - // this, however, if the crate type is only an rlib as there's - // no full crate graph to process, that'll happen later. - // - // This use case currently comes up primarily for targets that - // require LTO so the request for LTO is always unconditionally - // passed down to the backend, but we don't actually want to do - // anything about it yet until we've got a final product. - Lto::Yes | Lto::Fat | Lto::Thin => { - cgcx.crate_types.len() != 1 || - cgcx.crate_types[0] != config::CrateTypeRlib - } - - // When we're automatically doing ThinLTO for multi-codegen-unit - // builds we don't actually want to LTO the allocator modules if - // it shows up. This is due to various linker shenanigans that - // we'll encounter later. - // - // Additionally here's where we also factor in the current LLVM - // version. If it doesn't support ThinLTO we skip this. - Lto::ThinLocal => { - mtrans.kind != ModuleKind::Allocator && - llvm::LLVMRustThinLTOAvailable() - } - }; - - // Metadata modules never participate in LTO regardless of the lto - // settings. - let needs_lto = needs_lto && mtrans.kind != ModuleKind::Metadata; - - // Don't run LTO passes when cross-lang LTO is enabled. The linker - // will do that for us in this case. - let needs_lto = needs_lto && - !cgcx.opts.debugging_opts.cross_lang_lto.embed_bitcode(); - - if needs_lto { - Ok(WorkItemResult::NeedsLTO(mtrans)) - } else { - let module = codegen(cgcx, &diag_handler, mtrans, config, timeline)?; - Ok(WorkItemResult::Compiled(module)) - } - } - } -} - -enum Message { - Token(io::Result), - NeedsLTO { - result: ModuleTranslation, - worker_id: usize, - }, - Done { - result: Result, - worker_id: usize, - }, - TranslationDone { - llvm_work_item: WorkItem, - cost: u64, - }, - TranslationComplete, - TranslateItem, -} - -struct Diagnostic { - msg: String, - code: Option, - lvl: Level, -} - -#[derive(PartialEq, Clone, Copy, Debug)] -enum MainThreadWorkerState { - Idle, - Translating, - LLVMing, -} - -fn start_executing_work(tcx: TyCtxt, - crate_info: &CrateInfo, - shared_emitter: SharedEmitter, - trans_worker_send: Sender, - coordinator_receive: Receiver>, - total_cgus: usize, - jobserver: Client, - time_graph: Option, - modules_config: Arc, - metadata_config: Arc, - allocator_config: Arc) - -> thread::JoinHandle> { - let coordinator_send = tcx.tx_to_llvm_workers.lock().clone(); - let sess = tcx.sess; - - // Compute the set of symbols we need to retain when doing LTO (if we need to) - let exported_symbols = { - let mut exported_symbols = FxHashMap(); - - let copy_symbols = |cnum| { - let symbols = tcx.exported_symbols(cnum) - .iter() - .map(|&(s, lvl)| (s.symbol_name(tcx).to_string(), lvl)) - .collect(); - Arc::new(symbols) - }; - - match sess.lto() { - Lto::No => None, - Lto::ThinLocal => { - exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE)); - Some(Arc::new(exported_symbols)) - } - Lto::Yes | Lto::Fat | Lto::Thin => { - exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE)); - for &cnum in tcx.crates().iter() { - exported_symbols.insert(cnum, copy_symbols(cnum)); - } - Some(Arc::new(exported_symbols)) - } - } - }; - - // First up, convert our jobserver into a helper thread so we can use normal - // mpsc channels to manage our messages and such. - // After we've requested tokens then we'll, when we can, - // get tokens on `coordinator_receive` which will - // get managed in the main loop below. - let coordinator_send2 = coordinator_send.clone(); - let helper = jobserver.into_helper_thread(move |token| { - drop(coordinator_send2.send(Box::new(Message::Token(token)))); - }).expect("failed to spawn helper thread"); - - let mut each_linked_rlib_for_lto = Vec::new(); - drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| { - if link::ignored_for_lto(sess, crate_info, cnum) { - return - } - each_linked_rlib_for_lto.push((cnum, path.to_path_buf())); - })); - - let assembler_cmd = if modules_config.no_integrated_as { - // HACK: currently we use linker (gcc) as our assembler - let (name, mut cmd) = get_linker(sess); - cmd.args(&sess.target.target.options.asm_args); - Some(Arc::new(AssemblerCommand { - name, - cmd, - })) - } else { - None - }; - - let cgcx = CodegenContext { - crate_types: sess.crate_types.borrow().clone(), - each_linked_rlib_for_lto, - lto: sess.lto(), - no_landing_pads: sess.no_landing_pads(), - fewer_names: sess.fewer_names(), - save_temps: sess.opts.cg.save_temps, - opts: Arc::new(sess.opts.clone()), - time_passes: sess.time_passes(), - exported_symbols, - plugin_passes: sess.plugin_llvm_passes.borrow().clone(), - remark: sess.opts.cg.remark.clone(), - worker: 0, - incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()), - coordinator_send, - diag_emitter: shared_emitter.clone(), - time_graph, - output_filenames: tcx.output_filenames(LOCAL_CRATE), - regular_module_config: modules_config, - metadata_module_config: metadata_config, - allocator_module_config: allocator_config, - tm_factory: target_machine_factory(tcx.sess, false), - total_cgus, - msvc_imps_needed: msvc_imps_needed(tcx), - target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(), - debuginfo: tcx.sess.opts.debuginfo, - assembler_cmd, - }; - - // This is the "main loop" of parallel work happening for parallel codegen. - // It's here that we manage parallelism, schedule work, and work with - // messages coming from clients. - // - // There are a few environmental pre-conditions that shape how the system - // is set up: - // - // - Error reporting only can happen on the main thread because that's the - // only place where we have access to the compiler `Session`. - // - LLVM work can be done on any thread. - // - Translation can only happen on the main thread. - // - Each thread doing substantial work most be in possession of a `Token` - // from the `Jobserver`. - // - The compiler process always holds one `Token`. Any additional `Tokens` - // have to be requested from the `Jobserver`. - // - // Error Reporting - // =============== - // The error reporting restriction is handled separately from the rest: We - // set up a `SharedEmitter` the holds an open channel to the main thread. - // When an error occurs on any thread, the shared emitter will send the - // error message to the receiver main thread (`SharedEmitterMain`). The - // main thread will periodically query this error message queue and emit - // any error messages it has received. It might even abort compilation if - // has received a fatal error. In this case we rely on all other threads - // being torn down automatically with the main thread. - // Since the main thread will often be busy doing translation work, error - // reporting will be somewhat delayed, since the message queue can only be - // checked in between to work packages. - // - // Work Processing Infrastructure - // ============================== - // The work processing infrastructure knows three major actors: - // - // - the coordinator thread, - // - the main thread, and - // - LLVM worker threads - // - // The coordinator thread is running a message loop. It instructs the main - // thread about what work to do when, and it will spawn off LLVM worker - // threads as open LLVM WorkItems become available. - // - // The job of the main thread is to translate CGUs into LLVM work package - // (since the main thread is the only thread that can do this). The main - // thread will block until it receives a message from the coordinator, upon - // which it will translate one CGU, send it to the coordinator and block - // again. This way the coordinator can control what the main thread is - // doing. - // - // The coordinator keeps a queue of LLVM WorkItems, and when a `Token` is - // available, it will spawn off a new LLVM worker thread and let it process - // that a WorkItem. When a LLVM worker thread is done with its WorkItem, - // it will just shut down, which also frees all resources associated with - // the given LLVM module, and sends a message to the coordinator that the - // has been completed. - // - // Work Scheduling - // =============== - // The scheduler's goal is to minimize the time it takes to complete all - // work there is, however, we also want to keep memory consumption low - // if possible. These two goals are at odds with each other: If memory - // consumption were not an issue, we could just let the main thread produce - // LLVM WorkItems at full speed, assuring maximal utilization of - // Tokens/LLVM worker threads. However, since translation usual is faster - // than LLVM processing, the queue of LLVM WorkItems would fill up and each - // WorkItem potentially holds on to a substantial amount of memory. - // - // So the actual goal is to always produce just enough LLVM WorkItems as - // not to starve our LLVM worker threads. That means, once we have enough - // WorkItems in our queue, we can block the main thread, so it does not - // produce more until we need them. - // - // Doing LLVM Work on the Main Thread - // ---------------------------------- - // Since the main thread owns the compiler processes implicit `Token`, it is - // wasteful to keep it blocked without doing any work. Therefore, what we do - // in this case is: We spawn off an additional LLVM worker thread that helps - // reduce the queue. The work it is doing corresponds to the implicit - // `Token`. The coordinator will mark the main thread as being busy with - // LLVM work. (The actual work happens on another OS thread but we just care - // about `Tokens`, not actual threads). - // - // When any LLVM worker thread finishes while the main thread is marked as - // "busy with LLVM work", we can do a little switcheroo: We give the Token - // of the just finished thread to the LLVM worker thread that is working on - // behalf of the main thread's implicit Token, thus freeing up the main - // thread again. The coordinator can then again decide what the main thread - // should do. This allows the coordinator to make decisions at more points - // in time. - // - // Striking a Balance between Throughput and Memory Consumption - // ------------------------------------------------------------ - // Since our two goals, (1) use as many Tokens as possible and (2) keep - // memory consumption as low as possible, are in conflict with each other, - // we have to find a trade off between them. Right now, the goal is to keep - // all workers busy, which means that no worker should find the queue empty - // when it is ready to start. - // How do we do achieve this? Good question :) We actually never know how - // many `Tokens` are potentially available so it's hard to say how much to - // fill up the queue before switching the main thread to LLVM work. Also we - // currently don't have a means to estimate how long a running LLVM worker - // will still be busy with it's current WorkItem. However, we know the - // maximal count of available Tokens that makes sense (=the number of CPU - // cores), so we can take a conservative guess. The heuristic we use here - // is implemented in the `queue_full_enough()` function. - // - // Some Background on Jobservers - // ----------------------------- - // It's worth also touching on the management of parallelism here. We don't - // want to just spawn a thread per work item because while that's optimal - // parallelism it may overload a system with too many threads or violate our - // configuration for the maximum amount of cpu to use for this process. To - // manage this we use the `jobserver` crate. - // - // Job servers are an artifact of GNU make and are used to manage - // parallelism between processes. A jobserver is a glorified IPC semaphore - // basically. Whenever we want to run some work we acquire the semaphore, - // and whenever we're done with that work we release the semaphore. In this - // manner we can ensure that the maximum number of parallel workers is - // capped at any one point in time. - // - // LTO and the coordinator thread - // ------------------------------ - // - // The final job the coordinator thread is responsible for is managing LTO - // and how that works. When LTO is requested what we'll to is collect all - // optimized LLVM modules into a local vector on the coordinator. Once all - // modules have been translated and optimized we hand this to the `lto` - // module for further optimization. The `lto` module will return back a list - // of more modules to work on, which the coordinator will continue to spawn - // work for. - // - // Each LLVM module is automatically sent back to the coordinator for LTO if - // necessary. There's already optimizations in place to avoid sending work - // back to the coordinator if LTO isn't requested. - return thread::spawn(move || { - // We pretend to be within the top-level LLVM time-passes task here: - set_time_depth(1); - - let max_workers = ::num_cpus::get(); - let mut worker_id_counter = 0; - let mut free_worker_ids = Vec::new(); - let mut get_worker_id = |free_worker_ids: &mut Vec| { - if let Some(id) = free_worker_ids.pop() { - id - } else { - let id = worker_id_counter; - worker_id_counter += 1; - id - } - }; - - // This is where we collect codegen units that have gone all the way - // through translation and LLVM. - let mut compiled_modules = vec![]; - let mut compiled_metadata_module = None; - let mut compiled_allocator_module = None; - let mut needs_lto = Vec::new(); - let mut started_lto = false; - - // This flag tracks whether all items have gone through translations - let mut translation_done = false; - - // This is the queue of LLVM work items that still need processing. - let mut work_items = Vec::<(WorkItem, u64)>::new(); - - // This are the Jobserver Tokens we currently hold. Does not include - // the implicit Token the compiler process owns no matter what. - let mut tokens = Vec::new(); - - let mut main_thread_worker_state = MainThreadWorkerState::Idle; - let mut running = 0; - - let mut llvm_start_time = None; - - // Run the message loop while there's still anything that needs message - // processing: - while !translation_done || - work_items.len() > 0 || - running > 0 || - needs_lto.len() > 0 || - main_thread_worker_state != MainThreadWorkerState::Idle { - - // While there are still CGUs to be translated, the coordinator has - // to decide how to utilize the compiler processes implicit Token: - // For translating more CGU or for running them through LLVM. - if !translation_done { - if main_thread_worker_state == MainThreadWorkerState::Idle { - if !queue_full_enough(work_items.len(), running, max_workers) { - // The queue is not full enough, translate more items: - if let Err(_) = trans_worker_send.send(Message::TranslateItem) { - panic!("Could not send Message::TranslateItem to main thread") - } - main_thread_worker_state = MainThreadWorkerState::Translating; - } else { - // The queue is full enough to not let the worker - // threads starve. Use the implicit Token to do some - // LLVM work too. - let (item, _) = work_items.pop() - .expect("queue empty - queue_full_enough() broken?"); - let cgcx = CodegenContext { - worker: get_worker_id(&mut free_worker_ids), - .. cgcx.clone() - }; - maybe_start_llvm_timer(cgcx.config(item.kind()), - &mut llvm_start_time); - main_thread_worker_state = MainThreadWorkerState::LLVMing; - spawn_work(cgcx, item); - } - } - } else { - // If we've finished everything related to normal translation - // then it must be the case that we've got some LTO work to do. - // Perform the serial work here of figuring out what we're - // going to LTO and then push a bunch of work items onto our - // queue to do LTO - if work_items.len() == 0 && - running == 0 && - main_thread_worker_state == MainThreadWorkerState::Idle { - assert!(!started_lto); - assert!(needs_lto.len() > 0); - started_lto = true; - let modules = mem::replace(&mut needs_lto, Vec::new()); - for (work, cost) in generate_lto_work(&cgcx, modules) { - let insertion_index = work_items - .binary_search_by_key(&cost, |&(_, cost)| cost) - .unwrap_or_else(|e| e); - work_items.insert(insertion_index, (work, cost)); - helper.request_token(); - } - } - - // In this branch, we know that everything has been translated, - // so it's just a matter of determining whether the implicit - // Token is free to use for LLVM work. - match main_thread_worker_state { - MainThreadWorkerState::Idle => { - if let Some((item, _)) = work_items.pop() { - let cgcx = CodegenContext { - worker: get_worker_id(&mut free_worker_ids), - .. cgcx.clone() - }; - maybe_start_llvm_timer(cgcx.config(item.kind()), - &mut llvm_start_time); - main_thread_worker_state = MainThreadWorkerState::LLVMing; - spawn_work(cgcx, item); - } else { - // There is no unstarted work, so let the main thread - // take over for a running worker. Otherwise the - // implicit token would just go to waste. - // We reduce the `running` counter by one. The - // `tokens.truncate()` below will take care of - // giving the Token back. - debug_assert!(running > 0); - running -= 1; - main_thread_worker_state = MainThreadWorkerState::LLVMing; - } - } - MainThreadWorkerState::Translating => { - bug!("trans worker should not be translating after \ - translation was already completed") - } - MainThreadWorkerState::LLVMing => { - // Already making good use of that token - } - } - } - - // Spin up what work we can, only doing this while we've got available - // parallelism slots and work left to spawn. - while work_items.len() > 0 && running < tokens.len() { - let (item, _) = work_items.pop().unwrap(); - - maybe_start_llvm_timer(cgcx.config(item.kind()), - &mut llvm_start_time); - - let cgcx = CodegenContext { - worker: get_worker_id(&mut free_worker_ids), - .. cgcx.clone() - }; - - spawn_work(cgcx, item); - running += 1; - } - - // Relinquish accidentally acquired extra tokens - tokens.truncate(running); - - let msg = coordinator_receive.recv().unwrap(); - match *msg.downcast::().ok().unwrap() { - // Save the token locally and the next turn of the loop will use - // this to spawn a new unit of work, or it may get dropped - // immediately if we have no more work to spawn. - Message::Token(token) => { - match token { - Ok(token) => { - tokens.push(token); - - if main_thread_worker_state == MainThreadWorkerState::LLVMing { - // If the main thread token is used for LLVM work - // at the moment, we turn that thread into a regular - // LLVM worker thread, so the main thread is free - // to react to translation demand. - main_thread_worker_state = MainThreadWorkerState::Idle; - running += 1; - } - } - Err(e) => { - let msg = &format!("failed to acquire jobserver token: {}", e); - shared_emitter.fatal(msg); - // Exit the coordinator thread - panic!("{}", msg) - } - } - } - - Message::TranslationDone { llvm_work_item, cost } => { - // We keep the queue sorted by estimated processing cost, - // so that more expensive items are processed earlier. This - // is good for throughput as it gives the main thread more - // time to fill up the queue and it avoids scheduling - // expensive items to the end. - // Note, however, that this is not ideal for memory - // consumption, as LLVM module sizes are not evenly - // distributed. - let insertion_index = - work_items.binary_search_by_key(&cost, |&(_, cost)| cost); - let insertion_index = match insertion_index { - Ok(idx) | Err(idx) => idx - }; - work_items.insert(insertion_index, (llvm_work_item, cost)); - - helper.request_token(); - assert_eq!(main_thread_worker_state, - MainThreadWorkerState::Translating); - main_thread_worker_state = MainThreadWorkerState::Idle; - } - - Message::TranslationComplete => { - translation_done = true; - assert_eq!(main_thread_worker_state, - MainThreadWorkerState::Translating); - main_thread_worker_state = MainThreadWorkerState::Idle; - } - - // If a thread exits successfully then we drop a token associated - // with that worker and update our `running` count. We may later - // re-acquire a token to continue running more work. We may also not - // actually drop a token here if the worker was running with an - // "ephemeral token" - // - // Note that if the thread failed that means it panicked, so we - // abort immediately. - Message::Done { result: Ok(compiled_module), worker_id } => { - if main_thread_worker_state == MainThreadWorkerState::LLVMing { - main_thread_worker_state = MainThreadWorkerState::Idle; - } else { - running -= 1; - } - - free_worker_ids.push(worker_id); - - match compiled_module.kind { - ModuleKind::Regular => { - compiled_modules.push(compiled_module); - } - ModuleKind::Metadata => { - assert!(compiled_metadata_module.is_none()); - compiled_metadata_module = Some(compiled_module); - } - ModuleKind::Allocator => { - assert!(compiled_allocator_module.is_none()); - compiled_allocator_module = Some(compiled_module); - } - } - } - Message::NeedsLTO { result, worker_id } => { - assert!(!started_lto); - if main_thread_worker_state == MainThreadWorkerState::LLVMing { - main_thread_worker_state = MainThreadWorkerState::Idle; - } else { - running -= 1; - } - - free_worker_ids.push(worker_id); - needs_lto.push(result); - } - Message::Done { result: Err(()), worker_id: _ } => { - shared_emitter.fatal("aborting due to worker thread failure"); - // Exit the coordinator thread - return Err(()) - } - Message::TranslateItem => { - bug!("the coordinator should not receive translation requests") - } - } - } - - if let Some(llvm_start_time) = llvm_start_time { - let total_llvm_time = Instant::now().duration_since(llvm_start_time); - // This is the top-level timing for all of LLVM, set the time-depth - // to zero. - set_time_depth(0); - print_time_passes_entry(cgcx.time_passes, - "LLVM passes", - total_llvm_time); - } - - // Regardless of what order these modules completed in, report them to - // the backend in the same order every time to ensure that we're handing - // out deterministic results. - compiled_modules.sort_by(|a, b| a.name.cmp(&b.name)); - - let compiled_metadata_module = compiled_metadata_module - .expect("Metadata module not compiled?"); - - Ok(CompiledModules { - modules: compiled_modules, - metadata_module: compiled_metadata_module, - allocator_module: compiled_allocator_module, - }) - }); - - // A heuristic that determines if we have enough LLVM WorkItems in the - // queue so that the main thread can do LLVM work instead of translation - fn queue_full_enough(items_in_queue: usize, - workers_running: usize, - max_workers: usize) -> bool { - // Tune me, plz. - items_in_queue > 0 && - items_in_queue >= max_workers.saturating_sub(workers_running / 2) - } - - fn maybe_start_llvm_timer(config: &ModuleConfig, - llvm_start_time: &mut Option) { - // We keep track of the -Ztime-passes output manually, - // since the closure-based interface does not fit well here. - if config.time_passes { - if llvm_start_time.is_none() { - *llvm_start_time = Some(Instant::now()); - } - } - } -} - -pub const TRANS_WORKER_ID: usize = ::std::usize::MAX; -pub const TRANS_WORKER_TIMELINE: time_graph::TimelineId = - time_graph::TimelineId(TRANS_WORKER_ID); -pub const TRANS_WORK_PACKAGE_KIND: time_graph::WorkPackageKind = - time_graph::WorkPackageKind(&["#DE9597", "#FED1D3", "#FDC5C7", "#B46668", "#88494B"]); -const LLVM_WORK_PACKAGE_KIND: time_graph::WorkPackageKind = - time_graph::WorkPackageKind(&["#7DB67A", "#C6EEC4", "#ACDAAA", "#579354", "#3E6F3C"]); - -fn spawn_work(cgcx: CodegenContext, work: WorkItem) { - let depth = time_depth(); - - thread::spawn(move || { - set_time_depth(depth); - - // Set up a destructor which will fire off a message that we're done as - // we exit. - struct Bomb { - coordinator_send: Sender>, - result: Option, - worker_id: usize, - } - impl Drop for Bomb { - fn drop(&mut self) { - let worker_id = self.worker_id; - let msg = match self.result.take() { - Some(WorkItemResult::Compiled(m)) => { - Message::Done { result: Ok(m), worker_id } - } - Some(WorkItemResult::NeedsLTO(m)) => { - Message::NeedsLTO { result: m, worker_id } - } - None => Message::Done { result: Err(()), worker_id } - }; - drop(self.coordinator_send.send(Box::new(msg))); - } - } - - let mut bomb = Bomb { - coordinator_send: cgcx.coordinator_send.clone(), - result: None, - worker_id: cgcx.worker, - }; - - // Execute the work itself, and if it finishes successfully then flag - // ourselves as a success as well. - // - // Note that we ignore any `FatalError` coming out of `execute_work_item`, - // as a diagnostic was already sent off to the main thread - just - // surface that there was an error in this worker. - bomb.result = { - let timeline = cgcx.time_graph.as_ref().map(|tg| { - tg.start(time_graph::TimelineId(cgcx.worker), - LLVM_WORK_PACKAGE_KIND, - &work.name()) - }); - let mut timeline = timeline.unwrap_or(Timeline::noop()); - execute_work_item(&cgcx, work, &mut timeline).ok() - }; - }); -} - -pub fn run_assembler(cgcx: &CodegenContext, handler: &Handler, assembly: &Path, object: &Path) { - let assembler = cgcx.assembler_cmd - .as_ref() - .expect("cgcx.assembler_cmd is missing?"); - - let pname = &assembler.name; - let mut cmd = assembler.cmd.clone(); - cmd.arg("-c").arg("-o").arg(object).arg(assembly); - debug!("{:?}", cmd); - - match cmd.output() { - Ok(prog) => { - if !prog.status.success() { - let mut note = prog.stderr.clone(); - note.extend_from_slice(&prog.stdout); - - handler.struct_err(&format!("linking with `{}` failed: {}", - pname.display(), - prog.status)) - .note(&format!("{:?}", &cmd)) - .note(str::from_utf8(¬e[..]).unwrap()) - .emit(); - handler.abort_if_errors(); - } - }, - Err(e) => { - handler.err(&format!("could not exec the linker `{}`: {}", pname.display(), e)); - handler.abort_if_errors(); - } - } -} - -pub unsafe fn with_llvm_pmb(llmod: ModuleRef, - config: &ModuleConfig, - opt_level: llvm::CodeGenOptLevel, - prepare_for_thin_lto: bool, - f: &mut FnMut(llvm::PassManagerBuilderRef)) { - use std::ptr; - - // Create the PassManagerBuilder for LLVM. We configure it with - // reasonable defaults and prepare it to actually populate the pass - // manager. - let builder = llvm::LLVMPassManagerBuilderCreate(); - let opt_size = config.opt_size.unwrap_or(llvm::CodeGenOptSizeNone); - let inline_threshold = config.inline_threshold; - - let pgo_gen_path = config.pgo_gen.as_ref().map(|s| { - let s = if s.is_empty() { "default_%m.profraw" } else { s }; - CString::new(s.as_bytes()).unwrap() - }); - - let pgo_use_path = if config.pgo_use.is_empty() { - None - } else { - Some(CString::new(config.pgo_use.as_bytes()).unwrap()) - }; - - llvm::LLVMRustConfigurePassManagerBuilder( - builder, - opt_level, - config.merge_functions, - config.vectorize_slp, - config.vectorize_loop, - prepare_for_thin_lto, - pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()), - pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()), - ); - - llvm::LLVMPassManagerBuilderSetSizeLevel(builder, opt_size as u32); - - if opt_size != llvm::CodeGenOptSizeNone { - llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(builder, 1); - } - - llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins); - - // Here we match what clang does (kinda). For O0 we only inline - // always-inline functions (but don't add lifetime intrinsics), at O1 we - // inline with lifetime intrinsics, and O2+ we add an inliner with a - // thresholds copied from clang. - match (opt_level, opt_size, inline_threshold) { - (.., Some(t)) => { - llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32); - } - (llvm::CodeGenOptLevel::Aggressive, ..) => { - llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275); - } - (_, llvm::CodeGenOptSizeDefault, _) => { - llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 75); - } - (_, llvm::CodeGenOptSizeAggressive, _) => { - llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25); - } - (llvm::CodeGenOptLevel::None, ..) => { - llvm::LLVMRustAddAlwaysInlinePass(builder, false); - } - (llvm::CodeGenOptLevel::Less, ..) => { - llvm::LLVMRustAddAlwaysInlinePass(builder, true); - } - (llvm::CodeGenOptLevel::Default, ..) => { - llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225); - } - (llvm::CodeGenOptLevel::Other, ..) => { - bug!("CodeGenOptLevel::Other selected") - } - } - - f(builder); - llvm::LLVMPassManagerBuilderDispose(builder); -} - - -enum SharedEmitterMessage { - Diagnostic(Diagnostic), - InlineAsmError(u32, String), - AbortIfErrors, - Fatal(String), -} - -#[derive(Clone)] -pub struct SharedEmitter { - sender: Sender, -} - -pub struct SharedEmitterMain { - receiver: Receiver, -} - -impl SharedEmitter { - pub fn new() -> (SharedEmitter, SharedEmitterMain) { - let (sender, receiver) = channel(); - - (SharedEmitter { sender }, SharedEmitterMain { receiver }) - } - - fn inline_asm_error(&self, cookie: u32, msg: String) { - drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg))); - } - - fn fatal(&self, msg: &str) { - drop(self.sender.send(SharedEmitterMessage::Fatal(msg.to_string()))); - } -} - -impl Emitter for SharedEmitter { - fn emit(&mut self, db: &DiagnosticBuilder) { - drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { - msg: db.message(), - code: db.code.clone(), - lvl: db.level, - }))); - for child in &db.children { - drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { - msg: child.message(), - code: None, - lvl: child.level, - }))); - } - drop(self.sender.send(SharedEmitterMessage::AbortIfErrors)); - } -} - -impl SharedEmitterMain { - pub fn check(&self, sess: &Session, blocking: bool) { - loop { - let message = if blocking { - match self.receiver.recv() { - Ok(message) => Ok(message), - Err(_) => Err(()), - } - } else { - match self.receiver.try_recv() { - Ok(message) => Ok(message), - Err(_) => Err(()), - } - }; - - match message { - Ok(SharedEmitterMessage::Diagnostic(diag)) => { - let handler = sess.diagnostic(); - match diag.code { - Some(ref code) => { - handler.emit_with_code(&MultiSpan::new(), - &diag.msg, - code.clone(), - diag.lvl); - } - None => { - handler.emit(&MultiSpan::new(), - &diag.msg, - diag.lvl); - } - } - } - Ok(SharedEmitterMessage::InlineAsmError(cookie, msg)) => { - match Mark::from_u32(cookie).expn_info() { - Some(ei) => sess.span_err(ei.call_site, &msg), - None => sess.err(&msg), - } - } - Ok(SharedEmitterMessage::AbortIfErrors) => { - sess.abort_if_errors(); - } - Ok(SharedEmitterMessage::Fatal(msg)) => { - sess.fatal(&msg); - } - Err(_) => { - break; - } - } - - } - } -} - -pub struct OngoingCrateTranslation { - crate_name: Symbol, - link: LinkMeta, - metadata: EncodedMetadata, - windows_subsystem: Option, - linker_info: LinkerInfo, - crate_info: CrateInfo, - time_graph: Option, - coordinator_send: Sender>, - trans_worker_receive: Receiver, - shared_emitter_main: SharedEmitterMain, - future: thread::JoinHandle>, - output_filenames: Arc, -} - -impl OngoingCrateTranslation { - pub(crate) fn join( - self, - sess: &Session - ) -> (CrateTranslation, FxHashMap) { - self.shared_emitter_main.check(sess, true); - let compiled_modules = match self.future.join() { - Ok(Ok(compiled_modules)) => compiled_modules, - Ok(Err(())) => { - sess.abort_if_errors(); - panic!("expected abort due to worker thread errors") - }, - Err(_) => { - sess.fatal("Error during translation/LLVM phase."); - } - }; - - sess.abort_if_errors(); - - if let Some(time_graph) = self.time_graph { - time_graph.dump(&format!("{}-timings", self.crate_name)); - } - - let work_products = copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess, - &compiled_modules); - - produce_final_output_artifacts(sess, - &compiled_modules, - &self.output_filenames); - - // FIXME: time_llvm_passes support - does this use a global context or - // something? - if sess.codegen_units() == 1 && sess.time_llvm_passes() { - unsafe { llvm::LLVMRustPrintPassTimings(); } - } - - let trans = CrateTranslation { - crate_name: self.crate_name, - link: self.link, - metadata: self.metadata, - windows_subsystem: self.windows_subsystem, - linker_info: self.linker_info, - crate_info: self.crate_info, - - modules: compiled_modules.modules, - allocator_module: compiled_modules.allocator_module, - metadata_module: compiled_modules.metadata_module, - }; - - (trans, work_products) - } - - pub(crate) fn submit_pre_translated_module_to_llvm(&self, - tcx: TyCtxt, - mtrans: ModuleTranslation) { - self.wait_for_signal_to_translate_item(); - self.check_for_errors(tcx.sess); - - // These are generally cheap and won't through off scheduling. - let cost = 0; - submit_translated_module_to_llvm(tcx, mtrans, cost); - } - - pub fn translation_finished(&self, tcx: TyCtxt) { - self.wait_for_signal_to_translate_item(); - self.check_for_errors(tcx.sess); - drop(self.coordinator_send.send(Box::new(Message::TranslationComplete))); - } - - pub fn check_for_errors(&self, sess: &Session) { - self.shared_emitter_main.check(sess, false); - } - - pub fn wait_for_signal_to_translate_item(&self) { - match self.trans_worker_receive.recv() { - Ok(Message::TranslateItem) => { - // Nothing to do - } - Ok(_) => panic!("unexpected message"), - Err(_) => { - // One of the LLVM threads must have panicked, fall through so - // error handling can be reached. - } - } - } -} - -pub(crate) fn submit_translated_module_to_llvm(tcx: TyCtxt, - mtrans: ModuleTranslation, - cost: u64) { - let llvm_work_item = WorkItem::Optimize(mtrans); - drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::TranslationDone { - llvm_work_item, - cost, - }))); -} - -fn msvc_imps_needed(tcx: TyCtxt) -> bool { - tcx.sess.target.target.options.is_like_msvc && - tcx.sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) -} - -// Create a `__imp_ = &symbol` global for every public static `symbol`. -// This is required to satisfy `dllimport` references to static data in .rlibs -// when using MSVC linker. We do this only for data, as linker can fix up -// code references on its own. -// See #26591, #27438 -fn create_msvc_imps(cgcx: &CodegenContext, llcx: ContextRef, llmod: ModuleRef) { - if !cgcx.msvc_imps_needed { - return - } - // The x86 ABI seems to require that leading underscores are added to symbol - // names, so we need an extra underscore on 32-bit. There's also a leading - // '\x01' here which disables LLVM's symbol mangling (e.g. no extra - // underscores added in front). - let prefix = if cgcx.target_pointer_width == "32" { - "\x01__imp__" - } else { - "\x01__imp_" - }; - unsafe { - let i8p_ty = Type::i8p_llcx(llcx); - let globals = base::iter_globals(llmod) - .filter(|&val| { - llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage && - llvm::LLVMIsDeclaration(val) == 0 - }) - .map(move |val| { - let name = CStr::from_ptr(llvm::LLVMGetValueName(val)); - let mut imp_name = prefix.as_bytes().to_vec(); - imp_name.extend(name.to_bytes()); - let imp_name = CString::new(imp_name).unwrap(); - (imp_name, val) - }) - .collect::>(); - for (imp_name, val) in globals { - let imp = llvm::LLVMAddGlobal(llmod, - i8p_ty.to_ref(), - imp_name.as_ptr() as *const _); - llvm::LLVMSetInitializer(imp, consts::ptrcast(val, i8p_ty)); - llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage); - } - } -} diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs deleted file mode 100644 index feca36fa6c2..00000000000 --- a/src/librustc_trans/base.rs +++ /dev/null @@ -1,1411 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Translate the completed AST to the LLVM IR. -//! -//! Some functions here, such as trans_block and trans_expr, return a value -- -//! the result of the translation to LLVM -- while others, such as trans_fn -//! and trans_item, are called only for the side effect of adding a -//! particular definition to the LLVM IR output we're producing. -//! -//! Hopefully useful general knowledge about trans: -//! -//! * There's no way to find out the Ty type of a ValueRef. Doing so -//! would be "trying to get the eggs out of an omelette" (credit: -//! pcwalton). You can, instead, find out its TypeRef by calling val_ty, -//! but one TypeRef corresponds to many `Ty`s; for instance, tup(int, int, -//! int) and rec(x=int, y=int, z=int) will have the same TypeRef. - -use super::ModuleLlvm; -use super::ModuleSource; -use super::ModuleTranslation; -use super::ModuleKind; - -use abi; -use back::link; -use back::write::{self, OngoingCrateTranslation, create_target_machine}; -use llvm::{ContextRef, ModuleRef, ValueRef, Vector, get_param}; -use llvm; -use metadata; -use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc::middle::lang_items::StartFnLangItem; -use rustc::middle::weak_lang_items; -use rustc::mir::mono::{Linkage, Visibility, Stats}; -use rustc::middle::cstore::{EncodedMetadata}; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::layout::{self, Align, TyLayout, LayoutOf}; -use rustc::ty::maps::Providers; -use rustc::dep_graph::{DepNode, DepConstructor}; -use rustc::ty::subst::Kind; -use rustc::middle::cstore::{self, LinkMeta, LinkagePreference}; -use rustc::middle::exported_symbols; -use rustc::util::common::{time, print_time_passes_entry}; -use rustc::session::config::{self, NoDebugInfo}; -use rustc::session::Session; -use rustc_incremental; -use allocator; -use mir::place::PlaceRef; -use attributes; -use builder::{Builder, MemFlags}; -use callee; -use common::{C_bool, C_bytes_in_context, C_i32, C_usize}; -use rustc_mir::monomorphize::collector::{self, MonoItemCollectionMode}; -use common::{self, C_struct_in_context, C_array, val_ty}; -use consts; -use context::{self, CodegenCx}; -use debuginfo; -use declare; -use meth; -use mir; -use monomorphize::Instance; -use monomorphize::partitioning::{self, PartitioningStrategy, CodegenUnit, CodegenUnitExt}; -use rustc_trans_utils::symbol_names_test; -use time_graph; -use trans_item::{MonoItem, BaseMonoItemExt, MonoItemExt, DefPathBasedNames}; -use type_::Type; -use type_of::LayoutLlvmExt; -use rustc::util::nodemap::{FxHashMap, FxHashSet, DefIdSet}; -use CrateInfo; -use rustc_data_structures::sync::Lrc; -use rustc_target::spec::TargetTriple; - -use std::any::Any; -use std::collections::BTreeMap; -use std::ffi::CString; -use std::str; -use std::sync::Arc; -use std::time::{Instant, Duration}; -use std::i32; -use std::cmp; -use std::sync::mpsc; -use syntax_pos::Span; -use syntax_pos::symbol::InternedString; -use syntax::attr; -use rustc::hir; -use syntax::ast; - -use mir::operand::OperandValue; - -pub use rustc_trans_utils::check_for_rustc_errors_attr; - -pub struct StatRecorder<'a, 'tcx: 'a> { - cx: &'a CodegenCx<'a, 'tcx>, - name: Option, - istart: usize, -} - -impl<'a, 'tcx> StatRecorder<'a, 'tcx> { - pub fn new(cx: &'a CodegenCx<'a, 'tcx>, name: String) -> StatRecorder<'a, 'tcx> { - let istart = cx.stats.borrow().n_llvm_insns; - StatRecorder { - cx, - name: Some(name), - istart, - } - } -} - -impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { - fn drop(&mut self) { - if self.cx.sess().trans_stats() { - let mut stats = self.cx.stats.borrow_mut(); - let iend = stats.n_llvm_insns; - stats.fn_stats.push((self.name.take().unwrap(), iend - self.istart)); - stats.n_fns += 1; - // Reset LLVM insn count to avoid compound costs. - stats.n_llvm_insns = self.istart; - } - } -} - -pub fn bin_op_to_icmp_predicate(op: hir::BinOp_, - signed: bool) - -> llvm::IntPredicate { - match op { - hir::BiEq => llvm::IntEQ, - hir::BiNe => llvm::IntNE, - hir::BiLt => if signed { llvm::IntSLT } else { llvm::IntULT }, - hir::BiLe => if signed { llvm::IntSLE } else { llvm::IntULE }, - hir::BiGt => if signed { llvm::IntSGT } else { llvm::IntUGT }, - hir::BiGe => if signed { llvm::IntSGE } else { llvm::IntUGE }, - op => { - bug!("comparison_op_to_icmp_predicate: expected comparison operator, \ - found {:?}", - op) - } - } -} - -pub fn bin_op_to_fcmp_predicate(op: hir::BinOp_) -> llvm::RealPredicate { - match op { - hir::BiEq => llvm::RealOEQ, - hir::BiNe => llvm::RealUNE, - hir::BiLt => llvm::RealOLT, - hir::BiLe => llvm::RealOLE, - hir::BiGt => llvm::RealOGT, - hir::BiGe => llvm::RealOGE, - op => { - bug!("comparison_op_to_fcmp_predicate: expected comparison operator, \ - found {:?}", - op); - } - } -} - -pub fn compare_simd_types<'a, 'tcx>( - bx: &Builder<'a, 'tcx>, - lhs: ValueRef, - rhs: ValueRef, - t: Ty<'tcx>, - ret_ty: Type, - op: hir::BinOp_ -) -> ValueRef { - let signed = match t.sty { - ty::TyFloat(_) => { - let cmp = bin_op_to_fcmp_predicate(op); - return bx.sext(bx.fcmp(cmp, lhs, rhs), ret_ty); - }, - ty::TyUint(_) => false, - ty::TyInt(_) => true, - _ => bug!("compare_simd_types: invalid SIMD type"), - }; - - let cmp = bin_op_to_icmp_predicate(op, signed); - // LLVM outputs an `< size x i1 >`, so we need to perform a sign extension - // to get the correctly sized type. This will compile to a single instruction - // once the IR is converted to assembly if the SIMD instruction is supported - // by the target architecture. - bx.sext(bx.icmp(cmp, lhs, rhs), ret_ty) -} - -/// Retrieve the information we are losing (making dynamic) in an unsizing -/// adjustment. -/// -/// The `old_info` argument is a bit funny. It is intended for use -/// in an upcast, where the new vtable for an object will be derived -/// from the old one. -pub fn unsized_info<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>, - source: Ty<'tcx>, - target: Ty<'tcx>, - old_info: Option) - -> ValueRef { - let (source, target) = cx.tcx.struct_lockstep_tails(source, target); - match (&source.sty, &target.sty) { - (&ty::TyArray(_, len), &ty::TySlice(_)) => { - C_usize(cx, len.unwrap_usize(cx.tcx)) - } - (&ty::TyDynamic(..), &ty::TyDynamic(..)) => { - // For now, upcasts are limited to changes in marker - // traits, and hence never actually require an actual - // change to the vtable. - old_info.expect("unsized_info: missing old info for trait upcast") - } - (_, &ty::TyDynamic(ref data, ..)) => { - let vtable_ptr = cx.layout_of(cx.tcx.mk_mut_ptr(target)) - .field(cx, abi::FAT_PTR_EXTRA); - consts::ptrcast(meth::get_vtable(cx, source, data.principal()), - vtable_ptr.llvm_type(cx)) - } - _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", - source, - target), - } -} - -/// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer. -pub fn unsize_thin_ptr<'a, 'tcx>( - bx: &Builder<'a, 'tcx>, - src: ValueRef, - src_ty: Ty<'tcx>, - dst_ty: Ty<'tcx> -) -> (ValueRef, ValueRef) { - debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty); - match (&src_ty.sty, &dst_ty.sty) { - (&ty::TyRef(_, a, _), - &ty::TyRef(_, b, _)) | - (&ty::TyRef(_, a, _), - &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) | - (&ty::TyRawPtr(ty::TypeAndMut { ty: a, .. }), - &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => { - assert!(bx.cx.type_is_sized(a)); - let ptr_ty = bx.cx.layout_of(b).llvm_type(bx.cx).ptr_to(); - (bx.pointercast(src, ptr_ty), unsized_info(bx.cx, a, b, None)) - } - (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => { - let (a, b) = (src_ty.boxed_ty(), dst_ty.boxed_ty()); - assert!(bx.cx.type_is_sized(a)); - let ptr_ty = bx.cx.layout_of(b).llvm_type(bx.cx).ptr_to(); - (bx.pointercast(src, ptr_ty), unsized_info(bx.cx, a, b, None)) - } - (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => { - assert_eq!(def_a, def_b); - - let src_layout = bx.cx.layout_of(src_ty); - let dst_layout = bx.cx.layout_of(dst_ty); - let mut result = None; - for i in 0..src_layout.fields.count() { - let src_f = src_layout.field(bx.cx, i); - assert_eq!(src_layout.fields.offset(i).bytes(), 0); - assert_eq!(dst_layout.fields.offset(i).bytes(), 0); - if src_f.is_zst() { - continue; - } - assert_eq!(src_layout.size, src_f.size); - - let dst_f = dst_layout.field(bx.cx, i); - assert_ne!(src_f.ty, dst_f.ty); - assert_eq!(result, None); - result = Some(unsize_thin_ptr(bx, src, src_f.ty, dst_f.ty)); - } - let (lldata, llextra) = result.unwrap(); - // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. - (bx.bitcast(lldata, dst_layout.scalar_pair_element_llvm_type(bx.cx, 0)), - bx.bitcast(llextra, dst_layout.scalar_pair_element_llvm_type(bx.cx, 1))) - } - _ => bug!("unsize_thin_ptr: called on bad types"), - } -} - -/// Coerce `src`, which is a reference to a value of type `src_ty`, -/// to a value of type `dst_ty` and store the result in `dst` -pub fn coerce_unsized_into<'a, 'tcx>(bx: &Builder<'a, 'tcx>, - src: PlaceRef<'tcx>, - dst: PlaceRef<'tcx>) { - let src_ty = src.layout.ty; - let dst_ty = dst.layout.ty; - let coerce_ptr = || { - let (base, info) = match src.load(bx).val { - OperandValue::Pair(base, info) => { - // fat-ptr to fat-ptr unsize preserves the vtable - // i.e. &'a fmt::Debug+Send => &'a fmt::Debug - // So we need to pointercast the base to ensure - // the types match up. - let thin_ptr = dst.layout.field(bx.cx, abi::FAT_PTR_ADDR); - (bx.pointercast(base, thin_ptr.llvm_type(bx.cx)), info) - } - OperandValue::Immediate(base) => { - unsize_thin_ptr(bx, base, src_ty, dst_ty) - } - OperandValue::Ref(..) => bug!() - }; - OperandValue::Pair(base, info).store(bx, dst); - }; - match (&src_ty.sty, &dst_ty.sty) { - (&ty::TyRef(..), &ty::TyRef(..)) | - (&ty::TyRef(..), &ty::TyRawPtr(..)) | - (&ty::TyRawPtr(..), &ty::TyRawPtr(..)) => { - coerce_ptr() - } - (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => { - coerce_ptr() - } - - (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => { - assert_eq!(def_a, def_b); - - for i in 0..def_a.variants[0].fields.len() { - let src_f = src.project_field(bx, i); - let dst_f = dst.project_field(bx, i); - - if dst_f.layout.is_zst() { - continue; - } - - if src_f.layout.ty == dst_f.layout.ty { - memcpy_ty(bx, dst_f.llval, src_f.llval, src_f.layout, - src_f.align.min(dst_f.align), MemFlags::empty()); - } else { - coerce_unsized_into(bx, src_f, dst_f); - } - } - } - _ => bug!("coerce_unsized_into: invalid coercion {:?} -> {:?}", - src_ty, - dst_ty), - } -} - -pub fn cast_shift_expr_rhs( - cx: &Builder, op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef -) -> ValueRef { - cast_shift_rhs(op, lhs, rhs, |a, b| cx.trunc(a, b), |a, b| cx.zext(a, b)) -} - -fn cast_shift_rhs(op: hir::BinOp_, - lhs: ValueRef, - rhs: ValueRef, - trunc: F, - zext: G) - -> ValueRef - where F: FnOnce(ValueRef, Type) -> ValueRef, - G: FnOnce(ValueRef, Type) -> ValueRef -{ - // Shifts may have any size int on the rhs - if op.is_shift() { - let mut rhs_llty = val_ty(rhs); - let mut lhs_llty = val_ty(lhs); - if rhs_llty.kind() == Vector { - rhs_llty = rhs_llty.element_type() - } - if lhs_llty.kind() == Vector { - lhs_llty = lhs_llty.element_type() - } - let rhs_sz = rhs_llty.int_width(); - let lhs_sz = lhs_llty.int_width(); - if lhs_sz < rhs_sz { - trunc(rhs, lhs_llty) - } else if lhs_sz > rhs_sz { - // FIXME (#1877: If shifting by negative - // values becomes not undefined then this is wrong. - zext(rhs, lhs_llty) - } else { - rhs - } - } else { - rhs - } -} - -/// Returns whether this session's target will use SEH-based unwinding. -/// -/// This is only true for MSVC targets, and even then the 64-bit MSVC target -/// currently uses SEH-ish unwinding with DWARF info tables to the side (same as -/// 64-bit MinGW) instead of "full SEH". -pub fn wants_msvc_seh(sess: &Session) -> bool { - sess.target.target.options.is_like_msvc -} - -pub fn call_assume<'a, 'tcx>(bx: &Builder<'a, 'tcx>, val: ValueRef) { - let assume_intrinsic = bx.cx.get_intrinsic("llvm.assume"); - bx.call(assume_intrinsic, &[val], None); -} - -pub fn from_immediate(bx: &Builder, val: ValueRef) -> ValueRef { - if val_ty(val) == Type::i1(bx.cx) { - bx.zext(val, Type::i8(bx.cx)) - } else { - val - } -} - -pub fn to_immediate(bx: &Builder, val: ValueRef, layout: layout::TyLayout) -> ValueRef { - if let layout::Abi::Scalar(ref scalar) = layout.abi { - if scalar.is_bool() { - return bx.trunc(val, Type::i1(bx.cx)); - } - } - val -} - -pub fn call_memcpy(bx: &Builder, - dst: ValueRef, - src: ValueRef, - n_bytes: ValueRef, - align: Align, - flags: MemFlags) { - if flags.contains(MemFlags::NONTEMPORAL) { - // HACK(nox): This is inefficient but there is no nontemporal memcpy. - let val = bx.load(src, align); - let ptr = bx.pointercast(dst, val_ty(val).ptr_to()); - bx.store_with_flags(val, ptr, align, flags); - return; - } - let cx = bx.cx; - let ptr_width = &cx.sess().target.target.target_pointer_width; - let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width); - let memcpy = cx.get_intrinsic(&key); - let src_ptr = bx.pointercast(src, Type::i8p(cx)); - let dst_ptr = bx.pointercast(dst, Type::i8p(cx)); - let size = bx.intcast(n_bytes, cx.isize_ty, false); - let align = C_i32(cx, align.abi() as i32); - let volatile = C_bool(cx, flags.contains(MemFlags::VOLATILE)); - bx.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None); -} - -pub fn memcpy_ty<'a, 'tcx>( - bx: &Builder<'a, 'tcx>, - dst: ValueRef, - src: ValueRef, - layout: TyLayout<'tcx>, - align: Align, - flags: MemFlags, -) { - let size = layout.size.bytes(); - if size == 0 { - return; - } - - call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, flags); -} - -pub fn call_memset<'a, 'tcx>(bx: &Builder<'a, 'tcx>, - ptr: ValueRef, - fill_byte: ValueRef, - size: ValueRef, - align: ValueRef, - volatile: bool) -> ValueRef { - let ptr_width = &bx.cx.sess().target.target.target_pointer_width; - let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width); - let llintrinsicfn = bx.cx.get_intrinsic(&intrinsic_key); - let volatile = C_bool(bx.cx, volatile); - bx.call(llintrinsicfn, &[ptr, fill_byte, size, align, volatile], None) -} - -pub fn trans_instance<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, instance: Instance<'tcx>) { - let _s = if cx.sess().trans_stats() { - let mut instance_name = String::new(); - DefPathBasedNames::new(cx.tcx, true, true) - .push_def_path(instance.def_id(), &mut instance_name); - Some(StatRecorder::new(cx, instance_name)) - } else { - None - }; - - // this is an info! to allow collecting monomorphization statistics - // and to allow finding the last function before LLVM aborts from - // release builds. - info!("trans_instance({})", instance); - - let fn_ty = instance.ty(cx.tcx); - let sig = common::ty_fn_sig(cx, fn_ty); - let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - - let lldecl = match cx.instances.borrow().get(&instance) { - Some(&val) => val, - None => bug!("Instance `{:?}` not already declared", instance) - }; - - cx.stats.borrow_mut().n_closures += 1; - - // The `uwtable` attribute according to LLVM is: - // - // This attribute indicates that the ABI being targeted requires that an - // unwind table entry be produced for this function even if we can show - // that no exceptions passes by it. This is normally the case for the - // ELF x86-64 abi, but it can be disabled for some compilation units. - // - // Typically when we're compiling with `-C panic=abort` (which implies this - // `no_landing_pads` check) we don't need `uwtable` because we can't - // generate any exceptions! On Windows, however, exceptions include other - // events such as illegal instructions, segfaults, etc. This means that on - // Windows we end up still needing the `uwtable` attribute even if the `-C - // panic=abort` flag is passed. - // - // You can also find more info on why Windows is whitelisted here in: - // https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 - if !cx.sess().no_landing_pads() || - cx.sess().target.target.options.requires_uwtable { - attributes::emit_uwtable(lldecl, true); - } - - let mir = cx.tcx.instance_mir(instance.def); - mir::trans_mir(cx, lldecl, &mir, instance, sig); -} - -pub fn set_link_section(cx: &CodegenCx, - llval: ValueRef, - attrs: &[ast::Attribute]) { - if let Some(sect) = attr::first_attr_value_str_by_name(attrs, "link_section") { - if contains_null(§.as_str()) { - cx.sess().fatal(&format!("Illegal null byte in link_section value: `{}`", §)); - } - unsafe { - let buf = CString::new(sect.as_str().as_bytes()).unwrap(); - llvm::LLVMSetSection(llval, buf.as_ptr()); - } - } -} - -/// Create the `main` function which will initialize the rust runtime and call -/// users main function. -fn maybe_create_entry_wrapper(cx: &CodegenCx) { - let (main_def_id, span) = match *cx.sess().entry_fn.borrow() { - Some((id, span, _)) => { - (cx.tcx.hir.local_def_id(id), span) - } - None => return, - }; - - let instance = Instance::mono(cx.tcx, main_def_id); - - if !cx.codegen_unit.contains_item(&MonoItem::Fn(instance)) { - // We want to create the wrapper in the same codegen unit as Rust's main - // function. - return; - } - - let main_llfn = callee::get_fn(cx, instance); - - let et = cx.sess().entry_fn.get().map(|e| e.2); - match et { - Some(config::EntryMain) => create_entry_fn(cx, span, main_llfn, main_def_id, true), - Some(config::EntryStart) => create_entry_fn(cx, span, main_llfn, main_def_id, false), - None => {} // Do nothing. - } - - fn create_entry_fn<'cx>(cx: &'cx CodegenCx, - sp: Span, - rust_main: ValueRef, - rust_main_def_id: DefId, - use_start_lang_item: bool) { - let llfty = Type::func(&[Type::c_int(cx), Type::i8p(cx).ptr_to()], &Type::c_int(cx)); - - let main_ret_ty = cx.tcx.fn_sig(rust_main_def_id).output(); - // Given that `main()` has no arguments, - // then its return type cannot have - // late-bound regions, since late-bound - // regions must appear in the argument - // listing. - let main_ret_ty = cx.tcx.erase_regions( - &main_ret_ty.no_late_bound_regions().unwrap(), - ); - - if declare::get_defined_value(cx, "main").is_some() { - // FIXME: We should be smart and show a better diagnostic here. - cx.sess().struct_span_err(sp, "entry symbol `main` defined multiple times") - .help("did you use #[no_mangle] on `fn main`? Use #[start] instead") - .emit(); - cx.sess().abort_if_errors(); - bug!(); - } - let llfn = declare::declare_cfn(cx, "main", llfty); - - // `main` should respect same config for frame pointer elimination as rest of code - attributes::set_frame_pointer_elimination(cx, llfn); - - let bx = Builder::new_block(cx, llfn, "top"); - - debuginfo::gdb::insert_reference_to_gdb_debug_scripts_section_global(&bx); - - // Params from native main() used as args for rust start function - let param_argc = get_param(llfn, 0); - let param_argv = get_param(llfn, 1); - let arg_argc = bx.intcast(param_argc, cx.isize_ty, true); - let arg_argv = param_argv; - - let (start_fn, args) = if use_start_lang_item { - let start_def_id = cx.tcx.require_lang_item(StartFnLangItem); - let start_fn = callee::resolve_and_get_fn( - cx, - start_def_id, - cx.tcx.intern_substs(&[Kind::from(main_ret_ty)]), - ); - (start_fn, vec![bx.pointercast(rust_main, Type::i8p(cx).ptr_to()), - arg_argc, arg_argv]) - } else { - debug!("using user-defined start fn"); - (rust_main, vec![arg_argc, arg_argv]) - }; - - let result = bx.call(start_fn, &args, None); - bx.ret(bx.intcast(result, Type::c_int(cx), true)); - } -} - -fn contains_null(s: &str) -> bool { - s.bytes().any(|b| b == 0) -} - -fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, - llmod_id: &str, - link_meta: &LinkMeta) - -> (ContextRef, ModuleRef, EncodedMetadata) { - use std::io::Write; - use flate2::Compression; - use flate2::write::DeflateEncoder; - - let (metadata_llcx, metadata_llmod) = unsafe { - context::create_context_and_module(tcx.sess, llmod_id) - }; - - #[derive(PartialEq, Eq, PartialOrd, Ord)] - enum MetadataKind { - None, - Uncompressed, - Compressed - } - - let kind = tcx.sess.crate_types.borrow().iter().map(|ty| { - match *ty { - config::CrateTypeExecutable | - config::CrateTypeStaticlib | - config::CrateTypeCdylib => MetadataKind::None, - - config::CrateTypeRlib => MetadataKind::Uncompressed, - - config::CrateTypeDylib | - config::CrateTypeProcMacro => MetadataKind::Compressed, - } - }).max().unwrap(); - - if kind == MetadataKind::None { - return (metadata_llcx, - metadata_llmod, - EncodedMetadata::new()); - } - - let metadata = tcx.encode_metadata(link_meta); - if kind == MetadataKind::Uncompressed { - return (metadata_llcx, metadata_llmod, metadata); - } - - assert!(kind == MetadataKind::Compressed); - let mut compressed = tcx.metadata_encoding_version(); - DeflateEncoder::new(&mut compressed, Compression::fast()) - .write_all(&metadata.raw_data).unwrap(); - - let llmeta = C_bytes_in_context(metadata_llcx, &compressed); - let llconst = C_struct_in_context(metadata_llcx, &[llmeta], false); - let name = exported_symbols::metadata_symbol_name(tcx); - let buf = CString::new(name).unwrap(); - let llglobal = unsafe { - llvm::LLVMAddGlobal(metadata_llmod, val_ty(llconst).to_ref(), buf.as_ptr()) - }; - unsafe { - llvm::LLVMSetInitializer(llglobal, llconst); - let section_name = metadata::metadata_section_name(&tcx.sess.target.target); - let name = CString::new(section_name).unwrap(); - llvm::LLVMSetSection(llglobal, name.as_ptr()); - - // Also generate a .section directive to force no - // flags, at least for ELF outputs, so that the - // metadata doesn't get loaded into memory. - let directive = format!(".section {}", section_name); - let directive = CString::new(directive).unwrap(); - llvm::LLVMSetModuleInlineAsm(metadata_llmod, directive.as_ptr()) - } - return (metadata_llcx, metadata_llmod, metadata); -} - -pub struct ValueIter { - cur: ValueRef, - step: unsafe extern "C" fn(ValueRef) -> ValueRef, -} - -impl Iterator for ValueIter { - type Item = ValueRef; - - fn next(&mut self) -> Option { - let old = self.cur; - if !old.is_null() { - self.cur = unsafe { (self.step)(old) }; - Some(old) - } else { - None - } - } -} - -pub fn iter_globals(llmod: llvm::ModuleRef) -> ValueIter { - unsafe { - ValueIter { - cur: llvm::LLVMGetFirstGlobal(llmod), - step: llvm::LLVMGetNextGlobal, - } - } -} - -pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - rx: mpsc::Receiver>) - -> OngoingCrateTranslation { - - check_for_rustc_errors_attr(tcx); - - if let Some(true) = tcx.sess.opts.debugging_opts.thinlto { - if unsafe { !llvm::LLVMRustThinLTOAvailable() } { - tcx.sess.fatal("this compiler's LLVM does not support ThinLTO"); - } - } - - if (tcx.sess.opts.debugging_opts.pgo_gen.is_some() || - !tcx.sess.opts.debugging_opts.pgo_use.is_empty()) && - unsafe { !llvm::LLVMRustPGOAvailable() } - { - tcx.sess.fatal("this compiler's LLVM does not support PGO"); - } - - let crate_hash = tcx.crate_hash(LOCAL_CRATE); - let link_meta = link::build_link_meta(crate_hash); - - // Translate the metadata. - let llmod_id = "metadata"; - let (metadata_llcx, metadata_llmod, metadata) = - time(tcx.sess, "write metadata", || { - write_metadata(tcx, llmod_id, &link_meta) - }); - - let metadata_module = ModuleTranslation { - name: link::METADATA_MODULE_NAME.to_string(), - llmod_id: llmod_id.to_string(), - source: ModuleSource::Translated(ModuleLlvm { - llcx: metadata_llcx, - llmod: metadata_llmod, - tm: create_target_machine(tcx.sess, false), - }), - kind: ModuleKind::Metadata, - }; - - let time_graph = if tcx.sess.opts.debugging_opts.trans_time_graph { - Some(time_graph::TimeGraph::new()) - } else { - None - }; - - // Skip crate items and just output metadata in -Z no-trans mode. - if tcx.sess.opts.debugging_opts.no_trans || - !tcx.sess.opts.output_types.should_trans() { - let ongoing_translation = write::start_async_translation( - tcx, - time_graph.clone(), - link_meta, - metadata, - rx, - 1); - - ongoing_translation.submit_pre_translated_module_to_llvm(tcx, metadata_module); - ongoing_translation.translation_finished(tcx); - - assert_and_save_dep_graph(tcx); - - ongoing_translation.check_for_errors(tcx.sess); - - return ongoing_translation; - } - - // Run the translation item collector and partition the collected items into - // codegen units. - let codegen_units = - tcx.collect_and_partition_translation_items(LOCAL_CRATE).1; - let codegen_units = (*codegen_units).clone(); - - // Force all codegen_unit queries so they are already either red or green - // when compile_codegen_unit accesses them. We are not able to re-execute - // the codegen_unit query from just the DepNode, so an unknown color would - // lead to having to re-execute compile_codegen_unit, possibly - // unnecessarily. - if tcx.dep_graph.is_fully_enabled() { - for cgu in &codegen_units { - tcx.codegen_unit(cgu.name().clone()); - } - } - - let ongoing_translation = write::start_async_translation( - tcx, - time_graph.clone(), - link_meta, - metadata, - rx, - codegen_units.len()); - - // Translate an allocator shim, if any - let allocator_module = if let Some(kind) = *tcx.sess.allocator_kind.get() { - unsafe { - let llmod_id = "allocator"; - let (llcx, llmod) = - context::create_context_and_module(tcx.sess, llmod_id); - let modules = ModuleLlvm { - llmod, - llcx, - tm: create_target_machine(tcx.sess, false), - }; - time(tcx.sess, "write allocator module", || { - allocator::trans(tcx, &modules, kind) - }); - - Some(ModuleTranslation { - name: link::ALLOCATOR_MODULE_NAME.to_string(), - llmod_id: llmod_id.to_string(), - source: ModuleSource::Translated(modules), - kind: ModuleKind::Allocator, - }) - } - } else { - None - }; - - if let Some(allocator_module) = allocator_module { - ongoing_translation.submit_pre_translated_module_to_llvm(tcx, allocator_module); - } - - ongoing_translation.submit_pre_translated_module_to_llvm(tcx, metadata_module); - - // We sort the codegen units by size. This way we can schedule work for LLVM - // a bit more efficiently. - let codegen_units = { - let mut codegen_units = codegen_units; - codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); - codegen_units - }; - - let mut total_trans_time = Duration::new(0, 0); - let mut all_stats = Stats::default(); - - for cgu in codegen_units.into_iter() { - ongoing_translation.wait_for_signal_to_translate_item(); - ongoing_translation.check_for_errors(tcx.sess); - - // First, if incremental compilation is enabled, we try to re-use the - // codegen unit from the cache. - if tcx.dep_graph.is_fully_enabled() { - let cgu_id = cgu.work_product_id(); - - // Check whether there is a previous work-product we can - // re-use. Not only must the file exist, and the inputs not - // be dirty, but the hash of the symbols we will generate must - // be the same. - if let Some(buf) = tcx.dep_graph.previous_work_product(&cgu_id) { - let dep_node = &DepNode::new(tcx, - DepConstructor::CompileCodegenUnit(cgu.name().clone())); - - // We try to mark the DepNode::CompileCodegenUnit green. If we - // succeed it means that none of the dependencies has changed - // and we can safely re-use. - if let Some(dep_node_index) = tcx.dep_graph.try_mark_green(tcx, dep_node) { - // Append ".rs" to LLVM module identifier. - // - // LLVM code generator emits a ".file filename" directive - // for ELF backends. Value of the "filename" is set as the - // LLVM module identifier. Due to a LLVM MC bug[1], LLVM - // crashes if the module identifier is same as other symbols - // such as a function name in the module. - // 1. http://llvm.org/bugs/show_bug.cgi?id=11479 - let llmod_id = format!("{}.rs", cgu.name()); - - let module = ModuleTranslation { - name: cgu.name().to_string(), - source: ModuleSource::Preexisting(buf), - kind: ModuleKind::Regular, - llmod_id, - }; - tcx.dep_graph.mark_loaded_from_cache(dep_node_index, true); - write::submit_translated_module_to_llvm(tcx, module, 0); - // Continue to next cgu, this one is done. - continue - } - } else { - // This can happen if files were deleted from the cache - // directory for some reason. We just re-compile then. - } - } - - let _timing_guard = time_graph.as_ref().map(|time_graph| { - time_graph.start(write::TRANS_WORKER_TIMELINE, - write::TRANS_WORK_PACKAGE_KIND, - &format!("codegen {}", cgu.name())) - }); - let start_time = Instant::now(); - all_stats.extend(tcx.compile_codegen_unit(*cgu.name())); - total_trans_time += start_time.elapsed(); - ongoing_translation.check_for_errors(tcx.sess); - } - - ongoing_translation.translation_finished(tcx); - - // Since the main thread is sometimes blocked during trans, we keep track - // -Ztime-passes output manually. - print_time_passes_entry(tcx.sess.time_passes(), - "translate to LLVM IR", - total_trans_time); - - if tcx.sess.opts.incremental.is_some() { - ::rustc_incremental::assert_module_sources::assert_module_sources(tcx); - } - - symbol_names_test::report_symbol_names(tcx); - - if tcx.sess.trans_stats() { - println!("--- trans stats ---"); - println!("n_glues_created: {}", all_stats.n_glues_created); - println!("n_null_glues: {}", all_stats.n_null_glues); - println!("n_real_glues: {}", all_stats.n_real_glues); - - println!("n_fns: {}", all_stats.n_fns); - println!("n_inlines: {}", all_stats.n_inlines); - println!("n_closures: {}", all_stats.n_closures); - println!("fn stats:"); - all_stats.fn_stats.sort_by_key(|&(_, insns)| insns); - for &(ref name, insns) in all_stats.fn_stats.iter() { - println!("{} insns, {}", insns, *name); - } - } - - if tcx.sess.count_llvm_insns() { - for (k, v) in all_stats.llvm_insns.iter() { - println!("{:7} {}", *v, *k); - } - } - - ongoing_translation.check_for_errors(tcx.sess); - - assert_and_save_dep_graph(tcx); - ongoing_translation -} - -fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - time(tcx.sess, - "assert dep graph", - || rustc_incremental::assert_dep_graph(tcx)); - - time(tcx.sess, - "serialize dep graph", - || rustc_incremental::save_dep_graph(tcx)); -} - -fn collect_and_partition_translation_items<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - cnum: CrateNum, -) -> (Arc, Arc>>>) -{ - assert_eq!(cnum, LOCAL_CRATE); - - let collection_mode = match tcx.sess.opts.debugging_opts.print_trans_items { - Some(ref s) => { - let mode_string = s.to_lowercase(); - let mode_string = mode_string.trim(); - if mode_string == "eager" { - MonoItemCollectionMode::Eager - } else { - if mode_string != "lazy" { - let message = format!("Unknown codegen-item collection mode '{}'. \ - Falling back to 'lazy' mode.", - mode_string); - tcx.sess.warn(&message); - } - - MonoItemCollectionMode::Lazy - } - } - None => { - if tcx.sess.opts.cg.link_dead_code { - MonoItemCollectionMode::Eager - } else { - MonoItemCollectionMode::Lazy - } - } - }; - - let (items, inlining_map) = - time(tcx.sess, "translation item collection", || { - collector::collect_crate_mono_items(tcx, collection_mode) - }); - - tcx.sess.abort_if_errors(); - - ::rustc_mir::monomorphize::assert_symbols_are_distinct(tcx, items.iter()); - - let strategy = if tcx.sess.opts.incremental.is_some() { - PartitioningStrategy::PerModule - } else { - PartitioningStrategy::FixedUnitCount(tcx.sess.codegen_units()) - }; - - let codegen_units = time(tcx.sess, "codegen unit partitioning", || { - partitioning::partition(tcx, - items.iter().cloned(), - strategy, - &inlining_map) - .into_iter() - .map(Arc::new) - .collect::>() - }); - - let translation_items: DefIdSet = items.iter().filter_map(|trans_item| { - match *trans_item { - MonoItem::Fn(ref instance) => Some(instance.def_id()), - MonoItem::Static(def_id) => Some(def_id), - _ => None, - } - }).collect(); - - if tcx.sess.opts.debugging_opts.print_trans_items.is_some() { - let mut item_to_cgus = FxHashMap(); - - for cgu in &codegen_units { - for (&trans_item, &linkage) in cgu.items() { - item_to_cgus.entry(trans_item) - .or_insert(Vec::new()) - .push((cgu.name().clone(), linkage)); - } - } - - let mut item_keys: Vec<_> = items - .iter() - .map(|i| { - let mut output = i.to_string(tcx); - output.push_str(" @@"); - let mut empty = Vec::new(); - let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); - cgus.as_mut_slice().sort_by_key(|&(ref name, _)| name.clone()); - cgus.dedup(); - for &(ref cgu_name, (linkage, _)) in cgus.iter() { - output.push_str(" "); - output.push_str(&cgu_name.as_str()); - - let linkage_abbrev = match linkage { - Linkage::External => "External", - Linkage::AvailableExternally => "Available", - Linkage::LinkOnceAny => "OnceAny", - Linkage::LinkOnceODR => "OnceODR", - Linkage::WeakAny => "WeakAny", - Linkage::WeakODR => "WeakODR", - Linkage::Appending => "Appending", - Linkage::Internal => "Internal", - Linkage::Private => "Private", - Linkage::ExternalWeak => "ExternalWeak", - Linkage::Common => "Common", - }; - - output.push_str("["); - output.push_str(linkage_abbrev); - output.push_str("]"); - } - output - }) - .collect(); - - item_keys.sort(); - - for item in item_keys { - println!("TRANS_ITEM {}", item); - } - } - - (Arc::new(translation_items), Arc::new(codegen_units)) -} - -impl CrateInfo { - pub fn new(tcx: TyCtxt) -> CrateInfo { - let mut info = CrateInfo { - panic_runtime: None, - compiler_builtins: None, - profiler_runtime: None, - sanitizer_runtime: None, - is_no_builtins: FxHashSet(), - native_libraries: FxHashMap(), - used_libraries: tcx.native_libraries(LOCAL_CRATE), - link_args: tcx.link_args(LOCAL_CRATE), - crate_name: FxHashMap(), - used_crates_dynamic: cstore::used_crates(tcx, LinkagePreference::RequireDynamic), - used_crates_static: cstore::used_crates(tcx, LinkagePreference::RequireStatic), - used_crate_source: FxHashMap(), - wasm_custom_sections: BTreeMap::new(), - wasm_imports: FxHashMap(), - lang_item_to_crate: FxHashMap(), - missing_lang_items: FxHashMap(), - }; - let lang_items = tcx.lang_items(); - - let load_wasm_items = tcx.sess.crate_types.borrow() - .iter() - .any(|c| *c != config::CrateTypeRlib) && - tcx.sess.opts.target_triple == TargetTriple::from_triple("wasm32-unknown-unknown"); - - if load_wasm_items { - info!("attempting to load all wasm sections"); - for &id in tcx.wasm_custom_sections(LOCAL_CRATE).iter() { - let (name, contents) = fetch_wasm_section(tcx, id); - info.wasm_custom_sections.entry(name) - .or_insert(Vec::new()) - .extend(contents); - } - info.load_wasm_imports(tcx, LOCAL_CRATE); - } - - for &cnum in tcx.crates().iter() { - info.native_libraries.insert(cnum, tcx.native_libraries(cnum)); - info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string()); - info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum)); - if tcx.is_panic_runtime(cnum) { - info.panic_runtime = Some(cnum); - } - if tcx.is_compiler_builtins(cnum) { - info.compiler_builtins = Some(cnum); - } - if tcx.is_profiler_runtime(cnum) { - info.profiler_runtime = Some(cnum); - } - if tcx.is_sanitizer_runtime(cnum) { - info.sanitizer_runtime = Some(cnum); - } - if tcx.is_no_builtins(cnum) { - info.is_no_builtins.insert(cnum); - } - if load_wasm_items { - for &id in tcx.wasm_custom_sections(cnum).iter() { - let (name, contents) = fetch_wasm_section(tcx, id); - info.wasm_custom_sections.entry(name) - .or_insert(Vec::new()) - .extend(contents); - } - info.load_wasm_imports(tcx, cnum); - } - let missing = tcx.missing_lang_items(cnum); - for &item in missing.iter() { - if let Ok(id) = lang_items.require(item) { - info.lang_item_to_crate.insert(item, id.krate); - } - } - - // No need to look for lang items that are whitelisted and don't - // actually need to exist. - let missing = missing.iter() - .cloned() - .filter(|&l| !weak_lang_items::whitelisted(tcx, l)) - .collect(); - info.missing_lang_items.insert(cnum, missing); - } - - return info - } - - fn load_wasm_imports(&mut self, tcx: TyCtxt, cnum: CrateNum) { - for (&id, module) in tcx.wasm_import_module_map(cnum).iter() { - let instance = Instance::mono(tcx, id); - let import_name = tcx.symbol_name(instance); - self.wasm_imports.insert(import_name.to_string(), module.clone()); - } - } -} - -fn is_translated_item(tcx: TyCtxt, id: DefId) -> bool { - let (all_trans_items, _) = - tcx.collect_and_partition_translation_items(LOCAL_CRATE); - all_trans_items.contains(&id) -} - -fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - cgu: InternedString) -> Stats { - let cgu = tcx.codegen_unit(cgu); - - let start_time = Instant::now(); - let (stats, module) = module_translation(tcx, cgu); - let time_to_translate = start_time.elapsed(); - - // We assume that the cost to run LLVM on a CGU is proportional to - // the time we needed for translating it. - let cost = time_to_translate.as_secs() * 1_000_000_000 + - time_to_translate.subsec_nanos() as u64; - - write::submit_translated_module_to_llvm(tcx, - module, - cost); - return stats; - - fn module_translation<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - cgu: Arc>) - -> (Stats, ModuleTranslation) - { - let cgu_name = cgu.name().to_string(); - - // Append ".rs" to LLVM module identifier. - // - // LLVM code generator emits a ".file filename" directive - // for ELF backends. Value of the "filename" is set as the - // LLVM module identifier. Due to a LLVM MC bug[1], LLVM - // crashes if the module identifier is same as other symbols - // such as a function name in the module. - // 1. http://llvm.org/bugs/show_bug.cgi?id=11479 - let llmod_id = format!("{}-{}.rs", - cgu.name(), - tcx.crate_disambiguator(LOCAL_CRATE) - .to_fingerprint().to_hex()); - - // Instantiate translation items without filling out definitions yet... - let cx = CodegenCx::new(tcx, cgu, &llmod_id); - let module = { - let trans_items = cx.codegen_unit - .items_in_deterministic_order(cx.tcx); - for &(trans_item, (linkage, visibility)) in &trans_items { - trans_item.predefine(&cx, linkage, visibility); - } - - // ... and now that we have everything pre-defined, fill out those definitions. - for &(trans_item, _) in &trans_items { - trans_item.define(&cx); - } - - // If this codegen unit contains the main function, also create the - // wrapper here - maybe_create_entry_wrapper(&cx); - - // Run replace-all-uses-with for statics that need it - for &(old_g, new_g) in cx.statics_to_rauw.borrow().iter() { - unsafe { - let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g)); - llvm::LLVMReplaceAllUsesWith(old_g, bitcast); - llvm::LLVMDeleteGlobal(old_g); - } - } - - // Create the llvm.used variable - // This variable has type [N x i8*] and is stored in the llvm.metadata section - if !cx.used_statics.borrow().is_empty() { - let name = CString::new("llvm.used").unwrap(); - let section = CString::new("llvm.metadata").unwrap(); - let array = C_array(Type::i8(&cx).ptr_to(), &*cx.used_statics.borrow()); - - unsafe { - let g = llvm::LLVMAddGlobal(cx.llmod, - val_ty(array).to_ref(), - name.as_ptr()); - llvm::LLVMSetInitializer(g, array); - llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage); - llvm::LLVMSetSection(g, section.as_ptr()); - } - } - - // Finalize debuginfo - if cx.sess().opts.debuginfo != NoDebugInfo { - debuginfo::finalize(&cx); - } - - let llvm_module = ModuleLlvm { - llcx: cx.llcx, - llmod: cx.llmod, - tm: create_target_machine(cx.sess(), false), - }; - - ModuleTranslation { - name: cgu_name, - source: ModuleSource::Translated(llvm_module), - kind: ModuleKind::Regular, - llmod_id, - } - }; - - (cx.into_stats(), module) - } -} - -pub fn provide(providers: &mut Providers) { - providers.collect_and_partition_translation_items = - collect_and_partition_translation_items; - - providers.is_translated_item = is_translated_item; - - providers.codegen_unit = |tcx, name| { - let (_, all) = tcx.collect_and_partition_translation_items(LOCAL_CRATE); - all.iter() - .find(|cgu| *cgu.name() == name) - .cloned() - .expect(&format!("failed to find cgu with name {:?}", name)) - }; - providers.compile_codegen_unit = compile_codegen_unit; - - provide_extern(providers); -} - -pub fn provide_extern(providers: &mut Providers) { - providers.dllimport_foreign_items = |tcx, krate| { - let module_map = tcx.foreign_modules(krate); - let module_map = module_map.iter() - .map(|lib| (lib.def_id, lib)) - .collect::>(); - - let dllimports = tcx.native_libraries(krate) - .iter() - .filter(|lib| { - if lib.kind != cstore::NativeLibraryKind::NativeUnknown { - return false - } - let cfg = match lib.cfg { - Some(ref cfg) => cfg, - None => return true, - }; - attr::cfg_matches(cfg, &tcx.sess.parse_sess, None) - }) - .filter_map(|lib| lib.foreign_module) - .map(|id| &module_map[&id]) - .flat_map(|module| module.foreign_items.iter().cloned()) - .collect(); - Lrc::new(dllimports) - }; - - providers.is_dllimport_foreign_item = |tcx, def_id| { - tcx.dllimport_foreign_items(def_id.krate).contains(&def_id) - }; -} - -pub fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage { - match linkage { - Linkage::External => llvm::Linkage::ExternalLinkage, - Linkage::AvailableExternally => llvm::Linkage::AvailableExternallyLinkage, - Linkage::LinkOnceAny => llvm::Linkage::LinkOnceAnyLinkage, - Linkage::LinkOnceODR => llvm::Linkage::LinkOnceODRLinkage, - Linkage::WeakAny => llvm::Linkage::WeakAnyLinkage, - Linkage::WeakODR => llvm::Linkage::WeakODRLinkage, - Linkage::Appending => llvm::Linkage::AppendingLinkage, - Linkage::Internal => llvm::Linkage::InternalLinkage, - Linkage::Private => llvm::Linkage::PrivateLinkage, - Linkage::ExternalWeak => llvm::Linkage::ExternalWeakLinkage, - Linkage::Common => llvm::Linkage::CommonLinkage, - } -} - -pub fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility { - match linkage { - Visibility::Default => llvm::Visibility::Default, - Visibility::Hidden => llvm::Visibility::Hidden, - Visibility::Protected => llvm::Visibility::Protected, - } -} - -// FIXME(mw): Anything that is produced via DepGraph::with_task() must implement -// the HashStable trait. Normally DepGraph::with_task() calls are -// hidden behind queries, but CGU creation is a special case in two -// ways: (1) it's not a query and (2) CGU are output nodes, so their -// Fingerprints are not actually needed. It remains to be clarified -// how exactly this case will be handled in the red/green system but -// for now we content ourselves with providing a no-op HashStable -// implementation for CGUs. -mod temp_stable_hash_impls { - use rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher, - HashStable}; - use ModuleTranslation; - - impl HashStable for ModuleTranslation { - fn hash_stable(&self, - _: &mut HCX, - _: &mut StableHasher) { - // do nothing - } - } -} - -fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec) { - use rustc::mir::interpret::GlobalId; - use rustc::middle::const_val::ConstVal; - - info!("loading wasm section {:?}", id); - - let section = tcx.get_attrs(id) - .iter() - .find(|a| a.check_name("wasm_custom_section")) - .expect("missing #[wasm_custom_section] attribute") - .value_str() - .expect("malformed #[wasm_custom_section] attribute"); - - let instance = ty::Instance::mono(tcx, id); - let cid = GlobalId { - instance, - promoted: None - }; - let param_env = ty::ParamEnv::reveal_all(); - let val = tcx.const_eval(param_env.and(cid)).unwrap(); - - let const_val = match val.val { - ConstVal::Value(val) => val, - ConstVal::Unevaluated(..) => bug!("should be evaluated"), - }; - - let alloc = tcx.const_value_to_allocation((const_val, val.ty)); - (section.to_string(), alloc.bytes.clone()) -} diff --git a/src/librustc_trans/build.rs b/src/librustc_trans/build.rs deleted file mode 100644 index 97accbb4b8f..00000000000 --- a/src/librustc_trans/build.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn main() { - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-env-changed=CFG_VERSION"); - println!("cargo:rerun-if-env-changed=CFG_PREFIX"); - println!("cargo:rerun-if-env-changed=CFG_LLVM_ROOT"); -} diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs deleted file mode 100644 index 4153c61e526..00000000000 --- a/src/librustc_trans/builder.rs +++ /dev/null @@ -1,1425 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code)] // FFI wrappers - -use llvm; -use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect}; -use llvm::{Opcode, IntPredicate, RealPredicate, False, OperandBundleDef}; -use llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef}; -use common::*; -use type_::Type; -use value::Value; -use libc::{c_uint, c_char}; -use rustc::ty::TyCtxt; -use rustc::ty::layout::{Align, Size}; -use rustc::session::{config, Session}; - -use std::borrow::Cow; -use std::ffi::CString; -use std::ops::Range; -use std::ptr; -use syntax_pos::Span; - -// All Builders must have an llfn associated with them -#[must_use] -pub struct Builder<'a, 'tcx: 'a> { - pub llbuilder: BuilderRef, - pub cx: &'a CodegenCx<'a, 'tcx>, -} - -impl<'a, 'tcx> Drop for Builder<'a, 'tcx> { - fn drop(&mut self) { - unsafe { - llvm::LLVMDisposeBuilder(self.llbuilder); - } - } -} - -// This is a really awful way to get a zero-length c-string, but better (and a -// lot more efficient) than doing str::as_c_str("", ...) every time. -fn noname() -> *const c_char { - static CNULL: c_char = 0; - &CNULL -} - -bitflags! { - pub struct MemFlags: u8 { - const VOLATILE = 1 << 0; - const NONTEMPORAL = 1 << 1; - } -} - -impl<'a, 'tcx> Builder<'a, 'tcx> { - pub fn new_block<'b>(cx: &'a CodegenCx<'a, 'tcx>, llfn: ValueRef, name: &'b str) -> Self { - let bx = Builder::with_cx(cx); - let llbb = unsafe { - let name = CString::new(name).unwrap(); - llvm::LLVMAppendBasicBlockInContext( - cx.llcx, - llfn, - name.as_ptr() - ) - }; - bx.position_at_end(llbb); - bx - } - - pub fn with_cx(cx: &'a CodegenCx<'a, 'tcx>) -> Self { - // Create a fresh builder from the crate context. - let llbuilder = unsafe { - llvm::LLVMCreateBuilderInContext(cx.llcx) - }; - Builder { - llbuilder, - cx, - } - } - - pub fn build_sibling_block<'b>(&self, name: &'b str) -> Builder<'a, 'tcx> { - Builder::new_block(self.cx, self.llfn(), name) - } - - pub fn sess(&self) -> &Session { - self.cx.sess() - } - - pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { - self.cx.tcx - } - - pub fn llfn(&self) -> ValueRef { - unsafe { - llvm::LLVMGetBasicBlockParent(self.llbb()) - } - } - - pub fn llbb(&self) -> BasicBlockRef { - unsafe { - llvm::LLVMGetInsertBlock(self.llbuilder) - } - } - - fn count_insn(&self, category: &str) { - if self.cx.sess().trans_stats() { - self.cx.stats.borrow_mut().n_llvm_insns += 1; - } - if self.cx.sess().count_llvm_insns() { - *self.cx.stats - .borrow_mut() - .llvm_insns - .entry(category.to_string()) - .or_insert(0) += 1; - } - } - - pub fn set_value_name(&self, value: ValueRef, name: &str) { - let cname = CString::new(name.as_bytes()).unwrap(); - unsafe { - llvm::LLVMSetValueName(value, cname.as_ptr()); - } - } - - pub fn position_before(&self, insn: ValueRef) { - unsafe { - llvm::LLVMPositionBuilderBefore(self.llbuilder, insn); - } - } - - pub fn position_at_end(&self, llbb: BasicBlockRef) { - unsafe { - llvm::LLVMPositionBuilderAtEnd(self.llbuilder, llbb); - } - } - - pub fn position_at_start(&self, llbb: BasicBlockRef) { - unsafe { - llvm::LLVMRustPositionBuilderAtStart(self.llbuilder, llbb); - } - } - - pub fn ret_void(&self) { - self.count_insn("retvoid"); - unsafe { - llvm::LLVMBuildRetVoid(self.llbuilder); - } - } - - pub fn ret(&self, v: ValueRef) { - self.count_insn("ret"); - unsafe { - llvm::LLVMBuildRet(self.llbuilder, v); - } - } - - pub fn aggregate_ret(&self, ret_vals: &[ValueRef]) { - unsafe { - llvm::LLVMBuildAggregateRet(self.llbuilder, - ret_vals.as_ptr(), - ret_vals.len() as c_uint); - } - } - - pub fn br(&self, dest: BasicBlockRef) { - self.count_insn("br"); - unsafe { - llvm::LLVMBuildBr(self.llbuilder, dest); - } - } - - pub fn cond_br(&self, cond: ValueRef, then_llbb: BasicBlockRef, else_llbb: BasicBlockRef) { - self.count_insn("condbr"); - unsafe { - llvm::LLVMBuildCondBr(self.llbuilder, cond, then_llbb, else_llbb); - } - } - - pub fn switch(&self, v: ValueRef, else_llbb: BasicBlockRef, num_cases: usize) -> ValueRef { - unsafe { - llvm::LLVMBuildSwitch(self.llbuilder, v, else_llbb, num_cases as c_uint) - } - } - - pub fn indirect_br(&self, addr: ValueRef, num_dests: usize) { - self.count_insn("indirectbr"); - unsafe { - llvm::LLVMBuildIndirectBr(self.llbuilder, addr, num_dests as c_uint); - } - } - - pub fn invoke(&self, - llfn: ValueRef, - args: &[ValueRef], - then: BasicBlockRef, - catch: BasicBlockRef, - bundle: Option<&OperandBundleDef>) -> ValueRef { - self.count_insn("invoke"); - - debug!("Invoke {:?} with args ({})", - Value(llfn), - args.iter() - .map(|&v| format!("{:?}", Value(v))) - .collect::>() - .join(", ")); - - let args = self.check_call("invoke", llfn, args); - let bundle = bundle.as_ref().map(|b| b.raw()).unwrap_or(ptr::null_mut()); - - unsafe { - llvm::LLVMRustBuildInvoke(self.llbuilder, - llfn, - args.as_ptr(), - args.len() as c_uint, - then, - catch, - bundle, - noname()) - } - } - - pub fn unreachable(&self) { - self.count_insn("unreachable"); - unsafe { - llvm::LLVMBuildUnreachable(self.llbuilder); - } - } - - /* Arithmetic */ - pub fn add(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("add"); - unsafe { - llvm::LLVMBuildAdd(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn nswadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("nswadd"); - unsafe { - llvm::LLVMBuildNSWAdd(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn nuwadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("nuwadd"); - unsafe { - llvm::LLVMBuildNUWAdd(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn fadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("fadd"); - unsafe { - llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn fadd_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("fadd"); - unsafe { - let instr = llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname()); - llvm::LLVMRustSetHasUnsafeAlgebra(instr); - instr - } - } - - pub fn sub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("sub"); - unsafe { - llvm::LLVMBuildSub(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn nswsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("nwsub"); - unsafe { - llvm::LLVMBuildNSWSub(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn nuwsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("nuwsub"); - unsafe { - llvm::LLVMBuildNUWSub(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn fsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("sub"); - unsafe { - llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn fsub_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("sub"); - unsafe { - let instr = llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname()); - llvm::LLVMRustSetHasUnsafeAlgebra(instr); - instr - } - } - - pub fn mul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("mul"); - unsafe { - llvm::LLVMBuildMul(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn nswmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("nswmul"); - unsafe { - llvm::LLVMBuildNSWMul(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn nuwmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("nuwmul"); - unsafe { - llvm::LLVMBuildNUWMul(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn fmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("fmul"); - unsafe { - llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn fmul_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("fmul"); - unsafe { - let instr = llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname()); - llvm::LLVMRustSetHasUnsafeAlgebra(instr); - instr - } - } - - - pub fn udiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("udiv"); - unsafe { - llvm::LLVMBuildUDiv(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn exactudiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("exactudiv"); - unsafe { - llvm::LLVMBuildExactUDiv(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn sdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("sdiv"); - unsafe { - llvm::LLVMBuildSDiv(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn exactsdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("exactsdiv"); - unsafe { - llvm::LLVMBuildExactSDiv(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn fdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("fdiv"); - unsafe { - llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn fdiv_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("fdiv"); - unsafe { - let instr = llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname()); - llvm::LLVMRustSetHasUnsafeAlgebra(instr); - instr - } - } - - pub fn urem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("urem"); - unsafe { - llvm::LLVMBuildURem(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn srem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("srem"); - unsafe { - llvm::LLVMBuildSRem(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn frem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("frem"); - unsafe { - llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn frem_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("frem"); - unsafe { - let instr = llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname()); - llvm::LLVMRustSetHasUnsafeAlgebra(instr); - instr - } - } - - pub fn shl(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("shl"); - unsafe { - llvm::LLVMBuildShl(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn lshr(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("lshr"); - unsafe { - llvm::LLVMBuildLShr(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn ashr(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("ashr"); - unsafe { - llvm::LLVMBuildAShr(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn and(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("and"); - unsafe { - llvm::LLVMBuildAnd(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn or(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("or"); - unsafe { - llvm::LLVMBuildOr(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn xor(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("xor"); - unsafe { - llvm::LLVMBuildXor(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn binop(&self, op: Opcode, lhs: ValueRef, rhs: ValueRef) - -> ValueRef { - self.count_insn("binop"); - unsafe { - llvm::LLVMBuildBinOp(self.llbuilder, op, lhs, rhs, noname()) - } - } - - pub fn neg(&self, v: ValueRef) -> ValueRef { - self.count_insn("neg"); - unsafe { - llvm::LLVMBuildNeg(self.llbuilder, v, noname()) - } - } - - pub fn nswneg(&self, v: ValueRef) -> ValueRef { - self.count_insn("nswneg"); - unsafe { - llvm::LLVMBuildNSWNeg(self.llbuilder, v, noname()) - } - } - - pub fn nuwneg(&self, v: ValueRef) -> ValueRef { - self.count_insn("nuwneg"); - unsafe { - llvm::LLVMBuildNUWNeg(self.llbuilder, v, noname()) - } - } - pub fn fneg(&self, v: ValueRef) -> ValueRef { - self.count_insn("fneg"); - unsafe { - llvm::LLVMBuildFNeg(self.llbuilder, v, noname()) - } - } - - pub fn not(&self, v: ValueRef) -> ValueRef { - self.count_insn("not"); - unsafe { - llvm::LLVMBuildNot(self.llbuilder, v, noname()) - } - } - - pub fn alloca(&self, ty: Type, name: &str, align: Align) -> ValueRef { - let bx = Builder::with_cx(self.cx); - bx.position_at_start(unsafe { - llvm::LLVMGetFirstBasicBlock(self.llfn()) - }); - bx.dynamic_alloca(ty, name, align) - } - - pub fn dynamic_alloca(&self, ty: Type, name: &str, align: Align) -> ValueRef { - self.count_insn("alloca"); - unsafe { - let alloca = if name.is_empty() { - llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname()) - } else { - let name = CString::new(name).unwrap(); - llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), - name.as_ptr()) - }; - llvm::LLVMSetAlignment(alloca, align.abi() as c_uint); - alloca - } - } - - pub fn free(&self, ptr: ValueRef) { - self.count_insn("free"); - unsafe { - llvm::LLVMBuildFree(self.llbuilder, ptr); - } - } - - pub fn load(&self, ptr: ValueRef, align: Align) -> ValueRef { - self.count_insn("load"); - unsafe { - let load = llvm::LLVMBuildLoad(self.llbuilder, ptr, noname()); - llvm::LLVMSetAlignment(load, align.abi() as c_uint); - load - } - } - - pub fn volatile_load(&self, ptr: ValueRef) -> ValueRef { - self.count_insn("load.volatile"); - unsafe { - let insn = llvm::LLVMBuildLoad(self.llbuilder, ptr, noname()); - llvm::LLVMSetVolatile(insn, llvm::True); - insn - } - } - - pub fn atomic_load(&self, ptr: ValueRef, order: AtomicOrdering, align: Align) -> ValueRef { - self.count_insn("load.atomic"); - unsafe { - let load = llvm::LLVMRustBuildAtomicLoad(self.llbuilder, ptr, noname(), order); - // FIXME(eddyb) Isn't it UB to use `pref` instead of `abi` here? - // However, 64-bit atomic loads on `i686-apple-darwin` appear to - // require `___atomic_load` with ABI-alignment, so it's staying. - llvm::LLVMSetAlignment(load, align.pref() as c_uint); - load - } - } - - - pub fn range_metadata(&self, load: ValueRef, range: Range) { - unsafe { - let llty = val_ty(load); - let v = [ - C_uint_big(llty, range.start), - C_uint_big(llty, range.end) - ]; - - llvm::LLVMSetMetadata(load, llvm::MD_range as c_uint, - llvm::LLVMMDNodeInContext(self.cx.llcx, - v.as_ptr(), - v.len() as c_uint)); - } - } - - pub fn nonnull_metadata(&self, load: ValueRef) { - unsafe { - llvm::LLVMSetMetadata(load, llvm::MD_nonnull as c_uint, - llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0)); - } - } - - pub fn store(&self, val: ValueRef, ptr: ValueRef, align: Align) -> ValueRef { - self.store_with_flags(val, ptr, align, MemFlags::empty()) - } - - pub fn store_with_flags( - &self, - val: ValueRef, - ptr: ValueRef, - align: Align, - flags: MemFlags, - ) -> ValueRef { - debug!("Store {:?} -> {:?} ({:?})", Value(val), Value(ptr), flags); - assert!(!self.llbuilder.is_null()); - self.count_insn("store"); - let ptr = self.check_store(val, ptr); - unsafe { - let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr); - llvm::LLVMSetAlignment(store, align.abi() as c_uint); - if flags.contains(MemFlags::VOLATILE) { - llvm::LLVMSetVolatile(store, llvm::True); - } - if flags.contains(MemFlags::NONTEMPORAL) { - // According to LLVM [1] building a nontemporal store must - // *always* point to a metadata value of the integer 1. - // - // [1]: http://llvm.org/docs/LangRef.html#store-instruction - let one = C_i32(self.cx, 1); - let node = llvm::LLVMMDNodeInContext(self.cx.llcx, &one, 1); - llvm::LLVMSetMetadata(store, llvm::MD_nontemporal as c_uint, node); - } - store - } - } - - pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef, - order: AtomicOrdering, align: Align) { - debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); - self.count_insn("store.atomic"); - let ptr = self.check_store(val, ptr); - unsafe { - let store = llvm::LLVMRustBuildAtomicStore(self.llbuilder, val, ptr, order); - // FIXME(eddyb) Isn't it UB to use `pref` instead of `abi` here? - // Also see `atomic_load` for more context. - llvm::LLVMSetAlignment(store, align.pref() as c_uint); - } - } - - pub fn gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef { - self.count_insn("gep"); - unsafe { - llvm::LLVMBuildGEP(self.llbuilder, ptr, indices.as_ptr(), - indices.len() as c_uint, noname()) - } - } - - pub fn inbounds_gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef { - self.count_insn("inboundsgep"); - unsafe { - llvm::LLVMBuildInBoundsGEP( - self.llbuilder, ptr, indices.as_ptr(), indices.len() as c_uint, noname()) - } - } - - pub fn struct_gep(&self, ptr: ValueRef, idx: u64) -> ValueRef { - self.count_insn("structgep"); - assert_eq!(idx as c_uint as u64, idx); - unsafe { - llvm::LLVMBuildStructGEP(self.llbuilder, ptr, idx as c_uint, noname()) - } - } - - pub fn global_string(&self, _str: *const c_char) -> ValueRef { - self.count_insn("globalstring"); - unsafe { - llvm::LLVMBuildGlobalString(self.llbuilder, _str, noname()) - } - } - - pub fn global_string_ptr(&self, _str: *const c_char) -> ValueRef { - self.count_insn("globalstringptr"); - unsafe { - llvm::LLVMBuildGlobalStringPtr(self.llbuilder, _str, noname()) - } - } - - /* Casts */ - pub fn trunc(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("trunc"); - unsafe { - llvm::LLVMBuildTrunc(self.llbuilder, val, dest_ty.to_ref(), noname()) - } - } - - pub fn zext(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("zext"); - unsafe { - llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty.to_ref(), noname()) - } - } - - pub fn sext(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("sext"); - unsafe { - llvm::LLVMBuildSExt(self.llbuilder, val, dest_ty.to_ref(), noname()) - } - } - - pub fn fptoui(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("fptoui"); - unsafe { - llvm::LLVMBuildFPToUI(self.llbuilder, val, dest_ty.to_ref(), noname()) - } - } - - pub fn fptosi(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("fptosi"); - unsafe { - llvm::LLVMBuildFPToSI(self.llbuilder, val, dest_ty.to_ref(),noname()) - } - } - - pub fn uitofp(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("uitofp"); - unsafe { - llvm::LLVMBuildUIToFP(self.llbuilder, val, dest_ty.to_ref(), noname()) - } - } - - pub fn sitofp(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("sitofp"); - unsafe { - llvm::LLVMBuildSIToFP(self.llbuilder, val, dest_ty.to_ref(), noname()) - } - } - - pub fn fptrunc(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("fptrunc"); - unsafe { - llvm::LLVMBuildFPTrunc(self.llbuilder, val, dest_ty.to_ref(), noname()) - } - } - - pub fn fpext(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("fpext"); - unsafe { - llvm::LLVMBuildFPExt(self.llbuilder, val, dest_ty.to_ref(), noname()) - } - } - - pub fn ptrtoint(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("ptrtoint"); - unsafe { - llvm::LLVMBuildPtrToInt(self.llbuilder, val, dest_ty.to_ref(), noname()) - } - } - - pub fn inttoptr(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("inttoptr"); - unsafe { - llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty.to_ref(), noname()) - } - } - - pub fn bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("bitcast"); - unsafe { - llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty.to_ref(), noname()) - } - } - - pub fn zext_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("zextorbitcast"); - unsafe { - llvm::LLVMBuildZExtOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname()) - } - } - - pub fn sext_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("sextorbitcast"); - unsafe { - llvm::LLVMBuildSExtOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname()) - } - } - - pub fn trunc_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("truncorbitcast"); - unsafe { - llvm::LLVMBuildTruncOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname()) - } - } - - pub fn cast(&self, op: Opcode, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("cast"); - unsafe { - llvm::LLVMBuildCast(self.llbuilder, op, val, dest_ty.to_ref(), noname()) - } - } - - pub fn pointercast(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("pointercast"); - unsafe { - llvm::LLVMBuildPointerCast(self.llbuilder, val, dest_ty.to_ref(), noname()) - } - } - - pub fn intcast(&self, val: ValueRef, dest_ty: Type, is_signed: bool) -> ValueRef { - self.count_insn("intcast"); - unsafe { - llvm::LLVMRustBuildIntCast(self.llbuilder, val, dest_ty.to_ref(), is_signed) - } - } - - pub fn fpcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef { - self.count_insn("fpcast"); - unsafe { - llvm::LLVMBuildFPCast(self.llbuilder, val, dest_ty.to_ref(), noname()) - } - } - - - /* Comparisons */ - pub fn icmp(&self, op: IntPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("icmp"); - unsafe { - llvm::LLVMBuildICmp(self.llbuilder, op as c_uint, lhs, rhs, noname()) - } - } - - pub fn fcmp(&self, op: RealPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("fcmp"); - unsafe { - llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, noname()) - } - } - - /* Miscellaneous instructions */ - pub fn empty_phi(&self, ty: Type) -> ValueRef { - self.count_insn("emptyphi"); - unsafe { - llvm::LLVMBuildPhi(self.llbuilder, ty.to_ref(), noname()) - } - } - - pub fn phi(&self, ty: Type, vals: &[ValueRef], bbs: &[BasicBlockRef]) -> ValueRef { - assert_eq!(vals.len(), bbs.len()); - let phi = self.empty_phi(ty); - self.count_insn("addincoming"); - unsafe { - llvm::LLVMAddIncoming(phi, vals.as_ptr(), - bbs.as_ptr(), - vals.len() as c_uint); - phi - } - } - - pub fn add_span_comment(&self, sp: Span, text: &str) { - if self.cx.sess().asm_comments() { - let s = format!("{} ({})", - text, - self.cx.sess().codemap().span_to_string(sp)); - debug!("{}", s); - self.add_comment(&s); - } - } - - pub fn add_comment(&self, text: &str) { - if self.cx.sess().asm_comments() { - let sanitized = text.replace("$", ""); - let comment_text = format!("{} {}", "#", - sanitized.replace("\n", "\n\t# ")); - self.count_insn("inlineasm"); - let comment_text = CString::new(comment_text).unwrap(); - let asm = unsafe { - llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.cx)).to_ref(), - comment_text.as_ptr(), noname(), False, - False) - }; - self.call(asm, &[], None); - } - } - - pub fn inline_asm_call(&self, asm: *const c_char, cons: *const c_char, - inputs: &[ValueRef], output: Type, - volatile: bool, alignstack: bool, - dia: AsmDialect) -> ValueRef { - self.count_insn("inlineasm"); - - let volatile = if volatile { llvm::True } - else { llvm::False }; - let alignstack = if alignstack { llvm::True } - else { llvm::False }; - - let argtys = inputs.iter().map(|v| { - debug!("Asm Input Type: {:?}", Value(*v)); - val_ty(*v) - }).collect::>(); - - debug!("Asm Output Type: {:?}", output); - let fty = Type::func(&argtys[..], &output); - unsafe { - let v = llvm::LLVMRustInlineAsm( - fty.to_ref(), asm, cons, volatile, alignstack, dia); - self.call(v, inputs, None) - } - } - - pub fn call(&self, llfn: ValueRef, args: &[ValueRef], - bundle: Option<&OperandBundleDef>) -> ValueRef { - self.count_insn("call"); - - debug!("Call {:?} with args ({})", - Value(llfn), - args.iter() - .map(|&v| format!("{:?}", Value(v))) - .collect::>() - .join(", ")); - - let args = self.check_call("call", llfn, args); - let bundle = bundle.as_ref().map(|b| b.raw()).unwrap_or(ptr::null_mut()); - - unsafe { - llvm::LLVMRustBuildCall(self.llbuilder, llfn, args.as_ptr(), - args.len() as c_uint, bundle, noname()) - } - } - - pub fn minnum(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("minnum"); - unsafe { - let instr = llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs); - if instr.is_null() { - bug!("LLVMRustBuildMinNum is not available in LLVM version < 6.0"); - } - instr - } - } - pub fn maxnum(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("maxnum"); - unsafe { - let instr = llvm::LLVMRustBuildMaxNum(self.llbuilder, lhs, rhs); - if instr.is_null() { - bug!("LLVMRustBuildMaxNum is not available in LLVM version < 6.0"); - } - instr - } - } - - pub fn select(&self, cond: ValueRef, then_val: ValueRef, else_val: ValueRef) -> ValueRef { - self.count_insn("select"); - unsafe { - llvm::LLVMBuildSelect(self.llbuilder, cond, then_val, else_val, noname()) - } - } - - pub fn va_arg(&self, list: ValueRef, ty: Type) -> ValueRef { - self.count_insn("vaarg"); - unsafe { - llvm::LLVMBuildVAArg(self.llbuilder, list, ty.to_ref(), noname()) - } - } - - pub fn extract_element(&self, vec: ValueRef, idx: ValueRef) -> ValueRef { - self.count_insn("extractelement"); - unsafe { - llvm::LLVMBuildExtractElement(self.llbuilder, vec, idx, noname()) - } - } - - pub fn insert_element(&self, vec: ValueRef, elt: ValueRef, idx: ValueRef) -> ValueRef { - self.count_insn("insertelement"); - unsafe { - llvm::LLVMBuildInsertElement(self.llbuilder, vec, elt, idx, noname()) - } - } - - pub fn shuffle_vector(&self, v1: ValueRef, v2: ValueRef, mask: ValueRef) -> ValueRef { - self.count_insn("shufflevector"); - unsafe { - llvm::LLVMBuildShuffleVector(self.llbuilder, v1, v2, mask, noname()) - } - } - - pub fn vector_splat(&self, num_elts: usize, elt: ValueRef) -> ValueRef { - unsafe { - let elt_ty = val_ty(elt); - let undef = llvm::LLVMGetUndef(Type::vector(&elt_ty, num_elts as u64).to_ref()); - let vec = self.insert_element(undef, elt, C_i32(self.cx, 0)); - let vec_i32_ty = Type::vector(&Type::i32(self.cx), num_elts as u64); - self.shuffle_vector(vec, undef, C_null(vec_i32_ty)) - } - } - - pub fn vector_reduce_fadd_fast(&self, acc: ValueRef, src: ValueRef) -> ValueRef { - self.count_insn("vector.reduce.fadd_fast"); - unsafe { - // FIXME: add a non-fast math version once - // https://bugs.llvm.org/show_bug.cgi?id=36732 - // is fixed. - let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src); - if instr.is_null() { - bug!("LLVMRustBuildVectorReduceFAdd is not available in LLVM version < 5.0"); - } - llvm::LLVMRustSetHasUnsafeAlgebra(instr); - instr - } - } - pub fn vector_reduce_fmul_fast(&self, acc: ValueRef, src: ValueRef) -> ValueRef { - self.count_insn("vector.reduce.fmul_fast"); - unsafe { - // FIXME: add a non-fast math version once - // https://bugs.llvm.org/show_bug.cgi?id=36732 - // is fixed. - let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src); - if instr.is_null() { - bug!("LLVMRustBuildVectorReduceFMul is not available in LLVM version < 5.0"); - } - llvm::LLVMRustSetHasUnsafeAlgebra(instr); - instr - } - } - pub fn vector_reduce_add(&self, src: ValueRef) -> ValueRef { - self.count_insn("vector.reduce.add"); - unsafe { - let instr = llvm::LLVMRustBuildVectorReduceAdd(self.llbuilder, src); - if instr.is_null() { - bug!("LLVMRustBuildVectorReduceAdd is not available in LLVM version < 5.0"); - } - instr - } - } - pub fn vector_reduce_mul(&self, src: ValueRef) -> ValueRef { - self.count_insn("vector.reduce.mul"); - unsafe { - let instr = llvm::LLVMRustBuildVectorReduceMul(self.llbuilder, src); - if instr.is_null() { - bug!("LLVMRustBuildVectorReduceMul is not available in LLVM version < 5.0"); - } - instr - } - } - pub fn vector_reduce_and(&self, src: ValueRef) -> ValueRef { - self.count_insn("vector.reduce.and"); - unsafe { - let instr = llvm::LLVMRustBuildVectorReduceAnd(self.llbuilder, src); - if instr.is_null() { - bug!("LLVMRustBuildVectorReduceAnd is not available in LLVM version < 5.0"); - } - instr - } - } - pub fn vector_reduce_or(&self, src: ValueRef) -> ValueRef { - self.count_insn("vector.reduce.or"); - unsafe { - let instr = llvm::LLVMRustBuildVectorReduceOr(self.llbuilder, src); - if instr.is_null() { - bug!("LLVMRustBuildVectorReduceOr is not available in LLVM version < 5.0"); - } - instr - } - } - pub fn vector_reduce_xor(&self, src: ValueRef) -> ValueRef { - self.count_insn("vector.reduce.xor"); - unsafe { - let instr = llvm::LLVMRustBuildVectorReduceXor(self.llbuilder, src); - if instr.is_null() { - bug!("LLVMRustBuildVectorReduceXor is not available in LLVM version < 5.0"); - } - instr - } - } - pub fn vector_reduce_fmin(&self, src: ValueRef) -> ValueRef { - self.count_insn("vector.reduce.fmin"); - unsafe { - let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ false); - if instr.is_null() { - bug!("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0"); - } - instr - } - } - pub fn vector_reduce_fmax(&self, src: ValueRef) -> ValueRef { - self.count_insn("vector.reduce.fmax"); - unsafe { - let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ false); - if instr.is_null() { - bug!("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0"); - } - instr - } - } - pub fn vector_reduce_fmin_fast(&self, src: ValueRef) -> ValueRef { - self.count_insn("vector.reduce.fmin_fast"); - unsafe { - let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ true); - if instr.is_null() { - bug!("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0"); - } - llvm::LLVMRustSetHasUnsafeAlgebra(instr); - instr - } - } - pub fn vector_reduce_fmax_fast(&self, src: ValueRef) -> ValueRef { - self.count_insn("vector.reduce.fmax_fast"); - unsafe { - let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ true); - if instr.is_null() { - bug!("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0"); - } - llvm::LLVMRustSetHasUnsafeAlgebra(instr); - instr - } - } - pub fn vector_reduce_min(&self, src: ValueRef, is_signed: bool) -> ValueRef { - self.count_insn("vector.reduce.min"); - unsafe { - let instr = llvm::LLVMRustBuildVectorReduceMin(self.llbuilder, src, is_signed); - if instr.is_null() { - bug!("LLVMRustBuildVectorReduceMin is not available in LLVM version < 5.0"); - } - instr - } - } - pub fn vector_reduce_max(&self, src: ValueRef, is_signed: bool) -> ValueRef { - self.count_insn("vector.reduce.max"); - unsafe { - let instr = llvm::LLVMRustBuildVectorReduceMax(self.llbuilder, src, is_signed); - if instr.is_null() { - bug!("LLVMRustBuildVectorReduceMax is not available in LLVM version < 5.0"); - } - instr - } - } - - pub fn extract_value(&self, agg_val: ValueRef, idx: u64) -> ValueRef { - self.count_insn("extractvalue"); - assert_eq!(idx as c_uint as u64, idx); - unsafe { - llvm::LLVMBuildExtractValue(self.llbuilder, agg_val, idx as c_uint, noname()) - } - } - - pub fn insert_value(&self, agg_val: ValueRef, elt: ValueRef, - idx: u64) -> ValueRef { - self.count_insn("insertvalue"); - assert_eq!(idx as c_uint as u64, idx); - unsafe { - llvm::LLVMBuildInsertValue(self.llbuilder, agg_val, elt, idx as c_uint, - noname()) - } - } - - pub fn is_null(&self, val: ValueRef) -> ValueRef { - self.count_insn("isnull"); - unsafe { - llvm::LLVMBuildIsNull(self.llbuilder, val, noname()) - } - } - - pub fn is_not_null(&self, val: ValueRef) -> ValueRef { - self.count_insn("isnotnull"); - unsafe { - llvm::LLVMBuildIsNotNull(self.llbuilder, val, noname()) - } - } - - pub fn ptrdiff(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("ptrdiff"); - unsafe { - llvm::LLVMBuildPtrDiff(self.llbuilder, lhs, rhs, noname()) - } - } - - pub fn trap(&self) { - unsafe { - let bb: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder); - let fn_: ValueRef = llvm::LLVMGetBasicBlockParent(bb); - let m: ModuleRef = llvm::LLVMGetGlobalParent(fn_); - let p = "llvm.trap\0".as_ptr(); - let t: ValueRef = llvm::LLVMGetNamedFunction(m, p as *const _); - assert!((t as isize != 0)); - let args: &[ValueRef] = &[]; - self.count_insn("trap"); - llvm::LLVMRustBuildCall(self.llbuilder, t, - args.as_ptr(), args.len() as c_uint, - ptr::null_mut(), - noname()); - } - } - - pub fn landing_pad(&self, ty: Type, pers_fn: ValueRef, - num_clauses: usize) -> ValueRef { - self.count_insn("landingpad"); - unsafe { - llvm::LLVMBuildLandingPad(self.llbuilder, ty.to_ref(), pers_fn, - num_clauses as c_uint, noname()) - } - } - - pub fn add_clause(&self, landing_pad: ValueRef, clause: ValueRef) { - unsafe { - llvm::LLVMAddClause(landing_pad, clause); - } - } - - pub fn set_cleanup(&self, landing_pad: ValueRef) { - self.count_insn("setcleanup"); - unsafe { - llvm::LLVMSetCleanup(landing_pad, llvm::True); - } - } - - pub fn resume(&self, exn: ValueRef) -> ValueRef { - self.count_insn("resume"); - unsafe { - llvm::LLVMBuildResume(self.llbuilder, exn) - } - } - - pub fn cleanup_pad(&self, - parent: Option, - args: &[ValueRef]) -> ValueRef { - self.count_insn("cleanuppad"); - let parent = parent.unwrap_or(ptr::null_mut()); - let name = CString::new("cleanuppad").unwrap(); - let ret = unsafe { - llvm::LLVMRustBuildCleanupPad(self.llbuilder, - parent, - args.len() as c_uint, - args.as_ptr(), - name.as_ptr()) - }; - assert!(!ret.is_null(), "LLVM does not have support for cleanuppad"); - return ret - } - - pub fn cleanup_ret(&self, cleanup: ValueRef, - unwind: Option) -> ValueRef { - self.count_insn("cleanupret"); - let unwind = unwind.unwrap_or(ptr::null_mut()); - let ret = unsafe { - llvm::LLVMRustBuildCleanupRet(self.llbuilder, cleanup, unwind) - }; - assert!(!ret.is_null(), "LLVM does not have support for cleanupret"); - return ret - } - - pub fn catch_pad(&self, - parent: ValueRef, - args: &[ValueRef]) -> ValueRef { - self.count_insn("catchpad"); - let name = CString::new("catchpad").unwrap(); - let ret = unsafe { - llvm::LLVMRustBuildCatchPad(self.llbuilder, parent, - args.len() as c_uint, args.as_ptr(), - name.as_ptr()) - }; - assert!(!ret.is_null(), "LLVM does not have support for catchpad"); - return ret - } - - pub fn catch_ret(&self, pad: ValueRef, unwind: BasicBlockRef) -> ValueRef { - self.count_insn("catchret"); - let ret = unsafe { - llvm::LLVMRustBuildCatchRet(self.llbuilder, pad, unwind) - }; - assert!(!ret.is_null(), "LLVM does not have support for catchret"); - return ret - } - - pub fn catch_switch(&self, - parent: Option, - unwind: Option, - num_handlers: usize) -> ValueRef { - self.count_insn("catchswitch"); - let parent = parent.unwrap_or(ptr::null_mut()); - let unwind = unwind.unwrap_or(ptr::null_mut()); - let name = CString::new("catchswitch").unwrap(); - let ret = unsafe { - llvm::LLVMRustBuildCatchSwitch(self.llbuilder, parent, unwind, - num_handlers as c_uint, - name.as_ptr()) - }; - assert!(!ret.is_null(), "LLVM does not have support for catchswitch"); - return ret - } - - pub fn add_handler(&self, catch_switch: ValueRef, handler: BasicBlockRef) { - unsafe { - llvm::LLVMRustAddHandler(catch_switch, handler); - } - } - - pub fn set_personality_fn(&self, personality: ValueRef) { - unsafe { - llvm::LLVMSetPersonalityFn(self.llfn(), personality); - } - } - - // Atomic Operations - pub fn atomic_cmpxchg(&self, dst: ValueRef, - cmp: ValueRef, src: ValueRef, - order: AtomicOrdering, - failure_order: AtomicOrdering, - weak: llvm::Bool) -> ValueRef { - unsafe { - llvm::LLVMRustBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src, - order, failure_order, weak) - } - } - pub fn atomic_rmw(&self, op: AtomicRmwBinOp, - dst: ValueRef, src: ValueRef, - order: AtomicOrdering) -> ValueRef { - unsafe { - llvm::LLVMBuildAtomicRMW(self.llbuilder, op, dst, src, order, False) - } - } - - pub fn atomic_fence(&self, order: AtomicOrdering, scope: SynchronizationScope) { - unsafe { - llvm::LLVMRustBuildAtomicFence(self.llbuilder, order, scope); - } - } - - pub fn add_case(&self, s: ValueRef, on_val: ValueRef, dest: BasicBlockRef) { - unsafe { - llvm::LLVMAddCase(s, on_val, dest) - } - } - - pub fn add_incoming_to_phi(&self, phi: ValueRef, val: ValueRef, bb: BasicBlockRef) { - unsafe { - llvm::LLVMAddIncoming(phi, &val, &bb, 1 as c_uint); - } - } - - pub fn set_invariant_load(&self, load: ValueRef) { - unsafe { - llvm::LLVMSetMetadata(load, llvm::MD_invariant_load as c_uint, - llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0)); - } - } - - /// Returns the ptr value that should be used for storing `val`. - fn check_store<'b>(&self, - val: ValueRef, - ptr: ValueRef) -> ValueRef { - let dest_ptr_ty = val_ty(ptr); - let stored_ty = val_ty(val); - let stored_ptr_ty = stored_ty.ptr_to(); - - assert_eq!(dest_ptr_ty.kind(), llvm::TypeKind::Pointer); - - if dest_ptr_ty == stored_ptr_ty { - ptr - } else { - debug!("Type mismatch in store. \ - Expected {:?}, got {:?}; inserting bitcast", - dest_ptr_ty, stored_ptr_ty); - self.bitcast(ptr, stored_ptr_ty) - } - } - - /// Returns the args that should be used for a call to `llfn`. - fn check_call<'b>(&self, - typ: &str, - llfn: ValueRef, - args: &'b [ValueRef]) -> Cow<'b, [ValueRef]> { - let mut fn_ty = val_ty(llfn); - // Strip off pointers - while fn_ty.kind() == llvm::TypeKind::Pointer { - fn_ty = fn_ty.element_type(); - } - - assert!(fn_ty.kind() == llvm::TypeKind::Function, - "builder::{} not passed a function, but {:?}", typ, fn_ty); - - let param_tys = fn_ty.func_params(); - - let all_args_match = param_tys.iter() - .zip(args.iter().map(|&v| val_ty(v))) - .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty); - - if all_args_match { - return Cow::Borrowed(args); - } - - let casted_args: Vec<_> = param_tys.into_iter() - .zip(args.iter()) - .enumerate() - .map(|(i, (expected_ty, &actual_val))| { - let actual_ty = val_ty(actual_val); - if expected_ty != actual_ty { - debug!("Type mismatch in function call of {:?}. \ - Expected {:?} for param {}, got {:?}; injecting bitcast", - Value(llfn), - expected_ty, i, actual_ty); - self.bitcast(actual_val, expected_ty) - } else { - actual_val - } - }) - .collect(); - - return Cow::Owned(casted_args); - } - - pub fn lifetime_start(&self, ptr: ValueRef, size: Size) { - self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size); - } - - pub fn lifetime_end(&self, ptr: ValueRef, size: Size) { - self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size); - } - - /// If LLVM lifetime intrinsic support is enabled (i.e. optimizations - /// on), and `ptr` is nonzero-sized, then extracts the size of `ptr` - /// and the intrinsic for `lt` and passes them to `emit`, which is in - /// charge of generating code to call the passed intrinsic on whatever - /// block of generated code is targeted for the intrinsic. - /// - /// If LLVM lifetime intrinsic support is disabled (i.e. optimizations - /// off) or `ptr` is zero-sized, then no-op (does not call `emit`). - fn call_lifetime_intrinsic(&self, intrinsic: &str, ptr: ValueRef, size: Size) { - if self.cx.sess().opts.optimize == config::OptLevel::No { - return; - } - - let size = size.bytes(); - if size == 0 { - return; - } - - let lifetime_intrinsic = self.cx.get_intrinsic(intrinsic); - - let ptr = self.pointercast(ptr, Type::i8p(self.cx)); - self.call(lifetime_intrinsic, &[C_u64(self.cx, size), ptr], None); - } -} diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs deleted file mode 100644 index 9263d9a5f5d..00000000000 --- a/src/librustc_trans/callee.rs +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Handles translation of callees as well as other call-related -//! things. Callees are a superset of normal rust values and sometimes -//! have different representations. In particular, top-level fn items -//! and methods are represented as just a fn ptr and not a full -//! closure. - -use attributes; -use common::{self, CodegenCx}; -use consts; -use declare; -use llvm::{self, ValueRef}; -use monomorphize::Instance; -use type_of::LayoutLlvmExt; - -use rustc::hir::def_id::DefId; -use rustc::ty::{self, TypeFoldable}; -use rustc::ty::layout::LayoutOf; -use rustc::ty::subst::Substs; -use rustc_target::spec::PanicStrategy; - -/// Translates a reference to a fn/method item, monomorphizing and -/// inlining as it goes. -/// -/// # Parameters -/// -/// - `cx`: the crate context -/// - `instance`: the instance to be instantiated -pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - instance: Instance<'tcx>) - -> ValueRef -{ - let tcx = cx.tcx; - - debug!("get_fn(instance={:?})", instance); - - assert!(!instance.substs.needs_infer()); - assert!(!instance.substs.has_escaping_regions()); - assert!(!instance.substs.has_param_types()); - - let fn_ty = instance.ty(cx.tcx); - if let Some(&llfn) = cx.instances.borrow().get(&instance) { - return llfn; - } - - let sym = tcx.symbol_name(instance).as_str(); - debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym); - - // Create a fn pointer with the substituted signature. - let fn_ptr_ty = tcx.mk_fn_ptr(common::ty_fn_sig(cx, fn_ty)); - let llptrty = cx.layout_of(fn_ptr_ty).llvm_type(cx); - - let llfn = if let Some(llfn) = declare::get_declared_value(cx, &sym) { - // This is subtle and surprising, but sometimes we have to bitcast - // the resulting fn pointer. The reason has to do with external - // functions. If you have two crates that both bind the same C - // library, they may not use precisely the same types: for - // example, they will probably each declare their own structs, - // which are distinct types from LLVM's point of view (nominal - // types). - // - // Now, if those two crates are linked into an application, and - // they contain inlined code, you can wind up with a situation - // where both of those functions wind up being loaded into this - // application simultaneously. In that case, the same function - // (from LLVM's point of view) requires two types. But of course - // LLVM won't allow one function to have two types. - // - // What we currently do, therefore, is declare the function with - // one of the two types (whichever happens to come first) and then - // bitcast as needed when the function is referenced to make sure - // it has the type we expect. - // - // This can occur on either a crate-local or crate-external - // reference. It also occurs when testing libcore and in some - // other weird situations. Annoying. - if common::val_ty(llfn) != llptrty { - debug!("get_fn: casting {:?} to {:?}", llfn, llptrty); - consts::ptrcast(llfn, llptrty) - } else { - debug!("get_fn: not casting pointer!"); - llfn - } - } else { - let llfn = declare::declare_fn(cx, &sym, fn_ty); - assert_eq!(common::val_ty(llfn), llptrty); - debug!("get_fn: not casting pointer!"); - - if instance.def.is_inline(tcx) { - attributes::inline(llfn, attributes::InlineAttr::Hint); - } - attributes::from_fn_attrs(cx, llfn, instance.def.def_id()); - - let instance_def_id = instance.def_id(); - - // Perhaps questionable, but we assume that anything defined - // *in Rust code* may unwind. Foreign items like `extern "C" { - // fn foo(); }` are assumed not to unwind **unless** they have - // a `#[unwind]` attribute. - if tcx.sess.panic_strategy() == PanicStrategy::Unwind { - if !tcx.is_foreign_item(instance_def_id) { - attributes::unwind(llfn, true); - } - } - - // Apply an appropriate linkage/visibility value to our item that we - // just declared. - // - // This is sort of subtle. Inside our codegen unit we started off - // compilation by predefining all our own `TransItem` instances. That - // is, everything we're translating ourselves is already defined. That - // means that anything we're actually translating in this codegen unit - // will have hit the above branch in `get_declared_value`. As a result, - // we're guaranteed here that we're declaring a symbol that won't get - // defined, or in other words we're referencing a value from another - // codegen unit or even another crate. - // - // So because this is a foreign value we blanket apply an external - // linkage directive because it's coming from a different object file. - // The visibility here is where it gets tricky. This symbol could be - // referencing some foreign crate or foreign library (an `extern` - // block) in which case we want to leave the default visibility. We may - // also, though, have multiple codegen units. It could be a - // monomorphization, in which case its expected visibility depends on - // whether we are sharing generics or not. The important thing here is - // that the visibility we apply to the declaration is the same one that - // has been applied to the definition (wherever that definition may be). - unsafe { - llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); - - let is_generic = instance.substs.types().next().is_some(); - - if is_generic { - // This is a monomorphization. Its expected visibility depends - // on whether we are in share-generics mode. - - if cx.tcx.share_generics() { - // We are in share_generics mode. - - if instance_def_id.is_local() { - // This is a definition from the current crate. If the - // definition is unreachable for downstream crates or - // the current crate does not re-export generics, the - // definition of the instance will have been declared - // as `hidden`. - if cx.tcx.is_unreachable_local_definition(instance_def_id) || - !cx.tcx.local_crate_exports_generics() { - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); - } - } else { - // This is a monomorphization of a generic function - // defined in an upstream crate. - if cx.tcx.upstream_monomorphizations_for(instance_def_id) - .map(|set| set.contains_key(instance.substs)) - .unwrap_or(false) { - // This is instantiated in another crate. It cannot - // be `hidden`. - } else { - // This is a local instantiation of an upstream definition. - // If the current crate does not re-export it - // (because it is a C library or an executable), it - // will have been declared `hidden`. - if !cx.tcx.local_crate_exports_generics() { - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); - } - } - } - } else { - // When not sharing generics, all instances are in the same - // crate and have hidden visibility - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); - } - } else { - // This is a non-generic function - if cx.tcx.is_translated_item(instance_def_id) { - // This is a function that is instantiated in the local crate - - if instance_def_id.is_local() { - // This is function that is defined in the local crate. - // If it is not reachable, it is hidden. - if !cx.tcx.is_reachable_non_generic(instance_def_id) { - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); - } - } else { - // This is a function from an upstream crate that has - // been instantiated here. These are always hidden. - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); - } - } - } - } - - if cx.use_dll_storage_attrs && - tcx.is_dllimport_foreign_item(instance_def_id) - { - unsafe { - llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); - } - } - - llfn - }; - - cx.instances.borrow_mut().insert(instance, llfn); - - llfn -} - -pub fn resolve_and_get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>) - -> ValueRef -{ - get_fn( - cx, - ty::Instance::resolve( - cx.tcx, - ty::ParamEnv::reveal_all(), - def_id, - substs - ).unwrap() - ) -} diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs deleted file mode 100644 index 75b56be3c16..00000000000 --- a/src/librustc_trans/common.rs +++ /dev/null @@ -1,449 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_camel_case_types, non_snake_case)] - -//! Code that is useful in various trans modules. - -use llvm; -use llvm::{ValueRef, ContextRef, TypeKind}; -use llvm::{True, False, Bool, OperandBundleDef}; -use rustc::hir::def_id::DefId; -use rustc::middle::lang_items::LangItem; -use abi; -use base; -use builder::Builder; -use consts; -use declare; -use type_::Type; -use type_of::LayoutLlvmExt; -use value::Value; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::layout::{HasDataLayout, LayoutOf}; -use rustc::hir; - -use libc::{c_uint, c_char}; -use std::iter; - -use rustc_target::spec::abi::Abi; -use syntax::symbol::LocalInternedString; -use syntax_pos::{Span, DUMMY_SP}; - -pub use context::CodegenCx; - -pub fn type_needs_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) -} - -pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.is_sized(tcx.at(DUMMY_SP), ty::ParamEnv::reveal_all()) -} - -pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.is_freeze(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP) -} - -/* -* A note on nomenclature of linking: "extern", "foreign", and "upcall". -* -* An "extern" is an LLVM symbol we wind up emitting an undefined external -* reference to. This means "we don't have the thing in this compilation unit, -* please make sure you link it in at runtime". This could be a reference to -* C code found in a C library, or rust code found in a rust crate. -* -* Most "externs" are implicitly declared (automatically) as a result of a -* user declaring an extern _module_ dependency; this causes the rust driver -* to locate an extern crate, scan its compilation metadata, and emit extern -* declarations for any symbols used by the declaring crate. -* -* A "foreign" is an extern that references C (or other non-rust ABI) code. -* There is no metadata to scan for extern references so in these cases either -* a header-digester like bindgen, or manual function prototypes, have to -* serve as declarators. So these are usually given explicitly as prototype -* declarations, in rust code, with ABI attributes on them noting which ABI to -* link via. -* -* An "upcall" is a foreign call generated by the compiler (not corresponding -* to any user-written call in the code) into the runtime library, to perform -* some helper task such as bringing a task to life, allocating memory, etc. -* -*/ - -/// A structure representing an active landing pad for the duration of a basic -/// block. -/// -/// Each `Block` may contain an instance of this, indicating whether the block -/// is part of a landing pad or not. This is used to make decision about whether -/// to emit `invoke` instructions (e.g. in a landing pad we don't continue to -/// use `invoke`) and also about various function call metadata. -/// -/// For GNU exceptions (`landingpad` + `resume` instructions) this structure is -/// just a bunch of `None` instances (not too interesting), but for MSVC -/// exceptions (`cleanuppad` + `cleanupret` instructions) this contains data. -/// When inside of a landing pad, each function call in LLVM IR needs to be -/// annotated with which landing pad it's a part of. This is accomplished via -/// the `OperandBundleDef` value created for MSVC landing pads. -pub struct Funclet { - cleanuppad: ValueRef, - operand: OperandBundleDef, -} - -impl Funclet { - pub fn new(cleanuppad: ValueRef) -> Funclet { - Funclet { - cleanuppad, - operand: OperandBundleDef::new("funclet", &[cleanuppad]), - } - } - - pub fn cleanuppad(&self) -> ValueRef { - self.cleanuppad - } - - pub fn bundle(&self) -> &OperandBundleDef { - &self.operand - } -} - -pub fn val_ty(v: ValueRef) -> Type { - unsafe { - Type::from_ref(llvm::LLVMTypeOf(v)) - } -} - -// LLVM constant constructors. -pub fn C_null(t: Type) -> ValueRef { - unsafe { - llvm::LLVMConstNull(t.to_ref()) - } -} - -pub fn C_undef(t: Type) -> ValueRef { - unsafe { - llvm::LLVMGetUndef(t.to_ref()) - } -} - -pub fn C_int(t: Type, i: i64) -> ValueRef { - unsafe { - llvm::LLVMConstInt(t.to_ref(), i as u64, True) - } -} - -pub fn C_uint(t: Type, i: u64) -> ValueRef { - unsafe { - llvm::LLVMConstInt(t.to_ref(), i, False) - } -} - -pub fn C_uint_big(t: Type, u: u128) -> ValueRef { - unsafe { - let words = [u as u64, (u >> 64) as u64]; - llvm::LLVMConstIntOfArbitraryPrecision(t.to_ref(), 2, words.as_ptr()) - } -} - -pub fn C_bool(cx: &CodegenCx, val: bool) -> ValueRef { - C_uint(Type::i1(cx), val as u64) -} - -pub fn C_i32(cx: &CodegenCx, i: i32) -> ValueRef { - C_int(Type::i32(cx), i as i64) -} - -pub fn C_u32(cx: &CodegenCx, i: u32) -> ValueRef { - C_uint(Type::i32(cx), i as u64) -} - -pub fn C_u64(cx: &CodegenCx, i: u64) -> ValueRef { - C_uint(Type::i64(cx), i) -} - -pub fn C_usize(cx: &CodegenCx, i: u64) -> ValueRef { - let bit_size = cx.data_layout().pointer_size.bits(); - if bit_size < 64 { - // make sure it doesn't overflow - assert!(i < (1< ValueRef { - C_uint(Type::i8(cx), i as u64) -} - - -// This is a 'c-like' raw string, which differs from -// our boxed-and-length-annotated strings. -pub fn C_cstr(cx: &CodegenCx, s: LocalInternedString, null_terminated: bool) -> ValueRef { - unsafe { - if let Some(&llval) = cx.const_cstr_cache.borrow().get(&s) { - return llval; - } - - let sc = llvm::LLVMConstStringInContext(cx.llcx, - s.as_ptr() as *const c_char, - s.len() as c_uint, - !null_terminated as Bool); - let sym = cx.generate_local_symbol_name("str"); - let g = declare::define_global(cx, &sym[..], val_ty(sc)).unwrap_or_else(||{ - bug!("symbol `{}` is already defined", sym); - }); - llvm::LLVMSetInitializer(g, sc); - llvm::LLVMSetGlobalConstant(g, True); - llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage); - - cx.const_cstr_cache.borrow_mut().insert(s, g); - g - } -} - -// NB: Do not use `do_spill_noroot` to make this into a constant string, or -// you will be kicked off fast isel. See issue #4352 for an example of this. -pub fn C_str_slice(cx: &CodegenCx, s: LocalInternedString) -> ValueRef { - let len = s.len(); - let cs = consts::ptrcast(C_cstr(cx, s, false), - cx.layout_of(cx.tcx.mk_str()).llvm_type(cx).ptr_to()); - C_fat_ptr(cx, cs, C_usize(cx, len as u64)) -} - -pub fn C_fat_ptr(cx: &CodegenCx, ptr: ValueRef, meta: ValueRef) -> ValueRef { - assert_eq!(abi::FAT_PTR_ADDR, 0); - assert_eq!(abi::FAT_PTR_EXTRA, 1); - C_struct(cx, &[ptr, meta], false) -} - -pub fn C_struct(cx: &CodegenCx, elts: &[ValueRef], packed: bool) -> ValueRef { - C_struct_in_context(cx.llcx, elts, packed) -} - -pub fn C_struct_in_context(llcx: ContextRef, elts: &[ValueRef], packed: bool) -> ValueRef { - unsafe { - llvm::LLVMConstStructInContext(llcx, - elts.as_ptr(), elts.len() as c_uint, - packed as Bool) - } -} - -pub fn C_array(ty: Type, elts: &[ValueRef]) -> ValueRef { - unsafe { - return llvm::LLVMConstArray(ty.to_ref(), elts.as_ptr(), elts.len() as c_uint); - } -} - -pub fn C_vector(elts: &[ValueRef]) -> ValueRef { - unsafe { - return llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint); - } -} - -pub fn C_bytes(cx: &CodegenCx, bytes: &[u8]) -> ValueRef { - C_bytes_in_context(cx.llcx, bytes) -} - -pub fn C_bytes_in_context(llcx: ContextRef, bytes: &[u8]) -> ValueRef { - unsafe { - let ptr = bytes.as_ptr() as *const c_char; - return llvm::LLVMConstStringInContext(llcx, ptr, bytes.len() as c_uint, True); - } -} - -pub fn const_get_elt(v: ValueRef, idx: u64) -> ValueRef { - unsafe { - assert_eq!(idx as c_uint as u64, idx); - let us = &[idx as c_uint]; - let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint); - - debug!("const_get_elt(v={:?}, idx={}, r={:?})", - Value(v), idx, Value(r)); - - r - } -} - -pub fn const_get_real(v: ValueRef) -> Option<(f64, bool)> { - unsafe { - if is_const_real(v) { - let mut loses_info: llvm::Bool = ::std::mem::uninitialized(); - let r = llvm::LLVMConstRealGetDouble(v, &mut loses_info as *mut llvm::Bool); - let loses_info = if loses_info == 1 { true } else { false }; - Some((r, loses_info)) - } else { - None - } - } -} - -pub fn const_to_uint(v: ValueRef) -> u64 { - unsafe { - llvm::LLVMConstIntGetZExtValue(v) - } -} - -pub fn is_const_integral(v: ValueRef) -> bool { - unsafe { - !llvm::LLVMIsAConstantInt(v).is_null() - } -} - -pub fn is_const_real(v: ValueRef) -> bool { - unsafe { - !llvm::LLVMIsAConstantFP(v).is_null() - } -} - - -#[inline] -fn hi_lo_to_u128(lo: u64, hi: u64) -> u128 { - ((hi as u128) << 64) | (lo as u128) -} - -pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option { - unsafe { - if is_const_integral(v) { - let (mut lo, mut hi) = (0u64, 0u64); - let success = llvm::LLVMRustConstInt128Get(v, sign_ext, - &mut hi as *mut u64, &mut lo as *mut u64); - if success { - Some(hi_lo_to_u128(lo, hi)) - } else { - None - } - } else { - None - } - } -} - -pub fn langcall(tcx: TyCtxt, - span: Option, - msg: &str, - li: LangItem) - -> DefId { - match tcx.lang_items().require(li) { - Ok(id) => id, - Err(s) => { - let msg = format!("{} {}", msg, s); - match span { - Some(span) => tcx.sess.span_fatal(span, &msg[..]), - None => tcx.sess.fatal(&msg[..]), - } - } - } -} - -// To avoid UB from LLVM, these two functions mask RHS with an -// appropriate mask unconditionally (i.e. the fallback behavior for -// all shifts). For 32- and 64-bit types, this matches the semantics -// of Java. (See related discussion on #1877 and #10183.) - -pub fn build_unchecked_lshift<'a, 'tcx>( - bx: &Builder<'a, 'tcx>, - lhs: ValueRef, - rhs: ValueRef -) -> ValueRef { - let rhs = base::cast_shift_expr_rhs(bx, hir::BinOp_::BiShl, lhs, rhs); - // #1877, #10183: Ensure that input is always valid - let rhs = shift_mask_rhs(bx, rhs); - bx.shl(lhs, rhs) -} - -pub fn build_unchecked_rshift<'a, 'tcx>( - bx: &Builder<'a, 'tcx>, lhs_t: Ty<'tcx>, lhs: ValueRef, rhs: ValueRef -) -> ValueRef { - let rhs = base::cast_shift_expr_rhs(bx, hir::BinOp_::BiShr, lhs, rhs); - // #1877, #10183: Ensure that input is always valid - let rhs = shift_mask_rhs(bx, rhs); - let is_signed = lhs_t.is_signed(); - if is_signed { - bx.ashr(lhs, rhs) - } else { - bx.lshr(lhs, rhs) - } -} - -fn shift_mask_rhs<'a, 'tcx>(bx: &Builder<'a, 'tcx>, rhs: ValueRef) -> ValueRef { - let rhs_llty = val_ty(rhs); - bx.and(rhs, shift_mask_val(bx, rhs_llty, rhs_llty, false)) -} - -pub fn shift_mask_val<'a, 'tcx>( - bx: &Builder<'a, 'tcx>, - llty: Type, - mask_llty: Type, - invert: bool -) -> ValueRef { - let kind = llty.kind(); - match kind { - TypeKind::Integer => { - // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc. - let val = llty.int_width() - 1; - if invert { - C_int(mask_llty, !val as i64) - } else { - C_uint(mask_llty, val) - } - }, - TypeKind::Vector => { - let mask = shift_mask_val(bx, llty.element_type(), mask_llty.element_type(), invert); - bx.vector_splat(mask_llty.vector_length(), mask) - }, - _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind), - } -} - -pub fn ty_fn_sig<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - ty: Ty<'tcx>) - -> ty::PolyFnSig<'tcx> -{ - match ty.sty { - ty::TyFnDef(..) | - // Shims currently have type TyFnPtr. Not sure this should remain. - ty::TyFnPtr(_) => ty.fn_sig(cx.tcx), - ty::TyClosure(def_id, substs) => { - let tcx = cx.tcx; - let sig = substs.closure_sig(def_id, tcx); - - let env_ty = tcx.closure_env_ty(def_id, substs).unwrap(); - sig.map_bound(|sig| tcx.mk_fn_sig( - iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), - sig.output(), - sig.variadic, - sig.unsafety, - sig.abi - )) - } - ty::TyGenerator(def_id, substs, _) => { - let tcx = cx.tcx; - let sig = substs.poly_sig(def_id, cx.tcx); - - let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv); - let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); - - sig.map_bound(|sig| { - let state_did = tcx.lang_items().gen_state().unwrap(); - let state_adt_ref = tcx.adt_def(state_did); - let state_substs = tcx.mk_substs([sig.yield_ty.into(), - sig.return_ty.into()].iter()); - let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); - - tcx.mk_fn_sig(iter::once(env_ty), - ret_ty, - false, - hir::Unsafety::Normal, - Abi::Rust - ) - }) - } - _ => bug!("unexpected type {:?} to ty_fn_sig", ty) - } -} - diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs deleted file mode 100644 index 405cb83ad4d..00000000000 --- a/src/librustc_trans/consts.rs +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use llvm; -use llvm::{SetUnnamedAddr}; -use llvm::{ValueRef, True}; -use rustc::hir::def_id::DefId; -use rustc::hir::map as hir_map; -use debuginfo; -use base; -use monomorphize::MonoItem; -use common::{CodegenCx, val_ty}; -use declare; -use monomorphize::Instance; -use type_::Type; -use type_of::LayoutLlvmExt; -use rustc::ty; -use rustc::ty::layout::{Align, LayoutOf}; - -use rustc::hir; - -use std::ffi::{CStr, CString}; -use syntax::ast; -use syntax::attr; - -pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef { - unsafe { - llvm::LLVMConstPointerCast(val, ty.to_ref()) - } -} - -pub fn bitcast(val: ValueRef, ty: Type) -> ValueRef { - unsafe { - llvm::LLVMConstBitCast(val, ty.to_ref()) - } -} - -fn set_global_alignment(cx: &CodegenCx, - gv: ValueRef, - mut align: Align) { - // The target may require greater alignment for globals than the type does. - // Note: GCC and Clang also allow `__attribute__((aligned))` on variables, - // which can force it to be smaller. Rust doesn't support this yet. - if let Some(min) = cx.sess().target.target.options.min_global_align { - match ty::layout::Align::from_bits(min, min) { - Ok(min) => align = align.max(min), - Err(err) => { - cx.sess().err(&format!("invalid minimum global alignment: {}", err)); - } - } - } - unsafe { - llvm::LLVMSetAlignment(gv, align.abi() as u32); - } -} - -pub fn addr_of_mut(cx: &CodegenCx, - cv: ValueRef, - align: Align, - kind: &str) - -> ValueRef { - unsafe { - let name = cx.generate_local_symbol_name(kind); - let gv = declare::define_global(cx, &name[..], val_ty(cv)).unwrap_or_else(||{ - bug!("symbol `{}` is already defined", name); - }); - llvm::LLVMSetInitializer(gv, cv); - set_global_alignment(cx, gv, align); - llvm::LLVMRustSetLinkage(gv, llvm::Linkage::PrivateLinkage); - SetUnnamedAddr(gv, true); - gv - } -} - -pub fn addr_of(cx: &CodegenCx, - cv: ValueRef, - align: Align, - kind: &str) - -> ValueRef { - if let Some(&gv) = cx.const_globals.borrow().get(&cv) { - unsafe { - // Upgrade the alignment in cases where the same constant is used with different - // alignment requirements - let llalign = align.abi() as u32; - if llalign > llvm::LLVMGetAlignment(gv) { - llvm::LLVMSetAlignment(gv, llalign); - } - } - return gv; - } - let gv = addr_of_mut(cx, cv, align, kind); - unsafe { - llvm::LLVMSetGlobalConstant(gv, True); - } - cx.const_globals.borrow_mut().insert(cv, gv); - gv -} - -pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { - let instance = Instance::mono(cx.tcx, def_id); - if let Some(&g) = cx.instances.borrow().get(&instance) { - return g; - } - - let defined_in_current_codegen_unit = cx.codegen_unit - .items() - .contains_key(&MonoItem::Static(def_id)); - assert!(!defined_in_current_codegen_unit, - "consts::get_static() should always hit the cache for \ - statics defined in the same CGU, but did not for `{:?}`", - def_id); - - let ty = instance.ty(cx.tcx); - let sym = cx.tcx.symbol_name(instance).as_str(); - - let g = if let Some(id) = cx.tcx.hir.as_local_node_id(def_id) { - - let llty = cx.layout_of(ty).llvm_type(cx); - let (g, attrs) = match cx.tcx.hir.get(id) { - hir_map::NodeItem(&hir::Item { - ref attrs, span, node: hir::ItemStatic(..), .. - }) => { - if declare::get_declared_value(cx, &sym[..]).is_some() { - span_bug!(span, "trans: Conflicting symbol names for static?"); - } - - let g = declare::define_global(cx, &sym[..], llty).unwrap(); - - if !cx.tcx.is_reachable_non_generic(def_id) { - unsafe { - llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden); - } - } - - (g, attrs) - } - - hir_map::NodeForeignItem(&hir::ForeignItem { - ref attrs, span, node: hir::ForeignItemStatic(..), .. - }) => { - let g = if let Some(linkage) = cx.tcx.trans_fn_attrs(def_id).linkage { - // If this is a static with a linkage specified, then we need to handle - // it a little specially. The typesystem prevents things like &T and - // extern "C" fn() from being non-null, so we can't just declare a - // static and call it a day. Some linkages (like weak) will make it such - // that the static actually has a null value. - let llty2 = match ty.sty { - ty::TyRawPtr(ref mt) => cx.layout_of(mt.ty).llvm_type(cx), - _ => { - cx.sess().span_fatal(span, "must have type `*const T` or `*mut T`"); - } - }; - unsafe { - // Declare a symbol `foo` with the desired linkage. - let g1 = declare::declare_global(cx, &sym, llty2); - llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage)); - - // Declare an internal global `extern_with_linkage_foo` which - // is initialized with the address of `foo`. If `foo` is - // discarded during linking (for example, if `foo` has weak - // linkage and there are no definitions), then - // `extern_with_linkage_foo` will instead be initialized to - // zero. - let mut real_name = "_rust_extern_with_linkage_".to_string(); - real_name.push_str(&sym); - let g2 = declare::define_global(cx, &real_name, llty).unwrap_or_else(||{ - cx.sess().span_fatal(span, - &format!("symbol `{}` is already defined", &sym)) - }); - llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage); - llvm::LLVMSetInitializer(g2, g1); - g2 - } - } else { - // Generate an external declaration. - declare::declare_global(cx, &sym, llty) - }; - - (g, attrs) - } - - item => bug!("get_static: expected static, found {:?}", item) - }; - - for attr in attrs { - if attr.check_name("thread_local") { - llvm::set_thread_local_mode(g, cx.tls_model); - } - } - - g - } else { - // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? - // FIXME(nagisa): investigate whether it can be changed into define_global - let g = declare::declare_global(cx, &sym, cx.layout_of(ty).llvm_type(cx)); - // Thread-local statics in some other crate need to *always* be linked - // against in a thread-local fashion, so we need to be sure to apply the - // thread-local attribute locally if it was present remotely. If we - // don't do this then linker errors can be generated where the linker - // complains that one object files has a thread local version of the - // symbol and another one doesn't. - for attr in cx.tcx.get_attrs(def_id).iter() { - if attr.check_name("thread_local") { - llvm::set_thread_local_mode(g, cx.tls_model); - } - } - if cx.use_dll_storage_attrs && !cx.tcx.is_foreign_item(def_id) { - // This item is external but not foreign, i.e. it originates from an external Rust - // crate. Since we don't know whether this crate will be linked dynamically or - // statically in the final application, we always mark such symbols as 'dllimport'. - // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs to - // make things work. - // - // However, in some scenarios we defer emission of statics to downstream - // crates, so there are cases where a static with an upstream DefId - // is actually present in the current crate. We can find out via the - // is_translated_item query. - if !cx.tcx.is_translated_item(def_id) { - unsafe { - llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); - } - } - } - g - }; - - if cx.use_dll_storage_attrs && cx.tcx.is_dllimport_foreign_item(def_id) { - // For foreign (native) libs we know the exact storage type to use. - unsafe { - llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); - } - } - - cx.instances.borrow_mut().insert(instance, g); - cx.statics.borrow_mut().insert(g, def_id); - g -} - -pub fn trans_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - def_id: DefId, - is_mutable: bool, - attrs: &[ast::Attribute]) { - unsafe { - let g = get_static(cx, def_id); - - let v = match ::mir::trans_static_initializer(cx, def_id) { - Ok(v) => v, - // Error has already been reported - Err(_) => return, - }; - - // boolean SSA values are i1, but they have to be stored in i8 slots, - // otherwise some LLVM optimization passes don't work as expected - let mut val_llty = val_ty(v); - let v = if val_llty == Type::i1(cx) { - val_llty = Type::i8(cx); - llvm::LLVMConstZExt(v, val_llty.to_ref()) - } else { - v - }; - - let instance = Instance::mono(cx.tcx, def_id); - let ty = instance.ty(cx.tcx); - let llty = cx.layout_of(ty).llvm_type(cx); - let g = if val_llty == llty { - g - } else { - // If we created the global with the wrong type, - // correct the type. - let empty_string = CString::new("").unwrap(); - let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(g)); - let name_string = CString::new(name_str_ref.to_bytes()).unwrap(); - llvm::LLVMSetValueName(g, empty_string.as_ptr()); - - let linkage = llvm::LLVMRustGetLinkage(g); - let visibility = llvm::LLVMRustGetVisibility(g); - - let new_g = llvm::LLVMRustGetOrInsertGlobal( - cx.llmod, name_string.as_ptr(), val_llty.to_ref()); - - llvm::LLVMRustSetLinkage(new_g, linkage); - llvm::LLVMRustSetVisibility(new_g, visibility); - - // To avoid breaking any invariants, we leave around the old - // global for the moment; we'll replace all references to it - // with the new global later. (See base::trans_crate.) - cx.statics_to_rauw.borrow_mut().push((g, new_g)); - new_g - }; - set_global_alignment(cx, g, cx.align_of(ty)); - llvm::LLVMSetInitializer(g, v); - - // As an optimization, all shared statics which do not have interior - // mutability are placed into read-only memory. - if !is_mutable { - if cx.type_is_freeze(ty) { - llvm::LLVMSetGlobalConstant(g, llvm::True); - } - } - - debuginfo::create_global_var_metadata(cx, def_id, g); - - if attr::contains_name(attrs, "thread_local") { - llvm::set_thread_local_mode(g, cx.tls_model); - } - - base::set_link_section(cx, g, attrs); - - if attr::contains_name(attrs, "used") { - // This static will be stored in the llvm.used variable which is an array of i8* - let cast = llvm::LLVMConstPointerCast(g, Type::i8p(cx).to_ref()); - cx.used_statics.borrow_mut().push(cast); - } - } -} diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs deleted file mode 100644 index 90b2fb4b59a..00000000000 --- a/src/librustc_trans/context.rs +++ /dev/null @@ -1,666 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use common; -use llvm; -use llvm::{ContextRef, ModuleRef, ValueRef}; -use rustc::dep_graph::DepGraphSafe; -use rustc::hir; -use rustc::hir::def_id::DefId; -use debuginfo; -use callee; -use base; -use declare; -use monomorphize::Instance; - -use monomorphize::partitioning::CodegenUnit; -use type_::Type; -use type_of::PointeeInfo; - -use rustc_data_structures::base_n; -use rustc::mir::mono::Stats; -use rustc::session::config::{self, NoDebugInfo}; -use rustc::session::Session; -use rustc::ty::layout::{LayoutError, LayoutOf, Size, TyLayout}; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc::util::nodemap::FxHashMap; -use rustc_target::spec::{HasTargetSpec, Target}; - -use std::ffi::{CStr, CString}; -use std::cell::{Cell, RefCell}; -use std::ptr; -use std::iter; -use std::str; -use std::sync::Arc; -use syntax::symbol::LocalInternedString; -use abi::Abi; - -/// There is one `CodegenCx` per compilation unit. Each one has its own LLVM -/// `ContextRef` so that several compilation units may be optimized in parallel. -/// All other LLVM data structures in the `CodegenCx` are tied to that `ContextRef`. -pub struct CodegenCx<'a, 'tcx: 'a> { - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - pub check_overflow: bool, - pub use_dll_storage_attrs: bool, - pub tls_model: llvm::ThreadLocalMode, - - pub llmod: ModuleRef, - pub llcx: ContextRef, - pub stats: RefCell, - pub codegen_unit: Arc>, - - /// Cache instances of monomorphic and polymorphic items - pub instances: RefCell, ValueRef>>, - /// Cache generated vtables - pub vtables: RefCell, - Option>), ValueRef>>, - /// Cache of constant strings, - pub const_cstr_cache: RefCell>, - - /// Reverse-direction for const ptrs cast from globals. - /// Key is a ValueRef holding a *T, - /// Val is a ValueRef holding a *[T]. - /// - /// Needed because LLVM loses pointer->pointee association - /// when we ptrcast, and we have to ptrcast during translation - /// of a [T] const because we form a slice, a (*T,usize) pair, not - /// a pointer to an LLVM array type. Similar for trait objects. - pub const_unsized: RefCell>, - - /// Cache of emitted const globals (value -> global) - pub const_globals: RefCell>, - - /// Mapping from static definitions to their DefId's. - pub statics: RefCell>, - - /// List of globals for static variables which need to be passed to the - /// LLVM function ReplaceAllUsesWith (RAUW) when translation is complete. - /// (We have to make sure we don't invalidate any ValueRefs referring - /// to constants.) - pub statics_to_rauw: RefCell>, - - /// Statics that will be placed in the llvm.used variable - /// See http://llvm.org/docs/LangRef.html#the-llvm-used-global-variable for details - pub used_statics: RefCell>, - - pub lltypes: RefCell, Option), Type>>, - pub scalar_lltypes: RefCell, Type>>, - pub pointee_infos: RefCell, Size), Option>>, - pub isize_ty: Type, - - pub dbg_cx: Option>, - - eh_personality: Cell>, - eh_unwind_resume: Cell>, - pub rust_try_fn: Cell>, - - intrinsics: RefCell>, - - /// A counter that is used for generating local symbol names - local_gen_sym_counter: Cell, -} - -impl<'a, 'tcx> DepGraphSafe for CodegenCx<'a, 'tcx> { -} - -pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode { - let reloc_model_arg = match sess.opts.cg.relocation_model { - Some(ref s) => &s[..], - None => &sess.target.target.options.relocation_model[..], - }; - - match ::back::write::RELOC_MODEL_ARGS.iter().find( - |&&arg| arg.0 == reloc_model_arg) { - Some(x) => x.1, - _ => { - sess.err(&format!("{:?} is not a valid relocation mode", - reloc_model_arg)); - sess.abort_if_errors(); - bug!(); - } - } -} - -fn get_tls_model(sess: &Session) -> llvm::ThreadLocalMode { - let tls_model_arg = match sess.opts.debugging_opts.tls_model { - Some(ref s) => &s[..], - None => &sess.target.target.options.tls_model[..], - }; - - match ::back::write::TLS_MODEL_ARGS.iter().find( - |&&arg| arg.0 == tls_model_arg) { - Some(x) => x.1, - _ => { - sess.err(&format!("{:?} is not a valid TLS model", - tls_model_arg)); - sess.abort_if_errors(); - bug!(); - } - } -} - -fn is_any_library(sess: &Session) -> bool { - sess.crate_types.borrow().iter().any(|ty| { - *ty != config::CrateTypeExecutable - }) -} - -pub fn is_pie_binary(sess: &Session) -> bool { - !is_any_library(sess) && get_reloc_model(sess) == llvm::RelocMode::PIC -} - -pub unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) { - let llcx = llvm::LLVMRustContextCreate(sess.fewer_names()); - let mod_name = CString::new(mod_name).unwrap(); - let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); - - // Ensure the data-layout values hardcoded remain the defaults. - if sess.target.target.options.is_builtin { - let tm = ::back::write::create_target_machine(sess, false); - llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm); - llvm::LLVMRustDisposeTargetMachine(tm); - - let data_layout = llvm::LLVMGetDataLayout(llmod); - let data_layout = str::from_utf8(CStr::from_ptr(data_layout).to_bytes()) - .ok().expect("got a non-UTF8 data-layout from LLVM"); - - // Unfortunately LLVM target specs change over time, and right now we - // don't have proper support to work with any more than one - // `data_layout` than the one that is in the rust-lang/rust repo. If - // this compiler is configured against a custom LLVM, we may have a - // differing data layout, even though we should update our own to use - // that one. - // - // As an interim hack, if CFG_LLVM_ROOT is not an empty string then we - // disable this check entirely as we may be configured with something - // that has a different target layout. - // - // Unsure if this will actually cause breakage when rustc is configured - // as such. - // - // FIXME(#34960) - let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or(""); - let custom_llvm_used = cfg_llvm_root.trim() != ""; - - if !custom_llvm_used && sess.target.target.data_layout != data_layout { - bug!("data-layout for builtin `{}` target, `{}`, \ - differs from LLVM default, `{}`", - sess.target.target.llvm_target, - sess.target.target.data_layout, - data_layout); - } - } - - let data_layout = CString::new(&sess.target.target.data_layout[..]).unwrap(); - llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); - - let llvm_target = sess.target.target.llvm_target.as_bytes(); - let llvm_target = CString::new(llvm_target).unwrap(); - llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); - - if is_pie_binary(sess) { - llvm::LLVMRustSetModulePIELevel(llmod); - } - - (llcx, llmod) -} - -impl<'a, 'tcx> CodegenCx<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, - codegen_unit: Arc>, - llmod_id: &str) - -> CodegenCx<'a, 'tcx> { - // An interesting part of Windows which MSVC forces our hand on (and - // apparently MinGW didn't) is the usage of `dllimport` and `dllexport` - // attributes in LLVM IR as well as native dependencies (in C these - // correspond to `__declspec(dllimport)`). - // - // Whenever a dynamic library is built by MSVC it must have its public - // interface specified by functions tagged with `dllexport` or otherwise - // they're not available to be linked against. This poses a few problems - // for the compiler, some of which are somewhat fundamental, but we use - // the `use_dll_storage_attrs` variable below to attach the `dllexport` - // attribute to all LLVM functions that are exported e.g. they're - // already tagged with external linkage). This is suboptimal for a few - // reasons: - // - // * If an object file will never be included in a dynamic library, - // there's no need to attach the dllexport attribute. Most object - // files in Rust are not destined to become part of a dll as binaries - // are statically linked by default. - // * If the compiler is emitting both an rlib and a dylib, the same - // source object file is currently used but with MSVC this may be less - // feasible. The compiler may be able to get around this, but it may - // involve some invasive changes to deal with this. - // - // The flipside of this situation is that whenever you link to a dll and - // you import a function from it, the import should be tagged with - // `dllimport`. At this time, however, the compiler does not emit - // `dllimport` for any declarations other than constants (where it is - // required), which is again suboptimal for even more reasons! - // - // * Calling a function imported from another dll without using - // `dllimport` causes the linker/compiler to have extra overhead (one - // `jmp` instruction on x86) when calling the function. - // * The same object file may be used in different circumstances, so a - // function may be imported from a dll if the object is linked into a - // dll, but it may be just linked against if linked into an rlib. - // * The compiler has no knowledge about whether native functions should - // be tagged dllimport or not. - // - // For now the compiler takes the perf hit (I do not have any numbers to - // this effect) by marking very little as `dllimport` and praying the - // linker will take care of everything. Fixing this problem will likely - // require adding a few attributes to Rust itself (feature gated at the - // start) and then strongly recommending static linkage on MSVC! - let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_msvc; - - let check_overflow = tcx.sess.overflow_checks(); - - let tls_model = get_tls_model(&tcx.sess); - - unsafe { - let (llcx, llmod) = create_context_and_module(&tcx.sess, - &llmod_id[..]); - - let dbg_cx = if tcx.sess.opts.debuginfo != NoDebugInfo { - let dctx = debuginfo::CrateDebugContext::new(llmod); - debuginfo::metadata::compile_unit_metadata(tcx, - &codegen_unit.name().as_str(), - &dctx); - Some(dctx) - } else { - None - }; - - let mut cx = CodegenCx { - tcx, - check_overflow, - use_dll_storage_attrs, - tls_model, - llmod, - llcx, - stats: RefCell::new(Stats::default()), - codegen_unit, - instances: RefCell::new(FxHashMap()), - vtables: RefCell::new(FxHashMap()), - const_cstr_cache: RefCell::new(FxHashMap()), - const_unsized: RefCell::new(FxHashMap()), - const_globals: RefCell::new(FxHashMap()), - statics: RefCell::new(FxHashMap()), - statics_to_rauw: RefCell::new(Vec::new()), - used_statics: RefCell::new(Vec::new()), - lltypes: RefCell::new(FxHashMap()), - scalar_lltypes: RefCell::new(FxHashMap()), - pointee_infos: RefCell::new(FxHashMap()), - isize_ty: Type::from_ref(ptr::null_mut()), - dbg_cx, - eh_personality: Cell::new(None), - eh_unwind_resume: Cell::new(None), - rust_try_fn: Cell::new(None), - intrinsics: RefCell::new(FxHashMap()), - local_gen_sym_counter: Cell::new(0), - }; - cx.isize_ty = Type::isize(&cx); - cx - } - } - - pub fn into_stats(self) -> Stats { - self.stats.into_inner() - } -} - -impl<'b, 'tcx> CodegenCx<'b, 'tcx> { - pub fn sess<'a>(&'a self) -> &'a Session { - &self.tcx.sess - } - - pub fn get_intrinsic(&self, key: &str) -> ValueRef { - if let Some(v) = self.intrinsics.borrow().get(key).cloned() { - return v; - } - match declare_intrinsic(self, key) { - Some(v) => return v, - None => bug!("unknown intrinsic '{}'", key) - } - } - - /// Generate a new symbol name with the given prefix. This symbol name must - /// only be used for definitions with `internal` or `private` linkage. - pub fn generate_local_symbol_name(&self, prefix: &str) -> String { - let idx = self.local_gen_sym_counter.get(); - self.local_gen_sym_counter.set(idx + 1); - // Include a '.' character, so there can be no accidental conflicts with - // user defined names - let mut name = String::with_capacity(prefix.len() + 6); - name.push_str(prefix); - name.push_str("."); - base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name); - name - } - - pub fn eh_personality(&self) -> ValueRef { - // The exception handling personality function. - // - // If our compilation unit has the `eh_personality` lang item somewhere - // within it, then we just need to translate that. Otherwise, we're - // building an rlib which will depend on some upstream implementation of - // this function, so we just codegen a generic reference to it. We don't - // specify any of the types for the function, we just make it a symbol - // that LLVM can later use. - // - // Note that MSVC is a little special here in that we don't use the - // `eh_personality` lang item at all. Currently LLVM has support for - // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the - // *name of the personality function* to decide what kind of unwind side - // tables/landing pads to emit. It looks like Dwarf is used by default, - // injecting a dependency on the `_Unwind_Resume` symbol for resuming - // an "exception", but for MSVC we want to force SEH. This means that we - // can't actually have the personality function be our standard - // `rust_eh_personality` function, but rather we wired it up to the - // CRT's custom personality function, which forces LLVM to consider - // landing pads as "landing pads for SEH". - if let Some(llpersonality) = self.eh_personality.get() { - return llpersonality - } - let tcx = self.tcx; - let llfn = match tcx.lang_items().eh_personality() { - Some(def_id) if !base::wants_msvc_seh(self.sess()) => { - callee::resolve_and_get_fn(self, def_id, tcx.intern_substs(&[])) - } - _ => { - let name = if base::wants_msvc_seh(self.sess()) { - "__CxxFrameHandler3" - } else { - "rust_eh_personality" - }; - let fty = Type::variadic_func(&[], &Type::i32(self)); - declare::declare_cfn(self, name, fty) - } - }; - self.eh_personality.set(Some(llfn)); - llfn - } - - // Returns a ValueRef of the "eh_unwind_resume" lang item if one is defined, - // otherwise declares it as an external function. - pub fn eh_unwind_resume(&self) -> ValueRef { - use attributes; - let unwresume = &self.eh_unwind_resume; - if let Some(llfn) = unwresume.get() { - return llfn; - } - - let tcx = self.tcx; - assert!(self.sess().target.target.options.custom_unwind_resume); - if let Some(def_id) = tcx.lang_items().eh_unwind_resume() { - let llfn = callee::resolve_and_get_fn(self, def_id, tcx.intern_substs(&[])); - unwresume.set(Some(llfn)); - return llfn; - } - - let ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( - iter::once(tcx.mk_mut_ptr(tcx.types.u8)), - tcx.types.never, - false, - hir::Unsafety::Unsafe, - Abi::C - ))); - - let llfn = declare::declare_fn(self, "rust_eh_unwind_resume", ty); - attributes::unwind(llfn, true); - unwresume.set(Some(llfn)); - llfn - } - - pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { - common::type_needs_drop(self.tcx, ty) - } - - pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - common::type_is_sized(self.tcx, ty) - } - - pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - common::type_is_freeze(self.tcx, ty) - } - - pub fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool { - use syntax_pos::DUMMY_SP; - if ty.is_sized(self.tcx.at(DUMMY_SP), ty::ParamEnv::reveal_all()) { - return false; - } - - let tail = self.tcx.struct_tail(ty); - match tail.sty { - ty::TyForeign(..) => false, - ty::TyStr | ty::TySlice(..) | ty::TyDynamic(..) => true, - _ => bug!("unexpected unsized tail: {:?}", tail.sty), - } - } -} - -impl<'a, 'tcx> ty::layout::HasDataLayout for &'a CodegenCx<'a, 'tcx> { - fn data_layout(&self) -> &ty::layout::TargetDataLayout { - &self.tcx.data_layout - } -} - -impl<'a, 'tcx> HasTargetSpec for &'a CodegenCx<'a, 'tcx> { - fn target_spec(&self) -> &Target { - &self.tcx.sess.target.target - } -} - -impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a CodegenCx<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { - self.tcx - } -} - -impl<'a, 'tcx> LayoutOf for &'a CodegenCx<'a, 'tcx> { - type Ty = Ty<'tcx>; - type TyLayout = TyLayout<'tcx>; - - fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { - self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) - .unwrap_or_else(|e| match e { - LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()), - _ => bug!("failed to get layout for `{}`: {}", ty, e) - }) - } -} - -/// Declare any llvm intrinsics that you might need -fn declare_intrinsic(cx: &CodegenCx, key: &str) -> Option { - macro_rules! ifn { - ($name:expr, fn() -> $ret:expr) => ( - if key == $name { - let f = declare::declare_cfn(cx, $name, Type::func(&[], &$ret)); - llvm::SetUnnamedAddr(f, false); - cx.intrinsics.borrow_mut().insert($name, f.clone()); - return Some(f); - } - ); - ($name:expr, fn(...) -> $ret:expr) => ( - if key == $name { - let f = declare::declare_cfn(cx, $name, Type::variadic_func(&[], &$ret)); - llvm::SetUnnamedAddr(f, false); - cx.intrinsics.borrow_mut().insert($name, f.clone()); - return Some(f); - } - ); - ($name:expr, fn($($arg:expr),*) -> $ret:expr) => ( - if key == $name { - let f = declare::declare_cfn(cx, $name, Type::func(&[$($arg),*], &$ret)); - llvm::SetUnnamedAddr(f, false); - cx.intrinsics.borrow_mut().insert($name, f.clone()); - return Some(f); - } - ); - } - macro_rules! mk_struct { - ($($field_ty:expr),*) => (Type::struct_(cx, &[$($field_ty),*], false)) - } - - let i8p = Type::i8p(cx); - let void = Type::void(cx); - let i1 = Type::i1(cx); - let t_i8 = Type::i8(cx); - let t_i16 = Type::i16(cx); - let t_i32 = Type::i32(cx); - let t_i64 = Type::i64(cx); - let t_i128 = Type::i128(cx); - let t_f32 = Type::f32(cx); - let t_f64 = Type::f64(cx); - - ifn!("llvm.memcpy.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void); - ifn!("llvm.memcpy.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void); - ifn!("llvm.memcpy.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void); - ifn!("llvm.memmove.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void); - ifn!("llvm.memmove.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void); - ifn!("llvm.memmove.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void); - ifn!("llvm.memset.p0i8.i16", fn(i8p, t_i8, t_i16, t_i32, i1) -> void); - ifn!("llvm.memset.p0i8.i32", fn(i8p, t_i8, t_i32, t_i32, i1) -> void); - ifn!("llvm.memset.p0i8.i64", fn(i8p, t_i8, t_i64, t_i32, i1) -> void); - - ifn!("llvm.trap", fn() -> void); - ifn!("llvm.debugtrap", fn() -> void); - ifn!("llvm.frameaddress", fn(t_i32) -> i8p); - - ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32); - ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64); - ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32); - ifn!("llvm.pow.f64", fn(t_f64, t_f64) -> t_f64); - - ifn!("llvm.sqrt.f32", fn(t_f32) -> t_f32); - ifn!("llvm.sqrt.f64", fn(t_f64) -> t_f64); - ifn!("llvm.sin.f32", fn(t_f32) -> t_f32); - ifn!("llvm.sin.f64", fn(t_f64) -> t_f64); - ifn!("llvm.cos.f32", fn(t_f32) -> t_f32); - ifn!("llvm.cos.f64", fn(t_f64) -> t_f64); - ifn!("llvm.exp.f32", fn(t_f32) -> t_f32); - ifn!("llvm.exp.f64", fn(t_f64) -> t_f64); - ifn!("llvm.exp2.f32", fn(t_f32) -> t_f32); - ifn!("llvm.exp2.f64", fn(t_f64) -> t_f64); - ifn!("llvm.log.f32", fn(t_f32) -> t_f32); - ifn!("llvm.log.f64", fn(t_f64) -> t_f64); - ifn!("llvm.log10.f32", fn(t_f32) -> t_f32); - ifn!("llvm.log10.f64", fn(t_f64) -> t_f64); - ifn!("llvm.log2.f32", fn(t_f32) -> t_f32); - ifn!("llvm.log2.f64", fn(t_f64) -> t_f64); - - ifn!("llvm.fma.f32", fn(t_f32, t_f32, t_f32) -> t_f32); - ifn!("llvm.fma.f64", fn(t_f64, t_f64, t_f64) -> t_f64); - - ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32); - ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64); - - ifn!("llvm.floor.f32", fn(t_f32) -> t_f32); - ifn!("llvm.floor.f64", fn(t_f64) -> t_f64); - ifn!("llvm.ceil.f32", fn(t_f32) -> t_f32); - ifn!("llvm.ceil.f64", fn(t_f64) -> t_f64); - ifn!("llvm.trunc.f32", fn(t_f32) -> t_f32); - ifn!("llvm.trunc.f64", fn(t_f64) -> t_f64); - - ifn!("llvm.copysign.f32", fn(t_f32, t_f32) -> t_f32); - ifn!("llvm.copysign.f64", fn(t_f64, t_f64) -> t_f64); - ifn!("llvm.round.f32", fn(t_f32) -> t_f32); - ifn!("llvm.round.f64", fn(t_f64) -> t_f64); - - ifn!("llvm.rint.f32", fn(t_f32) -> t_f32); - ifn!("llvm.rint.f64", fn(t_f64) -> t_f64); - ifn!("llvm.nearbyint.f32", fn(t_f32) -> t_f32); - ifn!("llvm.nearbyint.f64", fn(t_f64) -> t_f64); - - ifn!("llvm.ctpop.i8", fn(t_i8) -> t_i8); - ifn!("llvm.ctpop.i16", fn(t_i16) -> t_i16); - ifn!("llvm.ctpop.i32", fn(t_i32) -> t_i32); - ifn!("llvm.ctpop.i64", fn(t_i64) -> t_i64); - ifn!("llvm.ctpop.i128", fn(t_i128) -> t_i128); - - ifn!("llvm.ctlz.i8", fn(t_i8 , i1) -> t_i8); - ifn!("llvm.ctlz.i16", fn(t_i16, i1) -> t_i16); - ifn!("llvm.ctlz.i32", fn(t_i32, i1) -> t_i32); - ifn!("llvm.ctlz.i64", fn(t_i64, i1) -> t_i64); - ifn!("llvm.ctlz.i128", fn(t_i128, i1) -> t_i128); - - ifn!("llvm.cttz.i8", fn(t_i8 , i1) -> t_i8); - ifn!("llvm.cttz.i16", fn(t_i16, i1) -> t_i16); - ifn!("llvm.cttz.i32", fn(t_i32, i1) -> t_i32); - ifn!("llvm.cttz.i64", fn(t_i64, i1) -> t_i64); - ifn!("llvm.cttz.i128", fn(t_i128, i1) -> t_i128); - - ifn!("llvm.bswap.i16", fn(t_i16) -> t_i16); - ifn!("llvm.bswap.i32", fn(t_i32) -> t_i32); - ifn!("llvm.bswap.i64", fn(t_i64) -> t_i64); - ifn!("llvm.bswap.i128", fn(t_i128) -> t_i128); - - ifn!("llvm.bitreverse.i8", fn(t_i8) -> t_i8); - ifn!("llvm.bitreverse.i16", fn(t_i16) -> t_i16); - ifn!("llvm.bitreverse.i32", fn(t_i32) -> t_i32); - ifn!("llvm.bitreverse.i64", fn(t_i64) -> t_i64); - ifn!("llvm.bitreverse.i128", fn(t_i128) -> t_i128); - - ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); - ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); - ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); - ifn!("llvm.sadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); - ifn!("llvm.sadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); - - ifn!("llvm.uadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); - ifn!("llvm.uadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); - ifn!("llvm.uadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); - ifn!("llvm.uadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); - ifn!("llvm.uadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); - - ifn!("llvm.ssub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); - ifn!("llvm.ssub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); - ifn!("llvm.ssub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); - ifn!("llvm.ssub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); - ifn!("llvm.ssub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); - - ifn!("llvm.usub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); - ifn!("llvm.usub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); - ifn!("llvm.usub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); - ifn!("llvm.usub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); - ifn!("llvm.usub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); - - ifn!("llvm.smul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); - ifn!("llvm.smul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); - ifn!("llvm.smul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); - ifn!("llvm.smul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); - ifn!("llvm.smul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); - - ifn!("llvm.umul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); - ifn!("llvm.umul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); - ifn!("llvm.umul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); - ifn!("llvm.umul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); - ifn!("llvm.umul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); - - ifn!("llvm.lifetime.start", fn(t_i64,i8p) -> void); - ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void); - - ifn!("llvm.expect.i1", fn(i1, i1) -> i1); - ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32); - ifn!("llvm.localescape", fn(...) -> void); - ifn!("llvm.localrecover", fn(i8p, i8p, t_i32) -> i8p); - ifn!("llvm.x86.seh.recoverfp", fn(i8p, i8p) -> i8p); - - ifn!("llvm.assume", fn(i1) -> void); - ifn!("llvm.prefetch", fn(i8p, t_i32, t_i32, t_i32) -> void); - - if cx.sess().opts.debuginfo != NoDebugInfo { - ifn!("llvm.dbg.declare", fn(Type::metadata(cx), Type::metadata(cx)) -> void); - ifn!("llvm.dbg.value", fn(Type::metadata(cx), t_i64, Type::metadata(cx)) -> void); - } - return None; -} diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs deleted file mode 100644 index bddb3d90940..00000000000 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::{FunctionDebugContext, FunctionDebugContextData}; -use super::metadata::file_metadata; -use super::utils::{DIB, span_start}; - -use llvm; -use llvm::debuginfo::DIScope; -use common::CodegenCx; -use rustc::mir::{Mir, VisibilityScope}; - -use libc::c_uint; -use std::ptr; - -use syntax_pos::Pos; - -use rustc_data_structures::bitvec::BitVector; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; - -use syntax_pos::BytePos; - -#[derive(Clone, Copy, Debug)] -pub struct MirDebugScope { - pub scope_metadata: DIScope, - // Start and end offsets of the file to which this DIScope belongs. - // These are used to quickly determine whether some span refers to the same file. - pub file_start_pos: BytePos, - pub file_end_pos: BytePos, -} - -impl MirDebugScope { - pub fn is_valid(&self) -> bool { - !self.scope_metadata.is_null() - } -} - -/// Produce DIScope DIEs for each MIR Scope which has variables defined in it. -/// If debuginfo is disabled, the returned vector is empty. -pub fn create_mir_scopes(cx: &CodegenCx, mir: &Mir, debug_context: &FunctionDebugContext) - -> IndexVec { - let null_scope = MirDebugScope { - scope_metadata: ptr::null_mut(), - file_start_pos: BytePos(0), - file_end_pos: BytePos(0) - }; - let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes); - - let debug_context = match *debug_context { - FunctionDebugContext::RegularContext(ref data) => data, - FunctionDebugContext::DebugInfoDisabled | - FunctionDebugContext::FunctionWithoutDebugInfo => { - return scopes; - } - }; - - // Find all the scopes with variables defined in them. - let mut has_variables = BitVector::new(mir.visibility_scopes.len()); - for var in mir.vars_iter() { - let decl = &mir.local_decls[var]; - has_variables.insert(decl.source_info.scope.index()); - } - - // Instantiate all scopes. - for idx in 0..mir.visibility_scopes.len() { - let scope = VisibilityScope::new(idx); - make_mir_scope(cx, &mir, &has_variables, debug_context, scope, &mut scopes); - } - - scopes -} - -fn make_mir_scope(cx: &CodegenCx, - mir: &Mir, - has_variables: &BitVector, - debug_context: &FunctionDebugContextData, - scope: VisibilityScope, - scopes: &mut IndexVec) { - if scopes[scope].is_valid() { - return; - } - - let scope_data = &mir.visibility_scopes[scope]; - let parent_scope = if let Some(parent) = scope_data.parent_scope { - make_mir_scope(cx, mir, has_variables, debug_context, parent, scopes); - scopes[parent] - } else { - // The root is the function itself. - let loc = span_start(cx, mir.span); - scopes[scope] = MirDebugScope { - scope_metadata: debug_context.fn_metadata, - file_start_pos: loc.file.start_pos, - file_end_pos: loc.file.end_pos, - }; - return; - }; - - if !has_variables.contains(scope.index()) { - // Do not create a DIScope if there are no variables - // defined in this MIR Scope, to avoid debuginfo bloat. - - // However, we don't skip creating a nested scope if - // our parent is the root, because we might want to - // put arguments in the root and not have shadowing. - if parent_scope.scope_metadata != debug_context.fn_metadata { - scopes[scope] = parent_scope; - return; - } - } - - let loc = span_start(cx, scope_data.span); - let file_metadata = file_metadata(cx, - &loc.file.name, - debug_context.defining_crate); - - let scope_metadata = unsafe { - llvm::LLVMRustDIBuilderCreateLexicalBlock( - DIB(cx), - parent_scope.scope_metadata, - file_metadata, - loc.line as c_uint, - loc.col.to_usize() as c_uint) - }; - scopes[scope] = MirDebugScope { - scope_metadata, - file_start_pos: loc.file.start_pos, - file_end_pos: loc.file.end_pos, - }; -} diff --git a/src/librustc_trans/debuginfo/doc.rs b/src/librustc_trans/debuginfo/doc.rs deleted file mode 100644 index cbecc0eb7d1..00000000000 --- a/src/librustc_trans/debuginfo/doc.rs +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! # Debug Info Module -//! -//! This module serves the purpose of generating debug symbols. We use LLVM's -//! [source level debugging](http://!llvm.org/docs/SourceLevelDebugging.html) -//! features for generating the debug information. The general principle is -//! this: -//! -//! Given the right metadata in the LLVM IR, the LLVM code generator is able to -//! create DWARF debug symbols for the given code. The -//! [metadata](http://!llvm.org/docs/LangRef.html#metadata-type) is structured -//! much like DWARF *debugging information entries* (DIE), representing type -//! information such as datatype layout, function signatures, block layout, -//! variable location and scope information, etc. It is the purpose of this -//! module to generate correct metadata and insert it into the LLVM IR. -//! -//! As the exact format of metadata trees may change between different LLVM -//! versions, we now use LLVM -//! [DIBuilder](http://!llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html) -//! to create metadata where possible. This will hopefully ease the adaption of -//! this module to future LLVM versions. -//! -//! The public API of the module is a set of functions that will insert the -//! correct metadata into the LLVM IR when called with the right parameters. -//! The module is thus driven from an outside client with functions like -//! `debuginfo::create_local_var_metadata(bx: block, local: &ast::local)`. -//! -//! Internally the module will try to reuse already created metadata by -//! utilizing a cache. The way to get a shared metadata node when needed is -//! thus to just call the corresponding function in this module: -//! -//! let file_metadata = file_metadata(crate_context, path); -//! -//! The function will take care of probing the cache for an existing node for -//! that exact file path. -//! -//! All private state used by the module is stored within either the -//! CrateDebugContext struct (owned by the CodegenCx) or the -//! FunctionDebugContext (owned by the FunctionCx). -//! -//! This file consists of three conceptual sections: -//! 1. The public interface of the module -//! 2. Module-internal metadata creation functions -//! 3. Minor utility functions -//! -//! -//! ## Recursive Types -//! -//! Some kinds of types, such as structs and enums can be recursive. That means -//! that the type definition of some type X refers to some other type which in -//! turn (transitively) refers to X. This introduces cycles into the type -//! referral graph. A naive algorithm doing an on-demand, depth-first traversal -//! of this graph when describing types, can get trapped in an endless loop -//! when it reaches such a cycle. -//! -//! For example, the following simple type for a singly-linked list... -//! -//! ``` -//! struct List { -//! value: i32, -//! tail: Option>, -//! } -//! ``` -//! -//! will generate the following callstack with a naive DFS algorithm: -//! -//! ``` -//! describe(t = List) -//! describe(t = i32) -//! describe(t = Option>) -//! describe(t = Box) -//! describe(t = List) // at the beginning again... -//! ... -//! ``` -//! -//! To break cycles like these, we use "forward declarations". That is, when -//! the algorithm encounters a possibly recursive type (any struct or enum), it -//! immediately creates a type description node and inserts it into the cache -//! *before* describing the members of the type. This type description is just -//! a stub (as type members are not described and added to it yet) but it -//! allows the algorithm to already refer to the type. After the stub is -//! inserted into the cache, the algorithm continues as before. If it now -//! encounters a recursive reference, it will hit the cache and does not try to -//! describe the type anew. -//! -//! This behavior is encapsulated in the 'RecursiveTypeDescription' enum, -//! which represents a kind of continuation, storing all state needed to -//! continue traversal at the type members after the type has been registered -//! with the cache. (This implementation approach might be a tad over- -//! engineered and may change in the future) -//! -//! -//! ## Source Locations and Line Information -//! -//! In addition to data type descriptions the debugging information must also -//! allow to map machine code locations back to source code locations in order -//! to be useful. This functionality is also handled in this module. The -//! following functions allow to control source mappings: -//! -//! + set_source_location() -//! + clear_source_location() -//! + start_emitting_source_locations() -//! -//! `set_source_location()` allows to set the current source location. All IR -//! instructions created after a call to this function will be linked to the -//! given source location, until another location is specified with -//! `set_source_location()` or the source location is cleared with -//! `clear_source_location()`. In the later case, subsequent IR instruction -//! will not be linked to any source location. As you can see, this is a -//! stateful API (mimicking the one in LLVM), so be careful with source -//! locations set by previous calls. It's probably best to not rely on any -//! specific state being present at a given point in code. -//! -//! One topic that deserves some extra attention is *function prologues*. At -//! the beginning of a function's machine code there are typically a few -//! instructions for loading argument values into allocas and checking if -//! there's enough stack space for the function to execute. This *prologue* is -//! not visible in the source code and LLVM puts a special PROLOGUE END marker -//! into the line table at the first non-prologue instruction of the function. -//! In order to find out where the prologue ends, LLVM looks for the first -//! instruction in the function body that is linked to a source location. So, -//! when generating prologue instructions we have to make sure that we don't -//! emit source location information until the 'real' function body begins. For -//! this reason, source location emission is disabled by default for any new -//! function being translated and is only activated after a call to the third -//! function from the list above, `start_emitting_source_locations()`. This -//! function should be called right before regularly starting to translate the -//! top-level block of the given function. -//! -//! There is one exception to the above rule: `llvm.dbg.declare` instruction -//! must be linked to the source location of the variable being declared. For -//! function parameters these `llvm.dbg.declare` instructions typically occur -//! in the middle of the prologue, however, they are ignored by LLVM's prologue -//! detection. The `create_argument_metadata()` and related functions take care -//! of linking the `llvm.dbg.declare` instructions to the correct source -//! locations even while source location emission is still disabled, so there -//! is no need to do anything special with source location handling here. -//! -//! ## Unique Type Identification -//! -//! In order for link-time optimization to work properly, LLVM needs a unique -//! type identifier that tells it across compilation units which types are the -//! same as others. This type identifier is created by -//! TypeMap::get_unique_type_id_of_type() using the following algorithm: -//! -//! (1) Primitive types have their name as ID -//! (2) Structs, enums and traits have a multipart identifier -//! -//! (1) The first part is the SVH (strict version hash) of the crate they -//! were originally defined in -//! -//! (2) The second part is the ast::NodeId of the definition in their -//! original crate -//! -//! (3) The final part is a concatenation of the type IDs of their concrete -//! type arguments if they are generic types. -//! -//! (3) Tuple-, pointer and function types are structurally identified, which -//! means that they are equivalent if their component types are equivalent -//! (i.e. (i32, i32) is the same regardless in which crate it is used). -//! -//! This algorithm also provides a stable ID for types that are defined in one -//! crate but instantiated from metadata within another crate. We just have to -//! take care to always map crate and node IDs back to the original crate -//! context. -//! -//! As a side-effect these unique type IDs also help to solve a problem arising -//! from lifetime parameters. Since lifetime parameters are completely omitted -//! in debuginfo, more than one `Ty` instance may map to the same debuginfo -//! type metadata, that is, some struct `Struct<'a>` may have N instantiations -//! with different concrete substitutions for `'a`, and thus there will be N -//! `Ty` instances for the type `Struct<'a>` even though it is not generic -//! otherwise. Unfortunately this means that we cannot use `ty::type_id()` as -//! cheap identifier for type metadata---we have done this in the past, but it -//! led to unnecessary metadata duplication in the best case and LLVM -//! assertions in the worst. However, the unique type ID as described above -//! *can* be used as identifier. Since it is comparatively expensive to -//! construct, though, `ty::type_id()` is still used additionally as an -//! optimization for cases where the exact same type has been seen before -//! (which is most of the time). diff --git a/src/librustc_trans/debuginfo/gdb.rs b/src/librustc_trans/debuginfo/gdb.rs deleted file mode 100644 index 0b4858c7ab0..00000000000 --- a/src/librustc_trans/debuginfo/gdb.rs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// .debug_gdb_scripts binary section. - -use llvm; - -use common::{C_bytes, CodegenCx, C_i32}; -use builder::Builder; -use declare; -use type_::Type; -use rustc::session::config::NoDebugInfo; - -use std::ptr; -use syntax::attr; - - -/// Inserts a side-effect free instruction sequence that makes sure that the -/// .debug_gdb_scripts global is referenced, so it isn't removed by the linker. -pub fn insert_reference_to_gdb_debug_scripts_section_global(bx: &Builder) { - if needs_gdb_debug_scripts_section(bx.cx) { - let gdb_debug_scripts_section = get_or_insert_gdb_debug_scripts_section_global(bx.cx); - // Load just the first byte as that's all that's necessary to force - // LLVM to keep around the reference to the global. - let indices = [C_i32(bx.cx, 0), C_i32(bx.cx, 0)]; - let element = bx.inbounds_gep(gdb_debug_scripts_section, &indices); - let volative_load_instruction = bx.volatile_load(element); - unsafe { - llvm::LLVMSetAlignment(volative_load_instruction, 1); - } - } -} - -/// Allocates the global variable responsible for the .debug_gdb_scripts binary -/// section. -pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx) - -> llvm::ValueRef { - let c_section_var_name = "__rustc_debug_gdb_scripts_section__\0"; - let section_var_name = &c_section_var_name[..c_section_var_name.len()-1]; - - let section_var = unsafe { - llvm::LLVMGetNamedGlobal(cx.llmod, - c_section_var_name.as_ptr() as *const _) - }; - - if section_var == ptr::null_mut() { - let section_name = b".debug_gdb_scripts\0"; - let section_contents = b"\x01gdb_load_rust_pretty_printers.py\0"; - - unsafe { - let llvm_type = Type::array(&Type::i8(cx), - section_contents.len() as u64); - - let section_var = declare::define_global(cx, section_var_name, - llvm_type).unwrap_or_else(||{ - bug!("symbol `{}` is already defined", section_var_name) - }); - llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _); - llvm::LLVMSetInitializer(section_var, C_bytes(cx, section_contents)); - llvm::LLVMSetGlobalConstant(section_var, llvm::True); - llvm::LLVMSetUnnamedAddr(section_var, llvm::True); - llvm::LLVMRustSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage); - // This should make sure that the whole section is not larger than - // the string it contains. Otherwise we get a warning from GDB. - llvm::LLVMSetAlignment(section_var, 1); - section_var - } - } else { - section_var - } -} - -pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx) -> bool { - let omit_gdb_pretty_printer_section = - attr::contains_name(&cx.tcx.hir.krate_attrs(), - "omit_gdb_pretty_printer_section"); - - !omit_gdb_pretty_printer_section && - cx.sess().opts.debuginfo != NoDebugInfo && - cx.sess().target.target.options.emit_debug_gdb_scripts -} diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs deleted file mode 100644 index 4e77c0df65e..00000000000 --- a/src/librustc_trans/debuginfo/metadata.rs +++ /dev/null @@ -1,1773 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use self::RecursiveTypeDescription::*; -use self::MemberDescriptionFactory::*; -use self::EnumDiscriminantInfo::*; - -use super::utils::{debug_context, DIB, span_start, - get_namespace_for_item, create_DIArray, is_node_local_to_unit}; -use super::namespace::mangled_name_of_instance; -use super::type_names::compute_debuginfo_type_name; -use super::{CrateDebugContext}; -use abi; - -use llvm::{self, ValueRef}; -use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, - DICompositeType, DILexicalBlock, DIFlags}; - -use rustc::hir::TransFnAttrFlags; -use rustc::hir::def::CtorKind; -use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; -use rustc::ty::fold::TypeVisitor; -use rustc::ty::util::TypeIdHasher; -use rustc::ich::Fingerprint; -use rustc::ty::Instance; -use common::CodegenCx; -use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; -use rustc::ty::layout::{self, Align, LayoutOf, PrimitiveExt, Size, TyLayout}; -use rustc::session::config; -use rustc::util::nodemap::FxHashMap; -use rustc::util::common::path2cstr; - -use libc::{c_uint, c_longlong}; -use std::ffi::CString; -use std::fmt::Write; -use std::ptr; -use std::path::{Path, PathBuf}; -use syntax::ast; -use syntax::symbol::{Interner, InternedString, Symbol}; -use syntax_pos::{self, Span, FileName}; - - -// From DWARF 5. -// See http://www.dwarfstd.org/ShowIssue.php?issue=140129.1 -const DW_LANG_RUST: c_uint = 0x1c; -#[allow(non_upper_case_globals)] -const DW_ATE_boolean: c_uint = 0x02; -#[allow(non_upper_case_globals)] -const DW_ATE_float: c_uint = 0x04; -#[allow(non_upper_case_globals)] -const DW_ATE_signed: c_uint = 0x05; -#[allow(non_upper_case_globals)] -const DW_ATE_unsigned: c_uint = 0x07; -#[allow(non_upper_case_globals)] -const DW_ATE_unsigned_char: c_uint = 0x08; - -pub const UNKNOWN_LINE_NUMBER: c_uint = 0; -pub const UNKNOWN_COLUMN_NUMBER: c_uint = 0; - -// ptr::null() doesn't work :( -pub const NO_SCOPE_METADATA: DIScope = (0 as DIScope); - -#[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)] -pub struct UniqueTypeId(ast::Name); - -// The TypeMap is where the CrateDebugContext holds the type metadata nodes -// created so far. The metadata nodes are indexed by UniqueTypeId, and, for -// faster lookup, also by Ty. The TypeMap is responsible for creating -// UniqueTypeIds. -pub struct TypeMap<'tcx> { - // The UniqueTypeIds created so far - unique_id_interner: Interner, - // A map from UniqueTypeId to debuginfo metadata for that type. This is a 1:1 mapping. - unique_id_to_metadata: FxHashMap, - // A map from types to debuginfo metadata. This is a N:1 mapping. - type_to_metadata: FxHashMap, DIType>, - // A map from types to UniqueTypeId. This is a N:1 mapping. - type_to_unique_id: FxHashMap, UniqueTypeId> -} - -impl<'tcx> TypeMap<'tcx> { - pub fn new() -> TypeMap<'tcx> { - TypeMap { - unique_id_interner: Interner::new(), - type_to_metadata: FxHashMap(), - unique_id_to_metadata: FxHashMap(), - type_to_unique_id: FxHashMap(), - } - } - - // Adds a Ty to metadata mapping to the TypeMap. The method will fail if - // the mapping already exists. - fn register_type_with_metadata<'a>(&mut self, - type_: Ty<'tcx>, - metadata: DIType) { - if self.type_to_metadata.insert(type_, metadata).is_some() { - bug!("Type metadata for Ty '{}' is already in the TypeMap!", type_); - } - } - - // Adds a UniqueTypeId to metadata mapping to the TypeMap. The method will - // fail if the mapping already exists. - fn register_unique_id_with_metadata(&mut self, - unique_type_id: UniqueTypeId, - metadata: DIType) { - if self.unique_id_to_metadata.insert(unique_type_id, metadata).is_some() { - bug!("Type metadata for unique id '{}' is already in the TypeMap!", - self.get_unique_type_id_as_string(unique_type_id)); - } - } - - fn find_metadata_for_type(&self, type_: Ty<'tcx>) -> Option { - self.type_to_metadata.get(&type_).cloned() - } - - fn find_metadata_for_unique_id(&self, unique_type_id: UniqueTypeId) -> Option { - self.unique_id_to_metadata.get(&unique_type_id).cloned() - } - - // Get the string representation of a UniqueTypeId. This method will fail if - // the id is unknown. - fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> &str { - let UniqueTypeId(interner_key) = unique_type_id; - self.unique_id_interner.get(interner_key) - } - - // Get the UniqueTypeId for the given type. If the UniqueTypeId for the given - // type has been requested before, this is just a table lookup. Otherwise an - // ID will be generated and stored for later lookup. - fn get_unique_type_id_of_type<'a>(&mut self, cx: &CodegenCx<'a, 'tcx>, - type_: Ty<'tcx>) -> UniqueTypeId { - // Let's see if we already have something in the cache - match self.type_to_unique_id.get(&type_).cloned() { - Some(unique_type_id) => return unique_type_id, - None => { /* generate one */} - }; - - // The hasher we are using to generate the UniqueTypeId. We want - // something that provides more than the 64 bits of the DefaultHasher. - let mut type_id_hasher = TypeIdHasher::::new(cx.tcx); - type_id_hasher.visit_ty(type_); - let unique_type_id = type_id_hasher.finish().to_hex(); - - let key = self.unique_id_interner.intern(&unique_type_id); - self.type_to_unique_id.insert(type_, UniqueTypeId(key)); - - return UniqueTypeId(key); - } - - // Get the UniqueTypeId for an enum variant. Enum variants are not really - // types of their own, so they need special handling. We still need a - // UniqueTypeId for them, since to debuginfo they *are* real types. - fn get_unique_type_id_of_enum_variant<'a>(&mut self, - cx: &CodegenCx<'a, 'tcx>, - enum_type: Ty<'tcx>, - variant_name: &str) - -> UniqueTypeId { - let enum_type_id = self.get_unique_type_id_of_type(cx, enum_type); - let enum_variant_type_id = format!("{}::{}", - self.get_unique_type_id_as_string(enum_type_id), - variant_name); - let interner_key = self.unique_id_interner.intern(&enum_variant_type_id); - UniqueTypeId(interner_key) - } -} - -// A description of some recursive type. It can either be already finished (as -// with FinalMetadata) or it is not yet finished, but contains all information -// needed to generate the missing parts of the description. See the -// documentation section on Recursive Types at the top of this file for more -// information. -enum RecursiveTypeDescription<'tcx> { - UnfinishedMetadata { - unfinished_type: Ty<'tcx>, - unique_type_id: UniqueTypeId, - metadata_stub: DICompositeType, - member_description_factory: MemberDescriptionFactory<'tcx>, - }, - FinalMetadata(DICompositeType) -} - -fn create_and_register_recursive_type_forward_declaration<'a, 'tcx>( - cx: &CodegenCx<'a, 'tcx>, - unfinished_type: Ty<'tcx>, - unique_type_id: UniqueTypeId, - metadata_stub: DICompositeType, - member_description_factory: MemberDescriptionFactory<'tcx>) - -> RecursiveTypeDescription<'tcx> { - - // Insert the stub into the TypeMap in order to allow for recursive references - let mut type_map = debug_context(cx).type_map.borrow_mut(); - type_map.register_unique_id_with_metadata(unique_type_id, metadata_stub); - type_map.register_type_with_metadata(unfinished_type, metadata_stub); - - UnfinishedMetadata { - unfinished_type, - unique_type_id, - metadata_stub, - member_description_factory, - } -} - -impl<'tcx> RecursiveTypeDescription<'tcx> { - // Finishes up the description of the type in question (mostly by providing - // descriptions of the fields of the given type) and returns the final type - // metadata. - fn finalize<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> MetadataCreationResult { - match *self { - FinalMetadata(metadata) => MetadataCreationResult::new(metadata, false), - UnfinishedMetadata { - unfinished_type, - unique_type_id, - metadata_stub, - ref member_description_factory, - } => { - // Make sure that we have a forward declaration of the type in - // the TypeMap so that recursive references are possible. This - // will always be the case if the RecursiveTypeDescription has - // been properly created through the - // create_and_register_recursive_type_forward_declaration() - // function. - { - let type_map = debug_context(cx).type_map.borrow(); - if type_map.find_metadata_for_unique_id(unique_type_id).is_none() || - type_map.find_metadata_for_type(unfinished_type).is_none() { - bug!("Forward declaration of potentially recursive type \ - '{:?}' was not found in TypeMap!", - unfinished_type); - } - } - - // ... then create the member descriptions ... - let member_descriptions = - member_description_factory.create_member_descriptions(cx); - - // ... and attach them to the stub to complete it. - set_members_of_composite_type(cx, - metadata_stub, - &member_descriptions[..]); - return MetadataCreationResult::new(metadata_stub, true); - } - } - } -} - -// Returns from the enclosing function if the type metadata with the given -// unique id can be found in the type map -macro_rules! return_if_metadata_created_in_meantime { - ($cx: expr, $unique_type_id: expr) => ( - match debug_context($cx).type_map - .borrow() - .find_metadata_for_unique_id($unique_type_id) { - Some(metadata) => return MetadataCreationResult::new(metadata, true), - None => { /* proceed normally */ } - } - ) -} - -fn fixed_vec_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - unique_type_id: UniqueTypeId, - array_or_slice_type: Ty<'tcx>, - element_type: Ty<'tcx>, - span: Span) - -> MetadataCreationResult { - let element_type_metadata = type_metadata(cx, element_type, span); - - return_if_metadata_created_in_meantime!(cx, unique_type_id); - - let (size, align) = cx.size_and_align_of(array_or_slice_type); - - let upper_bound = match array_or_slice_type.sty { - ty::TyArray(_, len) => { - len.unwrap_usize(cx.tcx) as c_longlong - } - _ => -1 - }; - - let subrange = unsafe { - llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) - }; - - let subscripts = create_DIArray(DIB(cx), &[subrange]); - let metadata = unsafe { - llvm::LLVMRustDIBuilderCreateArrayType( - DIB(cx), - size.bits(), - align.abi_bits() as u32, - element_type_metadata, - subscripts) - }; - - return MetadataCreationResult::new(metadata, false); -} - -fn vec_slice_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - slice_ptr_type: Ty<'tcx>, - element_type: Ty<'tcx>, - unique_type_id: UniqueTypeId, - span: Span) - -> MetadataCreationResult { - let data_ptr_type = cx.tcx.mk_imm_ptr(element_type); - - let data_ptr_metadata = type_metadata(cx, data_ptr_type, span); - - return_if_metadata_created_in_meantime!(cx, unique_type_id); - - let slice_type_name = compute_debuginfo_type_name(cx, slice_ptr_type, true); - - let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type); - let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize); - - let member_descriptions = [ - MemberDescription { - name: "data_ptr".to_string(), - type_metadata: data_ptr_metadata, - offset: Size::from_bytes(0), - size: pointer_size, - align: pointer_align, - flags: DIFlags::FlagZero, - }, - MemberDescription { - name: "length".to_string(), - type_metadata: type_metadata(cx, cx.tcx.types.usize, span), - offset: pointer_size, - size: usize_size, - align: usize_align, - flags: DIFlags::FlagZero, - }, - ]; - - let file_metadata = unknown_file_metadata(cx); - - let metadata = composite_type_metadata(cx, - slice_ptr_type, - &slice_type_name[..], - unique_type_id, - &member_descriptions, - NO_SCOPE_METADATA, - file_metadata, - span); - MetadataCreationResult::new(metadata, false) -} - -fn subroutine_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - unique_type_id: UniqueTypeId, - signature: ty::PolyFnSig<'tcx>, - span: Span) - -> MetadataCreationResult -{ - let signature = cx.tcx.normalize_erasing_late_bound_regions( - ty::ParamEnv::reveal_all(), - &signature, - ); - - let mut signature_metadata: Vec = Vec::with_capacity(signature.inputs().len() + 1); - - // return type - signature_metadata.push(match signature.output().sty { - ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(), - _ => type_metadata(cx, signature.output(), span) - }); - - // regular arguments - for &argument_type in signature.inputs() { - signature_metadata.push(type_metadata(cx, argument_type, span)); - } - - return_if_metadata_created_in_meantime!(cx, unique_type_id); - - return MetadataCreationResult::new( - unsafe { - llvm::LLVMRustDIBuilderCreateSubroutineType( - DIB(cx), - unknown_file_metadata(cx), - create_DIArray(DIB(cx), &signature_metadata[..])) - }, - false); -} - -// FIXME(1563) This is all a bit of a hack because 'trait pointer' is an ill- -// defined concept. For the case of an actual trait pointer (i.e., Box, -// &Trait), trait_object_type should be the whole thing (e.g, Box) and -// trait_type should be the actual trait (e.g., Trait). Where the trait is part -// of a DST struct, there is no trait_object_type and the results of this -// function will be a little bit weird. -fn trait_pointer_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - trait_type: Ty<'tcx>, - trait_object_type: Option>, - unique_type_id: UniqueTypeId) - -> DIType { - // The implementation provided here is a stub. It makes sure that the trait - // type is assigned the correct name, size, namespace, and source location. - // But it does not describe the trait's methods. - - let containing_scope = match trait_type.sty { - ty::TyDynamic(ref data, ..) => if let Some(principal) = data.principal() { - let def_id = principal.def_id(); - get_namespace_for_item(cx, def_id) - } else { - NO_SCOPE_METADATA - }, - _ => { - bug!("debuginfo: Unexpected trait-object type in \ - trait_pointer_metadata(): {:?}", - trait_type); - } - }; - - let trait_object_type = trait_object_type.unwrap_or(trait_type); - let trait_type_name = - compute_debuginfo_type_name(cx, trait_object_type, false); - - let file_metadata = unknown_file_metadata(cx); - - let layout = cx.layout_of(cx.tcx.mk_mut_ptr(trait_type)); - - assert_eq!(abi::FAT_PTR_ADDR, 0); - assert_eq!(abi::FAT_PTR_EXTRA, 1); - - let data_ptr_field = layout.field(cx, 0); - let vtable_field = layout.field(cx, 1); - let member_descriptions = [ - MemberDescription { - name: "pointer".to_string(), - type_metadata: type_metadata(cx, - cx.tcx.mk_mut_ptr(cx.tcx.types.u8), - syntax_pos::DUMMY_SP), - offset: layout.fields.offset(0), - size: data_ptr_field.size, - align: data_ptr_field.align, - flags: DIFlags::FlagArtificial, - }, - MemberDescription { - name: "vtable".to_string(), - type_metadata: type_metadata(cx, vtable_field.ty, syntax_pos::DUMMY_SP), - offset: layout.fields.offset(1), - size: vtable_field.size, - align: vtable_field.align, - flags: DIFlags::FlagArtificial, - }, - ]; - - composite_type_metadata(cx, - trait_object_type, - &trait_type_name[..], - unique_type_id, - &member_descriptions, - containing_scope, - file_metadata, - syntax_pos::DUMMY_SP) -} - -pub fn type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - t: Ty<'tcx>, - usage_site_span: Span) - -> DIType { - // Get the unique type id of this type. - let unique_type_id = { - let mut type_map = debug_context(cx).type_map.borrow_mut(); - // First, try to find the type in TypeMap. If we have seen it before, we - // can exit early here. - match type_map.find_metadata_for_type(t) { - Some(metadata) => { - return metadata; - }, - None => { - // The Ty is not in the TypeMap but maybe we have already seen - // an equivalent type (e.g. only differing in region arguments). - // In order to find out, generate the unique type id and look - // that up. - let unique_type_id = type_map.get_unique_type_id_of_type(cx, t); - match type_map.find_metadata_for_unique_id(unique_type_id) { - Some(metadata) => { - // There is already an equivalent type in the TypeMap. - // Register this Ty as an alias in the cache and - // return the cached metadata. - type_map.register_type_with_metadata(t, metadata); - return metadata; - }, - None => { - // There really is no type metadata for this type, so - // proceed by creating it. - unique_type_id - } - } - } - } - }; - - debug!("type_metadata: {:?}", t); - - let ptr_metadata = |ty: Ty<'tcx>| { - match ty.sty { - ty::TySlice(typ) => { - Ok(vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span)) - } - ty::TyStr => { - Ok(vec_slice_metadata(cx, t, cx.tcx.types.u8, unique_type_id, usage_site_span)) - } - ty::TyDynamic(..) => { - Ok(MetadataCreationResult::new( - trait_pointer_metadata(cx, ty, Some(t), unique_type_id), - false)) - } - _ => { - let pointee_metadata = type_metadata(cx, ty, usage_site_span); - - match debug_context(cx).type_map - .borrow() - .find_metadata_for_unique_id(unique_type_id) { - Some(metadata) => return Err(metadata), - None => { /* proceed normally */ } - }; - - Ok(MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), - false)) - } - } - }; - - let MetadataCreationResult { metadata, already_stored_in_typemap } = match t.sty { - ty::TyNever | - ty::TyBool | - ty::TyChar | - ty::TyInt(_) | - ty::TyUint(_) | - ty::TyFloat(_) => { - MetadataCreationResult::new(basic_type_metadata(cx, t), false) - } - ty::TyTuple(ref elements) if elements.is_empty() => { - MetadataCreationResult::new(basic_type_metadata(cx, t), false) - } - ty::TyArray(typ, _) | - ty::TySlice(typ) => { - fixed_vec_metadata(cx, unique_type_id, t, typ, usage_site_span) - } - ty::TyStr => { - fixed_vec_metadata(cx, unique_type_id, t, cx.tcx.types.i8, usage_site_span) - } - ty::TyDynamic(..) => { - MetadataCreationResult::new( - trait_pointer_metadata(cx, t, None, unique_type_id), - false) - } - ty::TyForeign(..) => { - MetadataCreationResult::new( - foreign_type_metadata(cx, t, unique_type_id), - false) - } - ty::TyRawPtr(ty::TypeAndMut{ty, ..}) | - ty::TyRef(_, ty, _) => { - match ptr_metadata(ty) { - Ok(res) => res, - Err(metadata) => return metadata, - } - } - ty::TyAdt(def, _) if def.is_box() => { - match ptr_metadata(t.boxed_ty()) { - Ok(res) => res, - Err(metadata) => return metadata, - } - } - ty::TyFnDef(..) | ty::TyFnPtr(_) => { - let fn_metadata = subroutine_type_metadata(cx, - unique_type_id, - t.fn_sig(cx.tcx), - usage_site_span).metadata; - match debug_context(cx).type_map - .borrow() - .find_metadata_for_unique_id(unique_type_id) { - Some(metadata) => return metadata, - None => { /* proceed normally */ } - }; - - // This is actually a function pointer, so wrap it in pointer DI - MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false) - - } - ty::TyClosure(def_id, substs) => { - let upvar_tys : Vec<_> = substs.upvar_tys(def_id, cx.tcx).collect(); - prepare_tuple_metadata(cx, - t, - &upvar_tys, - unique_type_id, - usage_site_span).finalize(cx) - } - ty::TyGenerator(def_id, substs, _) => { - let upvar_tys : Vec<_> = substs.field_tys(def_id, cx.tcx).map(|t| { - cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t) - }).collect(); - prepare_tuple_metadata(cx, - t, - &upvar_tys, - unique_type_id, - usage_site_span).finalize(cx) - } - ty::TyAdt(def, ..) => match def.adt_kind() { - AdtKind::Struct => { - prepare_struct_metadata(cx, - t, - unique_type_id, - usage_site_span).finalize(cx) - } - AdtKind::Union => { - prepare_union_metadata(cx, - t, - unique_type_id, - usage_site_span).finalize(cx) - } - AdtKind::Enum => { - prepare_enum_metadata(cx, - t, - def.did, - unique_type_id, - usage_site_span).finalize(cx) - } - }, - ty::TyTuple(ref elements) => { - prepare_tuple_metadata(cx, - t, - &elements[..], - unique_type_id, - usage_site_span).finalize(cx) - } - _ => { - bug!("debuginfo: unexpected type in type_metadata: {:?}", t) - } - }; - - { - let mut type_map = debug_context(cx).type_map.borrow_mut(); - - if already_stored_in_typemap { - // Also make sure that we already have a TypeMap entry for the unique type id. - let metadata_for_uid = match type_map.find_metadata_for_unique_id(unique_type_id) { - Some(metadata) => metadata, - None => { - span_bug!(usage_site_span, - "Expected type metadata for unique \ - type id '{}' to already be in \ - the debuginfo::TypeMap but it \ - was not. (Ty = {})", - type_map.get_unique_type_id_as_string(unique_type_id), - t); - } - }; - - match type_map.find_metadata_for_type(t) { - Some(metadata) => { - if metadata != metadata_for_uid { - span_bug!(usage_site_span, - "Mismatch between Ty and \ - UniqueTypeId maps in \ - debuginfo::TypeMap. \ - UniqueTypeId={}, Ty={}", - type_map.get_unique_type_id_as_string(unique_type_id), - t); - } - } - None => { - type_map.register_type_with_metadata(t, metadata); - } - } - } else { - type_map.register_type_with_metadata(t, metadata); - type_map.register_unique_id_with_metadata(unique_type_id, metadata); - } - } - - metadata -} - -pub fn file_metadata(cx: &CodegenCx, - file_name: &FileName, - defining_crate: CrateNum) -> DIFile { - debug!("file_metadata: file_name: {}, defining_crate: {}", - file_name, - defining_crate); - - let directory = if defining_crate == LOCAL_CRATE { - &cx.sess().working_dir.0 - } else { - // If the path comes from an upstream crate we assume it has been made - // independent of the compiler's working directory one way or another. - Path::new("") - }; - - file_metadata_raw(cx, &file_name.to_string(), &directory.to_string_lossy()) -} - -pub fn unknown_file_metadata(cx: &CodegenCx) -> DIFile { - file_metadata_raw(cx, "", "") -} - -fn file_metadata_raw(cx: &CodegenCx, - file_name: &str, - directory: &str) - -> DIFile { - let key = (Symbol::intern(file_name), Symbol::intern(directory)); - - if let Some(file_metadata) = debug_context(cx).created_files.borrow().get(&key) { - return *file_metadata; - } - - debug!("file_metadata: file_name: {}, directory: {}", file_name, directory); - - let file_name = CString::new(file_name).unwrap(); - let directory = CString::new(directory).unwrap(); - - let file_metadata = unsafe { - llvm::LLVMRustDIBuilderCreateFile(DIB(cx), - file_name.as_ptr(), - directory.as_ptr()) - }; - - let mut created_files = debug_context(cx).created_files.borrow_mut(); - created_files.insert(key, file_metadata); - file_metadata -} - -fn basic_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - t: Ty<'tcx>) -> DIType { - - debug!("basic_type_metadata: {:?}", t); - - let (name, encoding) = match t.sty { - ty::TyNever => ("!", DW_ATE_unsigned), - ty::TyTuple(ref elements) if elements.is_empty() => - ("()", DW_ATE_unsigned), - ty::TyBool => ("bool", DW_ATE_boolean), - ty::TyChar => ("char", DW_ATE_unsigned_char), - ty::TyInt(int_ty) => { - (int_ty.ty_to_string(), DW_ATE_signed) - }, - ty::TyUint(uint_ty) => { - (uint_ty.ty_to_string(), DW_ATE_unsigned) - }, - ty::TyFloat(float_ty) => { - (float_ty.ty_to_string(), DW_ATE_float) - }, - _ => bug!("debuginfo::basic_type_metadata - t is invalid type") - }; - - let (size, align) = cx.size_and_align_of(t); - let name = CString::new(name).unwrap(); - let ty_metadata = unsafe { - llvm::LLVMRustDIBuilderCreateBasicType( - DIB(cx), - name.as_ptr(), - size.bits(), - align.abi_bits() as u32, - encoding) - }; - - return ty_metadata; -} - -fn foreign_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - t: Ty<'tcx>, - unique_type_id: UniqueTypeId) -> DIType { - debug!("foreign_type_metadata: {:?}", t); - - let name = compute_debuginfo_type_name(cx, t, false); - create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA) -} - -fn pointer_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - pointer_type: Ty<'tcx>, - pointee_type_metadata: DIType) - -> DIType { - let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type); - let name = compute_debuginfo_type_name(cx, pointer_type, false); - let name = CString::new(name).unwrap(); - unsafe { - llvm::LLVMRustDIBuilderCreatePointerType( - DIB(cx), - pointee_type_metadata, - pointer_size.bits(), - pointer_align.abi_bits() as u32, - name.as_ptr()) - } -} - -pub fn compile_unit_metadata(tcx: TyCtxt, - codegen_unit_name: &str, - debug_context: &CrateDebugContext) - -> DIDescriptor { - let mut name_in_debuginfo = match tcx.sess.local_crate_source_file { - Some(ref path) => path.clone(), - None => PathBuf::from(&*tcx.crate_name(LOCAL_CRATE).as_str()), - }; - - // The OSX linker has an idiosyncrasy where it will ignore some debuginfo - // if multiple object files with the same DW_AT_name are linked together. - // As a workaround we generate unique names for each object file. Those do - // not correspond to an actual source file but that should be harmless. - if tcx.sess.target.target.options.is_like_osx { - name_in_debuginfo.push("@"); - name_in_debuginfo.push(codegen_unit_name); - } - - debug!("compile_unit_metadata: {:?}", name_in_debuginfo); - // FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice. - let producer = format!("clang LLVM (rustc version {})", - (option_env!("CFG_VERSION")).expect("CFG_VERSION")); - - let name_in_debuginfo = name_in_debuginfo.to_string_lossy().into_owned(); - let name_in_debuginfo = CString::new(name_in_debuginfo).unwrap(); - let work_dir = CString::new(&tcx.sess.working_dir.0.to_string_lossy()[..]).unwrap(); - let producer = CString::new(producer).unwrap(); - let flags = "\0"; - let split_name = "\0"; - - unsafe { - let file_metadata = llvm::LLVMRustDIBuilderCreateFile( - debug_context.builder, name_in_debuginfo.as_ptr(), work_dir.as_ptr()); - - let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit( - debug_context.builder, - DW_LANG_RUST, - file_metadata, - producer.as_ptr(), - tcx.sess.opts.optimize != config::OptLevel::No, - flags.as_ptr() as *const _, - 0, - split_name.as_ptr() as *const _); - - if tcx.sess.opts.debugging_opts.profile { - let cu_desc_metadata = llvm::LLVMRustMetadataAsValue(debug_context.llcontext, - unit_metadata); - - let gcov_cu_info = [ - path_to_mdstring(debug_context.llcontext, - &tcx.output_filenames(LOCAL_CRATE).with_extension("gcno")), - path_to_mdstring(debug_context.llcontext, - &tcx.output_filenames(LOCAL_CRATE).with_extension("gcda")), - cu_desc_metadata, - ]; - let gcov_metadata = llvm::LLVMMDNodeInContext(debug_context.llcontext, - gcov_cu_info.as_ptr(), - gcov_cu_info.len() as c_uint); - - let llvm_gcov_ident = CString::new("llvm.gcov").unwrap(); - llvm::LLVMAddNamedMetadataOperand(debug_context.llmod, - llvm_gcov_ident.as_ptr(), - gcov_metadata); - } - - return unit_metadata; - }; - - fn path_to_mdstring(llcx: llvm::ContextRef, path: &Path) -> llvm::ValueRef { - let path_str = path2cstr(path); - unsafe { - llvm::LLVMMDStringInContext(llcx, - path_str.as_ptr(), - path_str.as_bytes().len() as c_uint) - } - } -} - -struct MetadataCreationResult { - metadata: DIType, - already_stored_in_typemap: bool -} - -impl MetadataCreationResult { - fn new(metadata: DIType, already_stored_in_typemap: bool) -> MetadataCreationResult { - MetadataCreationResult { - metadata, - already_stored_in_typemap, - } - } -} - -// Description of a type member, which can either be a regular field (as in -// structs or tuples) or an enum variant. -#[derive(Debug)] -struct MemberDescription { - name: String, - type_metadata: DIType, - offset: Size, - size: Size, - align: Align, - flags: DIFlags, -} - -// A factory for MemberDescriptions. It produces a list of member descriptions -// for some record-like type. MemberDescriptionFactories are used to defer the -// creation of type member descriptions in order to break cycles arising from -// recursive type definitions. -enum MemberDescriptionFactory<'tcx> { - StructMDF(StructMemberDescriptionFactory<'tcx>), - TupleMDF(TupleMemberDescriptionFactory<'tcx>), - EnumMDF(EnumMemberDescriptionFactory<'tcx>), - UnionMDF(UnionMemberDescriptionFactory<'tcx>), - VariantMDF(VariantMemberDescriptionFactory<'tcx>) -} - -impl<'tcx> MemberDescriptionFactory<'tcx> { - fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>) - -> Vec { - match *self { - StructMDF(ref this) => { - this.create_member_descriptions(cx) - } - TupleMDF(ref this) => { - this.create_member_descriptions(cx) - } - EnumMDF(ref this) => { - this.create_member_descriptions(cx) - } - UnionMDF(ref this) => { - this.create_member_descriptions(cx) - } - VariantMDF(ref this) => { - this.create_member_descriptions(cx) - } - } - } -} - -//=----------------------------------------------------------------------------- -// Structs -//=----------------------------------------------------------------------------- - -// Creates MemberDescriptions for the fields of a struct -struct StructMemberDescriptionFactory<'tcx> { - ty: Ty<'tcx>, - variant: &'tcx ty::VariantDef, - span: Span, -} - -impl<'tcx> StructMemberDescriptionFactory<'tcx> { - fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>) - -> Vec { - let layout = cx.layout_of(self.ty); - self.variant.fields.iter().enumerate().map(|(i, f)| { - let name = if self.variant.ctor_kind == CtorKind::Fn { - format!("__{}", i) - } else { - f.name.to_string() - }; - let field = layout.field(cx, i); - let (size, align) = field.size_and_align(); - MemberDescription { - name, - type_metadata: type_metadata(cx, field.ty, self.span), - offset: layout.fields.offset(i), - size, - align, - flags: DIFlags::FlagZero, - } - }).collect() - } -} - - -fn prepare_struct_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - struct_type: Ty<'tcx>, - unique_type_id: UniqueTypeId, - span: Span) - -> RecursiveTypeDescription<'tcx> { - let struct_name = compute_debuginfo_type_name(cx, struct_type, false); - - let (struct_def_id, variant) = match struct_type.sty { - ty::TyAdt(def, _) => (def.did, def.non_enum_variant()), - _ => bug!("prepare_struct_metadata on a non-ADT") - }; - - let containing_scope = get_namespace_for_item(cx, struct_def_id); - - let struct_metadata_stub = create_struct_stub(cx, - struct_type, - &struct_name, - unique_type_id, - containing_scope); - - create_and_register_recursive_type_forward_declaration( - cx, - struct_type, - unique_type_id, - struct_metadata_stub, - StructMDF(StructMemberDescriptionFactory { - ty: struct_type, - variant, - span, - }) - ) -} - -//=----------------------------------------------------------------------------- -// Tuples -//=----------------------------------------------------------------------------- - -// Creates MemberDescriptions for the fields of a tuple -struct TupleMemberDescriptionFactory<'tcx> { - ty: Ty<'tcx>, - component_types: Vec>, - span: Span, -} - -impl<'tcx> TupleMemberDescriptionFactory<'tcx> { - fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>) - -> Vec { - let layout = cx.layout_of(self.ty); - self.component_types.iter().enumerate().map(|(i, &component_type)| { - let (size, align) = cx.size_and_align_of(component_type); - MemberDescription { - name: format!("__{}", i), - type_metadata: type_metadata(cx, component_type, self.span), - offset: layout.fields.offset(i), - size, - align, - flags: DIFlags::FlagZero, - } - }).collect() - } -} - -fn prepare_tuple_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - tuple_type: Ty<'tcx>, - component_types: &[Ty<'tcx>], - unique_type_id: UniqueTypeId, - span: Span) - -> RecursiveTypeDescription<'tcx> { - let tuple_name = compute_debuginfo_type_name(cx, tuple_type, false); - - create_and_register_recursive_type_forward_declaration( - cx, - tuple_type, - unique_type_id, - create_struct_stub(cx, - tuple_type, - &tuple_name[..], - unique_type_id, - NO_SCOPE_METADATA), - TupleMDF(TupleMemberDescriptionFactory { - ty: tuple_type, - component_types: component_types.to_vec(), - span, - }) - ) -} - -//=----------------------------------------------------------------------------- -// Unions -//=----------------------------------------------------------------------------- - -struct UnionMemberDescriptionFactory<'tcx> { - layout: TyLayout<'tcx>, - variant: &'tcx ty::VariantDef, - span: Span, -} - -impl<'tcx> UnionMemberDescriptionFactory<'tcx> { - fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>) - -> Vec { - self.variant.fields.iter().enumerate().map(|(i, f)| { - let field = self.layout.field(cx, i); - let (size, align) = field.size_and_align(); - MemberDescription { - name: f.name.to_string(), - type_metadata: type_metadata(cx, field.ty, self.span), - offset: Size::from_bytes(0), - size, - align, - flags: DIFlags::FlagZero, - } - }).collect() - } -} - -fn prepare_union_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - union_type: Ty<'tcx>, - unique_type_id: UniqueTypeId, - span: Span) - -> RecursiveTypeDescription<'tcx> { - let union_name = compute_debuginfo_type_name(cx, union_type, false); - - let (union_def_id, variant) = match union_type.sty { - ty::TyAdt(def, _) => (def.did, def.non_enum_variant()), - _ => bug!("prepare_union_metadata on a non-ADT") - }; - - let containing_scope = get_namespace_for_item(cx, union_def_id); - - let union_metadata_stub = create_union_stub(cx, - union_type, - &union_name, - unique_type_id, - containing_scope); - - create_and_register_recursive_type_forward_declaration( - cx, - union_type, - unique_type_id, - union_metadata_stub, - UnionMDF(UnionMemberDescriptionFactory { - layout: cx.layout_of(union_type), - variant, - span, - }) - ) -} - -//=----------------------------------------------------------------------------- -// Enums -//=----------------------------------------------------------------------------- - -// Describes the members of an enum value: An enum is described as a union of -// structs in DWARF. This MemberDescriptionFactory provides the description for -// the members of this union; so for every variant of the given enum, this -// factory will produce one MemberDescription (all with no name and a fixed -// offset of zero bytes). -struct EnumMemberDescriptionFactory<'tcx> { - enum_type: Ty<'tcx>, - layout: TyLayout<'tcx>, - discriminant_type_metadata: Option, - containing_scope: DIScope, - span: Span, -} - -impl<'tcx> EnumMemberDescriptionFactory<'tcx> { - fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>) - -> Vec { - let adt = &self.enum_type.ty_adt_def().unwrap(); - match self.layout.variants { - layout::Variants::Single { .. } if adt.variants.is_empty() => vec![], - layout::Variants::Single { index } => { - let (variant_type_metadata, member_description_factory) = - describe_enum_variant(cx, - self.layout, - &adt.variants[index], - NoDiscriminant, - self.containing_scope, - self.span); - - let member_descriptions = - member_description_factory.create_member_descriptions(cx); - - set_members_of_composite_type(cx, - variant_type_metadata, - &member_descriptions[..]); - vec![ - MemberDescription { - name: "".to_string(), - type_metadata: variant_type_metadata, - offset: Size::from_bytes(0), - size: self.layout.size, - align: self.layout.align, - flags: DIFlags::FlagZero - } - ] - } - layout::Variants::Tagged { ref variants, .. } => { - let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata - .expect("")); - (0..variants.len()).map(|i| { - let variant = self.layout.for_variant(cx, i); - let (variant_type_metadata, member_desc_factory) = - describe_enum_variant(cx, - variant, - &adt.variants[i], - discriminant_info, - self.containing_scope, - self.span); - - let member_descriptions = member_desc_factory - .create_member_descriptions(cx); - - set_members_of_composite_type(cx, - variant_type_metadata, - &member_descriptions); - MemberDescription { - name: "".to_string(), - type_metadata: variant_type_metadata, - offset: Size::from_bytes(0), - size: variant.size, - align: variant.align, - flags: DIFlags::FlagZero - } - }).collect() - } - layout::Variants::NicheFilling { dataful_variant, ref niche_variants, .. } => { - let variant = self.layout.for_variant(cx, dataful_variant); - // Create a description of the non-null variant - let (variant_type_metadata, member_description_factory) = - describe_enum_variant(cx, - variant, - &adt.variants[dataful_variant], - OptimizedDiscriminant, - self.containing_scope, - self.span); - - let variant_member_descriptions = - member_description_factory.create_member_descriptions(cx); - - set_members_of_composite_type(cx, - variant_type_metadata, - &variant_member_descriptions[..]); - - // Encode the information about the null variant in the union - // member's name. - let mut name = String::from("RUST$ENCODED$ENUM$"); - // HACK(eddyb) the debuggers should just handle offset+size - // of discriminant instead of us having to recover its path. - // Right now it's not even going to work for `niche_start > 0`, - // and for multiple niche variants it only supports the first. - fn compute_field_path<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - name: &mut String, - layout: TyLayout<'tcx>, - offset: Size, - size: Size) { - for i in 0..layout.fields.count() { - let field_offset = layout.fields.offset(i); - if field_offset > offset { - continue; - } - let inner_offset = offset - field_offset; - let field = layout.field(cx, i); - if inner_offset + size <= field.size { - write!(name, "{}$", i).unwrap(); - compute_field_path(cx, name, field, inner_offset, size); - } - } - } - compute_field_path(cx, &mut name, - self.layout, - self.layout.fields.offset(0), - self.layout.field(cx, 0).size); - name.push_str(&adt.variants[*niche_variants.start()].name.as_str()); - - // Create the (singleton) list of descriptions of union members. - vec![ - MemberDescription { - name, - type_metadata: variant_type_metadata, - offset: Size::from_bytes(0), - size: variant.size, - align: variant.align, - flags: DIFlags::FlagZero - } - ] - } - } - } -} - -// Creates MemberDescriptions for the fields of a single enum variant. -struct VariantMemberDescriptionFactory<'tcx> { - // Cloned from the layout::Struct describing the variant. - offsets: Vec, - args: Vec<(String, Ty<'tcx>)>, - discriminant_type_metadata: Option, - span: Span, -} - -impl<'tcx> VariantMemberDescriptionFactory<'tcx> { - fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>) - -> Vec { - self.args.iter().enumerate().map(|(i, &(ref name, ty))| { - let (size, align) = cx.size_and_align_of(ty); - MemberDescription { - name: name.to_string(), - type_metadata: match self.discriminant_type_metadata { - Some(metadata) if i == 0 => metadata, - _ => type_metadata(cx, ty, self.span) - }, - offset: self.offsets[i], - size, - align, - flags: DIFlags::FlagZero - } - }).collect() - } -} - -#[derive(Copy, Clone)] -enum EnumDiscriminantInfo { - RegularDiscriminant(DIType), - OptimizedDiscriminant, - NoDiscriminant -} - -// Returns a tuple of (1) type_metadata_stub of the variant, (2) the llvm_type -// of the variant, and (3) a MemberDescriptionFactory for producing the -// descriptions of the fields of the variant. This is a rudimentary version of a -// full RecursiveTypeDescription. -fn describe_enum_variant<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - layout: layout::TyLayout<'tcx>, - variant: &'tcx ty::VariantDef, - discriminant_info: EnumDiscriminantInfo, - containing_scope: DIScope, - span: Span) - -> (DICompositeType, MemberDescriptionFactory<'tcx>) { - let variant_name = variant.name.as_str(); - let unique_type_id = debug_context(cx).type_map - .borrow_mut() - .get_unique_type_id_of_enum_variant( - cx, - layout.ty, - &variant_name); - - let metadata_stub = create_struct_stub(cx, - layout.ty, - &variant_name, - unique_type_id, - containing_scope); - - // If this is not a univariant enum, there is also the discriminant field. - let (discr_offset, discr_arg) = match discriminant_info { - RegularDiscriminant(_) => { - let enum_layout = cx.layout_of(layout.ty); - (Some(enum_layout.fields.offset(0)), - Some(("RUST$ENUM$DISR".to_string(), enum_layout.field(cx, 0).ty))) - } - _ => (None, None), - }; - let offsets = discr_offset.into_iter().chain((0..layout.fields.count()).map(|i| { - layout.fields.offset(i) - })).collect(); - - // Build an array of (field name, field type) pairs to be captured in the factory closure. - let args = discr_arg.into_iter().chain((0..layout.fields.count()).map(|i| { - let name = if variant.ctor_kind == CtorKind::Fn { - format!("__{}", i) - } else { - variant.fields[i].name.to_string() - }; - (name, layout.field(cx, i).ty) - })).collect(); - - let member_description_factory = - VariantMDF(VariantMemberDescriptionFactory { - offsets, - args, - discriminant_type_metadata: match discriminant_info { - RegularDiscriminant(discriminant_type_metadata) => { - Some(discriminant_type_metadata) - } - _ => None - }, - span, - }); - - (metadata_stub, member_description_factory) -} - -fn prepare_enum_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - enum_type: Ty<'tcx>, - enum_def_id: DefId, - unique_type_id: UniqueTypeId, - span: Span) - -> RecursiveTypeDescription<'tcx> { - let enum_name = compute_debuginfo_type_name(cx, enum_type, false); - - let containing_scope = get_namespace_for_item(cx, enum_def_id); - // FIXME: This should emit actual file metadata for the enum, but we - // currently can't get the necessary information when it comes to types - // imported from other crates. Formerly we violated the ODR when performing - // LTO because we emitted debuginfo for the same type with varying file - // metadata, so as a workaround we pretend that the type comes from - // - let file_metadata = unknown_file_metadata(cx); - - let def = enum_type.ty_adt_def().unwrap(); - let enumerators_metadata: Vec = def.discriminants(cx.tcx) - .zip(&def.variants) - .map(|(discr, v)| { - let token = v.name.as_str(); - let name = CString::new(token.as_bytes()).unwrap(); - unsafe { - llvm::LLVMRustDIBuilderCreateEnumerator( - DIB(cx), - name.as_ptr(), - // FIXME: what if enumeration has i128 discriminant? - discr.val as u64) - } - }) - .collect(); - - let discriminant_type_metadata = |discr: layout::Primitive| { - let disr_type_key = (enum_def_id, discr); - let cached_discriminant_type_metadata = debug_context(cx).created_enum_disr_types - .borrow() - .get(&disr_type_key).cloned(); - match cached_discriminant_type_metadata { - Some(discriminant_type_metadata) => discriminant_type_metadata, - None => { - let (discriminant_size, discriminant_align) = - (discr.size(cx), discr.align(cx)); - let discriminant_base_type_metadata = - type_metadata(cx, discr.to_ty(cx.tcx), syntax_pos::DUMMY_SP); - let discriminant_name = get_enum_discriminant_name(cx, enum_def_id).as_str(); - - let name = CString::new(discriminant_name.as_bytes()).unwrap(); - let discriminant_type_metadata = unsafe { - llvm::LLVMRustDIBuilderCreateEnumerationType( - DIB(cx), - containing_scope, - name.as_ptr(), - file_metadata, - UNKNOWN_LINE_NUMBER, - discriminant_size.bits(), - discriminant_align.abi_bits() as u32, - create_DIArray(DIB(cx), &enumerators_metadata), - discriminant_base_type_metadata) - }; - - debug_context(cx).created_enum_disr_types - .borrow_mut() - .insert(disr_type_key, discriminant_type_metadata); - - discriminant_type_metadata - } - } - }; - - let layout = cx.layout_of(enum_type); - - let discriminant_type_metadata = match layout.variants { - layout::Variants::Single { .. } | - layout::Variants::NicheFilling { .. } => None, - layout::Variants::Tagged { ref tag, .. } => { - Some(discriminant_type_metadata(tag.value)) - } - }; - - match (&layout.abi, discriminant_type_metadata) { - (&layout::Abi::Scalar(_), Some(discr)) => return FinalMetadata(discr), - _ => {} - } - - let (enum_type_size, enum_type_align) = layout.size_and_align(); - - let enum_name = CString::new(enum_name).unwrap(); - let unique_type_id_str = CString::new( - debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes() - ).unwrap(); - let enum_metadata = unsafe { - llvm::LLVMRustDIBuilderCreateUnionType( - DIB(cx), - containing_scope, - enum_name.as_ptr(), - file_metadata, - UNKNOWN_LINE_NUMBER, - enum_type_size.bits(), - enum_type_align.abi_bits() as u32, - DIFlags::FlagZero, - ptr::null_mut(), - 0, // RuntimeLang - unique_type_id_str.as_ptr()) - }; - - return create_and_register_recursive_type_forward_declaration( - cx, - enum_type, - unique_type_id, - enum_metadata, - EnumMDF(EnumMemberDescriptionFactory { - enum_type, - layout, - discriminant_type_metadata, - containing_scope, - span, - }), - ); - - fn get_enum_discriminant_name(cx: &CodegenCx, - def_id: DefId) - -> InternedString { - cx.tcx.item_name(def_id) - } -} - -/// Creates debug information for a composite type, that is, anything that -/// results in a LLVM struct. -/// -/// Examples of Rust types to use this are: structs, tuples, boxes, vecs, and enums. -fn composite_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - composite_type: Ty<'tcx>, - composite_type_name: &str, - composite_type_unique_id: UniqueTypeId, - member_descriptions: &[MemberDescription], - containing_scope: DIScope, - - // Ignore source location information as long as it - // can't be reconstructed for non-local crates. - _file_metadata: DIFile, - _definition_span: Span) - -> DICompositeType { - // Create the (empty) struct metadata node ... - let composite_type_metadata = create_struct_stub(cx, - composite_type, - composite_type_name, - composite_type_unique_id, - containing_scope); - // ... and immediately create and add the member descriptions. - set_members_of_composite_type(cx, - composite_type_metadata, - member_descriptions); - - return composite_type_metadata; -} - -fn set_members_of_composite_type(cx: &CodegenCx, - composite_type_metadata: DICompositeType, - member_descriptions: &[MemberDescription]) { - // In some rare cases LLVM metadata uniquing would lead to an existing type - // description being used instead of a new one created in - // create_struct_stub. This would cause a hard to trace assertion in - // DICompositeType::SetTypeArray(). The following check makes sure that we - // get a better error message if this should happen again due to some - // regression. - { - let mut composite_types_completed = - debug_context(cx).composite_types_completed.borrow_mut(); - if composite_types_completed.contains(&composite_type_metadata) { - bug!("debuginfo::set_members_of_composite_type() - \ - Already completed forward declaration re-encountered."); - } else { - composite_types_completed.insert(composite_type_metadata); - } - } - - let member_metadata: Vec = member_descriptions - .iter() - .map(|member_description| { - let member_name = member_description.name.as_bytes(); - let member_name = CString::new(member_name).unwrap(); - unsafe { - llvm::LLVMRustDIBuilderCreateMemberType( - DIB(cx), - composite_type_metadata, - member_name.as_ptr(), - unknown_file_metadata(cx), - UNKNOWN_LINE_NUMBER, - member_description.size.bits(), - member_description.align.abi_bits() as u32, - member_description.offset.bits(), - member_description.flags, - member_description.type_metadata) - } - }) - .collect(); - - unsafe { - let type_array = create_DIArray(DIB(cx), &member_metadata[..]); - llvm::LLVMRustDICompositeTypeSetTypeArray( - DIB(cx), composite_type_metadata, type_array); - } -} - -// A convenience wrapper around LLVMRustDIBuilderCreateStructType(). Does not do -// any caching, does not add any fields to the struct. This can be done later -// with set_members_of_composite_type(). -fn create_struct_stub<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - struct_type: Ty<'tcx>, - struct_type_name: &str, - unique_type_id: UniqueTypeId, - containing_scope: DIScope) - -> DICompositeType { - let (struct_size, struct_align) = cx.size_and_align_of(struct_type); - - let name = CString::new(struct_type_name).unwrap(); - let unique_type_id = CString::new( - debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes() - ).unwrap(); - let metadata_stub = unsafe { - // LLVMRustDIBuilderCreateStructType() wants an empty array. A null - // pointer will lead to hard to trace and debug LLVM assertions - // later on in llvm/lib/IR/Value.cpp. - let empty_array = create_DIArray(DIB(cx), &[]); - - llvm::LLVMRustDIBuilderCreateStructType( - DIB(cx), - containing_scope, - name.as_ptr(), - unknown_file_metadata(cx), - UNKNOWN_LINE_NUMBER, - struct_size.bits(), - struct_align.abi_bits() as u32, - DIFlags::FlagZero, - ptr::null_mut(), - empty_array, - 0, - ptr::null_mut(), - unique_type_id.as_ptr()) - }; - - return metadata_stub; -} - -fn create_union_stub<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - union_type: Ty<'tcx>, - union_type_name: &str, - unique_type_id: UniqueTypeId, - containing_scope: DIScope) - -> DICompositeType { - let (union_size, union_align) = cx.size_and_align_of(union_type); - - let name = CString::new(union_type_name).unwrap(); - let unique_type_id = CString::new( - debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes() - ).unwrap(); - let metadata_stub = unsafe { - // LLVMRustDIBuilderCreateUnionType() wants an empty array. A null - // pointer will lead to hard to trace and debug LLVM assertions - // later on in llvm/lib/IR/Value.cpp. - let empty_array = create_DIArray(DIB(cx), &[]); - - llvm::LLVMRustDIBuilderCreateUnionType( - DIB(cx), - containing_scope, - name.as_ptr(), - unknown_file_metadata(cx), - UNKNOWN_LINE_NUMBER, - union_size.bits(), - union_align.abi_bits() as u32, - DIFlags::FlagZero, - empty_array, - 0, // RuntimeLang - unique_type_id.as_ptr()) - }; - - return metadata_stub; -} - -/// Creates debug information for the given global variable. -/// -/// Adds the created metadata nodes directly to the crate's IR. -pub fn create_global_var_metadata(cx: &CodegenCx, - def_id: DefId, - global: ValueRef) { - if cx.dbg_cx.is_none() { - return; - } - - let tcx = cx.tcx; - let attrs = tcx.trans_fn_attrs(def_id); - - if attrs.flags.contains(TransFnAttrFlags::NO_DEBUG) { - return; - } - - let no_mangle = attrs.flags.contains(TransFnAttrFlags::NO_MANGLE); - // We may want to remove the namespace scope if we're in an extern block, see: - // https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952 - let var_scope = get_namespace_for_item(cx, def_id); - let span = tcx.def_span(def_id); - - let (file_metadata, line_number) = if span != syntax_pos::DUMMY_SP { - let loc = span_start(cx, span); - (file_metadata(cx, &loc.file.name, LOCAL_CRATE), loc.line as c_uint) - } else { - (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER) - }; - - let is_local_to_unit = is_node_local_to_unit(cx, def_id); - let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx); - let type_metadata = type_metadata(cx, variable_type, span); - let var_name = tcx.item_name(def_id).to_string(); - let var_name = CString::new(var_name).unwrap(); - let linkage_name = if no_mangle { - None - } else { - let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)); - Some(CString::new(linkage_name.to_string()).unwrap()) - }; - - let global_align = cx.align_of(variable_type); - - unsafe { - llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx), - var_scope, - var_name.as_ptr(), - // If null, linkage_name field is omitted, - // which is what we want for no_mangle statics - linkage_name.as_ref() - .map_or(ptr::null(), |name| name.as_ptr()), - file_metadata, - line_number, - type_metadata, - is_local_to_unit, - global, - ptr::null_mut(), - global_align.abi() as u32, - ); - } -} - -// Creates an "extension" of an existing DIScope into another file. -pub fn extend_scope_to_file(cx: &CodegenCx, - scope_metadata: DIScope, - file: &syntax_pos::FileMap, - defining_crate: CrateNum) - -> DILexicalBlock { - let file_metadata = file_metadata(cx, &file.name, defining_crate); - unsafe { - llvm::LLVMRustDIBuilderCreateLexicalBlockFile( - DIB(cx), - scope_metadata, - file_metadata) - } -} - -/// Creates debug information for the given vtable, which is for the -/// given type. -/// -/// Adds the created metadata nodes directly to the crate's IR. -pub fn create_vtable_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - ty: ty::Ty<'tcx>, - vtable: ValueRef) { - if cx.dbg_cx.is_none() { - return; - } - - let type_metadata = type_metadata(cx, ty, syntax_pos::DUMMY_SP); - - unsafe { - // LLVMRustDIBuilderCreateStructType() wants an empty array. A null - // pointer will lead to hard to trace and debug LLVM assertions - // later on in llvm/lib/IR/Value.cpp. - let empty_array = create_DIArray(DIB(cx), &[]); - - let name = CString::new("vtable").unwrap(); - - // Create a new one each time. We don't want metadata caching - // here, because each vtable will refer to a unique containing - // type. - let vtable_type = llvm::LLVMRustDIBuilderCreateStructType( - DIB(cx), - NO_SCOPE_METADATA, - name.as_ptr(), - unknown_file_metadata(cx), - UNKNOWN_LINE_NUMBER, - Size::from_bytes(0).bits(), - cx.tcx.data_layout.pointer_align.abi_bits() as u32, - DIFlags::FlagArtificial, - ptr::null_mut(), - empty_array, - 0, - type_metadata, - name.as_ptr() - ); - - llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx), - NO_SCOPE_METADATA, - name.as_ptr(), - // LLVM 3.9 - // doesn't accept - // null here, so - // pass the name - // as the linkage - // name. - name.as_ptr(), - unknown_file_metadata(cx), - UNKNOWN_LINE_NUMBER, - vtable_type, - true, - vtable, - ptr::null_mut(), - 0); - } -} diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs deleted file mode 100644 index 2039a90a043..00000000000 --- a/src/librustc_trans/debuginfo/mod.rs +++ /dev/null @@ -1,542 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// See doc.rs for documentation. -mod doc; - -use self::VariableAccess::*; -use self::VariableKind::*; - -use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit}; -use self::namespace::mangled_name_of_instance; -use self::type_names::compute_debuginfo_type_name; -use self::metadata::{type_metadata, file_metadata, TypeMap}; -use self::source_loc::InternalDebugLocation::{self, UnknownLocation}; - -use llvm; -use llvm::{ModuleRef, ContextRef, ValueRef}; -use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, DIFlags}; -use rustc::hir::TransFnAttrFlags; -use rustc::hir::def_id::{DefId, CrateNum}; -use rustc::ty::subst::{Substs, UnpackedKind}; - -use abi::Abi; -use common::CodegenCx; -use builder::Builder; -use monomorphize::Instance; -use rustc::ty::{self, ParamEnv, Ty, InstanceDef}; -use rustc::mir; -use rustc::session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; -use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet}; - -use libc::c_uint; -use std::cell::{Cell, RefCell}; -use std::ffi::CString; -use std::ptr; - -use syntax_pos::{self, Span, Pos}; -use syntax::ast; -use syntax::symbol::{Symbol, InternedString}; -use rustc::ty::layout::{self, LayoutOf}; - -pub mod gdb; -mod utils; -mod namespace; -mod type_names; -pub mod metadata; -mod create_scope_map; -mod source_loc; - -pub use self::create_scope_map::{create_mir_scopes, MirDebugScope}; -pub use self::source_loc::start_emitting_source_locations; -pub use self::metadata::create_global_var_metadata; -pub use self::metadata::create_vtable_metadata; -pub use self::metadata::extend_scope_to_file; -pub use self::source_loc::set_source_location; - -#[allow(non_upper_case_globals)] -const DW_TAG_auto_variable: c_uint = 0x100; -#[allow(non_upper_case_globals)] -const DW_TAG_arg_variable: c_uint = 0x101; - -/// A context object for maintaining all state needed by the debuginfo module. -pub struct CrateDebugContext<'tcx> { - llcontext: ContextRef, - llmod: ModuleRef, - builder: DIBuilderRef, - created_files: RefCell>, - created_enum_disr_types: RefCell>, - - type_map: RefCell>, - namespace_map: RefCell>, - - // This collection is used to assert that composite types (structs, enums, - // ...) have their members only set once: - composite_types_completed: RefCell>, -} - -impl<'tcx> CrateDebugContext<'tcx> { - pub fn new(llmod: ModuleRef) -> CrateDebugContext<'tcx> { - debug!("CrateDebugContext::new"); - let builder = unsafe { llvm::LLVMRustDIBuilderCreate(llmod) }; - // DIBuilder inherits context from the module, so we'd better use the same one - let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) }; - CrateDebugContext { - llcontext, - llmod, - builder, - created_files: RefCell::new(FxHashMap()), - created_enum_disr_types: RefCell::new(FxHashMap()), - type_map: RefCell::new(TypeMap::new()), - namespace_map: RefCell::new(DefIdMap()), - composite_types_completed: RefCell::new(FxHashSet()), - } - } -} - -pub enum FunctionDebugContext { - RegularContext(FunctionDebugContextData), - DebugInfoDisabled, - FunctionWithoutDebugInfo, -} - -impl FunctionDebugContext { - pub fn get_ref<'a>(&'a self, span: Span) -> &'a FunctionDebugContextData { - match *self { - FunctionDebugContext::RegularContext(ref data) => data, - FunctionDebugContext::DebugInfoDisabled => { - span_bug!(span, "{}", FunctionDebugContext::debuginfo_disabled_message()); - } - FunctionDebugContext::FunctionWithoutDebugInfo => { - span_bug!(span, "{}", FunctionDebugContext::should_be_ignored_message()); - } - } - } - - fn debuginfo_disabled_message() -> &'static str { - "debuginfo: Error trying to access FunctionDebugContext although debug info is disabled!" - } - - fn should_be_ignored_message() -> &'static str { - "debuginfo: Error trying to access FunctionDebugContext for function that should be \ - ignored by debug info!" - } -} - -pub struct FunctionDebugContextData { - fn_metadata: DISubprogram, - source_locations_enabled: Cell, - pub defining_crate: CrateNum, -} - -pub enum VariableAccess<'a> { - // The llptr given is an alloca containing the variable's value - DirectVariable { alloca: ValueRef }, - // The llptr given is an alloca containing the start of some pointer chain - // leading to the variable's content. - IndirectVariable { alloca: ValueRef, address_operations: &'a [i64] } -} - -pub enum VariableKind { - ArgumentVariable(usize /*index*/), - LocalVariable, - CapturedVariable, -} - -/// Create any deferred debug metadata nodes -pub fn finalize(cx: &CodegenCx) { - if cx.dbg_cx.is_none() { - return; - } - - debug!("finalize"); - - if gdb::needs_gdb_debug_scripts_section(cx) { - // Add a .debug_gdb_scripts section to this compile-unit. This will - // cause GDB to try and load the gdb_load_rust_pretty_printers.py file, - // which activates the Rust pretty printers for binary this section is - // contained in. - gdb::get_or_insert_gdb_debug_scripts_section_global(cx); - } - - unsafe { - llvm::LLVMRustDIBuilderFinalize(DIB(cx)); - llvm::LLVMRustDIBuilderDispose(DIB(cx)); - // Debuginfo generation in LLVM by default uses a higher - // version of dwarf than macOS currently understands. We can - // instruct LLVM to emit an older version of dwarf, however, - // for macOS to understand. For more info see #11352 - // This can be overridden using --llvm-opts -dwarf-version,N. - // Android has the same issue (#22398) - if cx.sess().target.target.options.is_like_osx || - cx.sess().target.target.options.is_like_android { - llvm::LLVMRustAddModuleFlag(cx.llmod, - "Dwarf Version\0".as_ptr() as *const _, - 2) - } - - // Indicate that we want CodeView debug information on MSVC - if cx.sess().target.target.options.is_like_msvc { - llvm::LLVMRustAddModuleFlag(cx.llmod, - "CodeView\0".as_ptr() as *const _, - 1) - } - - // Prevent bitcode readers from deleting the debug info. - let ptr = "Debug Info Version\0".as_ptr(); - llvm::LLVMRustAddModuleFlag(cx.llmod, ptr as *const _, - llvm::LLVMRustDebugMetadataVersion()); - }; -} - -/// Creates the function-specific debug context. -/// -/// Returns the FunctionDebugContext for the function which holds state needed -/// for debug info creation. The function may also return another variant of the -/// FunctionDebugContext enum which indicates why no debuginfo should be created -/// for the function. -pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - instance: Instance<'tcx>, - sig: ty::FnSig<'tcx>, - llfn: ValueRef, - mir: &mir::Mir) -> FunctionDebugContext { - if cx.sess().opts.debuginfo == NoDebugInfo { - return FunctionDebugContext::DebugInfoDisabled; - } - - if let InstanceDef::Item(def_id) = instance.def { - if cx.tcx.trans_fn_attrs(def_id).flags.contains(TransFnAttrFlags::NO_DEBUG) { - return FunctionDebugContext::FunctionWithoutDebugInfo; - } - } - - let span = mir.span; - - // This can be the case for functions inlined from another crate - if span == syntax_pos::DUMMY_SP { - // FIXME(simulacrum): Probably can't happen; remove. - return FunctionDebugContext::FunctionWithoutDebugInfo; - } - - let def_id = instance.def_id(); - let containing_scope = get_containing_scope(cx, instance); - let loc = span_start(cx, span); - let file_metadata = file_metadata(cx, &loc.file.name, def_id.krate); - - let function_type_metadata = unsafe { - let fn_signature = get_function_signature(cx, sig); - llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature) - }; - - // Find the enclosing function, in case this is a closure. - let def_key = cx.tcx.def_key(def_id); - let mut name = def_key.disambiguated_data.data.to_string(); - - let enclosing_fn_def_id = cx.tcx.closure_base_def_id(def_id); - - // Get_template_parameters() will append a `<...>` clause to the function - // name if necessary. - let generics = cx.tcx.generics_of(enclosing_fn_def_id); - let substs = instance.substs.truncate_to(cx.tcx, generics); - let template_parameters = get_template_parameters(cx, - &generics, - substs, - file_metadata, - &mut name); - - // Get the linkage_name, which is just the symbol name - let linkage_name = mangled_name_of_instance(cx, instance); - - let scope_line = span_start(cx, span).line; - let is_local_to_unit = is_node_local_to_unit(cx, def_id); - - let function_name = CString::new(name).unwrap(); - let linkage_name = CString::new(linkage_name.to_string()).unwrap(); - - let mut flags = DIFlags::FlagPrototyped; - - let local_id = cx.tcx.hir.as_local_node_id(def_id); - match *cx.sess().entry_fn.borrow() { - Some((id, _, _)) => { - if local_id == Some(id) { - flags = flags | DIFlags::FlagMainSubprogram; - } - } - None => {} - }; - if cx.layout_of(sig.output()).abi == ty::layout::Abi::Uninhabited { - flags = flags | DIFlags::FlagNoReturn; - } - - let fn_metadata = unsafe { - llvm::LLVMRustDIBuilderCreateFunction( - DIB(cx), - containing_scope, - function_name.as_ptr(), - linkage_name.as_ptr(), - file_metadata, - loc.line as c_uint, - function_type_metadata, - is_local_to_unit, - true, - scope_line as c_uint, - flags, - cx.sess().opts.optimize != config::OptLevel::No, - llfn, - template_parameters, - ptr::null_mut()) - }; - - // Initialize fn debug context (including scope map and namespace map) - let fn_debug_context = FunctionDebugContextData { - fn_metadata, - source_locations_enabled: Cell::new(false), - defining_crate: def_id.krate, - }; - - return FunctionDebugContext::RegularContext(fn_debug_context); - - fn get_function_signature<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - sig: ty::FnSig<'tcx>) -> DIArray { - if cx.sess().opts.debuginfo == LimitedDebugInfo { - return create_DIArray(DIB(cx), &[]); - } - - let mut signature = Vec::with_capacity(sig.inputs().len() + 1); - - // Return type -- llvm::DIBuilder wants this at index 0 - signature.push(match sig.output().sty { - ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(), - _ => type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP) - }); - - let inputs = if sig.abi == Abi::RustCall { - &sig.inputs()[..sig.inputs().len() - 1] - } else { - sig.inputs() - }; - - // Arguments types - if cx.sess().target.target.options.is_like_msvc { - // FIXME(#42800): - // There is a bug in MSDIA that leads to a crash when it encounters - // a fixed-size array of `u8` or something zero-sized in a - // function-type (see #40477). - // As a workaround, we replace those fixed-size arrays with a - // pointer-type. So a function `fn foo(a: u8, b: [u8; 4])` would - // appear as `fn foo(a: u8, b: *const u8)` in debuginfo, - // and a function `fn bar(x: [(); 7])` as `fn bar(x: *const ())`. - // This transformed type is wrong, but these function types are - // already inaccurate due to ABI adjustments (see #42800). - signature.extend(inputs.iter().map(|&t| { - let t = match t.sty { - ty::TyArray(ct, _) - if (ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() => { - cx.tcx.mk_imm_ptr(ct) - } - _ => t - }; - type_metadata(cx, t, syntax_pos::DUMMY_SP) - })); - } else { - signature.extend(inputs.iter().map(|t| { - type_metadata(cx, t, syntax_pos::DUMMY_SP) - })); - } - - if sig.abi == Abi::RustCall && !sig.inputs().is_empty() { - if let ty::TyTuple(args) = sig.inputs()[sig.inputs().len() - 1].sty { - for &argument_type in args { - signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP)); - } - } - } - - return create_DIArray(DIB(cx), &signature[..]); - } - - fn get_template_parameters<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - generics: &ty::Generics, - substs: &Substs<'tcx>, - file_metadata: DIFile, - name_to_append_suffix_to: &mut String) - -> DIArray - { - if substs.types().next().is_none() { - return create_DIArray(DIB(cx), &[]); - } - - name_to_append_suffix_to.push('<'); - for (i, actual_type) in substs.types().enumerate() { - if i != 0 { - name_to_append_suffix_to.push_str(","); - } - - let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), actual_type); - // Add actual type name to <...> clause of function name - let actual_type_name = compute_debuginfo_type_name(cx, - actual_type, - true); - name_to_append_suffix_to.push_str(&actual_type_name[..]); - } - name_to_append_suffix_to.push('>'); - - // Again, only create type information if full debuginfo is enabled - let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo { - let names = get_parameter_names(cx, generics); - substs.iter().zip(names).filter_map(|(kind, name)| { - if let UnpackedKind::Type(ty) = kind.unpack() { - let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); - let actual_type_metadata = - type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); - let name = CString::new(name.as_str().as_bytes()).unwrap(); - Some(unsafe { - llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( - DIB(cx), - ptr::null_mut(), - name.as_ptr(), - actual_type_metadata, - file_metadata, - 0, - 0) - }) - } else { - None - } - }).collect() - } else { - vec![] - }; - - return create_DIArray(DIB(cx), &template_params[..]); - } - - fn get_parameter_names(cx: &CodegenCx, - generics: &ty::Generics) - -> Vec { - let mut names = generics.parent.map_or(vec![], |def_id| { - get_parameter_names(cx, cx.tcx.generics_of(def_id)) - }); - names.extend(generics.params.iter().map(|param| param.name)); - names - } - - fn get_containing_scope<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>, - instance: Instance<'tcx>) - -> DIScope { - // First, let's see if this is a method within an inherent impl. Because - // if yes, we want to make the result subroutine DIE a child of the - // subroutine's self-type. - let self_type = cx.tcx.impl_of_method(instance.def_id()).and_then(|impl_def_id| { - // If the method does *not* belong to a trait, proceed - if cx.tcx.trait_id_of_impl(impl_def_id).is_none() { - let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions( - instance.substs, - ty::ParamEnv::reveal_all(), - &cx.tcx.type_of(impl_def_id), - ); - - // Only "class" methods are generally understood by LLVM, - // so avoid methods on other types (e.g. `<*mut T>::null`). - match impl_self_ty.sty { - ty::TyAdt(def, ..) if !def.is_box() => { - Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP)) - } - _ => None - } - } else { - // For trait method impls we still use the "parallel namespace" - // strategy - None - } - }); - - self_type.unwrap_or_else(|| { - namespace::item_namespace(cx, DefId { - krate: instance.def_id().krate, - index: cx.tcx - .def_key(instance.def_id()) - .parent - .expect("get_containing_scope: missing parent?") - }) - }) - } -} - -pub fn declare_local<'a, 'tcx>(bx: &Builder<'a, 'tcx>, - dbg_context: &FunctionDebugContext, - variable_name: ast::Name, - variable_type: Ty<'tcx>, - scope_metadata: DIScope, - variable_access: VariableAccess, - variable_kind: VariableKind, - span: Span) { - let cx = bx.cx; - - let file = span_start(cx, span).file; - let file_metadata = file_metadata(cx, - &file.name, - dbg_context.get_ref(span).defining_crate); - - let loc = span_start(cx, span); - let type_metadata = type_metadata(cx, variable_type, span); - - let (argument_index, dwarf_tag) = match variable_kind { - ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable), - LocalVariable | - CapturedVariable => (0, DW_TAG_auto_variable) - }; - let align = cx.align_of(variable_type); - - let name = CString::new(variable_name.as_str().as_bytes()).unwrap(); - match (variable_access, &[][..]) { - (DirectVariable { alloca }, address_operations) | - (IndirectVariable {alloca, address_operations}, _) => { - let metadata = unsafe { - llvm::LLVMRustDIBuilderCreateVariable( - DIB(cx), - dwarf_tag, - scope_metadata, - name.as_ptr(), - file_metadata, - loc.line as c_uint, - type_metadata, - cx.sess().opts.optimize != config::OptLevel::No, - DIFlags::FlagZero, - argument_index, - align.abi() as u32, - ) - }; - source_loc::set_debug_location(bx, - InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize())); - unsafe { - let debug_loc = llvm::LLVMGetCurrentDebugLocation(bx.llbuilder); - let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd( - DIB(cx), - alloca, - metadata, - address_operations.as_ptr(), - address_operations.len() as c_uint, - debug_loc, - bx.llbb()); - - llvm::LLVMSetInstDebugLocation(bx.llbuilder, instr); - } - } - } - - match variable_kind { - ArgumentVariable(_) | CapturedVariable => { - assert!(!dbg_context.get_ref(span).source_locations_enabled.get()); - source_loc::set_debug_location(bx, UnknownLocation); - } - _ => { /* nothing to do */ } - } -} diff --git a/src/librustc_trans/debuginfo/namespace.rs b/src/librustc_trans/debuginfo/namespace.rs deleted file mode 100644 index 51c45de9dc2..00000000000 --- a/src/librustc_trans/debuginfo/namespace.rs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Namespace Handling. - -use super::metadata::{unknown_file_metadata, UNKNOWN_LINE_NUMBER}; -use super::utils::{DIB, debug_context}; -use monomorphize::Instance; -use rustc::ty; - -use llvm; -use llvm::debuginfo::DIScope; -use rustc::hir::def_id::DefId; -use rustc::hir::map::DefPathData; -use common::CodegenCx; - -use std::ffi::CString; -use std::ptr; - -pub fn mangled_name_of_instance<'a, 'tcx>( - cx: &CodegenCx<'a, 'tcx>, - instance: Instance<'tcx>, -) -> ty::SymbolName { - let tcx = cx.tcx; - tcx.symbol_name(instance) -} - -pub fn item_namespace(cx: &CodegenCx, def_id: DefId) -> DIScope { - if let Some(&scope) = debug_context(cx).namespace_map.borrow().get(&def_id) { - return scope; - } - - let def_key = cx.tcx.def_key(def_id); - let parent_scope = def_key.parent.map_or(ptr::null_mut(), |parent| { - item_namespace(cx, DefId { - krate: def_id.krate, - index: parent - }) - }); - - let namespace_name = match def_key.disambiguated_data.data { - DefPathData::CrateRoot => cx.tcx.crate_name(def_id.krate).as_str(), - data => data.as_interned_str().as_str() - }; - - let namespace_name = CString::new(namespace_name.as_bytes()).unwrap(); - - let scope = unsafe { - llvm::LLVMRustDIBuilderCreateNameSpace( - DIB(cx), - parent_scope, - namespace_name.as_ptr(), - unknown_file_metadata(cx), - UNKNOWN_LINE_NUMBER) - }; - - debug_context(cx).namespace_map.borrow_mut().insert(def_id, scope); - scope -} diff --git a/src/librustc_trans/debuginfo/source_loc.rs b/src/librustc_trans/debuginfo/source_loc.rs deleted file mode 100644 index 7440296ce5d..00000000000 --- a/src/librustc_trans/debuginfo/source_loc.rs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use self::InternalDebugLocation::*; - -use super::utils::{debug_context, span_start}; -use super::metadata::UNKNOWN_COLUMN_NUMBER; -use super::FunctionDebugContext; - -use llvm; -use llvm::debuginfo::DIScope; -use builder::Builder; - -use libc::c_uint; -use std::ptr; -use syntax_pos::{Span, Pos}; - -/// Sets the current debug location at the beginning of the span. -/// -/// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...). -pub fn set_source_location( - debug_context: &FunctionDebugContext, bx: &Builder, scope: DIScope, span: Span -) { - let function_debug_context = match *debug_context { - FunctionDebugContext::DebugInfoDisabled => return, - FunctionDebugContext::FunctionWithoutDebugInfo => { - set_debug_location(bx, UnknownLocation); - return; - } - FunctionDebugContext::RegularContext(ref data) => data - }; - - let dbg_loc = if function_debug_context.source_locations_enabled.get() { - debug!("set_source_location: {}", bx.sess().codemap().span_to_string(span)); - let loc = span_start(bx.cx, span); - InternalDebugLocation::new(scope, loc.line, loc.col.to_usize()) - } else { - UnknownLocation - }; - set_debug_location(bx, dbg_loc); -} - -/// Enables emitting source locations for the given functions. -/// -/// Since we don't want source locations to be emitted for the function prelude, -/// they are disabled when beginning to translate a new function. This functions -/// switches source location emitting on and must therefore be called before the -/// first real statement/expression of the function is translated. -pub fn start_emitting_source_locations(dbg_context: &FunctionDebugContext) { - match *dbg_context { - FunctionDebugContext::RegularContext(ref data) => { - data.source_locations_enabled.set(true) - }, - _ => { /* safe to ignore */ } - } -} - - -#[derive(Copy, Clone, PartialEq)] -pub enum InternalDebugLocation { - KnownLocation { scope: DIScope, line: usize, col: usize }, - UnknownLocation -} - -impl InternalDebugLocation { - pub fn new(scope: DIScope, line: usize, col: usize) -> InternalDebugLocation { - KnownLocation { - scope, - line, - col, - } - } -} - -pub fn set_debug_location(bx: &Builder, debug_location: InternalDebugLocation) { - let metadata_node = match debug_location { - KnownLocation { scope, line, .. } => { - // Always set the column to zero like Clang and GCC - let col = UNKNOWN_COLUMN_NUMBER; - debug!("setting debug location to {} {}", line, col); - - unsafe { - llvm::LLVMRustDIBuilderCreateDebugLocation( - debug_context(bx.cx).llcontext, - line as c_uint, - col as c_uint, - scope, - ptr::null_mut()) - } - } - UnknownLocation => { - debug!("clearing debug location "); - ptr::null_mut() - } - }; - - unsafe { - llvm::LLVMSetCurrentDebugLocation(bx.llbuilder, metadata_node); - } -} diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs deleted file mode 100644 index 05a74db3a6c..00000000000 --- a/src/librustc_trans/debuginfo/type_names.rs +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Type Names for Debug Info. - -use common::CodegenCx; -use rustc::hir::def_id::DefId; -use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty}; - -use rustc::hir; - -// Compute the name of the type as it should be stored in debuginfo. Does not do -// any caching, i.e. calling the function twice with the same type will also do -// the work twice. The `qualified` parameter only affects the first level of the -// type name, further levels (i.e. type parameters) are always fully qualified. -pub fn compute_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - t: Ty<'tcx>, - qualified: bool) - -> String { - let mut result = String::with_capacity(64); - push_debuginfo_type_name(cx, t, qualified, &mut result); - result -} - -// Pushes the name of the type as it should be stored in debuginfo on the -// `output` String. See also compute_debuginfo_type_name(). -pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - t: Ty<'tcx>, - qualified: bool, - output: &mut String) { - // When targeting MSVC, emit C++ style type names for compatibility with - // .natvis visualizers (and perhaps other existing native debuggers?) - let cpp_like_names = cx.sess().target.target.options.is_like_msvc; - - match t.sty { - ty::TyBool => output.push_str("bool"), - ty::TyChar => output.push_str("char"), - ty::TyStr => output.push_str("str"), - ty::TyNever => output.push_str("!"), - ty::TyInt(int_ty) => output.push_str(int_ty.ty_to_string()), - ty::TyUint(uint_ty) => output.push_str(uint_ty.ty_to_string()), - ty::TyFloat(float_ty) => output.push_str(float_ty.ty_to_string()), - ty::TyForeign(def_id) => push_item_name(cx, def_id, qualified, output), - ty::TyAdt(def, substs) => { - push_item_name(cx, def.did, qualified, output); - push_type_params(cx, substs, output); - }, - ty::TyTuple(component_types) => { - output.push('('); - for &component_type in component_types { - push_debuginfo_type_name(cx, component_type, true, output); - output.push_str(", "); - } - if !component_types.is_empty() { - output.pop(); - output.pop(); - } - output.push(')'); - }, - ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { - if !cpp_like_names { - output.push('*'); - } - match mutbl { - hir::MutImmutable => output.push_str("const "), - hir::MutMutable => output.push_str("mut "), - } - - push_debuginfo_type_name(cx, inner_type, true, output); - - if cpp_like_names { - output.push('*'); - } - }, - ty::TyRef(_, inner_type, mutbl) => { - if !cpp_like_names { - output.push('&'); - } - if mutbl == hir::MutMutable { - output.push_str("mut "); - } - - push_debuginfo_type_name(cx, inner_type, true, output); - - if cpp_like_names { - output.push('*'); - } - }, - ty::TyArray(inner_type, len) => { - output.push('['); - push_debuginfo_type_name(cx, inner_type, true, output); - output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx))); - output.push(']'); - }, - ty::TySlice(inner_type) => { - if cpp_like_names { - output.push_str("slice<"); - } else { - output.push('['); - } - - push_debuginfo_type_name(cx, inner_type, true, output); - - if cpp_like_names { - output.push('>'); - } else { - output.push(']'); - } - }, - ty::TyDynamic(ref trait_data, ..) => { - if let Some(principal) = trait_data.principal() { - let principal = cx.tcx.normalize_erasing_late_bound_regions( - ty::ParamEnv::reveal_all(), - &principal, - ); - push_item_name(cx, principal.def_id, false, output); - push_type_params(cx, principal.substs, output); - } - }, - ty::TyFnDef(..) | ty::TyFnPtr(_) => { - let sig = t.fn_sig(cx.tcx); - if sig.unsafety() == hir::Unsafety::Unsafe { - output.push_str("unsafe "); - } - - let abi = sig.abi(); - if abi != ::abi::Abi::Rust { - output.push_str("extern \""); - output.push_str(abi.name()); - output.push_str("\" "); - } - - output.push_str("fn("); - - let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - if !sig.inputs().is_empty() { - for ¶meter_type in sig.inputs() { - push_debuginfo_type_name(cx, parameter_type, true, output); - output.push_str(", "); - } - output.pop(); - output.pop(); - } - - if sig.variadic { - if !sig.inputs().is_empty() { - output.push_str(", ..."); - } else { - output.push_str("..."); - } - } - - output.push(')'); - - if !sig.output().is_nil() { - output.push_str(" -> "); - push_debuginfo_type_name(cx, sig.output(), true, output); - } - }, - ty::TyClosure(..) => { - output.push_str("closure"); - } - ty::TyGenerator(..) => { - output.push_str("generator"); - } - ty::TyError | - ty::TyInfer(_) | - ty::TyProjection(..) | - ty::TyAnon(..) | - ty::TyGeneratorWitness(..) | - ty::TyParam(_) => { - bug!("debuginfo: Trying to create type name for \ - unexpected type: {:?}", t); - } - } - - fn push_item_name(cx: &CodegenCx, - def_id: DefId, - qualified: bool, - output: &mut String) { - if qualified { - output.push_str(&cx.tcx.crate_name(def_id.krate).as_str()); - for path_element in cx.tcx.def_path(def_id).data { - output.push_str("::"); - output.push_str(&path_element.data.as_interned_str().as_str()); - } - } else { - output.push_str(&cx.tcx.item_name(def_id).as_str()); - } - } - - // Pushes the type parameters in the given `Substs` to the output string. - // This ignores region parameters, since they can't reliably be - // reconstructed for items from non-local crates. For local crates, this - // would be possible but with inlining and LTO we have to use the least - // common denominator - otherwise we would run into conflicts. - fn push_type_params<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - substs: &Substs<'tcx>, - output: &mut String) { - if substs.types().next().is_none() { - return; - } - - output.push('<'); - - for type_parameter in substs.types() { - push_debuginfo_type_name(cx, type_parameter, true, output); - output.push_str(", "); - } - - output.pop(); - output.pop(); - - output.push('>'); - } -} diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs deleted file mode 100644 index 0a3f06b55f1..00000000000 --- a/src/librustc_trans/debuginfo/utils.rs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Utility Functions. - -use super::{CrateDebugContext}; -use super::namespace::item_namespace; - -use rustc::hir::def_id::DefId; -use rustc::ty::DefIdTree; - -use llvm; -use llvm::debuginfo::{DIScope, DIBuilderRef, DIDescriptor, DIArray}; -use common::{CodegenCx}; - -use syntax_pos::{self, Span}; - -pub fn is_node_local_to_unit(cx: &CodegenCx, def_id: DefId) -> bool -{ - // The is_local_to_unit flag indicates whether a function is local to the - // current compilation unit (i.e. if it is *static* in the C-sense). The - // *reachable* set should provide a good approximation of this, as it - // contains everything that might leak out of the current crate (by being - // externally visible or by being inlined into something externally - // visible). It might better to use the `exported_items` set from - // `driver::CrateAnalysis` in the future, but (atm) this set is not - // available in the translation pass. - !cx.tcx.is_reachable_non_generic(def_id) -} - -#[allow(non_snake_case)] -pub fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray { - return unsafe { - llvm::LLVMRustDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32) - }; -} - -/// Return syntax_pos::Loc corresponding to the beginning of the span -pub fn span_start(cx: &CodegenCx, span: Span) -> syntax_pos::Loc { - cx.sess().codemap().lookup_char_pos(span.lo()) -} - -#[inline] -pub fn debug_context<'a, 'tcx>(cx: &'a CodegenCx<'a, 'tcx>) - -> &'a CrateDebugContext<'tcx> { - cx.dbg_cx.as_ref().unwrap() -} - -#[inline] -#[allow(non_snake_case)] -pub fn DIB(cx: &CodegenCx) -> DIBuilderRef { - cx.dbg_cx.as_ref().unwrap().builder -} - -pub fn get_namespace_for_item(cx: &CodegenCx, def_id: DefId) -> DIScope { - item_namespace(cx, cx.tcx.parent(def_id) - .expect("get_namespace_for_item: missing parent?")) -} diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs deleted file mode 100644 index 97721ffbf06..00000000000 --- a/src/librustc_trans/declare.rs +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -//! Declare various LLVM values. -//! -//! Prefer using functions and methods from this module rather than calling LLVM -//! functions directly. These functions do some additional work to ensure we do -//! the right thing given the preconceptions of trans. -//! -//! Some useful guidelines: -//! -//! * Use declare_* family of methods if you are declaring, but are not -//! interested in defining the ValueRef they return. -//! * Use define_* family of methods when you might be defining the ValueRef. -//! * When in doubt, define. - -use llvm::{self, ValueRef}; -use llvm::AttributePlace::Function; -use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, LayoutOf}; -use rustc::session::config::Sanitizer; -use rustc_target::spec::PanicStrategy; -use abi::{Abi, FnType, FnTypeExt}; -use attributes; -use context::CodegenCx; -use common; -use type_::Type; -use value::Value; - -use std::ffi::CString; - - -/// Declare a global value. -/// -/// If there’s a value with the same name already declared, the function will -/// return its ValueRef instead. -pub fn declare_global(cx: &CodegenCx, name: &str, ty: Type) -> llvm::ValueRef { - debug!("declare_global(name={:?})", name); - let namebuf = CString::new(name).unwrap_or_else(|_|{ - bug!("name {:?} contains an interior null byte", name) - }); - unsafe { - llvm::LLVMRustGetOrInsertGlobal(cx.llmod, namebuf.as_ptr(), ty.to_ref()) - } -} - - -/// Declare a function. -/// -/// If there’s a value with the same name already declared, the function will -/// update the declaration and return existing ValueRef instead. -fn declare_raw_fn(cx: &CodegenCx, name: &str, callconv: llvm::CallConv, ty: Type) -> ValueRef { - debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty); - let namebuf = CString::new(name).unwrap_or_else(|_|{ - bug!("name {:?} contains an interior null byte", name) - }); - let llfn = unsafe { - llvm::LLVMRustGetOrInsertFunction(cx.llmod, namebuf.as_ptr(), ty.to_ref()) - }; - - llvm::SetFunctionCallConv(llfn, callconv); - // Function addresses in Rust are never significant, allowing functions to - // be merged. - llvm::SetUnnamedAddr(llfn, true); - - if cx.tcx.sess.opts.cg.no_redzone - .unwrap_or(cx.tcx.sess.target.target.options.disable_redzone) { - llvm::Attribute::NoRedZone.apply_llfn(Function, llfn); - } - - if let Some(ref sanitizer) = cx.tcx.sess.opts.debugging_opts.sanitizer { - match *sanitizer { - Sanitizer::Address => { - llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn); - }, - Sanitizer::Memory => { - llvm::Attribute::SanitizeMemory.apply_llfn(Function, llfn); - }, - Sanitizer::Thread => { - llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn); - }, - _ => {} - } - } - - match cx.tcx.sess.opts.cg.opt_level.as_ref().map(String::as_ref) { - Some("s") => { - llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); - }, - Some("z") => { - llvm::Attribute::MinSize.apply_llfn(Function, llfn); - llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); - }, - _ => {}, - } - - if cx.tcx.sess.panic_strategy() != PanicStrategy::Unwind { - attributes::unwind(llfn, false); - } - - llfn -} - - -/// Declare a C ABI function. -/// -/// Only use this for foreign function ABIs and glue. For Rust functions use -/// `declare_fn` instead. -/// -/// If there’s a value with the same name already declared, the function will -/// update the declaration and return existing ValueRef instead. -pub fn declare_cfn(cx: &CodegenCx, name: &str, fn_type: Type) -> ValueRef { - declare_raw_fn(cx, name, llvm::CCallConv, fn_type) -} - - -/// Declare a Rust function. -/// -/// If there’s a value with the same name already declared, the function will -/// update the declaration and return existing ValueRef instead. -pub fn declare_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, name: &str, - fn_type: Ty<'tcx>) -> ValueRef { - debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type); - let sig = common::ty_fn_sig(cx, fn_type); - let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - debug!("declare_rust_fn (after region erasure) sig={:?}", sig); - - let fty = FnType::new(cx, sig, &[]); - let llfn = declare_raw_fn(cx, name, fty.llvm_cconv(), fty.llvm_type(cx)); - - if cx.layout_of(sig.output()).abi == layout::Abi::Uninhabited { - llvm::Attribute::NoReturn.apply_llfn(Function, llfn); - } - - if sig.abi != Abi::Rust && sig.abi != Abi::RustCall { - attributes::unwind(llfn, false); - } - - fty.apply_attrs_llfn(llfn); - - llfn -} - - -/// Declare a global with an intention to define it. -/// -/// Use this function when you intend to define a global. This function will -/// return None if the name already has a definition associated with it. In that -/// case an error should be reported to the user, because it usually happens due -/// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes). -pub fn define_global(cx: &CodegenCx, name: &str, ty: Type) -> Option { - if get_defined_value(cx, name).is_some() { - None - } else { - Some(declare_global(cx, name, ty)) - } -} - -/// Declare a Rust function with an intention to define it. -/// -/// Use this function when you intend to define a function. This function will -/// return panic if the name already has a definition associated with it. This -/// can happen with #[no_mangle] or #[export_name], for example. -pub fn define_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - name: &str, - fn_type: Ty<'tcx>) -> ValueRef { - if get_defined_value(cx, name).is_some() { - cx.sess().fatal(&format!("symbol `{}` already defined", name)) - } else { - declare_fn(cx, name, fn_type) - } -} - -/// Declare a Rust function with an intention to define it. -/// -/// Use this function when you intend to define a function. This function will -/// return panic if the name already has a definition associated with it. This -/// can happen with #[no_mangle] or #[export_name], for example. -pub fn define_internal_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - name: &str, - fn_type: Ty<'tcx>) -> ValueRef { - let llfn = define_fn(cx, name, fn_type); - unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) }; - llfn -} - - -/// Get declared value by name. -pub fn get_declared_value(cx: &CodegenCx, name: &str) -> Option { - debug!("get_declared_value(name={:?})", name); - let namebuf = CString::new(name).unwrap_or_else(|_|{ - bug!("name {:?} contains an interior null byte", name) - }); - let val = unsafe { llvm::LLVMRustGetNamedValue(cx.llmod, namebuf.as_ptr()) }; - if val.is_null() { - debug!("get_declared_value: {:?} value is null", name); - None - } else { - debug!("get_declared_value: {:?} => {:?}", name, Value(val)); - Some(val) - } -} - -/// Get defined or externally defined (AvailableExternally linkage) value by -/// name. -pub fn get_defined_value(cx: &CodegenCx, name: &str) -> Option { - get_declared_value(cx, name).and_then(|val|{ - let declaration = unsafe { - llvm::LLVMIsDeclaration(val) != 0 - }; - if !declaration { - Some(val) - } else { - None - } - }) -} diff --git a/src/librustc_trans/diagnostics.rs b/src/librustc_trans/diagnostics.rs deleted file mode 100644 index 57cc33d09bb..00000000000 --- a/src/librustc_trans/diagnostics.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_snake_case)] - -register_long_diagnostics! { - -E0511: r##" -Invalid monomorphization of an intrinsic function was used. Erroneous code -example: - -```ignore (error-emitted-at-codegen-which-cannot-be-handled-by-compile_fail) -#![feature(platform_intrinsics)] - -extern "platform-intrinsic" { - fn simd_add(a: T, b: T) -> T; -} - -fn main() { - unsafe { simd_add(0, 1); } - // error: invalid monomorphization of `simd_add` intrinsic -} -``` - -The generic type has to be a SIMD type. Example: - -``` -#![feature(repr_simd)] -#![feature(platform_intrinsics)] - -#[repr(simd)] -#[derive(Copy, Clone)] -struct i32x2(i32, i32); - -extern "platform-intrinsic" { - fn simd_add(a: T, b: T) -> T; -} - -unsafe { simd_add(i32x2(0, 0), i32x2(1, 2)); } // ok! -``` -"##, - -} - - -register_diagnostics! { - E0558 -} diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs deleted file mode 100644 index c7275d09401..00000000000 --- a/src/librustc_trans/glue.rs +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! -// -// Code relating to drop glue. - -use std; - -use builder::Builder; -use common::*; -use llvm::{ValueRef}; -use llvm; -use meth; -use rustc::ty::layout::LayoutOf; -use rustc::ty::{self, Ty}; -use value::Value; - -pub fn size_and_align_of_dst<'a, 'tcx>(bx: &Builder<'a, 'tcx>, t: Ty<'tcx>, info: ValueRef) - -> (ValueRef, ValueRef) { - debug!("calculate size of DST: {}; with lost info: {:?}", - t, Value(info)); - if bx.cx.type_is_sized(t) { - let (size, align) = bx.cx.size_and_align_of(t); - debug!("size_and_align_of_dst t={} info={:?} size: {:?} align: {:?}", - t, Value(info), size, align); - let size = C_usize(bx.cx, size.bytes()); - let align = C_usize(bx.cx, align.abi()); - return (size, align); - } - assert!(!info.is_null()); - match t.sty { - ty::TyDynamic(..) => { - // load size/align from vtable - (meth::SIZE.get_usize(bx, info), meth::ALIGN.get_usize(bx, info)) - } - ty::TySlice(_) | ty::TyStr => { - let unit = t.sequence_element_type(bx.tcx()); - // The info in this case is the length of the str, so the size is that - // times the unit size. - let (size, align) = bx.cx.size_and_align_of(unit); - (bx.mul(info, C_usize(bx.cx, size.bytes())), - C_usize(bx.cx, align.abi())) - } - _ => { - let cx = bx.cx; - // First get the size of all statically known fields. - // Don't use size_of because it also rounds up to alignment, which we - // want to avoid, as the unsized field's alignment could be smaller. - assert!(!t.is_simd()); - let layout = cx.layout_of(t); - debug!("DST {} layout: {:?}", t, layout); - - let i = layout.fields.count() - 1; - let sized_size = layout.fields.offset(i).bytes(); - let sized_align = layout.align.abi(); - debug!("DST {} statically sized prefix size: {} align: {}", - t, sized_size, sized_align); - let sized_size = C_usize(cx, sized_size); - let sized_align = C_usize(cx, sized_align); - - // Recurse to get the size of the dynamically sized field (must be - // the last field). - let field_ty = layout.field(cx, i).ty; - let (unsized_size, mut unsized_align) = size_and_align_of_dst(bx, field_ty, info); - - // FIXME (#26403, #27023): We should be adding padding - // to `sized_size` (to accommodate the `unsized_align` - // required of the unsized field that follows) before - // summing it with `sized_size`. (Note that since #26403 - // is unfixed, we do not yet add the necessary padding - // here. But this is where the add would go.) - - // Return the sum of sizes and max of aligns. - let size = bx.add(sized_size, unsized_size); - - // Packed types ignore the alignment of their fields. - if let ty::TyAdt(def, _) = t.sty { - if def.repr.packed() { - unsized_align = sized_align; - } - } - - // Choose max of two known alignments (combined value must - // be aligned according to more restrictive of the two). - let align = match (const_to_opt_u128(sized_align, false), - const_to_opt_u128(unsized_align, false)) { - (Some(sized_align), Some(unsized_align)) => { - // If both alignments are constant, (the sized_align should always be), then - // pick the correct alignment statically. - C_usize(cx, std::cmp::max(sized_align, unsized_align) as u64) - } - _ => bx.select(bx.icmp(llvm::IntUGT, sized_align, unsized_align), - sized_align, - unsized_align) - }; - - // Issue #27023: must add any necessary padding to `size` - // (to make it a multiple of `align`) before returning it. - // - // Namely, the returned size should be, in C notation: - // - // `size + ((size & (align-1)) ? align : 0)` - // - // emulated via the semi-standard fast bit trick: - // - // `(size + (align-1)) & -align` - - let addend = bx.sub(align, C_usize(bx.cx, 1)); - let size = bx.and(bx.add(size, addend), bx.neg(align)); - - (size, align) - } - } -} diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs deleted file mode 100644 index 86aa48b6a9e..00000000000 --- a/src/librustc_trans/intrinsic.rs +++ /dev/null @@ -1,1465 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_upper_case_globals)] - -use intrinsics::{self, Intrinsic}; -use llvm; -use llvm::{ValueRef}; -use abi::{Abi, FnType, LlvmType, PassMode}; -use mir::place::PlaceRef; -use mir::operand::{OperandRef, OperandValue}; -use base::*; -use common::*; -use declare; -use glue; -use type_::Type; -use type_of::LayoutLlvmExt; -use rustc::ty::{self, Ty}; -use rustc::ty::layout::{HasDataLayout, LayoutOf}; -use rustc::hir; -use syntax::ast; -use syntax::symbol::Symbol; -use builder::Builder; - -use rustc::session::Session; -use syntax_pos::Span; - -use std::cmp::Ordering; -use std::iter; - -fn get_simple_intrinsic(cx: &CodegenCx, name: &str) -> Option { - let llvm_name = match name { - "sqrtf32" => "llvm.sqrt.f32", - "sqrtf64" => "llvm.sqrt.f64", - "powif32" => "llvm.powi.f32", - "powif64" => "llvm.powi.f64", - "sinf32" => "llvm.sin.f32", - "sinf64" => "llvm.sin.f64", - "cosf32" => "llvm.cos.f32", - "cosf64" => "llvm.cos.f64", - "powf32" => "llvm.pow.f32", - "powf64" => "llvm.pow.f64", - "expf32" => "llvm.exp.f32", - "expf64" => "llvm.exp.f64", - "exp2f32" => "llvm.exp2.f32", - "exp2f64" => "llvm.exp2.f64", - "logf32" => "llvm.log.f32", - "logf64" => "llvm.log.f64", - "log10f32" => "llvm.log10.f32", - "log10f64" => "llvm.log10.f64", - "log2f32" => "llvm.log2.f32", - "log2f64" => "llvm.log2.f64", - "fmaf32" => "llvm.fma.f32", - "fmaf64" => "llvm.fma.f64", - "fabsf32" => "llvm.fabs.f32", - "fabsf64" => "llvm.fabs.f64", - "copysignf32" => "llvm.copysign.f32", - "copysignf64" => "llvm.copysign.f64", - "floorf32" => "llvm.floor.f32", - "floorf64" => "llvm.floor.f64", - "ceilf32" => "llvm.ceil.f32", - "ceilf64" => "llvm.ceil.f64", - "truncf32" => "llvm.trunc.f32", - "truncf64" => "llvm.trunc.f64", - "rintf32" => "llvm.rint.f32", - "rintf64" => "llvm.rint.f64", - "nearbyintf32" => "llvm.nearbyint.f32", - "nearbyintf64" => "llvm.nearbyint.f64", - "roundf32" => "llvm.round.f32", - "roundf64" => "llvm.round.f64", - "assume" => "llvm.assume", - "abort" => "llvm.trap", - _ => return None - }; - Some(cx.get_intrinsic(&llvm_name)) -} - -/// Remember to add all intrinsics here, in librustc_typeck/check/mod.rs, -/// and in libcore/intrinsics.rs; if you need access to any llvm intrinsics, -/// add them to librustc_trans/trans/context.rs -pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, - callee_ty: Ty<'tcx>, - fn_ty: &FnType<'tcx, Ty<'tcx>>, - args: &[OperandRef<'tcx>], - llresult: ValueRef, - span: Span) { - let cx = bx.cx; - let tcx = cx.tcx; - - let (def_id, substs) = match callee_ty.sty { - ty::TyFnDef(def_id, substs) => (def_id, substs), - _ => bug!("expected fn item type, found {}", callee_ty) - }; - - let sig = callee_ty.fn_sig(tcx); - let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - let arg_tys = sig.inputs(); - let ret_ty = sig.output(); - let name = &*tcx.item_name(def_id).as_str(); - - let llret_ty = cx.layout_of(ret_ty).llvm_type(cx); - let result = PlaceRef::new_sized(llresult, fn_ty.ret.layout, fn_ty.ret.layout.align); - - let simple = get_simple_intrinsic(cx, name); - let llval = match name { - _ if simple.is_some() => { - bx.call(simple.unwrap(), - &args.iter().map(|arg| arg.immediate()).collect::>(), - None) - } - "unreachable" => { - return; - }, - "likely" => { - let expect = cx.get_intrinsic(&("llvm.expect.i1")); - bx.call(expect, &[args[0].immediate(), C_bool(cx, true)], None) - } - "unlikely" => { - let expect = cx.get_intrinsic(&("llvm.expect.i1")); - bx.call(expect, &[args[0].immediate(), C_bool(cx, false)], None) - } - "try" => { - try_intrinsic(bx, cx, - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - llresult); - return; - } - "breakpoint" => { - let llfn = cx.get_intrinsic(&("llvm.debugtrap")); - bx.call(llfn, &[], None) - } - "size_of" => { - let tp_ty = substs.type_at(0); - C_usize(cx, cx.size_of(tp_ty).bytes()) - } - "size_of_val" => { - let tp_ty = substs.type_at(0); - if let OperandValue::Pair(_, meta) = args[0].val { - let (llsize, _) = - glue::size_and_align_of_dst(bx, tp_ty, meta); - llsize - } else { - C_usize(cx, cx.size_of(tp_ty).bytes()) - } - } - "min_align_of" => { - let tp_ty = substs.type_at(0); - C_usize(cx, cx.align_of(tp_ty).abi()) - } - "min_align_of_val" => { - let tp_ty = substs.type_at(0); - if let OperandValue::Pair(_, meta) = args[0].val { - let (_, llalign) = - glue::size_and_align_of_dst(bx, tp_ty, meta); - llalign - } else { - C_usize(cx, cx.align_of(tp_ty).abi()) - } - } - "pref_align_of" => { - let tp_ty = substs.type_at(0); - C_usize(cx, cx.align_of(tp_ty).pref()) - } - "type_name" => { - let tp_ty = substs.type_at(0); - let ty_name = Symbol::intern(&tp_ty.to_string()).as_str(); - C_str_slice(cx, ty_name) - } - "type_id" => { - C_u64(cx, cx.tcx.type_id_hash(substs.type_at(0))) - } - "init" => { - let ty = substs.type_at(0); - if !cx.layout_of(ty).is_zst() { - // Just zero out the stack slot. - // If we store a zero constant, LLVM will drown in vreg allocation for large data - // structures, and the generated code will be awful. (A telltale sign of this is - // large quantities of `mov [byte ptr foo],0` in the generated code.) - memset_intrinsic(bx, false, ty, llresult, C_u8(cx, 0), C_usize(cx, 1)); - } - return; - } - // Effectively no-ops - "uninit" => { - return; - } - "needs_drop" => { - let tp_ty = substs.type_at(0); - - C_bool(cx, bx.cx.type_needs_drop(tp_ty)) - } - "offset" => { - let ptr = args[0].immediate(); - let offset = args[1].immediate(); - bx.inbounds_gep(ptr, &[offset]) - } - "arith_offset" => { - let ptr = args[0].immediate(); - let offset = args[1].immediate(); - bx.gep(ptr, &[offset]) - } - - "copy_nonoverlapping" => { - copy_intrinsic(bx, false, false, substs.type_at(0), - args[1].immediate(), args[0].immediate(), args[2].immediate()) - } - "copy" => { - copy_intrinsic(bx, true, false, substs.type_at(0), - args[1].immediate(), args[0].immediate(), args[2].immediate()) - } - "write_bytes" => { - memset_intrinsic(bx, false, substs.type_at(0), - args[0].immediate(), args[1].immediate(), args[2].immediate()) - } - - "volatile_copy_nonoverlapping_memory" => { - copy_intrinsic(bx, false, true, substs.type_at(0), - args[0].immediate(), args[1].immediate(), args[2].immediate()) - } - "volatile_copy_memory" => { - copy_intrinsic(bx, true, true, substs.type_at(0), - args[0].immediate(), args[1].immediate(), args[2].immediate()) - } - "volatile_set_memory" => { - memset_intrinsic(bx, true, substs.type_at(0), - args[0].immediate(), args[1].immediate(), args[2].immediate()) - } - "volatile_load" => { - let tp_ty = substs.type_at(0); - let mut ptr = args[0].immediate(); - if let PassMode::Cast(ty) = fn_ty.ret.mode { - ptr = bx.pointercast(ptr, ty.llvm_type(cx).ptr_to()); - } - let load = bx.volatile_load(ptr); - unsafe { - llvm::LLVMSetAlignment(load, cx.align_of(tp_ty).abi() as u32); - } - to_immediate(bx, load, cx.layout_of(tp_ty)) - }, - "volatile_store" => { - let dst = args[0].deref(bx.cx); - args[1].val.volatile_store(bx, dst); - return; - }, - "prefetch_read_data" | "prefetch_write_data" | - "prefetch_read_instruction" | "prefetch_write_instruction" => { - let expect = cx.get_intrinsic(&("llvm.prefetch")); - let (rw, cache_type) = match name { - "prefetch_read_data" => (0, 1), - "prefetch_write_data" => (1, 1), - "prefetch_read_instruction" => (0, 0), - "prefetch_write_instruction" => (1, 0), - _ => bug!() - }; - bx.call(expect, &[ - args[0].immediate(), - C_i32(cx, rw), - args[1].immediate(), - C_i32(cx, cache_type) - ], None) - }, - "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" | - "bitreverse" | "add_with_overflow" | "sub_with_overflow" | - "mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" | - "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" => { - let ty = arg_tys[0]; - match int_type_width_signed(ty, cx) { - Some((width, signed)) => - match name { - "ctlz" | "cttz" => { - let y = C_bool(bx.cx, false); - let llfn = cx.get_intrinsic(&format!("llvm.{}.i{}", name, width)); - bx.call(llfn, &[args[0].immediate(), y], None) - } - "ctlz_nonzero" | "cttz_nonzero" => { - let y = C_bool(bx.cx, true); - let llvm_name = &format!("llvm.{}.i{}", &name[..4], width); - let llfn = cx.get_intrinsic(llvm_name); - bx.call(llfn, &[args[0].immediate(), y], None) - } - "ctpop" => bx.call(cx.get_intrinsic(&format!("llvm.ctpop.i{}", width)), - &[args[0].immediate()], None), - "bswap" => { - if width == 8 { - args[0].immediate() // byte swap a u8/i8 is just a no-op - } else { - bx.call(cx.get_intrinsic(&format!("llvm.bswap.i{}", width)), - &[args[0].immediate()], None) - } - } - "bitreverse" => { - bx.call(cx.get_intrinsic(&format!("llvm.bitreverse.i{}", width)), - &[args[0].immediate()], None) - } - "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => { - let intrinsic = format!("llvm.{}{}.with.overflow.i{}", - if signed { 's' } else { 'u' }, - &name[..3], width); - let llfn = bx.cx.get_intrinsic(&intrinsic); - - // Convert `i1` to a `bool`, and write it to the out parameter - let pair = bx.call(llfn, &[ - args[0].immediate(), - args[1].immediate() - ], None); - let val = bx.extract_value(pair, 0); - let overflow = bx.zext(bx.extract_value(pair, 1), Type::bool(cx)); - - let dest = result.project_field(bx, 0); - bx.store(val, dest.llval, dest.align); - let dest = result.project_field(bx, 1); - bx.store(overflow, dest.llval, dest.align); - - return; - }, - "overflowing_add" => bx.add(args[0].immediate(), args[1].immediate()), - "overflowing_sub" => bx.sub(args[0].immediate(), args[1].immediate()), - "overflowing_mul" => bx.mul(args[0].immediate(), args[1].immediate()), - "exact_div" => - if signed { - bx.exactsdiv(args[0].immediate(), args[1].immediate()) - } else { - bx.exactudiv(args[0].immediate(), args[1].immediate()) - }, - "unchecked_div" => - if signed { - bx.sdiv(args[0].immediate(), args[1].immediate()) - } else { - bx.udiv(args[0].immediate(), args[1].immediate()) - }, - "unchecked_rem" => - if signed { - bx.srem(args[0].immediate(), args[1].immediate()) - } else { - bx.urem(args[0].immediate(), args[1].immediate()) - }, - "unchecked_shl" => bx.shl(args[0].immediate(), args[1].immediate()), - "unchecked_shr" => - if signed { - bx.ashr(args[0].immediate(), args[1].immediate()) - } else { - bx.lshr(args[0].immediate(), args[1].immediate()) - }, - _ => bug!(), - }, - None => { - span_invalid_monomorphization_error( - tcx.sess, span, - &format!("invalid monomorphization of `{}` intrinsic: \ - expected basic integer type, found `{}`", name, ty)); - return; - } - } - - }, - "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { - let sty = &arg_tys[0].sty; - match float_type_width(sty) { - Some(_width) => - match name { - "fadd_fast" => bx.fadd_fast(args[0].immediate(), args[1].immediate()), - "fsub_fast" => bx.fsub_fast(args[0].immediate(), args[1].immediate()), - "fmul_fast" => bx.fmul_fast(args[0].immediate(), args[1].immediate()), - "fdiv_fast" => bx.fdiv_fast(args[0].immediate(), args[1].immediate()), - "frem_fast" => bx.frem_fast(args[0].immediate(), args[1].immediate()), - _ => bug!(), - }, - None => { - span_invalid_monomorphization_error( - tcx.sess, span, - &format!("invalid monomorphization of `{}` intrinsic: \ - expected basic float type, found `{}`", name, sty)); - return; - } - } - - }, - - "discriminant_value" => { - args[0].deref(bx.cx).trans_get_discr(bx, ret_ty) - } - - "align_offset" => { - // `ptr as usize` - let ptr_val = bx.ptrtoint(args[0].immediate(), bx.cx.isize_ty); - // `ptr_val % align` - let align = args[1].immediate(); - let offset = bx.urem(ptr_val, align); - let zero = C_null(bx.cx.isize_ty); - // `offset == 0` - let is_zero = bx.icmp(llvm::IntPredicate::IntEQ, offset, zero); - // `if offset == 0 { 0 } else { align - offset }` - bx.select(is_zero, zero, bx.sub(align, offset)) - } - name if name.starts_with("simd_") => { - match generic_simd_intrinsic(bx, name, - callee_ty, - args, - ret_ty, llret_ty, - span) { - Ok(llval) => llval, - Err(()) => return - } - } - // This requires that atomic intrinsics follow a specific naming pattern: - // "atomic_[_]", and no ordering means SeqCst - name if name.starts_with("atomic_") => { - use llvm::AtomicOrdering::*; - - let split: Vec<&str> = name.split('_').collect(); - - let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak"; - let (order, failorder) = match split.len() { - 2 => (SequentiallyConsistent, SequentiallyConsistent), - 3 => match split[2] { - "unordered" => (Unordered, Unordered), - "relaxed" => (Monotonic, Monotonic), - "acq" => (Acquire, Acquire), - "rel" => (Release, Monotonic), - "acqrel" => (AcquireRelease, Acquire), - "failrelaxed" if is_cxchg => - (SequentiallyConsistent, Monotonic), - "failacq" if is_cxchg => - (SequentiallyConsistent, Acquire), - _ => cx.sess().fatal("unknown ordering in atomic intrinsic") - }, - 4 => match (split[2], split[3]) { - ("acq", "failrelaxed") if is_cxchg => - (Acquire, Monotonic), - ("acqrel", "failrelaxed") if is_cxchg => - (AcquireRelease, Monotonic), - _ => cx.sess().fatal("unknown ordering in atomic intrinsic") - }, - _ => cx.sess().fatal("Atomic intrinsic not in correct format"), - }; - - let invalid_monomorphization = |ty| { - span_invalid_monomorphization_error(tcx.sess, span, - &format!("invalid monomorphization of `{}` intrinsic: \ - expected basic integer type, found `{}`", name, ty)); - }; - - match split[1] { - "cxchg" | "cxchgweak" => { - let ty = substs.type_at(0); - if int_type_width_signed(ty, cx).is_some() { - let weak = if split[1] == "cxchgweak" { llvm::True } else { llvm::False }; - let pair = bx.atomic_cmpxchg( - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - order, - failorder, - weak); - let val = bx.extract_value(pair, 0); - let success = bx.zext(bx.extract_value(pair, 1), Type::bool(bx.cx)); - - let dest = result.project_field(bx, 0); - bx.store(val, dest.llval, dest.align); - let dest = result.project_field(bx, 1); - bx.store(success, dest.llval, dest.align); - return; - } else { - return invalid_monomorphization(ty); - } - } - - "load" => { - let ty = substs.type_at(0); - if int_type_width_signed(ty, cx).is_some() { - let align = cx.align_of(ty); - bx.atomic_load(args[0].immediate(), order, align) - } else { - return invalid_monomorphization(ty); - } - } - - "store" => { - let ty = substs.type_at(0); - if int_type_width_signed(ty, cx).is_some() { - let align = cx.align_of(ty); - bx.atomic_store(args[1].immediate(), args[0].immediate(), order, align); - return; - } else { - return invalid_monomorphization(ty); - } - } - - "fence" => { - bx.atomic_fence(order, llvm::SynchronizationScope::CrossThread); - return; - } - - "singlethreadfence" => { - bx.atomic_fence(order, llvm::SynchronizationScope::SingleThread); - return; - } - - // These are all AtomicRMW ops - op => { - let atom_op = match op { - "xchg" => llvm::AtomicXchg, - "xadd" => llvm::AtomicAdd, - "xsub" => llvm::AtomicSub, - "and" => llvm::AtomicAnd, - "nand" => llvm::AtomicNand, - "or" => llvm::AtomicOr, - "xor" => llvm::AtomicXor, - "max" => llvm::AtomicMax, - "min" => llvm::AtomicMin, - "umax" => llvm::AtomicUMax, - "umin" => llvm::AtomicUMin, - _ => cx.sess().fatal("unknown atomic operation") - }; - - let ty = substs.type_at(0); - if int_type_width_signed(ty, cx).is_some() { - bx.atomic_rmw(atom_op, args[0].immediate(), args[1].immediate(), order) - } else { - return invalid_monomorphization(ty); - } - } - } - } - - "nontemporal_store" => { - let dst = args[0].deref(bx.cx); - args[1].val.nontemporal_store(bx, dst); - return; - } - - _ => { - let intr = match Intrinsic::find(&name) { - Some(intr) => intr, - None => bug!("unknown intrinsic '{}'", name), - }; - fn one(x: Vec) -> T { - assert_eq!(x.len(), 1); - x.into_iter().next().unwrap() - } - fn ty_to_type(cx: &CodegenCx, t: &intrinsics::Type) -> Vec { - use intrinsics::Type::*; - match *t { - Void => vec![Type::void(cx)], - Integer(_signed, _width, llvm_width) => { - vec![Type::ix(cx, llvm_width as u64)] - } - Float(x) => { - match x { - 32 => vec![Type::f32(cx)], - 64 => vec![Type::f64(cx)], - _ => bug!() - } - } - Pointer(ref t, ref llvm_elem, _const) => { - let t = llvm_elem.as_ref().unwrap_or(t); - let elem = one(ty_to_type(cx, t)); - vec![elem.ptr_to()] - } - Vector(ref t, ref llvm_elem, length) => { - let t = llvm_elem.as_ref().unwrap_or(t); - let elem = one(ty_to_type(cx, t)); - vec![Type::vector(&elem, length as u64)] - } - Aggregate(false, ref contents) => { - let elems = contents.iter() - .map(|t| one(ty_to_type(cx, t))) - .collect::>(); - vec![Type::struct_(cx, &elems, false)] - } - Aggregate(true, ref contents) => { - contents.iter() - .flat_map(|t| ty_to_type(cx, t)) - .collect() - } - } - } - - // This allows an argument list like `foo, (bar, baz), - // qux` to be converted into `foo, bar, baz, qux`, integer - // arguments to be truncated as needed and pointers to be - // cast. - fn modify_as_needed<'a, 'tcx>(bx: &Builder<'a, 'tcx>, - t: &intrinsics::Type, - arg: &OperandRef<'tcx>) - -> Vec - { - match *t { - intrinsics::Type::Aggregate(true, ref contents) => { - // We found a tuple that needs squishing! So - // run over the tuple and load each field. - // - // This assumes the type is "simple", i.e. no - // destructors, and the contents are SIMD - // etc. - assert!(!bx.cx.type_needs_drop(arg.layout.ty)); - let (ptr, align) = match arg.val { - OperandValue::Ref(ptr, align) => (ptr, align), - _ => bug!() - }; - let arg = PlaceRef::new_sized(ptr, arg.layout, align); - (0..contents.len()).map(|i| { - arg.project_field(bx, i).load(bx).immediate() - }).collect() - } - intrinsics::Type::Pointer(_, Some(ref llvm_elem), _) => { - let llvm_elem = one(ty_to_type(bx.cx, llvm_elem)); - vec![bx.pointercast(arg.immediate(), llvm_elem.ptr_to())] - } - intrinsics::Type::Vector(_, Some(ref llvm_elem), length) => { - let llvm_elem = one(ty_to_type(bx.cx, llvm_elem)); - vec![bx.bitcast(arg.immediate(), Type::vector(&llvm_elem, length as u64))] - } - intrinsics::Type::Integer(_, width, llvm_width) if width != llvm_width => { - // the LLVM intrinsic uses a smaller integer - // size than the C intrinsic's signature, so - // we have to trim it down here. - vec![bx.trunc(arg.immediate(), Type::ix(bx.cx, llvm_width as u64))] - } - _ => vec![arg.immediate()], - } - } - - - let inputs = intr.inputs.iter() - .flat_map(|t| ty_to_type(cx, t)) - .collect::>(); - - let outputs = one(ty_to_type(cx, &intr.output)); - - let llargs: Vec<_> = intr.inputs.iter().zip(args).flat_map(|(t, arg)| { - modify_as_needed(bx, t, arg) - }).collect(); - assert_eq!(inputs.len(), llargs.len()); - - let val = match intr.definition { - intrinsics::IntrinsicDef::Named(name) => { - let f = declare::declare_cfn(cx, - name, - Type::func(&inputs, &outputs)); - bx.call(f, &llargs, None) - } - }; - - match *intr.output { - intrinsics::Type::Aggregate(flatten, ref elems) => { - // the output is a tuple so we need to munge it properly - assert!(!flatten); - - for i in 0..elems.len() { - let dest = result.project_field(bx, i); - let val = bx.extract_value(val, i as u64); - bx.store(val, dest.llval, dest.align); - } - return; - } - _ => val, - } - } - }; - - if !fn_ty.ret.is_ignore() { - if let PassMode::Cast(ty) = fn_ty.ret.mode { - let ptr = bx.pointercast(result.llval, ty.llvm_type(cx).ptr_to()); - bx.store(llval, ptr, result.align); - } else { - OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout) - .val.store(bx, result); - } - } -} - -fn copy_intrinsic<'a, 'tcx>(bx: &Builder<'a, 'tcx>, - allow_overlap: bool, - volatile: bool, - ty: Ty<'tcx>, - dst: ValueRef, - src: ValueRef, - count: ValueRef) - -> ValueRef { - let cx = bx.cx; - let (size, align) = cx.size_and_align_of(ty); - let size = C_usize(cx, size.bytes()); - let align = C_i32(cx, align.abi() as i32); - - let operation = if allow_overlap { - "memmove" - } else { - "memcpy" - }; - - let name = format!("llvm.{}.p0i8.p0i8.i{}", operation, - cx.data_layout().pointer_size.bits()); - - let dst_ptr = bx.pointercast(dst, Type::i8p(cx)); - let src_ptr = bx.pointercast(src, Type::i8p(cx)); - let llfn = cx.get_intrinsic(&name); - - bx.call(llfn, - &[dst_ptr, - src_ptr, - bx.mul(size, count), - align, - C_bool(cx, volatile)], - None) -} - -fn memset_intrinsic<'a, 'tcx>( - bx: &Builder<'a, 'tcx>, - volatile: bool, - ty: Ty<'tcx>, - dst: ValueRef, - val: ValueRef, - count: ValueRef -) -> ValueRef { - let cx = bx.cx; - let (size, align) = cx.size_and_align_of(ty); - let size = C_usize(cx, size.bytes()); - let align = C_i32(cx, align.abi() as i32); - let dst = bx.pointercast(dst, Type::i8p(cx)); - call_memset(bx, dst, val, bx.mul(size, count), align, volatile) -} - -fn try_intrinsic<'a, 'tcx>( - bx: &Builder<'a, 'tcx>, - cx: &CodegenCx, - func: ValueRef, - data: ValueRef, - local_ptr: ValueRef, - dest: ValueRef, -) { - if bx.sess().no_landing_pads() { - bx.call(func, &[data], None); - let ptr_align = bx.tcx().data_layout.pointer_align; - bx.store(C_null(Type::i8p(&bx.cx)), dest, ptr_align); - } else if wants_msvc_seh(bx.sess()) { - trans_msvc_try(bx, cx, func, data, local_ptr, dest); - } else { - trans_gnu_try(bx, cx, func, data, local_ptr, dest); - } -} - -// MSVC's definition of the `rust_try` function. -// -// This implementation uses the new exception handling instructions in LLVM -// which have support in LLVM for SEH on MSVC targets. Although these -// instructions are meant to work for all targets, as of the time of this -// writing, however, LLVM does not recommend the usage of these new instructions -// as the old ones are still more optimized. -fn trans_msvc_try<'a, 'tcx>(bx: &Builder<'a, 'tcx>, - cx: &CodegenCx, - func: ValueRef, - data: ValueRef, - local_ptr: ValueRef, - dest: ValueRef) { - let llfn = get_rust_try_fn(cx, &mut |bx| { - let cx = bx.cx; - - bx.set_personality_fn(bx.cx.eh_personality()); - - let normal = bx.build_sibling_block("normal"); - let catchswitch = bx.build_sibling_block("catchswitch"); - let catchpad = bx.build_sibling_block("catchpad"); - let caught = bx.build_sibling_block("caught"); - - let func = llvm::get_param(bx.llfn(), 0); - let data = llvm::get_param(bx.llfn(), 1); - let local_ptr = llvm::get_param(bx.llfn(), 2); - - // We're generating an IR snippet that looks like: - // - // declare i32 @rust_try(%func, %data, %ptr) { - // %slot = alloca i64* - // invoke %func(%data) to label %normal unwind label %catchswitch - // - // normal: - // ret i32 0 - // - // catchswitch: - // %cs = catchswitch within none [%catchpad] unwind to caller - // - // catchpad: - // %tok = catchpad within %cs [%type_descriptor, 0, %slot] - // %ptr[0] = %slot[0] - // %ptr[1] = %slot[1] - // catchret from %tok to label %caught - // - // caught: - // ret i32 1 - // } - // - // This structure follows the basic usage of throw/try/catch in LLVM. - // For example, compile this C++ snippet to see what LLVM generates: - // - // #include - // - // int bar(void (*foo)(void), uint64_t *ret) { - // try { - // foo(); - // return 0; - // } catch(uint64_t a[2]) { - // ret[0] = a[0]; - // ret[1] = a[1]; - // return 1; - // } - // } - // - // More information can be found in libstd's seh.rs implementation. - let i64p = Type::i64(cx).ptr_to(); - let ptr_align = bx.tcx().data_layout.pointer_align; - let slot = bx.alloca(i64p, "slot", ptr_align); - bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), - None); - - normal.ret(C_i32(cx, 0)); - - let cs = catchswitch.catch_switch(None, None, 1); - catchswitch.add_handler(cs, catchpad.llbb()); - - let tcx = cx.tcx; - let tydesc = match tcx.lang_items().msvc_try_filter() { - Some(did) => ::consts::get_static(cx, did), - None => bug!("msvc_try_filter not defined"), - }; - let tok = catchpad.catch_pad(cs, &[tydesc, C_i32(cx, 0), slot]); - let addr = catchpad.load(slot, ptr_align); - - let i64_align = bx.tcx().data_layout.i64_align; - let arg1 = catchpad.load(addr, i64_align); - let val1 = C_i32(cx, 1); - let arg2 = catchpad.load(catchpad.inbounds_gep(addr, &[val1]), i64_align); - let local_ptr = catchpad.bitcast(local_ptr, i64p); - catchpad.store(arg1, local_ptr, i64_align); - catchpad.store(arg2, catchpad.inbounds_gep(local_ptr, &[val1]), i64_align); - catchpad.catch_ret(tok, caught.llbb()); - - caught.ret(C_i32(cx, 1)); - }); - - // Note that no invoke is used here because by definition this function - // can't panic (that's what it's catching). - let ret = bx.call(llfn, &[func, data, local_ptr], None); - let i32_align = bx.tcx().data_layout.i32_align; - bx.store(ret, dest, i32_align); -} - -// Definition of the standard "try" function for Rust using the GNU-like model -// of exceptions (e.g. the normal semantics of LLVM's landingpad and invoke -// instructions). -// -// This translation is a little surprising because we always call a shim -// function instead of inlining the call to `invoke` manually here. This is done -// because in LLVM we're only allowed to have one personality per function -// definition. The call to the `try` intrinsic is being inlined into the -// function calling it, and that function may already have other personality -// functions in play. By calling a shim we're guaranteed that our shim will have -// the right personality function. -fn trans_gnu_try<'a, 'tcx>(bx: &Builder<'a, 'tcx>, - cx: &CodegenCx, - func: ValueRef, - data: ValueRef, - local_ptr: ValueRef, - dest: ValueRef) { - let llfn = get_rust_try_fn(cx, &mut |bx| { - let cx = bx.cx; - - // Translates the shims described above: - // - // bx: - // invoke %func(%args...) normal %normal unwind %catch - // - // normal: - // ret 0 - // - // catch: - // (ptr, _) = landingpad - // store ptr, %local_ptr - // ret 1 - // - // Note that the `local_ptr` data passed into the `try` intrinsic is - // expected to be `*mut *mut u8` for this to actually work, but that's - // managed by the standard library. - - let then = bx.build_sibling_block("then"); - let catch = bx.build_sibling_block("catch"); - - let func = llvm::get_param(bx.llfn(), 0); - let data = llvm::get_param(bx.llfn(), 1); - let local_ptr = llvm::get_param(bx.llfn(), 2); - bx.invoke(func, &[data], then.llbb(), catch.llbb(), None); - then.ret(C_i32(cx, 0)); - - // Type indicator for the exception being thrown. - // - // The first value in this tuple is a pointer to the exception object - // being thrown. The second value is a "selector" indicating which of - // the landing pad clauses the exception's type had been matched to. - // rust_try ignores the selector. - let lpad_ty = Type::struct_(cx, &[Type::i8p(cx), Type::i32(cx)], - false); - let vals = catch.landing_pad(lpad_ty, bx.cx.eh_personality(), 1); - catch.add_clause(vals, C_null(Type::i8p(cx))); - let ptr = catch.extract_value(vals, 0); - let ptr_align = bx.tcx().data_layout.pointer_align; - catch.store(ptr, catch.bitcast(local_ptr, Type::i8p(cx).ptr_to()), ptr_align); - catch.ret(C_i32(cx, 1)); - }); - - // Note that no invoke is used here because by definition this function - // can't panic (that's what it's catching). - let ret = bx.call(llfn, &[func, data, local_ptr], None); - let i32_align = bx.tcx().data_layout.i32_align; - bx.store(ret, dest, i32_align); -} - -// Helper function to give a Block to a closure to translate a shim function. -// This is currently primarily used for the `try` intrinsic functions above. -fn gen_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - name: &str, - inputs: Vec>, - output: Ty<'tcx>, - trans: &mut for<'b> FnMut(Builder<'b, 'tcx>)) - -> ValueRef { - let rust_fn_ty = cx.tcx.mk_fn_ptr(ty::Binder::bind(cx.tcx.mk_fn_sig( - inputs.into_iter(), - output, - false, - hir::Unsafety::Unsafe, - Abi::Rust - ))); - let llfn = declare::define_internal_fn(cx, name, rust_fn_ty); - let bx = Builder::new_block(cx, llfn, "entry-block"); - trans(bx); - llfn -} - -// Helper function used to get a handle to the `__rust_try` function used to -// catch exceptions. -// -// This function is only generated once and is then cached. -fn get_rust_try_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - trans: &mut for<'b> FnMut(Builder<'b, 'tcx>)) - -> ValueRef { - if let Some(llfn) = cx.rust_try_fn.get() { - return llfn; - } - - // Define the type up front for the signature of the rust_try function. - let tcx = cx.tcx; - let i8p = tcx.mk_mut_ptr(tcx.types.i8); - let fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( - iter::once(i8p), - tcx.mk_nil(), - false, - hir::Unsafety::Unsafe, - Abi::Rust - ))); - let output = tcx.types.i32; - let rust_try = gen_fn(cx, "__rust_try", vec![fn_ty, i8p, i8p], output, trans); - cx.rust_try_fn.set(Some(rust_try)); - return rust_try -} - -fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) { - span_err!(a, b, E0511, "{}", c); -} - -fn generic_simd_intrinsic<'a, 'tcx>( - bx: &Builder<'a, 'tcx>, - name: &str, - callee_ty: Ty<'tcx>, - args: &[OperandRef<'tcx>], - ret_ty: Ty<'tcx>, - llret_ty: Type, - span: Span -) -> Result { - // macros for error handling: - macro_rules! emit_error { - ($msg: tt) => { - emit_error!($msg, ) - }; - ($msg: tt, $($fmt: tt)*) => { - span_invalid_monomorphization_error( - bx.sess(), span, - &format!(concat!("invalid monomorphization of `{}` intrinsic: ", - $msg), - name, $($fmt)*)); - } - } - macro_rules! return_error { - ($($fmt: tt)*) => { - { - emit_error!($($fmt)*); - return Err(()); - } - } - } - - macro_rules! require { - ($cond: expr, $($fmt: tt)*) => { - if !$cond { - return_error!($($fmt)*); - } - }; - } - macro_rules! require_simd { - ($ty: expr, $position: expr) => { - require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty) - } - } - - - - let tcx = bx.tcx(); - let sig = tcx.normalize_erasing_late_bound_regions( - ty::ParamEnv::reveal_all(), - &callee_ty.fn_sig(tcx), - ); - let arg_tys = sig.inputs(); - - // every intrinsic takes a SIMD vector as its first argument - require_simd!(arg_tys[0], "input"); - let in_ty = arg_tys[0]; - let in_elem = arg_tys[0].simd_type(tcx); - let in_len = arg_tys[0].simd_size(tcx); - - let comparison = match name { - "simd_eq" => Some(hir::BiEq), - "simd_ne" => Some(hir::BiNe), - "simd_lt" => Some(hir::BiLt), - "simd_le" => Some(hir::BiLe), - "simd_gt" => Some(hir::BiGt), - "simd_ge" => Some(hir::BiGe), - _ => None - }; - - if let Some(cmp_op) = comparison { - require_simd!(ret_ty, "return"); - - let out_len = ret_ty.simd_size(tcx); - require!(in_len == out_len, - "expected return type with length {} (same as input type `{}`), \ - found `{}` with length {}", - in_len, in_ty, - ret_ty, out_len); - require!(llret_ty.element_type().kind() == llvm::Integer, - "expected return type with integer elements, found `{}` with non-integer `{}`", - ret_ty, - ret_ty.simd_type(tcx)); - - return Ok(compare_simd_types(bx, - args[0].immediate(), - args[1].immediate(), - in_elem, - llret_ty, - cmp_op)) - } - - if name.starts_with("simd_shuffle") { - let n: usize = match name["simd_shuffle".len()..].parse() { - Ok(n) => n, - Err(_) => span_bug!(span, - "bad `simd_shuffle` instruction only caught in trans?") - }; - - require_simd!(ret_ty, "return"); - - let out_len = ret_ty.simd_size(tcx); - require!(out_len == n, - "expected return type of length {}, found `{}` with length {}", - n, ret_ty, out_len); - require!(in_elem == ret_ty.simd_type(tcx), - "expected return element type `{}` (element of input `{}`), \ - found `{}` with element type `{}`", - in_elem, in_ty, - ret_ty, ret_ty.simd_type(tcx)); - - let total_len = in_len as u128 * 2; - - let vector = args[2].immediate(); - - let indices: Option> = (0..n) - .map(|i| { - let arg_idx = i; - let val = const_get_elt(vector, i as u64); - match const_to_opt_u128(val, true) { - None => { - emit_error!("shuffle index #{} is not a constant", arg_idx); - None - } - Some(idx) if idx >= total_len => { - emit_error!("shuffle index #{} is out of bounds (limit {})", - arg_idx, total_len); - None - } - Some(idx) => Some(C_i32(bx.cx, idx as i32)), - } - }) - .collect(); - let indices = match indices { - Some(i) => i, - None => return Ok(C_null(llret_ty)) - }; - - return Ok(bx.shuffle_vector(args[0].immediate(), - args[1].immediate(), - C_vector(&indices))) - } - - if name == "simd_insert" { - require!(in_elem == arg_tys[2], - "expected inserted type `{}` (element of input `{}`), found `{}`", - in_elem, in_ty, arg_tys[2]); - return Ok(bx.insert_element(args[0].immediate(), - args[2].immediate(), - args[1].immediate())) - } - if name == "simd_extract" { - require!(ret_ty == in_elem, - "expected return type `{}` (element of input `{}`), found `{}`", - in_elem, in_ty, ret_ty); - return Ok(bx.extract_element(args[0].immediate(), args[1].immediate())) - } - - if name == "simd_select" { - let m_elem_ty = in_elem; - let m_len = in_len; - let v_len = arg_tys[1].simd_size(tcx); - require!(m_len == v_len, - "mismatched lengths: mask length `{}` != other vector length `{}`", - m_len, v_len - ); - match m_elem_ty.sty { - ty::TyInt(_) => {}, - _ => { - return_error!("mask element type is `{}`, expected `i_`", m_elem_ty); - } - } - // truncate the mask to a vector of i1s - let i1 = Type::i1(bx.cx); - let i1xn = Type::vector(&i1, m_len as u64); - let m_i1s = bx.trunc(args[0].immediate(), i1xn); - return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); - } - - macro_rules! arith_red { - ($name:tt : $integer_reduce:ident, $float_reduce:ident, $ordered:expr) => { - if name == $name { - require!(ret_ty == in_elem, - "expected return type `{}` (element of input `{}`), found `{}`", - in_elem, in_ty, ret_ty); - return match in_elem.sty { - ty::TyInt(_) | ty::TyUint(_) => { - let r = bx.$integer_reduce(args[0].immediate()); - if $ordered { - // if overflow occurs, the result is the - // mathematical result modulo 2^n: - if name.contains("mul") { - Ok(bx.mul(args[1].immediate(), r)) - } else { - Ok(bx.add(args[1].immediate(), r)) - } - } else { - Ok(bx.$integer_reduce(args[0].immediate())) - } - }, - ty::TyFloat(f) => { - // ordered arithmetic reductions take an accumulator - let acc = if $ordered { - let acc = args[1].immediate(); - // FIXME: https://bugs.llvm.org/show_bug.cgi?id=36734 - // * if the accumulator of the fadd isn't 0, incorrect - // code is generated - // * if the accumulator of the fmul isn't 1, incorrect - // code is generated - match const_get_real(acc) { - None => return_error!("accumulator of {} is not a constant", $name), - Some((v, loses_info)) => { - if $name.contains("mul") && v != 1.0_f64 { - return_error!("accumulator of {} is not 1.0", $name); - } else if $name.contains("add") && v != 0.0_f64 { - return_error!("accumulator of {} is not 0.0", $name); - } else if loses_info { - return_error!("accumulator of {} loses information", $name); - } - } - } - acc - } else { - // unordered arithmetic reductions do not: - match f.bit_width() { - 32 => C_undef(Type::f32(bx.cx)), - 64 => C_undef(Type::f64(bx.cx)), - v => { - return_error!(r#" -unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, - $name, in_ty, in_elem, v, ret_ty - ) - } - } - - }; - Ok(bx.$float_reduce(acc, args[0].immediate())) - } - _ => { - return_error!( - "unsupported {} from `{}` with element `{}` to `{}`", - $name, in_ty, in_elem, ret_ty - ) - }, - } - } - } - } - - arith_red!("simd_reduce_add_ordered": vector_reduce_add, vector_reduce_fadd_fast, true); - arith_red!("simd_reduce_mul_ordered": vector_reduce_mul, vector_reduce_fmul_fast, true); - arith_red!("simd_reduce_add_unordered": vector_reduce_add, vector_reduce_fadd_fast, false); - arith_red!("simd_reduce_mul_unordered": vector_reduce_mul, vector_reduce_fmul_fast, false); - - macro_rules! minmax_red { - ($name:tt: $int_red:ident, $float_red:ident) => { - if name == $name { - require!(ret_ty == in_elem, - "expected return type `{}` (element of input `{}`), found `{}`", - in_elem, in_ty, ret_ty); - return match in_elem.sty { - ty::TyInt(_i) => { - Ok(bx.$int_red(args[0].immediate(), true)) - }, - ty::TyUint(_u) => { - Ok(bx.$int_red(args[0].immediate(), false)) - }, - ty::TyFloat(_f) => { - Ok(bx.$float_red(args[0].immediate())) - } - _ => { - return_error!("unsupported {} from `{}` with element `{}` to `{}`", - $name, in_ty, in_elem, ret_ty) - }, - } - } - - } - } - - minmax_red!("simd_reduce_min": vector_reduce_min, vector_reduce_fmin); - minmax_red!("simd_reduce_max": vector_reduce_max, vector_reduce_fmax); - - minmax_red!("simd_reduce_min_nanless": vector_reduce_min, vector_reduce_fmin_fast); - minmax_red!("simd_reduce_max_nanless": vector_reduce_max, vector_reduce_fmax_fast); - - macro_rules! bitwise_red { - ($name:tt : $red:ident, $boolean:expr) => { - if name == $name { - let input = if !$boolean { - require!(ret_ty == in_elem, - "expected return type `{}` (element of input `{}`), found `{}`", - in_elem, in_ty, ret_ty); - args[0].immediate() - } else { - match in_elem.sty { - ty::TyInt(_) | ty::TyUint(_) => {}, - _ => { - return_error!("unsupported {} from `{}` with element `{}` to `{}`", - $name, in_ty, in_elem, ret_ty) - } - } - - // boolean reductions operate on vectors of i1s: - let i1 = Type::i1(bx.cx); - let i1xn = Type::vector(&i1, in_len as u64); - bx.trunc(args[0].immediate(), i1xn) - }; - return match in_elem.sty { - ty::TyInt(_) | ty::TyUint(_) => { - let r = bx.$red(input); - Ok( - if !$boolean { - r - } else { - bx.zext(r, Type::bool(bx.cx)) - } - ) - }, - _ => { - return_error!("unsupported {} from `{}` with element `{}` to `{}`", - $name, in_ty, in_elem, ret_ty) - }, - } - } - } - } - - bitwise_red!("simd_reduce_and": vector_reduce_and, false); - bitwise_red!("simd_reduce_or": vector_reduce_or, false); - bitwise_red!("simd_reduce_xor": vector_reduce_xor, false); - bitwise_red!("simd_reduce_all": vector_reduce_and, true); - bitwise_red!("simd_reduce_any": vector_reduce_or, true); - - if name == "simd_cast" { - require_simd!(ret_ty, "return"); - let out_len = ret_ty.simd_size(tcx); - require!(in_len == out_len, - "expected return type with length {} (same as input type `{}`), \ - found `{}` with length {}", - in_len, in_ty, - ret_ty, out_len); - // casting cares about nominal type, not just structural type - let out_elem = ret_ty.simd_type(tcx); - - if in_elem == out_elem { return Ok(args[0].immediate()); } - - enum Style { Float, Int(/* is signed? */ bool), Unsupported } - - let (in_style, in_width) = match in_elem.sty { - // vectors of pointer-sized integers should've been - // disallowed before here, so this unwrap is safe. - ty::TyInt(i) => (Style::Int(true), i.bit_width().unwrap()), - ty::TyUint(u) => (Style::Int(false), u.bit_width().unwrap()), - ty::TyFloat(f) => (Style::Float, f.bit_width()), - _ => (Style::Unsupported, 0) - }; - let (out_style, out_width) = match out_elem.sty { - ty::TyInt(i) => (Style::Int(true), i.bit_width().unwrap()), - ty::TyUint(u) => (Style::Int(false), u.bit_width().unwrap()), - ty::TyFloat(f) => (Style::Float, f.bit_width()), - _ => (Style::Unsupported, 0) - }; - - match (in_style, out_style) { - (Style::Int(in_is_signed), Style::Int(_)) => { - return Ok(match in_width.cmp(&out_width) { - Ordering::Greater => bx.trunc(args[0].immediate(), llret_ty), - Ordering::Equal => args[0].immediate(), - Ordering::Less => if in_is_signed { - bx.sext(args[0].immediate(), llret_ty) - } else { - bx.zext(args[0].immediate(), llret_ty) - } - }) - } - (Style::Int(in_is_signed), Style::Float) => { - return Ok(if in_is_signed { - bx.sitofp(args[0].immediate(), llret_ty) - } else { - bx.uitofp(args[0].immediate(), llret_ty) - }) - } - (Style::Float, Style::Int(out_is_signed)) => { - return Ok(if out_is_signed { - bx.fptosi(args[0].immediate(), llret_ty) - } else { - bx.fptoui(args[0].immediate(), llret_ty) - }) - } - (Style::Float, Style::Float) => { - return Ok(match in_width.cmp(&out_width) { - Ordering::Greater => bx.fptrunc(args[0].immediate(), llret_ty), - Ordering::Equal => args[0].immediate(), - Ordering::Less => bx.fpext(args[0].immediate(), llret_ty) - }) - } - _ => {/* Unsupported. Fallthrough. */} - } - require!(false, - "unsupported cast from `{}` with element `{}` to `{}` with element `{}`", - in_ty, in_elem, - ret_ty, out_elem); - } - macro_rules! arith { - ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => { - $(if name == stringify!($name) { - match in_elem.sty { - $($(ty::$p(_))|* => { - return Ok(bx.$call(args[0].immediate(), args[1].immediate())) - })* - _ => {}, - } - require!(false, - "unsupported operation on `{}` with element `{}`", - in_ty, - in_elem) - })* - } - } - arith! { - simd_add: TyUint, TyInt => add, TyFloat => fadd; - simd_sub: TyUint, TyInt => sub, TyFloat => fsub; - simd_mul: TyUint, TyInt => mul, TyFloat => fmul; - simd_div: TyUint => udiv, TyInt => sdiv, TyFloat => fdiv; - simd_rem: TyUint => urem, TyInt => srem, TyFloat => frem; - simd_shl: TyUint, TyInt => shl; - simd_shr: TyUint => lshr, TyInt => ashr; - simd_and: TyUint, TyInt => and; - simd_or: TyUint, TyInt => or; - simd_xor: TyUint, TyInt => xor; - simd_fmax: TyFloat => maxnum; - simd_fmin: TyFloat => minnum; - } - span_bug!(span, "unknown SIMD intrinsic"); -} - -// Returns the width of an int Ty, and if it's signed or not -// Returns None if the type is not an integer -// FIXME: there’s multiple of this functions, investigate using some of the already existing -// stuffs. -fn int_type_width_signed(ty: Ty, cx: &CodegenCx) -> Option<(u64, bool)> { - match ty.sty { - ty::TyInt(t) => Some((match t { - ast::IntTy::Isize => { - match &cx.tcx.sess.target.target.target_pointer_width[..] { - "16" => 16, - "32" => 32, - "64" => 64, - tws => bug!("Unsupported target word size for isize: {}", tws), - } - }, - ast::IntTy::I8 => 8, - ast::IntTy::I16 => 16, - ast::IntTy::I32 => 32, - ast::IntTy::I64 => 64, - ast::IntTy::I128 => 128, - }, true)), - ty::TyUint(t) => Some((match t { - ast::UintTy::Usize => { - match &cx.tcx.sess.target.target.target_pointer_width[..] { - "16" => 16, - "32" => 32, - "64" => 64, - tws => bug!("Unsupported target word size for usize: {}", tws), - } - }, - ast::UintTy::U8 => 8, - ast::UintTy::U16 => 16, - ast::UintTy::U32 => 32, - ast::UintTy::U64 => 64, - ast::UintTy::U128 => 128, - }, false)), - _ => None, - } -} - -// Returns the width of a float TypeVariant -// Returns None if the type is not a float -fn float_type_width<'tcx>(sty: &ty::TypeVariants<'tcx>) - -> Option { - use rustc::ty::TyFloat; - match *sty { - TyFloat(t) => Some(match t { - ast::FloatTy::F32 => 32, - ast::FloatTy::F64 => 64, - }), - _ => None, - } -} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs deleted file mode 100644 index 6db95657ce0..00000000000 --- a/src/librustc_trans/lib.rs +++ /dev/null @@ -1,390 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The Rust compiler. -//! -//! # Note -//! -//! This API is completely unstable and subject to change. - -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/")] - -#![feature(box_patterns)] -#![feature(box_syntax)] -#![feature(custom_attribute)] -#![feature(fs_read_write)] -#![allow(unused_attributes)] -#![feature(libc)] -#![feature(quote)] -#![feature(range_contains)] -#![feature(rustc_diagnostic_macros)] -#![feature(slice_sort_by_cached_key)] -#![feature(optin_builtin_traits)] -#![feature(inclusive_range_methods)] - -use rustc::dep_graph::WorkProduct; -use syntax_pos::symbol::Symbol; - -#[macro_use] extern crate bitflags; -extern crate flate2; -extern crate libc; -#[macro_use] extern crate rustc; -extern crate jobserver; -extern crate num_cpus; -extern crate rustc_mir; -extern crate rustc_allocator; -extern crate rustc_apfloat; -extern crate rustc_target; -#[macro_use] extern crate rustc_data_structures; -extern crate rustc_demangle; -extern crate rustc_incremental; -extern crate rustc_llvm as llvm; -extern crate rustc_platform_intrinsics as intrinsics; -extern crate rustc_trans_utils; - -#[macro_use] extern crate log; -#[macro_use] extern crate syntax; -extern crate syntax_pos; -extern crate rustc_errors as errors; -extern crate serialize; -extern crate cc; // Used to locate MSVC -extern crate tempdir; - -use back::bytecode::RLIB_BYTECODE_EXTENSION; - -pub use llvm_util::target_features; - -use std::any::Any; -use std::path::PathBuf; -use std::sync::mpsc; -use std::collections::BTreeMap; -use rustc_data_structures::sync::Lrc; - -use rustc::dep_graph::DepGraph; -use rustc::hir::def_id::CrateNum; -use rustc::middle::cstore::MetadataLoader; -use rustc::middle::cstore::{NativeLibrary, CrateSource, LibSource}; -use rustc::middle::lang_items::LangItem; -use rustc::session::{Session, CompileIncomplete}; -use rustc::session::config::{OutputFilenames, OutputType, PrintRequest}; -use rustc::ty::{self, TyCtxt}; -use rustc::util::nodemap::{FxHashSet, FxHashMap}; -use rustc_mir::monomorphize; -use rustc_trans_utils::trans_crate::TransCrate; - -mod diagnostics; - -mod back { - pub use rustc_trans_utils::symbol_names; - mod archive; - pub mod bytecode; - mod command; - pub mod linker; - pub mod link; - mod lto; - pub mod symbol_export; - pub mod write; - mod rpath; - mod wasm; -} - -mod abi; -mod allocator; -mod asm; -mod attributes; -mod base; -mod builder; -mod callee; -mod common; -mod consts; -mod context; -mod debuginfo; -mod declare; -mod glue; -mod intrinsic; -mod llvm_util; -mod metadata; -mod meth; -mod mir; -mod time_graph; -mod trans_item; -mod type_; -mod type_of; -mod value; - -pub struct LlvmTransCrate(()); - -impl !Send for LlvmTransCrate {} // Llvm is on a per-thread basis -impl !Sync for LlvmTransCrate {} - -impl LlvmTransCrate { - pub fn new() -> Box { - box LlvmTransCrate(()) - } -} - -impl TransCrate for LlvmTransCrate { - fn init(&self, sess: &Session) { - llvm_util::init(sess); // Make sure llvm is inited - } - - fn print(&self, req: PrintRequest, sess: &Session) { - match req { - PrintRequest::RelocationModels => { - println!("Available relocation models:"); - for &(name, _) in back::write::RELOC_MODEL_ARGS.iter() { - println!(" {}", name); - } - println!(""); - } - PrintRequest::CodeModels => { - println!("Available code models:"); - for &(name, _) in back::write::CODE_GEN_MODEL_ARGS.iter(){ - println!(" {}", name); - } - println!(""); - } - PrintRequest::TlsModels => { - println!("Available TLS models:"); - for &(name, _) in back::write::TLS_MODEL_ARGS.iter(){ - println!(" {}", name); - } - println!(""); - } - req => llvm_util::print(req, sess), - } - } - - fn print_passes(&self) { - llvm_util::print_passes(); - } - - fn print_version(&self) { - llvm_util::print_version(); - } - - fn diagnostics(&self) -> &[(&'static str, &'static str)] { - &DIAGNOSTICS - } - - fn target_features(&self, sess: &Session) -> Vec { - target_features(sess) - } - - fn metadata_loader(&self) -> Box { - box metadata::LlvmMetadataLoader - } - - fn provide(&self, providers: &mut ty::maps::Providers) { - back::symbol_names::provide(providers); - back::symbol_export::provide(providers); - base::provide(providers); - attributes::provide(providers); - } - - fn provide_extern(&self, providers: &mut ty::maps::Providers) { - back::symbol_export::provide_extern(providers); - base::provide_extern(providers); - attributes::provide_extern(providers); - } - - fn trans_crate<'a, 'tcx>( - &self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - rx: mpsc::Receiver> - ) -> Box { - box base::trans_crate(tcx, rx) - } - - fn join_trans_and_link( - &self, - trans: Box, - sess: &Session, - dep_graph: &DepGraph, - outputs: &OutputFilenames, - ) -> Result<(), CompileIncomplete>{ - use rustc::util::common::time; - let (trans, work_products) = trans.downcast::<::back::write::OngoingCrateTranslation>() - .expect("Expected LlvmTransCrate's OngoingCrateTranslation, found Box") - .join(sess); - if sess.opts.debugging_opts.incremental_info { - back::write::dump_incremental_data(&trans); - } - - time(sess, - "serialize work products", - move || rustc_incremental::save_work_product_index(sess, &dep_graph, work_products)); - - sess.compile_status()?; - - if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe || - i == OutputType::Metadata) { - return Ok(()); - } - - // Run the linker on any artifacts that resulted from the LLVM run. - // This should produce either a finished executable or library. - time(sess, "linking", || { - back::link::link_binary(sess, &trans, outputs, &trans.crate_name.as_str()); - }); - - // Now that we won't touch anything in the incremental compilation directory - // any more, we can finalize it (which involves renaming it) - rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash); - - Ok(()) - } -} - -/// This is the entrypoint for a hot plugged rustc_trans -#[no_mangle] -pub fn __rustc_codegen_backend() -> Box { - LlvmTransCrate::new() -} - -struct ModuleTranslation { - /// The name of the module. When the crate may be saved between - /// compilations, incremental compilation requires that name be - /// unique amongst **all** crates. Therefore, it should contain - /// something unique to this crate (e.g., a module path) as well - /// as the crate name and disambiguator. - name: String, - llmod_id: String, - source: ModuleSource, - kind: ModuleKind, -} - -#[derive(Copy, Clone, Debug, PartialEq)] -enum ModuleKind { - Regular, - Metadata, - Allocator, -} - -impl ModuleTranslation { - fn llvm(&self) -> Option<&ModuleLlvm> { - match self.source { - ModuleSource::Translated(ref llvm) => Some(llvm), - ModuleSource::Preexisting(_) => None, - } - } - - fn into_compiled_module(self, - emit_obj: bool, - emit_bc: bool, - emit_bc_compressed: bool, - outputs: &OutputFilenames) -> CompiledModule { - let pre_existing = match self.source { - ModuleSource::Preexisting(_) => true, - ModuleSource::Translated(_) => false, - }; - let object = if emit_obj { - Some(outputs.temp_path(OutputType::Object, Some(&self.name))) - } else { - None - }; - let bytecode = if emit_bc { - Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name))) - } else { - None - }; - let bytecode_compressed = if emit_bc_compressed { - Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name)) - .with_extension(RLIB_BYTECODE_EXTENSION)) - } else { - None - }; - - CompiledModule { - llmod_id: self.llmod_id, - name: self.name.clone(), - kind: self.kind, - pre_existing, - object, - bytecode, - bytecode_compressed, - } - } -} - -#[derive(Debug)] -struct CompiledModule { - name: String, - llmod_id: String, - kind: ModuleKind, - pre_existing: bool, - object: Option, - bytecode: Option, - bytecode_compressed: Option, -} - -enum ModuleSource { - /// Copy the `.o` files or whatever from the incr. comp. directory. - Preexisting(WorkProduct), - - /// Rebuild from this LLVM module. - Translated(ModuleLlvm), -} - -#[derive(Debug)] -struct ModuleLlvm { - llcx: llvm::ContextRef, - llmod: llvm::ModuleRef, - tm: llvm::TargetMachineRef, -} - -unsafe impl Send for ModuleLlvm { } -unsafe impl Sync for ModuleLlvm { } - -impl Drop for ModuleLlvm { - fn drop(&mut self) { - unsafe { - llvm::LLVMDisposeModule(self.llmod); - llvm::LLVMContextDispose(self.llcx); - llvm::LLVMRustDisposeTargetMachine(self.tm); - } - } -} - -struct CrateTranslation { - crate_name: Symbol, - modules: Vec, - allocator_module: Option, - metadata_module: CompiledModule, - link: rustc::middle::cstore::LinkMeta, - metadata: rustc::middle::cstore::EncodedMetadata, - windows_subsystem: Option, - linker_info: back::linker::LinkerInfo, - crate_info: CrateInfo, -} - -// Misc info we load from metadata to persist beyond the tcx -struct CrateInfo { - panic_runtime: Option, - compiler_builtins: Option, - profiler_runtime: Option, - sanitizer_runtime: Option, - is_no_builtins: FxHashSet, - native_libraries: FxHashMap>>, - crate_name: FxHashMap, - used_libraries: Lrc>, - link_args: Lrc>, - used_crate_source: FxHashMap>, - used_crates_static: Vec<(CrateNum, LibSource)>, - used_crates_dynamic: Vec<(CrateNum, LibSource)>, - wasm_custom_sections: BTreeMap>, - wasm_imports: FxHashMap, - lang_item_to_crate: FxHashMap, - missing_lang_items: FxHashMap>, -} - -__build_diagnostic_array! { librustc_trans, DIAGNOSTICS } diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs deleted file mode 100644 index bbd1c39a19e..00000000000 --- a/src/librustc_trans/llvm_util.rs +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use syntax_pos::symbol::Symbol; -use back::write::create_target_machine; -use llvm; -use rustc::session::Session; -use rustc::session::config::PrintRequest; -use libc::c_int; -use std::ffi::CString; -use syntax::feature_gate::UnstableFeatures; - -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Once; - -static POISONED: AtomicBool = AtomicBool::new(false); -static INIT: Once = Once::new(); - -pub(crate) fn init(sess: &Session) { - unsafe { - // Before we touch LLVM, make sure that multithreading is enabled. - INIT.call_once(|| { - if llvm::LLVMStartMultithreaded() != 1 { - // use an extra bool to make sure that all future usage of LLVM - // cannot proceed despite the Once not running more than once. - POISONED.store(true, Ordering::SeqCst); - } - - configure_llvm(sess); - }); - - if POISONED.load(Ordering::SeqCst) { - bug!("couldn't enable multi-threaded LLVM"); - } - } -} - -fn require_inited() { - INIT.call_once(|| bug!("llvm is not initialized")); - if POISONED.load(Ordering::SeqCst) { - bug!("couldn't enable multi-threaded LLVM"); - } -} - -unsafe fn configure_llvm(sess: &Session) { - let mut llvm_c_strs = Vec::new(); - let mut llvm_args = Vec::new(); - - { - let mut add = |arg: &str| { - let s = CString::new(arg).unwrap(); - llvm_args.push(s.as_ptr()); - llvm_c_strs.push(s); - }; - add("rustc"); // fake program name - if sess.time_llvm_passes() { add("-time-passes"); } - if sess.print_llvm_passes() { add("-debug-pass=Structure"); } - if sess.opts.debugging_opts.disable_instrumentation_preinliner { - add("-disable-preinline"); - } - - for arg in &sess.opts.cg.llvm_args { - add(&(*arg)); - } - } - - llvm::LLVMInitializePasses(); - - llvm::initialize_available_targets(); - - llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, - llvm_args.as_ptr()); -} - -// WARNING: the features after applying `to_llvm_feature` must be known -// to LLVM or the feature detection code will walk past the end of the feature -// array, leading to crashes. - -const ARM_WHITELIST: &[(&str, Option<&str>)] = &[ - ("neon", Some("arm_target_feature")), - ("v7", Some("arm_target_feature")), - ("vfp2", Some("arm_target_feature")), - ("vfp3", Some("arm_target_feature")), - ("vfp4", Some("arm_target_feature")), -]; - -const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[ - ("fp", Some("aarch64_target_feature")), - ("neon", Some("aarch64_target_feature")), - ("sve", Some("aarch64_target_feature")), - ("crc", Some("aarch64_target_feature")), - ("crypto", Some("aarch64_target_feature")), - ("ras", Some("aarch64_target_feature")), - ("lse", Some("aarch64_target_feature")), - ("rdm", Some("aarch64_target_feature")), - ("fp16", Some("aarch64_target_feature")), - ("rcpc", Some("aarch64_target_feature")), - ("dotprod", Some("aarch64_target_feature")), - ("v8.1a", Some("aarch64_target_feature")), - ("v8.2a", Some("aarch64_target_feature")), - ("v8.3a", Some("aarch64_target_feature")), -]; - -const X86_WHITELIST: &[(&str, Option<&str>)] = &[ - ("aes", None), - ("avx", None), - ("avx2", None), - ("avx512bw", Some("avx512_target_feature")), - ("avx512cd", Some("avx512_target_feature")), - ("avx512dq", Some("avx512_target_feature")), - ("avx512er", Some("avx512_target_feature")), - ("avx512f", Some("avx512_target_feature")), - ("avx512ifma", Some("avx512_target_feature")), - ("avx512pf", Some("avx512_target_feature")), - ("avx512vbmi", Some("avx512_target_feature")), - ("avx512vl", Some("avx512_target_feature")), - ("avx512vpopcntdq", Some("avx512_target_feature")), - ("bmi1", None), - ("bmi2", None), - ("fma", None), - ("fxsr", None), - ("lzcnt", None), - ("mmx", Some("mmx_target_feature")), - ("pclmulqdq", None), - ("popcnt", None), - ("rdrand", None), - ("rdseed", None), - ("sha", None), - ("sse", None), - ("sse2", None), - ("sse3", None), - ("sse4.1", None), - ("sse4.2", None), - ("sse4a", Some("sse4a_target_feature")), - ("ssse3", None), - ("tbm", Some("tbm_target_feature")), - ("xsave", None), - ("xsavec", None), - ("xsaveopt", None), - ("xsaves", None), -]; - -const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[ - ("hvx", Some("hexagon_target_feature")), - ("hvx-double", Some("hexagon_target_feature")), -]; - -const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[ - ("altivec", Some("powerpc_target_feature")), - ("power8-altivec", Some("powerpc_target_feature")), - ("power9-altivec", Some("powerpc_target_feature")), - ("power8-vector", Some("powerpc_target_feature")), - ("power9-vector", Some("powerpc_target_feature")), - ("vsx", Some("powerpc_target_feature")), -]; - -const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[ - ("fp64", Some("mips_target_feature")), - ("msa", Some("mips_target_feature")), -]; - -/// When rustdoc is running, provide a list of all known features so that all their respective -/// primtives may be documented. -/// -/// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this -/// iterator! -pub fn all_known_features() -> impl Iterator)> { - ARM_WHITELIST.iter().cloned() - .chain(AARCH64_WHITELIST.iter().cloned()) - .chain(X86_WHITELIST.iter().cloned()) - .chain(HEXAGON_WHITELIST.iter().cloned()) - .chain(POWERPC_WHITELIST.iter().cloned()) - .chain(MIPS_WHITELIST.iter().cloned()) -} - -pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { - let arch = if sess.target.target.arch == "x86_64" { - "x86" - } else { - &*sess.target.target.arch - }; - match (arch, s) { - ("x86", "pclmulqdq") => "pclmul", - ("x86", "rdrand") => "rdrnd", - ("x86", "bmi1") => "bmi", - ("aarch64", "fp") => "fp-armv8", - ("aarch64", "fp16") => "fullfp16", - (_, s) => s, - } -} - -pub fn target_features(sess: &Session) -> Vec { - let target_machine = create_target_machine(sess, true); - target_feature_whitelist(sess) - .iter() - .filter_map(|&(feature, gate)| { - if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() { - Some(feature) - } else { - None - } - }) - .filter(|feature| { - let llvm_feature = to_llvm_feature(sess, feature); - let cstr = CString::new(llvm_feature).unwrap(); - unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } - }) - .map(|feature| Symbol::intern(feature)).collect() -} - -pub fn target_feature_whitelist(sess: &Session) - -> &'static [(&'static str, Option<&'static str>)] -{ - match &*sess.target.target.arch { - "arm" => ARM_WHITELIST, - "aarch64" => AARCH64_WHITELIST, - "x86" | "x86_64" => X86_WHITELIST, - "hexagon" => HEXAGON_WHITELIST, - "mips" | "mips64" => MIPS_WHITELIST, - "powerpc" | "powerpc64" => POWERPC_WHITELIST, - _ => &[], - } -} - -pub fn print_version() { - // Can be called without initializing LLVM - unsafe { - println!("LLVM version: {}.{}", - llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor()); - } -} - -pub fn print_passes() { - // Can be called without initializing LLVM - unsafe { llvm::LLVMRustPrintPasses(); } -} - -pub(crate) fn print(req: PrintRequest, sess: &Session) { - require_inited(); - let tm = create_target_machine(sess, true); - unsafe { - match req { - PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm), - PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm), - _ => bug!("rustc_trans can't handle print request: {:?}", req), - } - } -} diff --git a/src/librustc_trans/metadata.rs b/src/librustc_trans/metadata.rs deleted file mode 100644 index 144baa65c1b..00000000000 --- a/src/librustc_trans/metadata.rs +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use rustc::util::common; -use rustc::middle::cstore::MetadataLoader; -use rustc_target::spec::Target; -use llvm; -use llvm::{False, ObjectFile, mk_section_iter}; -use llvm::archive_ro::ArchiveRO; - -use rustc_data_structures::owning_ref::OwningRef; -use std::path::Path; -use std::ptr; -use std::slice; - -pub use rustc_data_structures::sync::MetadataRef; - -pub const METADATA_FILENAME: &str = "rust.metadata.bin"; - -pub struct LlvmMetadataLoader; - -impl MetadataLoader for LlvmMetadataLoader { - fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result { - // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap - // internally to read the file. We also avoid even using a memcpy by - // just keeping the archive along while the metadata is in use. - let archive = ArchiveRO::open(filename) - .map(|ar| OwningRef::new(box ar)) - .map_err(|e| { - debug!("llvm didn't like `{}`: {}", filename.display(), e); - format!("failed to read rlib metadata in '{}': {}", filename.display(), e) - })?; - let buf: OwningRef<_, [u8]> = archive - .try_map(|ar| { - ar.iter() - .filter_map(|s| s.ok()) - .find(|sect| sect.name() == Some(METADATA_FILENAME)) - .map(|s| s.data()) - .ok_or_else(|| { - debug!("didn't find '{}' in the archive", METADATA_FILENAME); - format!("failed to read rlib metadata: '{}'", - filename.display()) - }) - })?; - Ok(rustc_erase_owner!(buf)) - } - - fn get_dylib_metadata(&self, - target: &Target, - filename: &Path) - -> Result { - unsafe { - let buf = common::path2cstr(filename); - let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr()); - if mb as isize == 0 { - return Err(format!("error reading library: '{}'", filename.display())); - } - let of = ObjectFile::new(mb) - .map(|of| OwningRef::new(box of)) - .ok_or_else(|| format!("provided path not an object file: '{}'", - filename.display()))?; - let buf = of.try_map(|of| search_meta_section(of, target, filename))?; - Ok(rustc_erase_owner!(buf)) - } - } -} - -fn search_meta_section<'a>(of: &'a ObjectFile, - target: &Target, - filename: &Path) - -> Result<&'a [u8], String> { - unsafe { - let si = mk_section_iter(of.llof); - while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { - let mut name_buf = ptr::null(); - let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf); - let name = slice::from_raw_parts(name_buf as *const u8, name_len as usize).to_vec(); - let name = String::from_utf8(name).unwrap(); - debug!("get_metadata_section: name {}", name); - if read_metadata_section_name(target) == name { - let cbuf = llvm::LLVMGetSectionContents(si.llsi); - let csz = llvm::LLVMGetSectionSize(si.llsi) as usize; - // The buffer is valid while the object file is around - let buf: &'a [u8] = slice::from_raw_parts(cbuf as *const u8, csz); - return Ok(buf); - } - llvm::LLVMMoveToNextSection(si.llsi); - } - } - Err(format!("metadata not found: '{}'", filename.display())) -} - -pub fn metadata_section_name(target: &Target) -> &'static str { - // Historical note: - // - // When using link.exe it was seen that the section name `.note.rustc` - // was getting shortened to `.note.ru`, and according to the PE and COFF - // specification: - // - // > Executable images do not use a string table and do not support - // > section names longer than 8 characters - // - // https://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx - // - // As a result, we choose a slightly shorter name! As to why - // `.note.rustc` works on MinGW, that's another good question... - - if target.options.is_like_osx { - "__DATA,.rustc" - } else { - ".rustc" - } -} - -fn read_metadata_section_name(_target: &Target) -> &'static str { - ".rustc" -} diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs deleted file mode 100644 index 21bbdf31dcb..00000000000 --- a/src/librustc_trans/meth.rs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use llvm::ValueRef; -use abi::{FnType, FnTypeExt}; -use callee; -use common::*; -use builder::Builder; -use consts; -use monomorphize; -use type_::Type; -use value::Value; -use rustc::ty::{self, Ty}; -use rustc::ty::layout::HasDataLayout; -use debuginfo; - -#[derive(Copy, Clone, Debug)] -pub struct VirtualIndex(u64); - -pub const DESTRUCTOR: VirtualIndex = VirtualIndex(0); -pub const SIZE: VirtualIndex = VirtualIndex(1); -pub const ALIGN: VirtualIndex = VirtualIndex(2); - -impl<'a, 'tcx> VirtualIndex { - pub fn from_index(index: usize) -> Self { - VirtualIndex(index as u64 + 3) - } - - pub fn get_fn(self, bx: &Builder<'a, 'tcx>, - llvtable: ValueRef, - fn_ty: &FnType<'tcx, Ty<'tcx>>) -> ValueRef { - // Load the data pointer from the object. - debug!("get_fn({:?}, {:?})", Value(llvtable), self); - - let llvtable = bx.pointercast(llvtable, fn_ty.llvm_type(bx.cx).ptr_to().ptr_to()); - let ptr_align = bx.tcx().data_layout.pointer_align; - let ptr = bx.load(bx.inbounds_gep(llvtable, &[C_usize(bx.cx, self.0)]), ptr_align); - bx.nonnull_metadata(ptr); - // Vtable loads are invariant - bx.set_invariant_load(ptr); - ptr - } - - pub fn get_usize(self, bx: &Builder<'a, 'tcx>, llvtable: ValueRef) -> ValueRef { - // Load the data pointer from the object. - debug!("get_int({:?}, {:?})", Value(llvtable), self); - - let llvtable = bx.pointercast(llvtable, Type::isize(bx.cx).ptr_to()); - let usize_align = bx.tcx().data_layout.pointer_align; - let ptr = bx.load(bx.inbounds_gep(llvtable, &[C_usize(bx.cx, self.0)]), usize_align); - // Vtable loads are invariant - bx.set_invariant_load(ptr); - ptr - } -} - -/// Creates a dynamic vtable for the given type and vtable origin. -/// This is used only for objects. -/// -/// The vtables are cached instead of created on every call. -/// -/// The `trait_ref` encodes the erased self type. Hence if we are -/// making an object `Foo` from a value of type `Foo`, then -/// `trait_ref` would map `T:Trait`. -pub fn get_vtable<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - ty: Ty<'tcx>, - trait_ref: Option>) - -> ValueRef -{ - let tcx = cx.tcx; - - debug!("get_vtable(ty={:?}, trait_ref={:?})", ty, trait_ref); - - // Check the cache. - if let Some(&val) = cx.vtables.borrow().get(&(ty, trait_ref)) { - return val; - } - - // Not in the cache. Build it. - let nullptr = C_null(Type::i8p(cx)); - - let (size, align) = cx.size_and_align_of(ty); - let mut components: Vec<_> = [ - callee::get_fn(cx, monomorphize::resolve_drop_in_place(cx.tcx, ty)), - C_usize(cx, size.bytes()), - C_usize(cx, align.abi()) - ].iter().cloned().collect(); - - if let Some(trait_ref) = trait_ref { - let trait_ref = trait_ref.with_self_ty(tcx, ty); - let methods = tcx.vtable_methods(trait_ref); - let methods = methods.iter().cloned().map(|opt_mth| { - opt_mth.map_or(nullptr, |(def_id, substs)| { - callee::resolve_and_get_fn(cx, def_id, substs) - }) - }); - components.extend(methods); - } - - let vtable_const = C_struct(cx, &components, false); - let align = cx.data_layout().pointer_align; - let vtable = consts::addr_of(cx, vtable_const, align, "vtable"); - - debuginfo::create_vtable_metadata(cx, ty, vtable); - - cx.vtables.borrow_mut().insert((ty, trait_ref), vtable); - vtable -} diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs deleted file mode 100644 index 9e5298eb736..00000000000 --- a/src/librustc_trans/mir/analyze.rs +++ /dev/null @@ -1,361 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! An analysis to determine which locals require allocas and -//! which do not. - -use rustc_data_structures::bitvec::BitVector; -use rustc_data_structures::control_flow_graph::dominators::Dominators; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc::mir::{self, Location, TerminatorKind}; -use rustc::mir::visit::{Visitor, PlaceContext}; -use rustc::mir::traversal; -use rustc::ty; -use rustc::ty::layout::LayoutOf; -use type_of::LayoutLlvmExt; -use super::FunctionCx; - -pub fn non_ssa_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector { - let mir = fx.mir; - let mut analyzer = LocalAnalyzer::new(fx); - - analyzer.visit_mir(mir); - - for (index, ty) in mir.local_decls.iter().map(|l| l.ty).enumerate() { - let ty = fx.monomorphize(&ty); - debug!("local {} has type {:?}", index, ty); - let layout = fx.cx.layout_of(ty); - if layout.is_llvm_immediate() { - // These sorts of types are immediates that we can store - // in an ValueRef without an alloca. - } else if layout.is_llvm_scalar_pair() { - // We allow pairs and uses of any of their 2 fields. - } else { - // These sorts of types require an alloca. Note that - // is_llvm_immediate() may *still* be true, particularly - // for newtypes, but we currently force some types - // (e.g. structs) into an alloca unconditionally, just so - // that we don't have to deal with having two pathways - // (gep vs extractvalue etc). - analyzer.not_ssa(mir::Local::new(index)); - } - } - - analyzer.non_ssa_locals -} - -struct LocalAnalyzer<'mir, 'a: 'mir, 'tcx: 'a> { - fx: &'mir FunctionCx<'a, 'tcx>, - dominators: Dominators, - non_ssa_locals: BitVector, - // The location of the first visited direct assignment to each - // local, or an invalid location (out of bounds `block` index). - first_assignment: IndexVec -} - -impl<'mir, 'a, 'tcx> LocalAnalyzer<'mir, 'a, 'tcx> { - fn new(fx: &'mir FunctionCx<'a, 'tcx>) -> LocalAnalyzer<'mir, 'a, 'tcx> { - let invalid_location = - mir::BasicBlock::new(fx.mir.basic_blocks().len()).start_location(); - let mut analyzer = LocalAnalyzer { - fx, - dominators: fx.mir.dominators(), - non_ssa_locals: BitVector::new(fx.mir.local_decls.len()), - first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls) - }; - - // Arguments get assigned to by means of the function being called - for arg in fx.mir.args_iter() { - analyzer.first_assignment[arg] = mir::START_BLOCK.start_location(); - } - - analyzer - } - - fn first_assignment(&self, local: mir::Local) -> Option { - let location = self.first_assignment[local]; - if location.block.index() < self.fx.mir.basic_blocks().len() { - Some(location) - } else { - None - } - } - - fn not_ssa(&mut self, local: mir::Local) { - debug!("marking {:?} as non-SSA", local); - self.non_ssa_locals.insert(local.index()); - } - - fn assign(&mut self, local: mir::Local, location: Location) { - if self.first_assignment(local).is_some() { - self.not_ssa(local); - } else { - self.first_assignment[local] = location; - } - } -} - -impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { - fn visit_assign(&mut self, - block: mir::BasicBlock, - place: &mir::Place<'tcx>, - rvalue: &mir::Rvalue<'tcx>, - location: Location) { - debug!("visit_assign(block={:?}, place={:?}, rvalue={:?})", block, place, rvalue); - - if let mir::Place::Local(index) = *place { - self.assign(index, location); - if !self.fx.rvalue_creates_operand(rvalue) { - self.not_ssa(index); - } - } else { - self.visit_place(place, PlaceContext::Store, location); - } - - self.visit_rvalue(rvalue, location); - } - - fn visit_terminator_kind(&mut self, - block: mir::BasicBlock, - kind: &mir::TerminatorKind<'tcx>, - location: Location) { - let check = match *kind { - mir::TerminatorKind::Call { - func: mir::Operand::Constant(ref c), - ref args, .. - } => match c.ty.sty { - ty::TyFnDef(did, _) => Some((did, args)), - _ => None, - }, - _ => None, - }; - if let Some((def_id, args)) = check { - if Some(def_id) == self.fx.cx.tcx.lang_items().box_free_fn() { - // box_free(x) shares with `drop x` the property that it - // is not guaranteed to be statically dominated by the - // definition of x, so x must always be in an alloca. - if let mir::Operand::Move(ref place) = args[0] { - self.visit_place(place, PlaceContext::Drop, location); - } - } - } - - self.super_terminator_kind(block, kind, location); - } - - fn visit_place(&mut self, - place: &mir::Place<'tcx>, - context: PlaceContext<'tcx>, - location: Location) { - debug!("visit_place(place={:?}, context={:?})", place, context); - let cx = self.fx.cx; - - if let mir::Place::Projection(ref proj) = *place { - // Allow uses of projections that are ZSTs or from scalar fields. - let is_consume = match context { - PlaceContext::Copy | PlaceContext::Move => true, - _ => false - }; - if is_consume { - let base_ty = proj.base.ty(self.fx.mir, cx.tcx); - let base_ty = self.fx.monomorphize(&base_ty); - - // ZSTs don't require any actual memory access. - let elem_ty = base_ty.projection_ty(cx.tcx, &proj.elem).to_ty(cx.tcx); - let elem_ty = self.fx.monomorphize(&elem_ty); - if cx.layout_of(elem_ty).is_zst() { - return; - } - - if let mir::ProjectionElem::Field(..) = proj.elem { - let layout = cx.layout_of(base_ty.to_ty(cx.tcx)); - if layout.is_llvm_immediate() || layout.is_llvm_scalar_pair() { - // Recurse with the same context, instead of `Projection`, - // potentially stopping at non-operand projections, - // which would trigger `not_ssa` on locals. - self.visit_place(&proj.base, context, location); - return; - } - } - } - - // A deref projection only reads the pointer, never needs the place. - if let mir::ProjectionElem::Deref = proj.elem { - return self.visit_place(&proj.base, PlaceContext::Copy, location); - } - } - - self.super_place(place, context, location); - } - - fn visit_local(&mut self, - &local: &mir::Local, - context: PlaceContext<'tcx>, - location: Location) { - match context { - PlaceContext::Call => { - self.assign(local, location); - } - - PlaceContext::StorageLive | - PlaceContext::StorageDead | - PlaceContext::Validate => {} - - PlaceContext::Copy | - PlaceContext::Move => { - // Reads from uninitialized variables (e.g. in dead code, after - // optimizations) require locals to be in (uninitialized) memory. - // NB: there can be uninitialized reads of a local visited after - // an assignment to that local, if they happen on disjoint paths. - let ssa_read = match self.first_assignment(local) { - Some(assignment_location) => { - assignment_location.dominates(location, &self.dominators) - } - None => false - }; - if !ssa_read { - self.not_ssa(local); - } - } - - PlaceContext::Inspect | - PlaceContext::Store | - PlaceContext::AsmOutput | - PlaceContext::Borrow { .. } | - PlaceContext::Projection(..) => { - self.not_ssa(local); - } - - PlaceContext::Drop => { - let ty = mir::Place::Local(local).ty(self.fx.mir, self.fx.cx.tcx); - let ty = self.fx.monomorphize(&ty.to_ty(self.fx.cx.tcx)); - - // Only need the place if we're actually dropping it. - if self.fx.cx.type_needs_drop(ty) { - self.not_ssa(local); - } - } - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum CleanupKind { - NotCleanup, - Funclet, - Internal { funclet: mir::BasicBlock } -} - -impl CleanupKind { - pub fn funclet_bb(self, for_bb: mir::BasicBlock) -> Option { - match self { - CleanupKind::NotCleanup => None, - CleanupKind::Funclet => Some(for_bb), - CleanupKind::Internal { funclet } => Some(funclet), - } - } -} - -pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec { - fn discover_masters<'tcx>(result: &mut IndexVec, - mir: &mir::Mir<'tcx>) { - for (bb, data) in mir.basic_blocks().iter_enumerated() { - match data.terminator().kind { - TerminatorKind::Goto { .. } | - TerminatorKind::Resume | - TerminatorKind::Abort | - TerminatorKind::Return | - TerminatorKind::GeneratorDrop | - TerminatorKind::Unreachable | - TerminatorKind::SwitchInt { .. } | - TerminatorKind::Yield { .. } | - TerminatorKind::FalseEdges { .. } | - TerminatorKind::FalseUnwind { .. } => { - /* nothing to do */ - } - TerminatorKind::Call { cleanup: unwind, .. } | - TerminatorKind::Assert { cleanup: unwind, .. } | - TerminatorKind::DropAndReplace { unwind, .. } | - TerminatorKind::Drop { unwind, .. } => { - if let Some(unwind) = unwind { - debug!("cleanup_kinds: {:?}/{:?} registering {:?} as funclet", - bb, data, unwind); - result[unwind] = CleanupKind::Funclet; - } - } - } - } - } - - fn propagate<'tcx>(result: &mut IndexVec, - mir: &mir::Mir<'tcx>) { - let mut funclet_succs = IndexVec::from_elem(None, mir.basic_blocks()); - - let mut set_successor = |funclet: mir::BasicBlock, succ| { - match funclet_succs[funclet] { - ref mut s @ None => { - debug!("set_successor: updating successor of {:?} to {:?}", - funclet, succ); - *s = Some(succ); - }, - Some(s) => if s != succ { - span_bug!(mir.span, "funclet {:?} has 2 parents - {:?} and {:?}", - funclet, s, succ); - } - } - }; - - for (bb, data) in traversal::reverse_postorder(mir) { - let funclet = match result[bb] { - CleanupKind::NotCleanup => continue, - CleanupKind::Funclet => bb, - CleanupKind::Internal { funclet } => funclet, - }; - - debug!("cleanup_kinds: {:?}/{:?}/{:?} propagating funclet {:?}", - bb, data, result[bb], funclet); - - for &succ in data.terminator().successors() { - let kind = result[succ]; - debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}", - funclet, succ, kind); - match kind { - CleanupKind::NotCleanup => { - result[succ] = CleanupKind::Internal { funclet: funclet }; - } - CleanupKind::Funclet => { - if funclet != succ { - set_successor(funclet, succ); - } - } - CleanupKind::Internal { funclet: succ_funclet } => { - if funclet != succ_funclet { - // `succ` has 2 different funclet going into it, so it must - // be a funclet by itself. - - debug!("promoting {:?} to a funclet and updating {:?}", succ, - succ_funclet); - result[succ] = CleanupKind::Funclet; - set_successor(succ_funclet, succ); - set_successor(funclet, succ); - } - } - } - } - } - } - - let mut result = IndexVec::from_elem(CleanupKind::NotCleanup, mir.basic_blocks()); - - discover_masters(&mut result, mir); - propagate(&mut result, mir); - debug!("cleanup_kinds: result={:?}", result); - result -} diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs deleted file mode 100644 index e4989da36c0..00000000000 --- a/src/librustc_trans/mir/block.rs +++ /dev/null @@ -1,895 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use llvm::{self, ValueRef, BasicBlockRef}; -use rustc::middle::lang_items; -use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::layout::{self, LayoutOf}; -use rustc::mir; -use rustc::mir::interpret::EvalErrorKind; -use abi::{Abi, ArgType, ArgTypeExt, FnType, FnTypeExt, LlvmType, PassMode}; -use base; -use callee; -use builder::{Builder, MemFlags}; -use common::{self, C_bool, C_str_slice, C_struct, C_u32, C_uint_big, C_undef}; -use consts; -use meth; -use monomorphize; -use type_of::LayoutLlvmExt; -use type_::Type; - -use syntax::symbol::Symbol; -use syntax_pos::Pos; - -use super::{FunctionCx, LocalRef}; -use super::place::PlaceRef; -use super::operand::OperandRef; -use super::operand::OperandValue::{Pair, Ref, Immediate}; - -impl<'a, 'tcx> FunctionCx<'a, 'tcx> { - pub fn trans_block(&mut self, bb: mir::BasicBlock) { - let mut bx = self.build_block(bb); - let data = &self.mir[bb]; - - debug!("trans_block({:?}={:?})", bb, data); - - for statement in &data.statements { - bx = self.trans_statement(bx, statement); - } - - self.trans_terminator(bx, bb, data.terminator()); - } - - fn trans_terminator(&mut self, - mut bx: Builder<'a, 'tcx>, - bb: mir::BasicBlock, - terminator: &mir::Terminator<'tcx>) - { - debug!("trans_terminator: {:?}", terminator); - - // Create the cleanup bundle, if needed. - let tcx = bx.tcx(); - let span = terminator.source_info.span; - let funclet_bb = self.cleanup_kinds[bb].funclet_bb(bb); - let funclet = funclet_bb.and_then(|funclet_bb| self.funclets[funclet_bb].as_ref()); - - let cleanup_pad = funclet.map(|lp| lp.cleanuppad()); - let cleanup_bundle = funclet.map(|l| l.bundle()); - - let lltarget = |this: &mut Self, target: mir::BasicBlock| { - let lltarget = this.blocks[target]; - let target_funclet = this.cleanup_kinds[target].funclet_bb(target); - match (funclet_bb, target_funclet) { - (None, None) => (lltarget, false), - (Some(f), Some(t_f)) - if f == t_f || !base::wants_msvc_seh(tcx.sess) - => (lltarget, false), - (None, Some(_)) => { - // jump *into* cleanup - need a landing pad if GNU - (this.landing_pad_to(target), false) - } - (Some(_), None) => span_bug!(span, "{:?} - jump out of cleanup?", terminator), - (Some(_), Some(_)) => { - (this.landing_pad_to(target), true) - } - } - }; - - let llblock = |this: &mut Self, target: mir::BasicBlock| { - let (lltarget, is_cleanupret) = lltarget(this, target); - if is_cleanupret { - // MSVC cross-funclet jump - need a trampoline - - debug!("llblock: creating cleanup trampoline for {:?}", target); - let name = &format!("{:?}_cleanup_trampoline_{:?}", bb, target); - let trampoline = this.new_block(name); - trampoline.cleanup_ret(cleanup_pad.unwrap(), Some(lltarget)); - trampoline.llbb() - } else { - lltarget - } - }; - - let funclet_br = |this: &mut Self, bx: Builder, target: mir::BasicBlock| { - let (lltarget, is_cleanupret) = lltarget(this, target); - if is_cleanupret { - // micro-optimization: generate a `ret` rather than a jump - // to a trampoline. - bx.cleanup_ret(cleanup_pad.unwrap(), Some(lltarget)); - } else { - bx.br(lltarget); - } - }; - - let do_call = | - this: &mut Self, - bx: Builder<'a, 'tcx>, - fn_ty: FnType<'tcx, Ty<'tcx>>, - fn_ptr: ValueRef, - llargs: &[ValueRef], - destination: Option<(ReturnDest<'tcx>, mir::BasicBlock)>, - cleanup: Option - | { - if let Some(cleanup) = cleanup { - let ret_bx = if let Some((_, target)) = destination { - this.blocks[target] - } else { - this.unreachable_block() - }; - let invokeret = bx.invoke(fn_ptr, - &llargs, - ret_bx, - llblock(this, cleanup), - cleanup_bundle); - fn_ty.apply_attrs_callsite(&bx, invokeret); - - if let Some((ret_dest, target)) = destination { - let ret_bx = this.build_block(target); - this.set_debug_loc(&ret_bx, terminator.source_info); - this.store_return(&ret_bx, ret_dest, &fn_ty.ret, invokeret); - } - } else { - let llret = bx.call(fn_ptr, &llargs, cleanup_bundle); - fn_ty.apply_attrs_callsite(&bx, llret); - if this.mir[bb].is_cleanup { - // Cleanup is always the cold path. Don't inline - // drop glue. Also, when there is a deeply-nested - // struct, there are "symmetry" issues that cause - // exponential inlining - see issue #41696. - llvm::Attribute::NoInline.apply_callsite(llvm::AttributePlace::Function, llret); - } - - if let Some((ret_dest, target)) = destination { - this.store_return(&bx, ret_dest, &fn_ty.ret, llret); - funclet_br(this, bx, target); - } else { - bx.unreachable(); - } - } - }; - - self.set_debug_loc(&bx, terminator.source_info); - match terminator.kind { - mir::TerminatorKind::Resume => { - if let Some(cleanup_pad) = cleanup_pad { - bx.cleanup_ret(cleanup_pad, None); - } else { - let slot = self.get_personality_slot(&bx); - let lp0 = slot.project_field(&bx, 0).load(&bx).immediate(); - let lp1 = slot.project_field(&bx, 1).load(&bx).immediate(); - slot.storage_dead(&bx); - - if !bx.sess().target.target.options.custom_unwind_resume { - let mut lp = C_undef(self.landing_pad_type()); - lp = bx.insert_value(lp, lp0, 0); - lp = bx.insert_value(lp, lp1, 1); - bx.resume(lp); - } else { - bx.call(bx.cx.eh_unwind_resume(), &[lp0], cleanup_bundle); - bx.unreachable(); - } - } - } - - mir::TerminatorKind::Abort => { - // Call core::intrinsics::abort() - let fnname = bx.cx.get_intrinsic(&("llvm.trap")); - bx.call(fnname, &[], None); - bx.unreachable(); - } - - mir::TerminatorKind::Goto { target } => { - funclet_br(self, bx, target); - } - - mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => { - let discr = self.trans_operand(&bx, discr); - if switch_ty == bx.tcx().types.bool { - let lltrue = llblock(self, targets[0]); - let llfalse = llblock(self, targets[1]); - if let [0] = values[..] { - bx.cond_br(discr.immediate(), llfalse, lltrue); - } else { - assert_eq!(&values[..], &[1]); - bx.cond_br(discr.immediate(), lltrue, llfalse); - } - } else { - let (otherwise, targets) = targets.split_last().unwrap(); - let switch = bx.switch(discr.immediate(), - llblock(self, *otherwise), values.len()); - let switch_llty = bx.cx.layout_of(switch_ty).immediate_llvm_type(bx.cx); - for (&value, target) in values.iter().zip(targets) { - let llval = C_uint_big(switch_llty, value); - let llbb = llblock(self, *target); - bx.add_case(switch, llval, llbb) - } - } - } - - mir::TerminatorKind::Return => { - let llval = match self.fn_ty.ret.mode { - PassMode::Ignore | PassMode::Indirect(_) => { - bx.ret_void(); - return; - } - - PassMode::Direct(_) | PassMode::Pair(..) => { - let op = self.trans_consume(&bx, &mir::Place::Local(mir::RETURN_PLACE)); - if let Ref(llval, align) = op.val { - bx.load(llval, align) - } else { - op.immediate_or_packed_pair(&bx) - } - } - - PassMode::Cast(cast_ty) => { - let op = match self.locals[mir::RETURN_PLACE] { - LocalRef::Operand(Some(op)) => op, - LocalRef::Operand(None) => bug!("use of return before def"), - LocalRef::Place(tr_place) => { - OperandRef { - val: Ref(tr_place.llval, tr_place.align), - layout: tr_place.layout - } - } - }; - let llslot = match op.val { - Immediate(_) | Pair(..) => { - let scratch = PlaceRef::alloca(&bx, self.fn_ty.ret.layout, "ret"); - op.val.store(&bx, scratch); - scratch.llval - } - Ref(llval, align) => { - assert_eq!(align.abi(), op.layout.align.abi(), - "return place is unaligned!"); - llval - } - }; - bx.load( - bx.pointercast(llslot, cast_ty.llvm_type(bx.cx).ptr_to()), - self.fn_ty.ret.layout.align) - } - }; - bx.ret(llval); - } - - mir::TerminatorKind::Unreachable => { - bx.unreachable(); - } - - mir::TerminatorKind::Drop { ref location, target, unwind } => { - let ty = location.ty(self.mir, bx.tcx()).to_ty(bx.tcx()); - let ty = self.monomorphize(&ty); - let drop_fn = monomorphize::resolve_drop_in_place(bx.cx.tcx, ty); - - if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { - // we don't actually need to drop anything. - funclet_br(self, bx, target); - return - } - - let place = self.trans_place(&bx, location); - let mut args: &[_] = &[place.llval, place.llextra]; - args = &args[..1 + place.has_extra() as usize]; - let (drop_fn, fn_ty) = match ty.sty { - ty::TyDynamic(..) => { - let fn_ty = drop_fn.ty(bx.cx.tcx); - let sig = common::ty_fn_sig(bx.cx, fn_ty); - let sig = bx.tcx().normalize_erasing_late_bound_regions( - ty::ParamEnv::reveal_all(), - &sig, - ); - let fn_ty = FnType::new_vtable(bx.cx, sig, &[]); - args = &args[..1]; - (meth::DESTRUCTOR.get_fn(&bx, place.llextra, &fn_ty), fn_ty) - } - _ => { - (callee::get_fn(bx.cx, drop_fn), - FnType::of_instance(bx.cx, &drop_fn)) - } - }; - do_call(self, bx, fn_ty, drop_fn, args, - Some((ReturnDest::Nothing, target)), - unwind); - } - - mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => { - let cond = self.trans_operand(&bx, cond).immediate(); - let mut const_cond = common::const_to_opt_u128(cond, false).map(|c| c == 1); - - // This case can currently arise only from functions marked - // with #[rustc_inherit_overflow_checks] and inlined from - // another crate (mostly core::num generic/#[inline] fns), - // while the current crate doesn't use overflow checks. - // NOTE: Unlike binops, negation doesn't have its own - // checked operation, just a comparison with the minimum - // value, so we have to check for the assert message. - if !bx.cx.check_overflow { - if let mir::interpret::EvalErrorKind::OverflowNeg = *msg { - const_cond = Some(expected); - } - } - - // Don't translate the panic block if success if known. - if const_cond == Some(expected) { - funclet_br(self, bx, target); - return; - } - - // Pass the condition through llvm.expect for branch hinting. - let expect = bx.cx.get_intrinsic(&"llvm.expect.i1"); - let cond = bx.call(expect, &[cond, C_bool(bx.cx, expected)], None); - - // Create the failure block and the conditional branch to it. - let lltarget = llblock(self, target); - let panic_block = self.new_block("panic"); - if expected { - bx.cond_br(cond, lltarget, panic_block.llbb()); - } else { - bx.cond_br(cond, panic_block.llbb(), lltarget); - } - - // After this point, bx is the block for the call to panic. - bx = panic_block; - self.set_debug_loc(&bx, terminator.source_info); - - // Get the location information. - let loc = bx.sess().codemap().lookup_char_pos(span.lo()); - let filename = Symbol::intern(&loc.file.name.to_string()).as_str(); - let filename = C_str_slice(bx.cx, filename); - let line = C_u32(bx.cx, loc.line as u32); - let col = C_u32(bx.cx, loc.col.to_usize() as u32 + 1); - let align = tcx.data_layout.aggregate_align - .max(tcx.data_layout.i32_align) - .max(tcx.data_layout.pointer_align); - - // Put together the arguments to the panic entry point. - let (lang_item, args) = match *msg { - EvalErrorKind::BoundsCheck { ref len, ref index } => { - let len = self.trans_operand(&mut bx, len).immediate(); - let index = self.trans_operand(&mut bx, index).immediate(); - - let file_line_col = C_struct(bx.cx, &[filename, line, col], false); - let file_line_col = consts::addr_of(bx.cx, - file_line_col, - align, - "panic_bounds_check_loc"); - (lang_items::PanicBoundsCheckFnLangItem, - vec![file_line_col, index, len]) - } - _ => { - let str = msg.description(); - let msg_str = Symbol::intern(str).as_str(); - let msg_str = C_str_slice(bx.cx, msg_str); - let msg_file_line_col = C_struct(bx.cx, - &[msg_str, filename, line, col], - false); - let msg_file_line_col = consts::addr_of(bx.cx, - msg_file_line_col, - align, - "panic_loc"); - (lang_items::PanicFnLangItem, - vec![msg_file_line_col]) - } - }; - - // Obtain the panic entry point. - let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item); - let instance = ty::Instance::mono(bx.tcx(), def_id); - let fn_ty = FnType::of_instance(bx.cx, &instance); - let llfn = callee::get_fn(bx.cx, instance); - - // Translate the actual panic invoke/call. - do_call(self, bx, fn_ty, llfn, &args, None, cleanup); - } - - mir::TerminatorKind::DropAndReplace { .. } => { - bug!("undesugared DropAndReplace in trans: {:?}", terminator); - } - - mir::TerminatorKind::Call { ref func, ref args, ref destination, cleanup } => { - // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. - let callee = self.trans_operand(&bx, func); - - let (instance, mut llfn) = match callee.layout.ty.sty { - ty::TyFnDef(def_id, substs) => { - (Some(ty::Instance::resolve(bx.cx.tcx, - ty::ParamEnv::reveal_all(), - def_id, - substs).unwrap()), - None) - } - ty::TyFnPtr(_) => { - (None, Some(callee.immediate())) - } - _ => bug!("{} is not callable", callee.layout.ty) - }; - let def = instance.map(|i| i.def); - let sig = callee.layout.ty.fn_sig(bx.tcx()); - let sig = bx.tcx().normalize_erasing_late_bound_regions( - ty::ParamEnv::reveal_all(), - &sig, - ); - let abi = sig.abi; - - // Handle intrinsics old trans wants Expr's for, ourselves. - let intrinsic = match def { - Some(ty::InstanceDef::Intrinsic(def_id)) - => Some(bx.tcx().item_name(def_id).as_str()), - _ => None - }; - let intrinsic = intrinsic.as_ref().map(|s| &s[..]); - - if intrinsic == Some("transmute") { - let &(ref dest, target) = destination.as_ref().unwrap(); - self.trans_transmute(&bx, &args[0], dest); - funclet_br(self, bx, target); - return; - } - - let extra_args = &args[sig.inputs().len()..]; - let extra_args = extra_args.iter().map(|op_arg| { - let op_ty = op_arg.ty(self.mir, bx.tcx()); - self.monomorphize(&op_ty) - }).collect::>(); - - let fn_ty = match def { - Some(ty::InstanceDef::Virtual(..)) => { - FnType::new_vtable(bx.cx, sig, &extra_args) - } - Some(ty::InstanceDef::DropGlue(_, None)) => { - // empty drop glue - a nop. - let &(_, target) = destination.as_ref().unwrap(); - funclet_br(self, bx, target); - return; - } - _ => FnType::new(bx.cx, sig, &extra_args) - }; - - // The arguments we'll be passing. Plus one to account for outptr, if used. - let arg_count = fn_ty.args.len() + fn_ty.ret.is_indirect() as usize; - let mut llargs = Vec::with_capacity(arg_count); - - // Prepare the return value destination - let ret_dest = if let Some((ref dest, _)) = *destination { - let is_intrinsic = intrinsic.is_some(); - self.make_return_dest(&bx, dest, &fn_ty.ret, &mut llargs, - is_intrinsic) - } else { - ReturnDest::Nothing - }; - - if intrinsic.is_some() && intrinsic != Some("drop_in_place") { - use intrinsic::trans_intrinsic_call; - - let dest = match ret_dest { - _ if fn_ty.ret.is_indirect() => llargs[0], - ReturnDest::Nothing => { - C_undef(fn_ty.ret.memory_ty(bx.cx).ptr_to()) - } - ReturnDest::IndirectOperand(dst, _) | - ReturnDest::Store(dst) => dst.llval, - ReturnDest::DirectOperand(_) => - bug!("Cannot use direct operand with an intrinsic call") - }; - - let args: Vec<_> = args.iter().enumerate().map(|(i, arg)| { - // The indices passed to simd_shuffle* in the - // third argument must be constant. This is - // checked by const-qualification, which also - // promotes any complex rvalues to constants. - if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") { - match *arg { - mir::Operand::Copy(_) | - mir::Operand::Move(_) => { - span_bug!(span, "shuffle indices must be constant"); - } - mir::Operand::Constant(ref constant) => { - let (llval, ty) = self.simd_shuffle_indices( - &bx, - constant, - ); - return OperandRef { - val: Immediate(llval), - layout: bx.cx.layout_of(ty) - }; - } - } - } - - self.trans_operand(&bx, arg) - }).collect(); - - - let callee_ty = instance.as_ref().unwrap().ty(bx.cx.tcx); - trans_intrinsic_call(&bx, callee_ty, &fn_ty, &args, dest, - terminator.source_info.span); - - if let ReturnDest::IndirectOperand(dst, _) = ret_dest { - self.store_return(&bx, ret_dest, &fn_ty.ret, dst.llval); - } - - if let Some((_, target)) = *destination { - funclet_br(self, bx, target); - } else { - bx.unreachable(); - } - - return; - } - - // Split the rust-call tupled arguments off. - let (first_args, untuple) = if abi == Abi::RustCall && !args.is_empty() { - let (tup, args) = args.split_last().unwrap(); - (args, Some(tup)) - } else { - (&args[..], None) - }; - - for (i, arg) in first_args.iter().enumerate() { - let mut op = self.trans_operand(&bx, arg); - if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) { - if let Pair(data_ptr, meta) = op.val { - llfn = Some(meth::VirtualIndex::from_index(idx) - .get_fn(&bx, meta, &fn_ty)); - llargs.push(data_ptr); - continue; - } - } - - // The callee needs to own the argument memory if we pass it - // by-ref, so make a local copy of non-immediate constants. - match (arg, op.val) { - (&mir::Operand::Copy(_), Ref(..)) | - (&mir::Operand::Constant(_), Ref(..)) => { - let tmp = PlaceRef::alloca(&bx, op.layout, "const"); - op.val.store(&bx, tmp); - op.val = Ref(tmp.llval, tmp.align); - } - _ => {} - } - - self.trans_argument(&bx, op, &mut llargs, &fn_ty.args[i]); - } - if let Some(tup) = untuple { - self.trans_arguments_untupled(&bx, tup, &mut llargs, - &fn_ty.args[first_args.len()..]) - } - - let fn_ptr = match (llfn, instance) { - (Some(llfn), _) => llfn, - (None, Some(instance)) => callee::get_fn(bx.cx, instance), - _ => span_bug!(span, "no llfn for call"), - }; - - do_call(self, bx, fn_ty, fn_ptr, &llargs, - destination.as_ref().map(|&(_, target)| (ret_dest, target)), - cleanup); - } - mir::TerminatorKind::GeneratorDrop | - mir::TerminatorKind::Yield { .. } => bug!("generator ops in trans"), - mir::TerminatorKind::FalseEdges { .. } | - mir::TerminatorKind::FalseUnwind { .. } => bug!("borrowck false edges in trans"), - } - } - - fn trans_argument(&mut self, - bx: &Builder<'a, 'tcx>, - op: OperandRef<'tcx>, - llargs: &mut Vec, - arg: &ArgType<'tcx, Ty<'tcx>>) { - // Fill padding with undef value, where applicable. - if let Some(ty) = arg.pad { - llargs.push(C_undef(ty.llvm_type(bx.cx))); - } - - if arg.is_ignore() { - return; - } - - if let PassMode::Pair(..) = arg.mode { - match op.val { - Pair(a, b) => { - llargs.push(a); - llargs.push(b); - return; - } - _ => bug!("trans_argument: {:?} invalid for pair arugment", op) - } - } - - // Force by-ref if we have to load through a cast pointer. - let (mut llval, align, by_ref) = match op.val { - Immediate(_) | Pair(..) => { - match arg.mode { - PassMode::Indirect(_) | PassMode::Cast(_) => { - let scratch = PlaceRef::alloca(bx, arg.layout, "arg"); - op.val.store(bx, scratch); - (scratch.llval, scratch.align, true) - } - _ => { - (op.immediate_or_packed_pair(bx), arg.layout.align, false) - } - } - } - Ref(llval, align) => { - if arg.is_indirect() && align.abi() < arg.layout.align.abi() { - // `foo(packed.large_field)`. We can't pass the (unaligned) field directly. I - // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't - // have scary latent bugs around. - - let scratch = PlaceRef::alloca(bx, arg.layout, "arg"); - base::memcpy_ty(bx, scratch.llval, llval, op.layout, align, MemFlags::empty()); - (scratch.llval, scratch.align, true) - } else { - (llval, align, true) - } - } - }; - - if by_ref && !arg.is_indirect() { - // Have to load the argument, maybe while casting it. - if let PassMode::Cast(ty) = arg.mode { - llval = bx.load(bx.pointercast(llval, ty.llvm_type(bx.cx).ptr_to()), - align.min(arg.layout.align)); - } else { - // We can't use `PlaceRef::load` here because the argument - // may have a type we don't treat as immediate, but the ABI - // used for this call is passing it by-value. In that case, - // the load would just produce `OperandValue::Ref` instead - // of the `OperandValue::Immediate` we need for the call. - llval = bx.load(llval, align); - if let layout::Abi::Scalar(ref scalar) = arg.layout.abi { - if scalar.is_bool() { - bx.range_metadata(llval, 0..2); - } - } - // We store bools as i8 so we need to truncate to i1. - llval = base::to_immediate(bx, llval, arg.layout); - } - } - - llargs.push(llval); - } - - fn trans_arguments_untupled(&mut self, - bx: &Builder<'a, 'tcx>, - operand: &mir::Operand<'tcx>, - llargs: &mut Vec, - args: &[ArgType<'tcx, Ty<'tcx>>]) { - let tuple = self.trans_operand(bx, operand); - - // Handle both by-ref and immediate tuples. - if let Ref(llval, align) = tuple.val { - let tuple_ptr = PlaceRef::new_sized(llval, tuple.layout, align); - for i in 0..tuple.layout.fields.count() { - let field_ptr = tuple_ptr.project_field(bx, i); - self.trans_argument(bx, field_ptr.load(bx), llargs, &args[i]); - } - } else { - // If the tuple is immediate, the elements are as well. - for i in 0..tuple.layout.fields.count() { - let op = tuple.extract_field(bx, i); - self.trans_argument(bx, op, llargs, &args[i]); - } - } - } - - fn get_personality_slot(&mut self, bx: &Builder<'a, 'tcx>) -> PlaceRef<'tcx> { - let cx = bx.cx; - if let Some(slot) = self.personality_slot { - slot - } else { - let layout = cx.layout_of(cx.tcx.intern_tup(&[ - cx.tcx.mk_mut_ptr(cx.tcx.types.u8), - cx.tcx.types.i32 - ])); - let slot = PlaceRef::alloca(bx, layout, "personalityslot"); - self.personality_slot = Some(slot); - slot - } - } - - /// Return the landingpad wrapper around the given basic block - /// - /// No-op in MSVC SEH scheme. - fn landing_pad_to(&mut self, target_bb: mir::BasicBlock) -> BasicBlockRef { - if let Some(block) = self.landing_pads[target_bb] { - return block; - } - - let block = self.blocks[target_bb]; - let landing_pad = self.landing_pad_uncached(block); - self.landing_pads[target_bb] = Some(landing_pad); - landing_pad - } - - fn landing_pad_uncached(&mut self, target_bb: BasicBlockRef) -> BasicBlockRef { - if base::wants_msvc_seh(self.cx.sess()) { - span_bug!(self.mir.span, "landing pad was not inserted?") - } - - let bx = self.new_block("cleanup"); - - let llpersonality = self.cx.eh_personality(); - let llretty = self.landing_pad_type(); - let lp = bx.landing_pad(llretty, llpersonality, 1); - bx.set_cleanup(lp); - - let slot = self.get_personality_slot(&bx); - slot.storage_live(&bx); - Pair(bx.extract_value(lp, 0), bx.extract_value(lp, 1)).store(&bx, slot); - - bx.br(target_bb); - bx.llbb() - } - - fn landing_pad_type(&self) -> Type { - let cx = self.cx; - Type::struct_(cx, &[Type::i8p(cx), Type::i32(cx)], false) - } - - fn unreachable_block(&mut self) -> BasicBlockRef { - self.unreachable_block.unwrap_or_else(|| { - let bl = self.new_block("unreachable"); - bl.unreachable(); - self.unreachable_block = Some(bl.llbb()); - bl.llbb() - }) - } - - pub fn new_block(&self, name: &str) -> Builder<'a, 'tcx> { - Builder::new_block(self.cx, self.llfn, name) - } - - pub fn build_block(&self, bb: mir::BasicBlock) -> Builder<'a, 'tcx> { - let bx = Builder::with_cx(self.cx); - bx.position_at_end(self.blocks[bb]); - bx - } - - fn make_return_dest(&mut self, bx: &Builder<'a, 'tcx>, - dest: &mir::Place<'tcx>, fn_ret: &ArgType<'tcx, Ty<'tcx>>, - llargs: &mut Vec, is_intrinsic: bool) - -> ReturnDest<'tcx> { - // If the return is ignored, we can just return a do-nothing ReturnDest - if fn_ret.is_ignore() { - return ReturnDest::Nothing; - } - let dest = if let mir::Place::Local(index) = *dest { - match self.locals[index] { - LocalRef::Place(dest) => dest, - LocalRef::Operand(None) => { - // Handle temporary places, specifically Operand ones, as - // they don't have allocas - return if fn_ret.is_indirect() { - // Odd, but possible, case, we have an operand temporary, - // but the calling convention has an indirect return. - let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret"); - tmp.storage_live(bx); - llargs.push(tmp.llval); - ReturnDest::IndirectOperand(tmp, index) - } else if is_intrinsic { - // Currently, intrinsics always need a location to store - // the result. so we create a temporary alloca for the - // result - let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret"); - tmp.storage_live(bx); - ReturnDest::IndirectOperand(tmp, index) - } else { - ReturnDest::DirectOperand(index) - }; - } - LocalRef::Operand(Some(_)) => { - bug!("place local already assigned to"); - } - } - } else { - self.trans_place(bx, dest) - }; - if fn_ret.is_indirect() { - if dest.align.abi() < dest.layout.align.abi() { - // Currently, MIR code generation does not create calls - // that store directly to fields of packed structs (in - // fact, the calls it creates write only to temps), - // - // If someone changes that, please update this code path - // to create a temporary. - span_bug!(self.mir.span, "can't directly store to unaligned value"); - } - llargs.push(dest.llval); - ReturnDest::Nothing - } else { - ReturnDest::Store(dest) - } - } - - fn trans_transmute(&mut self, bx: &Builder<'a, 'tcx>, - src: &mir::Operand<'tcx>, - dst: &mir::Place<'tcx>) { - if let mir::Place::Local(index) = *dst { - match self.locals[index] { - LocalRef::Place(place) => self.trans_transmute_into(bx, src, place), - LocalRef::Operand(None) => { - let dst_layout = bx.cx.layout_of(self.monomorphized_place_ty(dst)); - assert!(!dst_layout.ty.has_erasable_regions()); - let place = PlaceRef::alloca(bx, dst_layout, "transmute_temp"); - place.storage_live(bx); - self.trans_transmute_into(bx, src, place); - let op = place.load(bx); - place.storage_dead(bx); - self.locals[index] = LocalRef::Operand(Some(op)); - } - LocalRef::Operand(Some(op)) => { - assert!(op.layout.is_zst(), - "assigning to initialized SSAtemp"); - } - } - } else { - let dst = self.trans_place(bx, dst); - self.trans_transmute_into(bx, src, dst); - } - } - - fn trans_transmute_into(&mut self, bx: &Builder<'a, 'tcx>, - src: &mir::Operand<'tcx>, - dst: PlaceRef<'tcx>) { - let src = self.trans_operand(bx, src); - let llty = src.layout.llvm_type(bx.cx); - let cast_ptr = bx.pointercast(dst.llval, llty.ptr_to()); - let align = src.layout.align.min(dst.layout.align); - src.val.store(bx, PlaceRef::new_sized(cast_ptr, src.layout, align)); - } - - - // Stores the return value of a function call into it's final location. - fn store_return(&mut self, - bx: &Builder<'a, 'tcx>, - dest: ReturnDest<'tcx>, - ret_ty: &ArgType<'tcx, Ty<'tcx>>, - llval: ValueRef) { - use self::ReturnDest::*; - - match dest { - Nothing => (), - Store(dst) => ret_ty.store(bx, llval, dst), - IndirectOperand(tmp, index) => { - let op = tmp.load(bx); - tmp.storage_dead(bx); - self.locals[index] = LocalRef::Operand(Some(op)); - } - DirectOperand(index) => { - // If there is a cast, we have to store and reload. - let op = if let PassMode::Cast(_) = ret_ty.mode { - let tmp = PlaceRef::alloca(bx, ret_ty.layout, "tmp_ret"); - tmp.storage_live(bx); - ret_ty.store(bx, llval, tmp); - let op = tmp.load(bx); - tmp.storage_dead(bx); - op - } else { - OperandRef::from_immediate_or_packed_pair(bx, llval, ret_ty.layout) - }; - self.locals[index] = LocalRef::Operand(Some(op)); - } - } - } -} - -enum ReturnDest<'tcx> { - // Do nothing, the return value is indirect or ignored - Nothing, - // Store the return value to the pointer - Store(PlaceRef<'tcx>), - // Stores an indirect return value to an operand local place - IndirectOperand(PlaceRef<'tcx>, mir::Local), - // Stores a direct return value to an operand local place - DirectOperand(mir::Local) -} diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs deleted file mode 100644 index a10b7c9c9f1..00000000000 --- a/src/librustc_trans/mir/constant.rs +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use llvm::{self, ValueRef}; -use rustc::middle::const_val::{ConstVal, ConstEvalErr}; -use rustc_mir::interpret::{read_target_uint, const_val_field}; -use rustc::hir::def_id::DefId; -use rustc::mir; -use rustc_data_structures::indexed_vec::Idx; -use rustc::mir::interpret::{GlobalId, MemoryPointer, PrimVal, Allocation, ConstValue}; -use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar}; -use builder::Builder; -use common::{CodegenCx}; -use common::{C_bytes, C_struct, C_uint_big, C_undef, C_usize}; -use consts; -use type_of::LayoutLlvmExt; -use type_::Type; -use syntax::ast::Mutability; - -use super::super::callee; -use super::FunctionCx; - -pub fn primval_to_llvm(cx: &CodegenCx, - cv: PrimVal, - scalar: &Scalar, - llty: Type) -> ValueRef { - let bits = if scalar.is_bool() { 1 } else { scalar.value.size(cx).bits() }; - match cv { - PrimVal::Undef => C_undef(Type::ix(cx, bits)), - PrimVal::Bytes(b) => { - let llval = C_uint_big(Type::ix(cx, bits), b); - if scalar.value == layout::Pointer { - unsafe { llvm::LLVMConstIntToPtr(llval, llty.to_ref()) } - } else { - consts::bitcast(llval, llty) - } - }, - PrimVal::Ptr(ptr) => { - if let Some(fn_instance) = cx.tcx.interpret_interner.get_fn(ptr.alloc_id) { - callee::get_fn(cx, fn_instance) - } else { - let static_ = cx - .tcx - .interpret_interner - .get_static(ptr.alloc_id); - let base_addr = if let Some(def_id) = static_ { - assert!(cx.tcx.is_static(def_id).is_some()); - consts::get_static(cx, def_id) - } else if let Some(alloc) = cx.tcx.interpret_interner - .get_alloc(ptr.alloc_id) { - let init = const_alloc_to_llvm(cx, alloc); - if alloc.runtime_mutability == Mutability::Mutable { - consts::addr_of_mut(cx, init, alloc.align, "byte_str") - } else { - consts::addr_of(cx, init, alloc.align, "byte_str") - } - } else { - bug!("missing allocation {:?}", ptr.alloc_id); - }; - - let llval = unsafe { llvm::LLVMConstInBoundsGEP( - consts::bitcast(base_addr, Type::i8p(cx)), - &C_usize(cx, ptr.offset), - 1, - ) }; - if scalar.value != layout::Pointer { - unsafe { llvm::LLVMConstPtrToInt(llval, llty.to_ref()) } - } else { - consts::bitcast(llval, llty) - } - } - } - } -} - -fn const_value_to_llvm<'tcx>(cx: &CodegenCx<'_, 'tcx>, val: ConstValue, ty: Ty<'tcx>) -> ValueRef { - let layout = cx.layout_of(ty); - - if layout.is_zst() { - return C_undef(layout.immediate_llvm_type(cx)); - } - - match val { - ConstValue::ByVal(x) => { - let scalar = match layout.abi { - layout::Abi::Scalar(ref x) => x, - _ => bug!("const_value_to_llvm: invalid ByVal layout: {:#?}", layout) - }; - primval_to_llvm( - cx, - x, - scalar, - layout.immediate_llvm_type(cx), - ) - }, - ConstValue::ByValPair(a, b) => { - let (a_scalar, b_scalar) = match layout.abi { - layout::Abi::ScalarPair(ref a, ref b) => (a, b), - _ => bug!("const_value_to_llvm: invalid ByValPair layout: {:#?}", layout) - }; - let a_llval = primval_to_llvm( - cx, - a, - a_scalar, - layout.scalar_pair_element_llvm_type(cx, 0), - ); - let b_llval = primval_to_llvm( - cx, - b, - b_scalar, - layout.scalar_pair_element_llvm_type(cx, 1), - ); - C_struct(cx, &[a_llval, b_llval], false) - }, - ConstValue::ByRef(alloc) => const_alloc_to_llvm(cx, alloc), - } -} - -pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef { - let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1); - let layout = cx.data_layout(); - let pointer_size = layout.pointer_size.bytes() as usize; - - let mut next_offset = 0; - for (&offset, &alloc_id) in &alloc.relocations { - assert_eq!(offset as usize as u64, offset); - let offset = offset as usize; - if offset > next_offset { - llvals.push(C_bytes(cx, &alloc.bytes[next_offset..offset])); - } - let ptr_offset = read_target_uint( - layout.endian, - &alloc.bytes[offset..(offset + pointer_size)], - ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64; - llvals.push(primval_to_llvm( - cx, - PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }), - &Scalar { - value: layout::Primitive::Pointer, - valid_range: 0..=!0 - }, - Type::i8p(cx) - )); - next_offset = offset + pointer_size; - } - if alloc.bytes.len() >= next_offset { - llvals.push(C_bytes(cx, &alloc.bytes[next_offset ..])); - } - - C_struct(cx, &llvals, true) -} - -pub fn trans_static_initializer<'a, 'tcx>( - cx: &CodegenCx<'a, 'tcx>, - def_id: DefId) - -> Result> -{ - let instance = ty::Instance::mono(cx.tcx, def_id); - let cid = GlobalId { - instance, - promoted: None - }; - let param_env = ty::ParamEnv::reveal_all(); - let static_ = cx.tcx.const_eval(param_env.and(cid))?; - - let val = match static_.val { - ConstVal::Value(val) => val, - _ => bug!("static const eval returned {:#?}", static_), - }; - Ok(const_value_to_llvm(cx, val, static_.ty)) -} - -impl<'a, 'tcx> FunctionCx<'a, 'tcx> { - fn const_to_const_value( - &mut self, - bx: &Builder<'a, 'tcx>, - constant: &'tcx ty::Const<'tcx>, - ) -> Result, ConstEvalErr<'tcx>> { - match constant.val { - ConstVal::Unevaluated(def_id, ref substs) => { - let tcx = bx.tcx(); - let param_env = ty::ParamEnv::reveal_all(); - let instance = ty::Instance::resolve(tcx, param_env, def_id, substs).unwrap(); - let cid = GlobalId { - instance, - promoted: None, - }; - let c = tcx.const_eval(param_env.and(cid))?; - self.const_to_const_value(bx, c) - }, - ConstVal::Value(val) => Ok(val), - } - } - - pub fn mir_constant_to_const_value( - &mut self, - bx: &Builder<'a, 'tcx>, - constant: &mir::Constant<'tcx>, - ) -> Result, ConstEvalErr<'tcx>> { - match constant.literal { - mir::Literal::Promoted { index } => { - let param_env = ty::ParamEnv::reveal_all(); - let cid = mir::interpret::GlobalId { - instance: self.instance, - promoted: Some(index), - }; - bx.tcx().const_eval(param_env.and(cid)) - } - mir::Literal::Value { value } => { - Ok(self.monomorphize(&value)) - } - }.and_then(|c| self.const_to_const_value(bx, c)) - } - - /// process constant containing SIMD shuffle indices - pub fn simd_shuffle_indices( - &mut self, - bx: &Builder<'a, 'tcx>, - constant: &mir::Constant<'tcx>, - ) -> (ValueRef, Ty<'tcx>) { - self.mir_constant_to_const_value(bx, constant) - .and_then(|c| { - let field_ty = constant.ty.builtin_index().unwrap(); - let fields = match constant.ty.sty { - ty::TyArray(_, n) => n.unwrap_usize(bx.tcx()), - ref other => bug!("invalid simd shuffle type: {}", other), - }; - let values: Result, _> = (0..fields).map(|field| { - let field = const_val_field( - bx.tcx(), - ty::ParamEnv::reveal_all(), - self.instance, - None, - mir::Field::new(field as usize), - c, - constant.ty, - )?; - if let Some(prim) = field.to_primval() { - let layout = bx.cx.layout_of(field_ty); - let scalar = match layout.abi { - layout::Abi::Scalar(ref x) => x, - _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) - }; - Ok(primval_to_llvm( - bx.cx, prim, scalar, - layout.immediate_llvm_type(bx.cx), - )) - } else { - bug!("simd shuffle field {:?}", field) - } - }).collect(); - let llval = C_struct(bx.cx, &values?, false); - Ok((llval, constant.ty)) - }) - .unwrap_or_else(|e| { - e.report(bx.tcx(), constant.span, "shuffle_indices"); - // We've errored, so we don't have to produce working code. - let ty = self.monomorphize(&constant.ty); - let llty = bx.cx.layout_of(ty).llvm_type(bx.cx); - (C_undef(llty), ty) - }) - } -} diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs deleted file mode 100644 index 8ea0983075d..00000000000 --- a/src/librustc_trans/mir/mod.rs +++ /dev/null @@ -1,652 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use common::{C_i32, C_null}; -use libc::c_uint; -use llvm::{self, ValueRef, BasicBlockRef}; -use llvm::debuginfo::DIScope; -use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts}; -use rustc::ty::layout::{LayoutOf, TyLayout}; -use rustc::mir::{self, Mir}; -use rustc::ty::subst::Substs; -use rustc::session::config::FullDebugInfo; -use base; -use builder::Builder; -use common::{CodegenCx, Funclet}; -use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext}; -use monomorphize::Instance; -use abi::{ArgAttribute, ArgTypeExt, FnType, FnTypeExt, PassMode}; -use type_::Type; - -use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span}; -use syntax::symbol::keywords; - -use std::iter; - -use rustc_data_structures::bitvec::BitVector; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; - -pub use self::constant::trans_static_initializer; - -use self::analyze::CleanupKind; -use self::place::PlaceRef; -use rustc::mir::traversal; - -use self::operand::{OperandRef, OperandValue}; - -/// Master context for translating MIR. -pub struct FunctionCx<'a, 'tcx:'a> { - instance: Instance<'tcx>, - - mir: &'a mir::Mir<'tcx>, - - debug_context: debuginfo::FunctionDebugContext, - - llfn: ValueRef, - - cx: &'a CodegenCx<'a, 'tcx>, - - fn_ty: FnType<'tcx, Ty<'tcx>>, - - /// When unwinding is initiated, we have to store this personality - /// value somewhere so that we can load it and re-use it in the - /// resume instruction. The personality is (afaik) some kind of - /// value used for C++ unwinding, which must filter by type: we - /// don't really care about it very much. Anyway, this value - /// contains an alloca into which the personality is stored and - /// then later loaded when generating the DIVERGE_BLOCK. - personality_slot: Option>, - - /// A `Block` for each MIR `BasicBlock` - blocks: IndexVec, - - /// The funclet status of each basic block - cleanup_kinds: IndexVec, - - /// When targeting MSVC, this stores the cleanup info for each funclet - /// BB. This is initialized as we compute the funclets' head block in RPO. - funclets: &'a IndexVec>, - - /// This stores the landing-pad block for a given BB, computed lazily on GNU - /// and eagerly on MSVC. - landing_pads: IndexVec>, - - /// Cached unreachable block - unreachable_block: Option, - - /// The location where each MIR arg/var/tmp/ret is stored. This is - /// usually an `PlaceRef` representing an alloca, but not always: - /// sometimes we can skip the alloca and just store the value - /// directly using an `OperandRef`, which makes for tighter LLVM - /// IR. The conditions for using an `OperandRef` are as follows: - /// - /// - the type of the local must be judged "immediate" by `is_llvm_immediate` - /// - the operand must never be referenced indirectly - /// - we should not take its address using the `&` operator - /// - nor should it appear in a place path like `tmp.a` - /// - the operand must be defined by an rvalue that can generate immediate - /// values - /// - /// Avoiding allocs can also be important for certain intrinsics, - /// notably `expect`. - locals: IndexVec>, - - /// Debug information for MIR scopes. - scopes: IndexVec, - - /// If this function is being monomorphized, this contains the type substitutions used. - param_substs: &'tcx Substs<'tcx>, -} - -impl<'a, 'tcx> FunctionCx<'a, 'tcx> { - pub fn monomorphize(&self, value: &T) -> T - where T: TypeFoldable<'tcx> - { - self.cx.tcx.subst_and_normalize_erasing_regions( - self.param_substs, - ty::ParamEnv::reveal_all(), - value, - ) - } - - pub fn set_debug_loc(&mut self, bx: &Builder, source_info: mir::SourceInfo) { - let (scope, span) = self.debug_loc(source_info); - debuginfo::set_source_location(&self.debug_context, bx, scope, span); - } - - pub fn debug_loc(&mut self, source_info: mir::SourceInfo) -> (DIScope, Span) { - // Bail out if debug info emission is not enabled. - match self.debug_context { - FunctionDebugContext::DebugInfoDisabled | - FunctionDebugContext::FunctionWithoutDebugInfo => { - return (self.scopes[source_info.scope].scope_metadata, source_info.span); - } - FunctionDebugContext::RegularContext(_) =>{} - } - - // In order to have a good line stepping behavior in debugger, we overwrite debug - // locations of macro expansions with that of the outermost expansion site - // (unless the crate is being compiled with `-Z debug-macros`). - if source_info.span.ctxt() == NO_EXPANSION || - self.cx.sess().opts.debugging_opts.debug_macros { - let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo()); - (scope, source_info.span) - } else { - // Walk up the macro expansion chain until we reach a non-expanded span. - // We also stop at the function body level because no line stepping can occur - // at the level above that. - let mut span = source_info.span; - while span.ctxt() != NO_EXPANSION && span.ctxt() != self.mir.span.ctxt() { - if let Some(info) = span.ctxt().outer().expn_info() { - span = info.call_site; - } else { - break; - } - } - let scope = self.scope_metadata_for_loc(source_info.scope, span.lo()); - // Use span of the outermost expansion site, while keeping the original lexical scope. - (scope, span) - } - } - - // DILocations inherit source file name from the parent DIScope. Due to macro expansions - // it may so happen that the current span belongs to a different file than the DIScope - // corresponding to span's containing visibility scope. If so, we need to create a DIScope - // "extension" into that file. - fn scope_metadata_for_loc(&self, scope_id: mir::VisibilityScope, pos: BytePos) - -> llvm::debuginfo::DIScope { - let scope_metadata = self.scopes[scope_id].scope_metadata; - if pos < self.scopes[scope_id].file_start_pos || - pos >= self.scopes[scope_id].file_end_pos { - let cm = self.cx.sess().codemap(); - let defining_crate = self.debug_context.get_ref(DUMMY_SP).defining_crate; - debuginfo::extend_scope_to_file(self.cx, - scope_metadata, - &cm.lookup_char_pos(pos).file, - defining_crate) - } else { - scope_metadata - } - } -} - -enum LocalRef<'tcx> { - Place(PlaceRef<'tcx>), - Operand(Option>), -} - -impl<'a, 'tcx> LocalRef<'tcx> { - fn new_operand(cx: &CodegenCx<'a, 'tcx>, layout: TyLayout<'tcx>) -> LocalRef<'tcx> { - if layout.is_zst() { - // Zero-size temporaries aren't always initialized, which - // doesn't matter because they don't contain data, but - // we need something in the operand. - LocalRef::Operand(Some(OperandRef::new_zst(cx, layout))) - } else { - LocalRef::Operand(None) - } - } -} - -/////////////////////////////////////////////////////////////////////////// - -pub fn trans_mir<'a, 'tcx: 'a>( - cx: &'a CodegenCx<'a, 'tcx>, - llfn: ValueRef, - mir: &'a Mir<'tcx>, - instance: Instance<'tcx>, - sig: ty::FnSig<'tcx>, -) { - let fn_ty = FnType::new(cx, sig, &[]); - debug!("fn_ty: {:?}", fn_ty); - let debug_context = - debuginfo::create_function_debug_context(cx, instance, sig, llfn, mir); - let bx = Builder::new_block(cx, llfn, "start"); - - if mir.basic_blocks().iter().any(|bb| bb.is_cleanup) { - bx.set_personality_fn(cx.eh_personality()); - } - - let cleanup_kinds = analyze::cleanup_kinds(&mir); - // Allocate a `Block` for every basic block, except - // the start block, if nothing loops back to it. - let reentrant_start_block = !mir.predecessors_for(mir::START_BLOCK).is_empty(); - let block_bxs: IndexVec = - mir.basic_blocks().indices().map(|bb| { - if bb == mir::START_BLOCK && !reentrant_start_block { - bx.llbb() - } else { - bx.build_sibling_block(&format!("{:?}", bb)).llbb() - } - }).collect(); - - // Compute debuginfo scopes from MIR scopes. - let scopes = debuginfo::create_mir_scopes(cx, mir, &debug_context); - let (landing_pads, funclets) = create_funclets(mir, &bx, &cleanup_kinds, &block_bxs); - - let mut fx = FunctionCx { - instance, - mir, - llfn, - fn_ty, - cx, - personality_slot: None, - blocks: block_bxs, - unreachable_block: None, - cleanup_kinds, - landing_pads, - funclets: &funclets, - scopes, - locals: IndexVec::new(), - debug_context, - param_substs: { - assert!(!instance.substs.needs_infer()); - instance.substs - }, - }; - - let memory_locals = analyze::non_ssa_locals(&fx); - - // Allocate variable and temp allocas - fx.locals = { - let args = arg_local_refs(&bx, &fx, &fx.scopes, &memory_locals); - - let mut allocate_local = |local| { - let decl = &mir.local_decls[local]; - let layout = bx.cx.layout_of(fx.monomorphize(&decl.ty)); - assert!(!layout.ty.has_erasable_regions()); - - if let Some(name) = decl.name { - // User variable - let debug_scope = fx.scopes[decl.source_info.scope]; - let dbg = debug_scope.is_valid() && bx.sess().opts.debuginfo == FullDebugInfo; - - if !memory_locals.contains(local.index()) && !dbg { - debug!("alloc: {:?} ({}) -> operand", local, name); - return LocalRef::new_operand(bx.cx, layout); - } - - debug!("alloc: {:?} ({}) -> place", local, name); - let place = PlaceRef::alloca(&bx, layout, &name.as_str()); - if dbg { - let (scope, span) = fx.debug_loc(decl.source_info); - declare_local(&bx, &fx.debug_context, name, layout.ty, scope, - VariableAccess::DirectVariable { alloca: place.llval }, - VariableKind::LocalVariable, span); - } - LocalRef::Place(place) - } else { - // Temporary or return place - if local == mir::RETURN_PLACE && fx.fn_ty.ret.is_indirect() { - debug!("alloc: {:?} (return place) -> place", local); - let llretptr = llvm::get_param(llfn, 0); - LocalRef::Place(PlaceRef::new_sized(llretptr, layout, layout.align)) - } else if memory_locals.contains(local.index()) { - debug!("alloc: {:?} -> place", local); - LocalRef::Place(PlaceRef::alloca(&bx, layout, &format!("{:?}", local))) - } else { - // If this is an immediate local, we do not create an - // alloca in advance. Instead we wait until we see the - // definition and update the operand there. - debug!("alloc: {:?} -> operand", local); - LocalRef::new_operand(bx.cx, layout) - } - } - }; - - let retptr = allocate_local(mir::RETURN_PLACE); - iter::once(retptr) - .chain(args.into_iter()) - .chain(mir.vars_and_temps_iter().map(allocate_local)) - .collect() - }; - - // Branch to the START block, if it's not the entry block. - if reentrant_start_block { - bx.br(fx.blocks[mir::START_BLOCK]); - } - - // Up until here, IR instructions for this function have explicitly not been annotated with - // source code location, so we don't step into call setup code. From here on, source location - // emitting should be enabled. - debuginfo::start_emitting_source_locations(&fx.debug_context); - - let rpo = traversal::reverse_postorder(&mir); - let mut visited = BitVector::new(mir.basic_blocks().len()); - - // Translate the body of each block using reverse postorder - for (bb, _) in rpo { - visited.insert(bb.index()); - fx.trans_block(bb); - } - - // Remove blocks that haven't been visited, or have no - // predecessors. - for bb in mir.basic_blocks().indices() { - // Unreachable block - if !visited.contains(bb.index()) { - debug!("trans_mir: block {:?} was not visited", bb); - unsafe { - llvm::LLVMDeleteBasicBlock(fx.blocks[bb]); - } - } - } -} - -fn create_funclets<'a, 'tcx>( - mir: &'a Mir<'tcx>, - bx: &Builder<'a, 'tcx>, - cleanup_kinds: &IndexVec, - block_bxs: &IndexVec) - -> (IndexVec>, - IndexVec>) -{ - block_bxs.iter_enumerated().zip(cleanup_kinds).map(|((bb, &llbb), cleanup_kind)| { - match *cleanup_kind { - CleanupKind::Funclet if base::wants_msvc_seh(bx.sess()) => {} - _ => return (None, None) - } - - let cleanup; - let ret_llbb; - match mir[bb].terminator.as_ref().map(|t| &t.kind) { - // This is a basic block that we're aborting the program for, - // notably in an `extern` function. These basic blocks are inserted - // so that we assert that `extern` functions do indeed not panic, - // and if they do we abort the process. - // - // On MSVC these are tricky though (where we're doing funclets). If - // we were to do a cleanuppad (like below) the normal functions like - // `longjmp` would trigger the abort logic, terminating the - // program. Instead we insert the equivalent of `catch(...)` for C++ - // which magically doesn't trigger when `longjmp` files over this - // frame. - // - // Lots more discussion can be found on #48251 but this codegen is - // modeled after clang's for: - // - // try { - // foo(); - // } catch (...) { - // bar(); - // } - Some(&mir::TerminatorKind::Abort) => { - let cs_bx = bx.build_sibling_block(&format!("cs_funclet{:?}", bb)); - let cp_bx = bx.build_sibling_block(&format!("cp_funclet{:?}", bb)); - ret_llbb = cs_bx.llbb(); - - let cs = cs_bx.catch_switch(None, None, 1); - cs_bx.add_handler(cs, cp_bx.llbb()); - - // The "null" here is actually a RTTI type descriptor for the - // C++ personality function, but `catch (...)` has no type so - // it's null. The 64 here is actually a bitfield which - // represents that this is a catch-all block. - let null = C_null(Type::i8p(bx.cx)); - let sixty_four = C_i32(bx.cx, 64); - cleanup = cp_bx.catch_pad(cs, &[null, sixty_four, null]); - cp_bx.br(llbb); - } - _ => { - let cleanup_bx = bx.build_sibling_block(&format!("funclet_{:?}", bb)); - ret_llbb = cleanup_bx.llbb(); - cleanup = cleanup_bx.cleanup_pad(None, &[]); - cleanup_bx.br(llbb); - } - }; - - (Some(ret_llbb), Some(Funclet::new(cleanup))) - }).unzip() -} - -/// Produce, for each argument, a `ValueRef` pointing at the -/// argument's value. As arguments are places, these are always -/// indirect. -fn arg_local_refs<'a, 'tcx>(bx: &Builder<'a, 'tcx>, - fx: &FunctionCx<'a, 'tcx>, - scopes: &IndexVec, - memory_locals: &BitVector) - -> Vec> { - let mir = fx.mir; - let tcx = bx.tcx(); - let mut idx = 0; - let mut llarg_idx = fx.fn_ty.ret.is_indirect() as usize; - - // Get the argument scope, if it exists and if we need it. - let arg_scope = scopes[mir::ARGUMENT_VISIBILITY_SCOPE]; - let arg_scope = if arg_scope.is_valid() && bx.sess().opts.debuginfo == FullDebugInfo { - Some(arg_scope.scope_metadata) - } else { - None - }; - - let deref_op = unsafe { - [llvm::LLVMRustDIBuilderCreateOpDeref()] - }; - - mir.args_iter().enumerate().map(|(arg_index, local)| { - let arg_decl = &mir.local_decls[local]; - - let name = if let Some(name) = arg_decl.name { - name.as_str().to_string() - } else { - format!("arg{}", arg_index) - }; - - if Some(local) == mir.spread_arg { - // This argument (e.g. the last argument in the "rust-call" ABI) - // is a tuple that was spread at the ABI level and now we have - // to reconstruct it into a tuple local variable, from multiple - // individual LLVM function arguments. - - let arg_ty = fx.monomorphize(&arg_decl.ty); - let tupled_arg_tys = match arg_ty.sty { - ty::TyTuple(ref tys) => tys, - _ => bug!("spread argument isn't a tuple?!") - }; - - let place = PlaceRef::alloca(bx, bx.cx.layout_of(arg_ty), &name); - for i in 0..tupled_arg_tys.len() { - let arg = &fx.fn_ty.args[idx]; - idx += 1; - if arg.pad.is_some() { - llarg_idx += 1; - } - arg.store_fn_arg(bx, &mut llarg_idx, place.project_field(bx, i)); - } - - // Now that we have one alloca that contains the aggregate value, - // we can create one debuginfo entry for the argument. - arg_scope.map(|scope| { - let variable_access = VariableAccess::DirectVariable { - alloca: place.llval - }; - declare_local( - bx, - &fx.debug_context, - arg_decl.name.unwrap_or(keywords::Invalid.name()), - arg_ty, scope, - variable_access, - VariableKind::ArgumentVariable(arg_index + 1), - DUMMY_SP - ); - }); - - return LocalRef::Place(place); - } - - let arg = &fx.fn_ty.args[idx]; - idx += 1; - if arg.pad.is_some() { - llarg_idx += 1; - } - - if arg_scope.is_none() && !memory_locals.contains(local.index()) { - // We don't have to cast or keep the argument in the alloca. - // FIXME(eddyb): We should figure out how to use llvm.dbg.value instead - // of putting everything in allocas just so we can use llvm.dbg.declare. - let local = |op| LocalRef::Operand(Some(op)); - match arg.mode { - PassMode::Ignore => { - return local(OperandRef::new_zst(bx.cx, arg.layout)); - } - PassMode::Direct(_) => { - let llarg = llvm::get_param(bx.llfn(), llarg_idx as c_uint); - bx.set_value_name(llarg, &name); - llarg_idx += 1; - return local( - OperandRef::from_immediate_or_packed_pair(bx, llarg, arg.layout)); - } - PassMode::Pair(..) => { - let a = llvm::get_param(bx.llfn(), llarg_idx as c_uint); - bx.set_value_name(a, &(name.clone() + ".0")); - llarg_idx += 1; - - let b = llvm::get_param(bx.llfn(), llarg_idx as c_uint); - bx.set_value_name(b, &(name + ".1")); - llarg_idx += 1; - - return local(OperandRef { - val: OperandValue::Pair(a, b), - layout: arg.layout - }); - } - _ => {} - } - } - - let place = if arg.is_indirect() { - // Don't copy an indirect argument to an alloca, the caller - // already put it in a temporary alloca and gave it up. - // FIXME: lifetimes - let llarg = llvm::get_param(bx.llfn(), llarg_idx as c_uint); - bx.set_value_name(llarg, &name); - llarg_idx += 1; - PlaceRef::new_sized(llarg, arg.layout, arg.layout.align) - } else { - let tmp = PlaceRef::alloca(bx, arg.layout, &name); - arg.store_fn_arg(bx, &mut llarg_idx, tmp); - tmp - }; - arg_scope.map(|scope| { - // Is this a regular argument? - if arg_index > 0 || mir.upvar_decls.is_empty() { - // The Rust ABI passes indirect variables using a pointer and a manual copy, so we - // need to insert a deref here, but the C ABI uses a pointer and a copy using the - // byval attribute, for which LLVM does the deref itself, so we must not add it. - // Starting with D31439 in LLVM 5, it *always* does the deref itself. - let mut variable_access = VariableAccess::DirectVariable { - alloca: place.llval - }; - if unsafe { llvm::LLVMRustVersionMajor() < 5 } { - if let PassMode::Indirect(ref attrs) = arg.mode { - if !attrs.contains(ArgAttribute::ByVal) { - variable_access = VariableAccess::IndirectVariable { - alloca: place.llval, - address_operations: &deref_op, - }; - } - } - } - - declare_local( - bx, - &fx.debug_context, - arg_decl.name.unwrap_or(keywords::Invalid.name()), - arg.layout.ty, - scope, - variable_access, - VariableKind::ArgumentVariable(arg_index + 1), - DUMMY_SP - ); - return; - } - - // Or is it the closure environment? - let (closure_layout, env_ref) = match arg.layout.ty.sty { - ty::TyRawPtr(ty::TypeAndMut { ty, .. }) | - ty::TyRef(_, ty, _) => (bx.cx.layout_of(ty), true), - _ => (arg.layout, false) - }; - - let (def_id, upvar_substs) = match closure_layout.ty.sty { - ty::TyClosure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)), - ty::TyGenerator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)), - _ => bug!("upvar_decls with non-closure arg0 type `{}`", closure_layout.ty) - }; - let upvar_tys = upvar_substs.upvar_tys(def_id, tcx); - - // Store the pointer to closure data in an alloca for debuginfo - // because that's what the llvm.dbg.declare intrinsic expects. - - // FIXME(eddyb) this shouldn't be necessary but SROA seems to - // mishandle DW_OP_plus not preceded by DW_OP_deref, i.e. it - // doesn't actually strip the offset when splitting the closure - // environment into its components so it ends up out of bounds. - let env_ptr = if !env_ref { - let scratch = PlaceRef::alloca(bx, - bx.cx.layout_of(tcx.mk_mut_ptr(arg.layout.ty)), - "__debuginfo_env_ptr"); - bx.store(place.llval, scratch.llval, scratch.align); - scratch.llval - } else { - place.llval - }; - - for (i, (decl, ty)) in mir.upvar_decls.iter().zip(upvar_tys).enumerate() { - let byte_offset_of_var_in_env = closure_layout.fields.offset(i).bytes(); - - let ops = unsafe { - [llvm::LLVMRustDIBuilderCreateOpDeref(), - llvm::LLVMRustDIBuilderCreateOpPlusUconst(), - byte_offset_of_var_in_env as i64, - llvm::LLVMRustDIBuilderCreateOpDeref()] - }; - - // The environment and the capture can each be indirect. - - // FIXME(eddyb) see above why we have to keep - // a pointer in an alloca for debuginfo atm. - let mut ops = if env_ref || true { &ops[..] } else { &ops[1..] }; - - let ty = if let (true, &ty::TyRef(_, ty, _)) = (decl.by_ref, &ty.sty) { - ty - } else { - ops = &ops[..ops.len() - 1]; - ty - }; - - let variable_access = VariableAccess::IndirectVariable { - alloca: env_ptr, - address_operations: &ops - }; - declare_local( - bx, - &fx.debug_context, - decl.debug_name, - ty, - scope, - variable_access, - VariableKind::CapturedVariable, - DUMMY_SP - ); - } - }); - LocalRef::Place(place) - }).collect() -} - -mod analyze; -mod block; -mod constant; -pub mod place; -pub mod operand; -mod rvalue; -mod statement; diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs deleted file mode 100644 index be14da1a195..00000000000 --- a/src/librustc_trans/mir/operand.rs +++ /dev/null @@ -1,427 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use llvm::ValueRef; -use rustc::middle::const_val::ConstEvalErr; -use rustc::mir; -use rustc::mir::interpret::ConstValue; -use rustc::ty; -use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; -use rustc_data_structures::indexed_vec::Idx; - -use base; -use common::{self, CodegenCx, C_null, C_undef, C_usize}; -use builder::{Builder, MemFlags}; -use value::Value; -use type_of::LayoutLlvmExt; -use type_::Type; -use consts; - -use std::fmt; -use std::ptr; - -use super::{FunctionCx, LocalRef}; -use super::constant::{primval_to_llvm, const_alloc_to_llvm}; -use super::place::PlaceRef; - -/// The representation of a Rust value. The enum variant is in fact -/// uniquely determined by the value's type, but is kept as a -/// safety check. -#[derive(Copy, Clone)] -pub enum OperandValue { - /// A reference to the actual operand. The data is guaranteed - /// to be valid for the operand's lifetime. - Ref(ValueRef, Align), - /// A single LLVM value. - Immediate(ValueRef), - /// A pair of immediate LLVM values. Used by fat pointers too. - Pair(ValueRef, ValueRef) -} - -impl fmt::Debug for OperandValue { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - OperandValue::Ref(r, align) => { - write!(f, "Ref({:?}, {:?})", Value(r), align) - } - OperandValue::Immediate(i) => { - write!(f, "Immediate({:?})", Value(i)) - } - OperandValue::Pair(a, b) => { - write!(f, "Pair({:?}, {:?})", Value(a), Value(b)) - } - } - } -} - -/// An `OperandRef` is an "SSA" reference to a Rust value, along with -/// its type. -/// -/// NOTE: unless you know a value's type exactly, you should not -/// generate LLVM opcodes acting on it and instead act via methods, -/// to avoid nasty edge cases. In particular, using `Builder::store` -/// directly is sure to cause problems -- use `OperandRef::store` -/// instead. -#[derive(Copy, Clone)] -pub struct OperandRef<'tcx> { - // The value. - pub val: OperandValue, - - // The layout of value, based on its Rust type. - pub layout: TyLayout<'tcx>, -} - -impl<'tcx> fmt::Debug for OperandRef<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "OperandRef({:?} @ {:?})", self.val, self.layout) - } -} - -impl<'a, 'tcx> OperandRef<'tcx> { - pub fn new_zst(cx: &CodegenCx<'a, 'tcx>, - layout: TyLayout<'tcx>) -> OperandRef<'tcx> { - assert!(layout.is_zst()); - OperandRef { - val: OperandValue::Immediate(C_undef(layout.immediate_llvm_type(cx))), - layout - } - } - - pub fn from_const(bx: &Builder<'a, 'tcx>, - val: ConstValue<'tcx>, - ty: ty::Ty<'tcx>) - -> Result, ConstEvalErr<'tcx>> { - let layout = bx.cx.layout_of(ty); - - if layout.is_zst() { - return Ok(OperandRef::new_zst(bx.cx, layout)); - } - - let val = match val { - ConstValue::ByVal(x) => { - let scalar = match layout.abi { - layout::Abi::Scalar(ref x) => x, - _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) - }; - let llval = primval_to_llvm( - bx.cx, - x, - scalar, - layout.immediate_llvm_type(bx.cx), - ); - OperandValue::Immediate(llval) - }, - ConstValue::ByValPair(a, b) => { - let (a_scalar, b_scalar) = match layout.abi { - layout::Abi::ScalarPair(ref a, ref b) => (a, b), - _ => bug!("from_const: invalid ByValPair layout: {:#?}", layout) - }; - let a_llval = primval_to_llvm( - bx.cx, - a, - a_scalar, - layout.scalar_pair_element_llvm_type(bx.cx, 0), - ); - let b_llval = primval_to_llvm( - bx.cx, - b, - b_scalar, - layout.scalar_pair_element_llvm_type(bx.cx, 1), - ); - OperandValue::Pair(a_llval, b_llval) - }, - ConstValue::ByRef(alloc) => { - let init = const_alloc_to_llvm(bx.cx, alloc); - let llval = consts::addr_of(bx.cx, init, layout.align, "byte_str"); - let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to()); - return Ok(PlaceRef::new_sized(llval, layout, alloc.align).load(bx)); - }, - }; - - Ok(OperandRef { - val, - layout - }) - } - - /// Asserts that this operand refers to a scalar and returns - /// a reference to its value. - pub fn immediate(self) -> ValueRef { - match self.val { - OperandValue::Immediate(s) => s, - _ => bug!("not immediate: {:?}", self) - } - } - - pub fn deref(self, cx: &CodegenCx<'a, 'tcx>) -> PlaceRef<'tcx> { - let projected_ty = self.layout.ty.builtin_deref(true) - .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)).ty; - let (llptr, llextra) = match self.val { - OperandValue::Immediate(llptr) => (llptr, ptr::null_mut()), - OperandValue::Pair(llptr, llextra) => (llptr, llextra), - OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self) - }; - let layout = cx.layout_of(projected_ty); - PlaceRef { - llval: llptr, - llextra, - layout, - align: layout.align, - } - } - - /// If this operand is a `Pair`, we return an aggregate with the two values. - /// For other cases, see `immediate`. - pub fn immediate_or_packed_pair(self, bx: &Builder<'a, 'tcx>) -> ValueRef { - if let OperandValue::Pair(a, b) = self.val { - let llty = self.layout.llvm_type(bx.cx); - debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}", - self, llty); - // Reconstruct the immediate aggregate. - let mut llpair = C_undef(llty); - llpair = bx.insert_value(llpair, a, 0); - llpair = bx.insert_value(llpair, b, 1); - llpair - } else { - self.immediate() - } - } - - /// If the type is a pair, we return a `Pair`, otherwise, an `Immediate`. - pub fn from_immediate_or_packed_pair(bx: &Builder<'a, 'tcx>, - llval: ValueRef, - layout: TyLayout<'tcx>) - -> OperandRef<'tcx> { - let val = if layout.is_llvm_scalar_pair() { - debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", - llval, layout); - - // Deconstruct the immediate aggregate. - OperandValue::Pair(bx.extract_value(llval, 0), - bx.extract_value(llval, 1)) - } else { - OperandValue::Immediate(llval) - }; - OperandRef { val, layout } - } - - pub fn extract_field(&self, bx: &Builder<'a, 'tcx>, i: usize) -> OperandRef<'tcx> { - let field = self.layout.field(bx.cx, i); - let offset = self.layout.fields.offset(i); - - let mut val = match (self.val, &self.layout.abi) { - // If the field is ZST, it has no data. - _ if field.is_zst() => { - return OperandRef::new_zst(bx.cx, field); - } - - // Newtype of a scalar, scalar pair or vector. - (OperandValue::Immediate(_), _) | - (OperandValue::Pair(..), _) if field.size == self.layout.size => { - assert_eq!(offset.bytes(), 0); - self.val - } - - // Extract a scalar component from a pair. - (OperandValue::Pair(a_llval, b_llval), &layout::Abi::ScalarPair(ref a, ref b)) => { - if offset.bytes() == 0 { - assert_eq!(field.size, a.value.size(bx.cx)); - OperandValue::Immediate(a_llval) - } else { - assert_eq!(offset, a.value.size(bx.cx) - .abi_align(b.value.align(bx.cx))); - assert_eq!(field.size, b.value.size(bx.cx)); - OperandValue::Immediate(b_llval) - } - } - - // `#[repr(simd)]` types are also immediate. - (OperandValue::Immediate(llval), &layout::Abi::Vector { .. }) => { - OperandValue::Immediate( - bx.extract_element(llval, C_usize(bx.cx, i as u64))) - } - - _ => bug!("OperandRef::extract_field({:?}): not applicable", self) - }; - - // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. - match val { - OperandValue::Immediate(ref mut llval) => { - *llval = bx.bitcast(*llval, field.immediate_llvm_type(bx.cx)); - } - OperandValue::Pair(ref mut a, ref mut b) => { - *a = bx.bitcast(*a, field.scalar_pair_element_llvm_type(bx.cx, 0)); - *b = bx.bitcast(*b, field.scalar_pair_element_llvm_type(bx.cx, 1)); - } - OperandValue::Ref(..) => bug!() - } - - OperandRef { - val, - layout: field - } - } -} - -impl<'a, 'tcx> OperandValue { - pub fn store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { - self.store_with_flags(bx, dest, MemFlags::empty()); - } - - pub fn volatile_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { - self.store_with_flags(bx, dest, MemFlags::VOLATILE); - } - - pub fn nontemporal_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { - self.store_with_flags(bx, dest, MemFlags::NONTEMPORAL); - } - - fn store_with_flags(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>, flags: MemFlags) { - debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest); - // Avoid generating stores of zero-sized values, because the only way to have a zero-sized - // value is through `undef`, and store itself is useless. - if dest.layout.is_zst() { - return; - } - match self { - OperandValue::Ref(r, source_align) => { - base::memcpy_ty(bx, dest.llval, r, dest.layout, - source_align.min(dest.align), flags) - } - OperandValue::Immediate(s) => { - let val = base::from_immediate(bx, s); - bx.store_with_flags(val, dest.llval, dest.align, flags); - } - OperandValue::Pair(a, b) => { - for (i, &x) in [a, b].iter().enumerate() { - let mut llptr = bx.struct_gep(dest.llval, i as u64); - // Make sure to always store i1 as i8. - if common::val_ty(x) == Type::i1(bx.cx) { - llptr = bx.pointercast(llptr, Type::i8p(bx.cx)); - } - let val = base::from_immediate(bx, x); - bx.store_with_flags(val, llptr, dest.align, flags); - } - } - } - } -} - -impl<'a, 'tcx> FunctionCx<'a, 'tcx> { - fn maybe_trans_consume_direct(&mut self, - bx: &Builder<'a, 'tcx>, - place: &mir::Place<'tcx>) - -> Option> - { - debug!("maybe_trans_consume_direct(place={:?})", place); - - // watch out for locals that do not have an - // alloca; they are handled somewhat differently - if let mir::Place::Local(index) = *place { - match self.locals[index] { - LocalRef::Operand(Some(o)) => { - return Some(o); - } - LocalRef::Operand(None) => { - bug!("use of {:?} before def", place); - } - LocalRef::Place(..) => { - // use path below - } - } - } - - // Moves out of scalar and scalar pair fields are trivial. - if let &mir::Place::Projection(ref proj) = place { - if let Some(o) = self.maybe_trans_consume_direct(bx, &proj.base) { - match proj.elem { - mir::ProjectionElem::Field(ref f, _) => { - return Some(o.extract_field(bx, f.index())); - } - mir::ProjectionElem::Index(_) | - mir::ProjectionElem::ConstantIndex { .. } => { - // ZSTs don't require any actual memory access. - // FIXME(eddyb) deduplicate this with the identical - // checks in `trans_consume` and `extract_field`. - let elem = o.layout.field(bx.cx, 0); - if elem.is_zst() { - return Some(OperandRef::new_zst(bx.cx, elem)); - } - } - _ => {} - } - } - } - - None - } - - pub fn trans_consume(&mut self, - bx: &Builder<'a, 'tcx>, - place: &mir::Place<'tcx>) - -> OperandRef<'tcx> - { - debug!("trans_consume(place={:?})", place); - - let ty = self.monomorphized_place_ty(place); - let layout = bx.cx.layout_of(ty); - - // ZSTs don't require any actual memory access. - if layout.is_zst() { - return OperandRef::new_zst(bx.cx, layout); - } - - if let Some(o) = self.maybe_trans_consume_direct(bx, place) { - return o; - } - - // for most places, to consume them we just load them - // out from their home - self.trans_place(bx, place).load(bx) - } - - pub fn trans_operand(&mut self, - bx: &Builder<'a, 'tcx>, - operand: &mir::Operand<'tcx>) - -> OperandRef<'tcx> - { - debug!("trans_operand(operand={:?})", operand); - - match *operand { - mir::Operand::Copy(ref place) | - mir::Operand::Move(ref place) => { - self.trans_consume(bx, place) - } - - mir::Operand::Constant(ref constant) => { - let ty = self.monomorphize(&constant.ty); - self.mir_constant_to_const_value(bx, constant) - .and_then(|c| OperandRef::from_const(bx, c, ty)) - .unwrap_or_else(|err| { - match constant.literal { - mir::Literal::Promoted { .. } => { - // don't report errors inside promoteds, just warnings. - }, - mir::Literal::Value { .. } => { - err.report(bx.tcx(), constant.span, "const operand") - }, - } - // We've errored, so we don't have to produce working code. - let layout = bx.cx.layout_of(ty); - PlaceRef::new_sized( - C_null(layout.llvm_type(bx.cx).ptr_to()), - layout, - layout.align, - ).load(bx) - }) - } - } - } -} diff --git a/src/librustc_trans/mir/place.rs b/src/librustc_trans/mir/place.rs deleted file mode 100644 index d4abd5fa88d..00000000000 --- a/src/librustc_trans/mir/place.rs +++ /dev/null @@ -1,499 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use llvm::{self, ValueRef}; -use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, Align, TyLayout, LayoutOf}; -use rustc::mir; -use rustc::mir::tcx::PlaceTy; -use rustc_data_structures::indexed_vec::Idx; -use base; -use builder::Builder; -use common::{CodegenCx, C_undef, C_usize, C_u8, C_u32, C_uint, C_null, C_uint_big}; -use consts; -use type_of::LayoutLlvmExt; -use type_::Type; -use value::Value; -use glue; - -use std::ptr; - -use super::{FunctionCx, LocalRef}; -use super::operand::{OperandRef, OperandValue}; - -#[derive(Copy, Clone, Debug)] -pub struct PlaceRef<'tcx> { - /// Pointer to the contents of the place - pub llval: ValueRef, - - /// This place's extra data if it is unsized, or null - pub llextra: ValueRef, - - /// Monomorphized type of this place, including variant information - pub layout: TyLayout<'tcx>, - - /// What alignment we know for this place - pub align: Align, -} - -impl<'a, 'tcx> PlaceRef<'tcx> { - pub fn new_sized(llval: ValueRef, - layout: TyLayout<'tcx>, - align: Align) - -> PlaceRef<'tcx> { - PlaceRef { - llval, - llextra: ptr::null_mut(), - layout, - align - } - } - - pub fn alloca(bx: &Builder<'a, 'tcx>, layout: TyLayout<'tcx>, name: &str) - -> PlaceRef<'tcx> { - debug!("alloca({:?}: {:?})", name, layout); - let tmp = bx.alloca(layout.llvm_type(bx.cx), name, layout.align); - Self::new_sized(tmp, layout, layout.align) - } - - pub fn len(&self, cx: &CodegenCx<'a, 'tcx>) -> ValueRef { - if let layout::FieldPlacement::Array { count, .. } = self.layout.fields { - if self.layout.is_unsized() { - assert!(self.has_extra()); - assert_eq!(count, 0); - self.llextra - } else { - C_usize(cx, count) - } - } else { - bug!("unexpected layout `{:#?}` in PlaceRef::len", self.layout) - } - } - - pub fn has_extra(&self) -> bool { - !self.llextra.is_null() - } - - pub fn load(&self, bx: &Builder<'a, 'tcx>) -> OperandRef<'tcx> { - debug!("PlaceRef::load: {:?}", self); - - assert!(!self.has_extra()); - - if self.layout.is_zst() { - return OperandRef::new_zst(bx.cx, self.layout); - } - - let scalar_load_metadata = |load, scalar: &layout::Scalar| { - let vr = scalar.valid_range.clone(); - match scalar.value { - layout::Int(..) => { - let range = scalar.valid_range_exclusive(bx.cx); - if range.start != range.end { - bx.range_metadata(load, range); - } - } - layout::Pointer if vr.start() < vr.end() && !vr.contains(&0) => { - bx.nonnull_metadata(load); - } - _ => {} - } - }; - - let val = if self.layout.is_llvm_immediate() { - let mut const_llval = ptr::null_mut(); - unsafe { - let global = llvm::LLVMIsAGlobalVariable(self.llval); - if !global.is_null() && llvm::LLVMIsGlobalConstant(global) == llvm::True { - const_llval = llvm::LLVMGetInitializer(global); - } - } - - let llval = if !const_llval.is_null() { - const_llval - } else { - let load = bx.load(self.llval, self.align); - if let layout::Abi::Scalar(ref scalar) = self.layout.abi { - scalar_load_metadata(load, scalar); - } - load - }; - OperandValue::Immediate(base::to_immediate(bx, llval, self.layout)) - } else if let layout::Abi::ScalarPair(ref a, ref b) = self.layout.abi { - let load = |i, scalar: &layout::Scalar| { - let mut llptr = bx.struct_gep(self.llval, i as u64); - // Make sure to always load i1 as i8. - if scalar.is_bool() { - llptr = bx.pointercast(llptr, Type::i8p(bx.cx)); - } - let load = bx.load(llptr, self.align); - scalar_load_metadata(load, scalar); - if scalar.is_bool() { - bx.trunc(load, Type::i1(bx.cx)) - } else { - load - } - }; - OperandValue::Pair(load(0, a), load(1, b)) - } else { - OperandValue::Ref(self.llval, self.align) - }; - - OperandRef { val, layout: self.layout } - } - - /// Access a field, at a point when the value's case is known. - pub fn project_field(self, bx: &Builder<'a, 'tcx>, ix: usize) -> PlaceRef<'tcx> { - let cx = bx.cx; - let field = self.layout.field(cx, ix); - let offset = self.layout.fields.offset(ix); - let align = self.align.min(self.layout.align).min(field.align); - - let simple = || { - // Unions and newtypes only use an offset of 0. - let llval = if offset.bytes() == 0 { - self.llval - } else if let layout::Abi::ScalarPair(ref a, ref b) = self.layout.abi { - // Offsets have to match either first or second field. - assert_eq!(offset, a.value.size(cx).abi_align(b.value.align(cx))); - bx.struct_gep(self.llval, 1) - } else { - bx.struct_gep(self.llval, self.layout.llvm_field_index(ix)) - }; - PlaceRef { - // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. - llval: bx.pointercast(llval, field.llvm_type(cx).ptr_to()), - llextra: if cx.type_has_metadata(field.ty) { - self.llextra - } else { - ptr::null_mut() - }, - layout: field, - align, - } - }; - - // Simple cases, which don't need DST adjustment: - // * no metadata available - just log the case - // * known alignment - sized types, [T], str or a foreign type - // * packed struct - there is no alignment padding - match field.ty.sty { - _ if !self.has_extra() => { - debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment", - ix, Value(self.llval)); - return simple(); - } - _ if !field.is_unsized() => return simple(), - ty::TySlice(..) | ty::TyStr | ty::TyForeign(..) => return simple(), - ty::TyAdt(def, _) => { - if def.repr.packed() { - // FIXME(eddyb) generalize the adjustment when we - // start supporting packing to larger alignments. - assert_eq!(self.layout.align.abi(), 1); - return simple(); - } - } - _ => {} - } - - // We need to get the pointer manually now. - // We do this by casting to a *i8, then offsetting it by the appropriate amount. - // We do this instead of, say, simply adjusting the pointer from the result of a GEP - // because the field may have an arbitrary alignment in the LLVM representation - // anyway. - // - // To demonstrate: - // struct Foo { - // x: u16, - // y: T - // } - // - // The type Foo> is represented in LLVM as { u16, { u16, u8 }}, meaning that - // the `y` field has 16-bit alignment. - - let meta = self.llextra; - - let unaligned_offset = C_usize(cx, offset.bytes()); - - // Get the alignment of the field - let (_, unsized_align) = glue::size_and_align_of_dst(bx, field.ty, meta); - - // Bump the unaligned offset up to the appropriate alignment using the - // following expression: - // - // (unaligned offset + (align - 1)) & -align - - // Calculate offset - let align_sub_1 = bx.sub(unsized_align, C_usize(cx, 1u64)); - let offset = bx.and(bx.add(unaligned_offset, align_sub_1), - bx.neg(unsized_align)); - - debug!("struct_field_ptr: DST field offset: {:?}", Value(offset)); - - // Cast and adjust pointer - let byte_ptr = bx.pointercast(self.llval, Type::i8p(cx)); - let byte_ptr = bx.gep(byte_ptr, &[offset]); - - // Finally, cast back to the type expected - let ll_fty = field.llvm_type(cx); - debug!("struct_field_ptr: Field type is {:?}", ll_fty); - - PlaceRef { - llval: bx.pointercast(byte_ptr, ll_fty.ptr_to()), - llextra: self.llextra, - layout: field, - align, - } - } - - /// Obtain the actual discriminant of a value. - pub fn trans_get_discr(self, bx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> ValueRef { - let cast_to = bx.cx.layout_of(cast_to).immediate_llvm_type(bx.cx); - if self.layout.abi == layout::Abi::Uninhabited { - return C_undef(cast_to); - } - match self.layout.variants { - layout::Variants::Single { index } => { - let discr_val = self.layout.ty.ty_adt_def().map_or( - index as u128, - |def| def.discriminant_for_variant(bx.cx.tcx, index).val); - return C_uint_big(cast_to, discr_val); - } - layout::Variants::Tagged { .. } | - layout::Variants::NicheFilling { .. } => {}, - } - - let discr = self.project_field(bx, 0); - let lldiscr = discr.load(bx).immediate(); - match self.layout.variants { - layout::Variants::Single { .. } => bug!(), - layout::Variants::Tagged { ref tag, .. } => { - let signed = match tag.value { - layout::Int(_, signed) => signed, - _ => false - }; - bx.intcast(lldiscr, cast_to, signed) - } - layout::Variants::NicheFilling { - dataful_variant, - ref niche_variants, - niche_start, - .. - } => { - let niche_llty = discr.layout.immediate_llvm_type(bx.cx); - if niche_variants.start() == niche_variants.end() { - // FIXME(eddyb) Check the actual primitive type here. - let niche_llval = if niche_start == 0 { - // HACK(eddyb) Using `C_null` as it works on all types. - C_null(niche_llty) - } else { - C_uint_big(niche_llty, niche_start) - }; - bx.select(bx.icmp(llvm::IntEQ, lldiscr, niche_llval), - C_uint(cast_to, *niche_variants.start() as u64), - C_uint(cast_to, dataful_variant as u64)) - } else { - // Rebase from niche values to discriminant values. - let delta = niche_start.wrapping_sub(*niche_variants.start() as u128); - let lldiscr = bx.sub(lldiscr, C_uint_big(niche_llty, delta)); - let lldiscr_max = C_uint(niche_llty, *niche_variants.end() as u64); - bx.select(bx.icmp(llvm::IntULE, lldiscr, lldiscr_max), - bx.intcast(lldiscr, cast_to, false), - C_uint(cast_to, dataful_variant as u64)) - } - } - } - } - - /// Set the discriminant for a new value of the given case of the given - /// representation. - pub fn trans_set_discr(&self, bx: &Builder<'a, 'tcx>, variant_index: usize) { - if self.layout.for_variant(bx.cx, variant_index).abi == layout::Abi::Uninhabited { - return; - } - match self.layout.variants { - layout::Variants::Single { index } => { - assert_eq!(index, variant_index); - } - layout::Variants::Tagged { .. } => { - let ptr = self.project_field(bx, 0); - let to = self.layout.ty.ty_adt_def().unwrap() - .discriminant_for_variant(bx.tcx(), variant_index) - .val; - bx.store( - C_uint_big(ptr.layout.llvm_type(bx.cx), to), - ptr.llval, - ptr.align); - } - layout::Variants::NicheFilling { - dataful_variant, - ref niche_variants, - niche_start, - .. - } => { - if variant_index != dataful_variant { - if bx.sess().target.target.arch == "arm" || - bx.sess().target.target.arch == "aarch64" { - // Issue #34427: As workaround for LLVM bug on ARM, - // use memset of 0 before assigning niche value. - let llptr = bx.pointercast(self.llval, Type::i8(bx.cx).ptr_to()); - let fill_byte = C_u8(bx.cx, 0); - let (size, align) = self.layout.size_and_align(); - let size = C_usize(bx.cx, size.bytes()); - let align = C_u32(bx.cx, align.abi() as u32); - base::call_memset(bx, llptr, fill_byte, size, align, false); - } - - let niche = self.project_field(bx, 0); - let niche_llty = niche.layout.immediate_llvm_type(bx.cx); - let niche_value = ((variant_index - *niche_variants.start()) as u128) - .wrapping_add(niche_start); - // FIXME(eddyb) Check the actual primitive type here. - let niche_llval = if niche_value == 0 { - // HACK(eddyb) Using `C_null` as it works on all types. - C_null(niche_llty) - } else { - C_uint_big(niche_llty, niche_value) - }; - OperandValue::Immediate(niche_llval).store(bx, niche); - } - } - } - } - - pub fn project_index(&self, bx: &Builder<'a, 'tcx>, llindex: ValueRef) - -> PlaceRef<'tcx> { - PlaceRef { - llval: bx.inbounds_gep(self.llval, &[C_usize(bx.cx, 0), llindex]), - llextra: ptr::null_mut(), - layout: self.layout.field(bx.cx, 0), - align: self.align - } - } - - pub fn project_downcast(&self, bx: &Builder<'a, 'tcx>, variant_index: usize) - -> PlaceRef<'tcx> { - let mut downcast = *self; - downcast.layout = self.layout.for_variant(bx.cx, variant_index); - - // Cast to the appropriate variant struct type. - let variant_ty = downcast.layout.llvm_type(bx.cx); - downcast.llval = bx.pointercast(downcast.llval, variant_ty.ptr_to()); - - downcast - } - - pub fn storage_live(&self, bx: &Builder<'a, 'tcx>) { - bx.lifetime_start(self.llval, self.layout.size); - } - - pub fn storage_dead(&self, bx: &Builder<'a, 'tcx>) { - bx.lifetime_end(self.llval, self.layout.size); - } -} - -impl<'a, 'tcx> FunctionCx<'a, 'tcx> { - pub fn trans_place(&mut self, - bx: &Builder<'a, 'tcx>, - place: &mir::Place<'tcx>) - -> PlaceRef<'tcx> { - debug!("trans_place(place={:?})", place); - - let cx = bx.cx; - let tcx = cx.tcx; - - if let mir::Place::Local(index) = *place { - match self.locals[index] { - LocalRef::Place(place) => { - return place; - } - LocalRef::Operand(..) => { - bug!("using operand local {:?} as place", place); - } - } - } - - let result = match *place { - mir::Place::Local(_) => bug!(), // handled above - mir::Place::Static(box mir::Static { def_id, ty }) => { - let layout = cx.layout_of(self.monomorphize(&ty)); - PlaceRef::new_sized(consts::get_static(cx, def_id), layout, layout.align) - }, - mir::Place::Projection(box mir::Projection { - ref base, - elem: mir::ProjectionElem::Deref - }) => { - // Load the pointer from its location. - self.trans_consume(bx, base).deref(bx.cx) - } - mir::Place::Projection(ref projection) => { - let tr_base = self.trans_place(bx, &projection.base); - - match projection.elem { - mir::ProjectionElem::Deref => bug!(), - mir::ProjectionElem::Field(ref field, _) => { - tr_base.project_field(bx, field.index()) - } - mir::ProjectionElem::Index(index) => { - let index = &mir::Operand::Copy(mir::Place::Local(index)); - let index = self.trans_operand(bx, index); - let llindex = index.immediate(); - tr_base.project_index(bx, llindex) - } - mir::ProjectionElem::ConstantIndex { offset, - from_end: false, - min_length: _ } => { - let lloffset = C_usize(bx.cx, offset as u64); - tr_base.project_index(bx, lloffset) - } - mir::ProjectionElem::ConstantIndex { offset, - from_end: true, - min_length: _ } => { - let lloffset = C_usize(bx.cx, offset as u64); - let lllen = tr_base.len(bx.cx); - let llindex = bx.sub(lllen, lloffset); - tr_base.project_index(bx, llindex) - } - mir::ProjectionElem::Subslice { from, to } => { - let mut subslice = tr_base.project_index(bx, - C_usize(bx.cx, from as u64)); - let projected_ty = PlaceTy::Ty { ty: tr_base.layout.ty } - .projection_ty(tcx, &projection.elem).to_ty(bx.tcx()); - subslice.layout = bx.cx.layout_of(self.monomorphize(&projected_ty)); - - if subslice.layout.is_unsized() { - assert!(tr_base.has_extra()); - subslice.llextra = bx.sub(tr_base.llextra, - C_usize(bx.cx, (from as u64) + (to as u64))); - } - - // Cast the place pointer type to the new - // array or slice type (*[%_; new_len]). - subslice.llval = bx.pointercast(subslice.llval, - subslice.layout.llvm_type(bx.cx).ptr_to()); - - subslice - } - mir::ProjectionElem::Downcast(_, v) => { - tr_base.project_downcast(bx, v) - } - } - } - }; - debug!("trans_place(place={:?}) => {:?}", place, result); - result - } - - pub fn monomorphized_place_ty(&self, place: &mir::Place<'tcx>) -> Ty<'tcx> { - let tcx = self.cx.tcx; - let place_ty = place.ty(self.mir, tcx); - self.monomorphize(&place_ty.to_ty(tcx)) - } -} - diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs deleted file mode 100644 index 3b447756450..00000000000 --- a/src/librustc_trans/mir/rvalue.rs +++ /dev/null @@ -1,952 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use llvm::{self, ValueRef}; -use rustc::ty::{self, Ty}; -use rustc::ty::cast::{CastTy, IntTy}; -use rustc::ty::layout::{self, LayoutOf}; -use rustc::mir; -use rustc::middle::lang_items::ExchangeMallocFnLangItem; -use rustc_apfloat::{ieee, Float, Status, Round}; -use std::{u128, i128}; - -use base; -use builder::Builder; -use callee; -use common::{self, val_ty}; -use common::{C_bool, C_u8, C_i32, C_u32, C_u64, C_undef, C_null, C_usize, C_uint, C_uint_big}; -use consts; -use monomorphize; -use type_::Type; -use type_of::LayoutLlvmExt; -use value::Value; - -use super::{FunctionCx, LocalRef}; -use super::operand::{OperandRef, OperandValue}; -use super::place::PlaceRef; - -impl<'a, 'tcx> FunctionCx<'a, 'tcx> { - pub fn trans_rvalue(&mut self, - bx: Builder<'a, 'tcx>, - dest: PlaceRef<'tcx>, - rvalue: &mir::Rvalue<'tcx>) - -> Builder<'a, 'tcx> - { - debug!("trans_rvalue(dest.llval={:?}, rvalue={:?})", - Value(dest.llval), rvalue); - - match *rvalue { - mir::Rvalue::Use(ref operand) => { - let tr_operand = self.trans_operand(&bx, operand); - // FIXME: consider not copying constants through stack. (fixable by translating - // constants into OperandValue::Ref, why don’t we do that yet if we don’t?) - tr_operand.val.store(&bx, dest); - bx - } - - mir::Rvalue::Cast(mir::CastKind::Unsize, ref source, _) => { - // The destination necessarily contains a fat pointer, so if - // it's a scalar pair, it's a fat pointer or newtype thereof. - if dest.layout.is_llvm_scalar_pair() { - // into-coerce of a thin pointer to a fat pointer - just - // use the operand path. - let (bx, temp) = self.trans_rvalue_operand(bx, rvalue); - temp.val.store(&bx, dest); - return bx; - } - - // Unsize of a nontrivial struct. I would prefer for - // this to be eliminated by MIR translation, but - // `CoerceUnsized` can be passed by a where-clause, - // so the (generic) MIR may not be able to expand it. - let operand = self.trans_operand(&bx, source); - match operand.val { - OperandValue::Pair(..) | - OperandValue::Immediate(_) => { - // unsize from an immediate structure. We don't - // really need a temporary alloca here, but - // avoiding it would require us to have - // `coerce_unsized_into` use extractvalue to - // index into the struct, and this case isn't - // important enough for it. - debug!("trans_rvalue: creating ugly alloca"); - let scratch = PlaceRef::alloca(&bx, operand.layout, "__unsize_temp"); - scratch.storage_live(&bx); - operand.val.store(&bx, scratch); - base::coerce_unsized_into(&bx, scratch, dest); - scratch.storage_dead(&bx); - } - OperandValue::Ref(llref, align) => { - let source = PlaceRef::new_sized(llref, operand.layout, align); - base::coerce_unsized_into(&bx, source, dest); - } - } - bx - } - - mir::Rvalue::Repeat(ref elem, count) => { - let tr_elem = self.trans_operand(&bx, elem); - - // Do not generate the loop for zero-sized elements or empty arrays. - if dest.layout.is_zst() { - return bx; - } - - let start = dest.project_index(&bx, C_usize(bx.cx, 0)).llval; - - if let OperandValue::Immediate(v) = tr_elem.val { - let align = C_i32(bx.cx, dest.align.abi() as i32); - let size = C_usize(bx.cx, dest.layout.size.bytes()); - - // Use llvm.memset.p0i8.* to initialize all zero arrays - if common::is_const_integral(v) && common::const_to_uint(v) == 0 { - let fill = C_u8(bx.cx, 0); - base::call_memset(&bx, start, fill, size, align, false); - return bx; - } - - // Use llvm.memset.p0i8.* to initialize byte arrays - let v = base::from_immediate(&bx, v); - if common::val_ty(v) == Type::i8(bx.cx) { - base::call_memset(&bx, start, v, size, align, false); - return bx; - } - } - - let count = C_usize(bx.cx, count); - let end = dest.project_index(&bx, count).llval; - - let header_bx = bx.build_sibling_block("repeat_loop_header"); - let body_bx = bx.build_sibling_block("repeat_loop_body"); - let next_bx = bx.build_sibling_block("repeat_loop_next"); - - bx.br(header_bx.llbb()); - let current = header_bx.phi(common::val_ty(start), &[start], &[bx.llbb()]); - - let keep_going = header_bx.icmp(llvm::IntNE, current, end); - header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb()); - - tr_elem.val.store(&body_bx, - PlaceRef::new_sized(current, tr_elem.layout, dest.align)); - - let next = body_bx.inbounds_gep(current, &[C_usize(bx.cx, 1)]); - body_bx.br(header_bx.llbb()); - header_bx.add_incoming_to_phi(current, next, body_bx.llbb()); - - next_bx - } - - mir::Rvalue::Aggregate(ref kind, ref operands) => { - let (dest, active_field_index) = match **kind { - mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => { - dest.trans_set_discr(&bx, variant_index); - if adt_def.is_enum() { - (dest.project_downcast(&bx, variant_index), active_field_index) - } else { - (dest, active_field_index) - } - } - _ => (dest, None) - }; - for (i, operand) in operands.iter().enumerate() { - let op = self.trans_operand(&bx, operand); - // Do not generate stores and GEPis for zero-sized fields. - if !op.layout.is_zst() { - let field_index = active_field_index.unwrap_or(i); - op.val.store(&bx, dest.project_field(&bx, field_index)); - } - } - bx - } - - _ => { - assert!(self.rvalue_creates_operand(rvalue)); - let (bx, temp) = self.trans_rvalue_operand(bx, rvalue); - temp.val.store(&bx, dest); - bx - } - } - } - - pub fn trans_rvalue_operand(&mut self, - bx: Builder<'a, 'tcx>, - rvalue: &mir::Rvalue<'tcx>) - -> (Builder<'a, 'tcx>, OperandRef<'tcx>) - { - assert!(self.rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); - - match *rvalue { - mir::Rvalue::Cast(ref kind, ref source, mir_cast_ty) => { - let operand = self.trans_operand(&bx, source); - debug!("cast operand is {:?}", operand); - let cast = bx.cx.layout_of(self.monomorphize(&mir_cast_ty)); - - let val = match *kind { - mir::CastKind::ReifyFnPointer => { - match operand.layout.ty.sty { - ty::TyFnDef(def_id, substs) => { - if bx.cx.tcx.has_attr(def_id, "rustc_args_required_const") { - bug!("reifying a fn ptr that requires \ - const arguments"); - } - OperandValue::Immediate( - callee::resolve_and_get_fn(bx.cx, def_id, substs)) - } - _ => { - bug!("{} cannot be reified to a fn ptr", operand.layout.ty) - } - } - } - mir::CastKind::ClosureFnPointer => { - match operand.layout.ty.sty { - ty::TyClosure(def_id, substs) => { - let instance = monomorphize::resolve_closure( - bx.cx.tcx, def_id, substs, ty::ClosureKind::FnOnce); - OperandValue::Immediate(callee::get_fn(bx.cx, instance)) - } - _ => { - bug!("{} cannot be cast to a fn ptr", operand.layout.ty) - } - } - } - mir::CastKind::UnsafeFnPointer => { - // this is a no-op at the LLVM level - operand.val - } - mir::CastKind::Unsize => { - assert!(cast.is_llvm_scalar_pair()); - match operand.val { - OperandValue::Pair(lldata, llextra) => { - // unsize from a fat pointer - this is a - // "trait-object-to-supertrait" coercion, for - // example, - // &'a fmt::Debug+Send => &'a fmt::Debug, - - // HACK(eddyb) have to bitcast pointers - // until LLVM removes pointee types. - let lldata = bx.pointercast(lldata, - cast.scalar_pair_element_llvm_type(bx.cx, 0)); - OperandValue::Pair(lldata, llextra) - } - OperandValue::Immediate(lldata) => { - // "standard" unsize - let (lldata, llextra) = base::unsize_thin_ptr(&bx, lldata, - operand.layout.ty, cast.ty); - OperandValue::Pair(lldata, llextra) - } - OperandValue::Ref(..) => { - bug!("by-ref operand {:?} in trans_rvalue_operand", - operand); - } - } - } - mir::CastKind::Misc if operand.layout.is_llvm_scalar_pair() => { - if let OperandValue::Pair(data_ptr, meta) = operand.val { - if cast.is_llvm_scalar_pair() { - let data_cast = bx.pointercast(data_ptr, - cast.scalar_pair_element_llvm_type(bx.cx, 0)); - OperandValue::Pair(data_cast, meta) - } else { // cast to thin-ptr - // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and - // pointer-cast of that pointer to desired pointer type. - let llcast_ty = cast.immediate_llvm_type(bx.cx); - let llval = bx.pointercast(data_ptr, llcast_ty); - OperandValue::Immediate(llval) - } - } else { - bug!("Unexpected non-Pair operand") - } - } - mir::CastKind::Misc => { - assert!(cast.is_llvm_immediate()); - let ll_t_out = cast.immediate_llvm_type(bx.cx); - if operand.layout.abi == layout::Abi::Uninhabited { - return (bx, OperandRef { - val: OperandValue::Immediate(C_undef(ll_t_out)), - layout: cast, - }); - } - let r_t_in = CastTy::from_ty(operand.layout.ty) - .expect("bad input type for cast"); - let r_t_out = CastTy::from_ty(cast.ty).expect("bad output type for cast"); - let ll_t_in = operand.layout.immediate_llvm_type(bx.cx); - match operand.layout.variants { - layout::Variants::Single { index } => { - if let Some(def) = operand.layout.ty.ty_adt_def() { - let discr_val = def - .discriminant_for_variant(bx.cx.tcx, index) - .val; - let discr = C_uint_big(ll_t_out, discr_val); - return (bx, OperandRef { - val: OperandValue::Immediate(discr), - layout: cast, - }); - } - } - layout::Variants::Tagged { .. } | - layout::Variants::NicheFilling { .. } => {}, - } - let llval = operand.immediate(); - - let mut signed = false; - if let layout::Abi::Scalar(ref scalar) = operand.layout.abi { - if let layout::Int(_, s) = scalar.value { - signed = s; - - if scalar.valid_range.end() > scalar.valid_range.start() { - // We want `table[e as usize]` to not - // have bound checks, and this is the most - // convenient place to put the `assume`. - - base::call_assume(&bx, bx.icmp( - llvm::IntULE, - llval, - C_uint_big(ll_t_in, *scalar.valid_range.end()) - )); - } - } - } - - let newval = match (r_t_in, r_t_out) { - (CastTy::Int(_), CastTy::Int(_)) => { - bx.intcast(llval, ll_t_out, signed) - } - (CastTy::Float, CastTy::Float) => { - let srcsz = ll_t_in.float_width(); - let dstsz = ll_t_out.float_width(); - if dstsz > srcsz { - bx.fpext(llval, ll_t_out) - } else if srcsz > dstsz { - bx.fptrunc(llval, ll_t_out) - } else { - llval - } - } - (CastTy::Ptr(_), CastTy::Ptr(_)) | - (CastTy::FnPtr, CastTy::Ptr(_)) | - (CastTy::RPtr(_), CastTy::Ptr(_)) => - bx.pointercast(llval, ll_t_out), - (CastTy::Ptr(_), CastTy::Int(_)) | - (CastTy::FnPtr, CastTy::Int(_)) => - bx.ptrtoint(llval, ll_t_out), - (CastTy::Int(_), CastTy::Ptr(_)) => { - let usize_llval = bx.intcast(llval, bx.cx.isize_ty, signed); - bx.inttoptr(usize_llval, ll_t_out) - } - (CastTy::Int(_), CastTy::Float) => - cast_int_to_float(&bx, signed, llval, ll_t_in, ll_t_out), - (CastTy::Float, CastTy::Int(IntTy::I)) => - cast_float_to_int(&bx, true, llval, ll_t_in, ll_t_out), - (CastTy::Float, CastTy::Int(_)) => - cast_float_to_int(&bx, false, llval, ll_t_in, ll_t_out), - _ => bug!("unsupported cast: {:?} to {:?}", operand.layout.ty, cast.ty) - }; - OperandValue::Immediate(newval) - } - }; - (bx, OperandRef { - val, - layout: cast - }) - } - - mir::Rvalue::Ref(_, bk, ref place) => { - let tr_place = self.trans_place(&bx, place); - - let ty = tr_place.layout.ty; - - // Note: places are indirect, so storing the `llval` into the - // destination effectively creates a reference. - let val = if !bx.cx.type_has_metadata(ty) { - OperandValue::Immediate(tr_place.llval) - } else { - OperandValue::Pair(tr_place.llval, tr_place.llextra) - }; - (bx, OperandRef { - val, - layout: self.cx.layout_of(self.cx.tcx.mk_ref( - self.cx.tcx.types.re_erased, - ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() } - )), - }) - } - - mir::Rvalue::Len(ref place) => { - let size = self.evaluate_array_len(&bx, place); - let operand = OperandRef { - val: OperandValue::Immediate(size), - layout: bx.cx.layout_of(bx.tcx().types.usize), - }; - (bx, operand) - } - - mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => { - let lhs = self.trans_operand(&bx, lhs); - let rhs = self.trans_operand(&bx, rhs); - let llresult = match (lhs.val, rhs.val) { - (OperandValue::Pair(lhs_addr, lhs_extra), - OperandValue::Pair(rhs_addr, rhs_extra)) => { - self.trans_fat_ptr_binop(&bx, op, - lhs_addr, lhs_extra, - rhs_addr, rhs_extra, - lhs.layout.ty) - } - - (OperandValue::Immediate(lhs_val), - OperandValue::Immediate(rhs_val)) => { - self.trans_scalar_binop(&bx, op, lhs_val, rhs_val, lhs.layout.ty) - } - - _ => bug!() - }; - let operand = OperandRef { - val: OperandValue::Immediate(llresult), - layout: bx.cx.layout_of( - op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty)), - }; - (bx, operand) - } - mir::Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => { - let lhs = self.trans_operand(&bx, lhs); - let rhs = self.trans_operand(&bx, rhs); - let result = self.trans_scalar_checked_binop(&bx, op, - lhs.immediate(), rhs.immediate(), - lhs.layout.ty); - let val_ty = op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty); - let operand_ty = bx.tcx().intern_tup(&[val_ty, bx.tcx().types.bool]); - let operand = OperandRef { - val: result, - layout: bx.cx.layout_of(operand_ty) - }; - - (bx, operand) - } - - mir::Rvalue::UnaryOp(op, ref operand) => { - let operand = self.trans_operand(&bx, operand); - let lloperand = operand.immediate(); - let is_float = operand.layout.ty.is_fp(); - let llval = match op { - mir::UnOp::Not => bx.not(lloperand), - mir::UnOp::Neg => if is_float { - bx.fneg(lloperand) - } else { - bx.neg(lloperand) - } - }; - (bx, OperandRef { - val: OperandValue::Immediate(llval), - layout: operand.layout, - }) - } - - mir::Rvalue::Discriminant(ref place) => { - let discr_ty = rvalue.ty(&*self.mir, bx.tcx()); - let discr = self.trans_place(&bx, place) - .trans_get_discr(&bx, discr_ty); - (bx, OperandRef { - val: OperandValue::Immediate(discr), - layout: self.cx.layout_of(discr_ty) - }) - } - - mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => { - assert!(bx.cx.type_is_sized(ty)); - let val = C_usize(bx.cx, bx.cx.size_of(ty).bytes()); - let tcx = bx.tcx(); - (bx, OperandRef { - val: OperandValue::Immediate(val), - layout: self.cx.layout_of(tcx.types.usize), - }) - } - - mir::Rvalue::NullaryOp(mir::NullOp::Box, content_ty) => { - let content_ty: Ty<'tcx> = self.monomorphize(&content_ty); - let (size, align) = bx.cx.size_and_align_of(content_ty); - let llsize = C_usize(bx.cx, size.bytes()); - let llalign = C_usize(bx.cx, align.abi()); - let box_layout = bx.cx.layout_of(bx.tcx().mk_box(content_ty)); - let llty_ptr = box_layout.llvm_type(bx.cx); - - // Allocate space: - let def_id = match bx.tcx().lang_items().require(ExchangeMallocFnLangItem) { - Ok(id) => id, - Err(s) => { - bx.sess().fatal(&format!("allocation of `{}` {}", box_layout.ty, s)); - } - }; - let instance = ty::Instance::mono(bx.tcx(), def_id); - let r = callee::get_fn(bx.cx, instance); - let val = bx.pointercast(bx.call(r, &[llsize, llalign], None), llty_ptr); - - let operand = OperandRef { - val: OperandValue::Immediate(val), - layout: box_layout, - }; - (bx, operand) - } - mir::Rvalue::Use(ref operand) => { - let operand = self.trans_operand(&bx, operand); - (bx, operand) - } - mir::Rvalue::Repeat(..) | - mir::Rvalue::Aggregate(..) => { - // According to `rvalue_creates_operand`, only ZST - // aggregate rvalues are allowed to be operands. - let ty = rvalue.ty(self.mir, self.cx.tcx); - (bx, OperandRef::new_zst(self.cx, - self.cx.layout_of(self.monomorphize(&ty)))) - } - } - } - - fn evaluate_array_len(&mut self, - bx: &Builder<'a, 'tcx>, - place: &mir::Place<'tcx>) -> ValueRef - { - // ZST are passed as operands and require special handling - // because trans_place() panics if Local is operand. - if let mir::Place::Local(index) = *place { - if let LocalRef::Operand(Some(op)) = self.locals[index] { - if let ty::TyArray(_, n) = op.layout.ty.sty { - let n = n.unwrap_usize(bx.cx.tcx); - return common::C_usize(bx.cx, n); - } - } - } - // use common size calculation for non zero-sized types - let tr_value = self.trans_place(&bx, place); - return tr_value.len(bx.cx); - } - - pub fn trans_scalar_binop(&mut self, - bx: &Builder<'a, 'tcx>, - op: mir::BinOp, - lhs: ValueRef, - rhs: ValueRef, - input_ty: Ty<'tcx>) -> ValueRef { - let is_float = input_ty.is_fp(); - let is_signed = input_ty.is_signed(); - let is_nil = input_ty.is_nil(); - match op { - mir::BinOp::Add => if is_float { - bx.fadd(lhs, rhs) - } else { - bx.add(lhs, rhs) - }, - mir::BinOp::Sub => if is_float { - bx.fsub(lhs, rhs) - } else { - bx.sub(lhs, rhs) - }, - mir::BinOp::Mul => if is_float { - bx.fmul(lhs, rhs) - } else { - bx.mul(lhs, rhs) - }, - mir::BinOp::Div => if is_float { - bx.fdiv(lhs, rhs) - } else if is_signed { - bx.sdiv(lhs, rhs) - } else { - bx.udiv(lhs, rhs) - }, - mir::BinOp::Rem => if is_float { - bx.frem(lhs, rhs) - } else if is_signed { - bx.srem(lhs, rhs) - } else { - bx.urem(lhs, rhs) - }, - mir::BinOp::BitOr => bx.or(lhs, rhs), - mir::BinOp::BitAnd => bx.and(lhs, rhs), - mir::BinOp::BitXor => bx.xor(lhs, rhs), - mir::BinOp::Offset => bx.inbounds_gep(lhs, &[rhs]), - mir::BinOp::Shl => common::build_unchecked_lshift(bx, lhs, rhs), - mir::BinOp::Shr => common::build_unchecked_rshift(bx, input_ty, lhs, rhs), - mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt | - mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => if is_nil { - C_bool(bx.cx, match op { - mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt => false, - mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => true, - _ => unreachable!() - }) - } else if is_float { - bx.fcmp( - base::bin_op_to_fcmp_predicate(op.to_hir_binop()), - lhs, rhs - ) - } else { - bx.icmp( - base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed), - lhs, rhs - ) - } - } - } - - pub fn trans_fat_ptr_binop(&mut self, - bx: &Builder<'a, 'tcx>, - op: mir::BinOp, - lhs_addr: ValueRef, - lhs_extra: ValueRef, - rhs_addr: ValueRef, - rhs_extra: ValueRef, - _input_ty: Ty<'tcx>) - -> ValueRef { - match op { - mir::BinOp::Eq => { - bx.and( - bx.icmp(llvm::IntEQ, lhs_addr, rhs_addr), - bx.icmp(llvm::IntEQ, lhs_extra, rhs_extra) - ) - } - mir::BinOp::Ne => { - bx.or( - bx.icmp(llvm::IntNE, lhs_addr, rhs_addr), - bx.icmp(llvm::IntNE, lhs_extra, rhs_extra) - ) - } - mir::BinOp::Le | mir::BinOp::Lt | - mir::BinOp::Ge | mir::BinOp::Gt => { - // a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1) - let (op, strict_op) = match op { - mir::BinOp::Lt => (llvm::IntULT, llvm::IntULT), - mir::BinOp::Le => (llvm::IntULE, llvm::IntULT), - mir::BinOp::Gt => (llvm::IntUGT, llvm::IntUGT), - mir::BinOp::Ge => (llvm::IntUGE, llvm::IntUGT), - _ => bug!(), - }; - - bx.or( - bx.icmp(strict_op, lhs_addr, rhs_addr), - bx.and( - bx.icmp(llvm::IntEQ, lhs_addr, rhs_addr), - bx.icmp(op, lhs_extra, rhs_extra) - ) - ) - } - _ => { - bug!("unexpected fat ptr binop"); - } - } - } - - pub fn trans_scalar_checked_binop(&mut self, - bx: &Builder<'a, 'tcx>, - op: mir::BinOp, - lhs: ValueRef, - rhs: ValueRef, - input_ty: Ty<'tcx>) -> OperandValue { - // This case can currently arise only from functions marked - // with #[rustc_inherit_overflow_checks] and inlined from - // another crate (mostly core::num generic/#[inline] fns), - // while the current crate doesn't use overflow checks. - if !bx.cx.check_overflow { - let val = self.trans_scalar_binop(bx, op, lhs, rhs, input_ty); - return OperandValue::Pair(val, C_bool(bx.cx, false)); - } - - let (val, of) = match op { - // These are checked using intrinsics - mir::BinOp::Add | mir::BinOp::Sub | mir::BinOp::Mul => { - let oop = match op { - mir::BinOp::Add => OverflowOp::Add, - mir::BinOp::Sub => OverflowOp::Sub, - mir::BinOp::Mul => OverflowOp::Mul, - _ => unreachable!() - }; - let intrinsic = get_overflow_intrinsic(oop, bx, input_ty); - let res = bx.call(intrinsic, &[lhs, rhs], None); - - (bx.extract_value(res, 0), - bx.extract_value(res, 1)) - } - mir::BinOp::Shl | mir::BinOp::Shr => { - let lhs_llty = val_ty(lhs); - let rhs_llty = val_ty(rhs); - let invert_mask = common::shift_mask_val(&bx, lhs_llty, rhs_llty, true); - let outer_bits = bx.and(rhs, invert_mask); - - let of = bx.icmp(llvm::IntNE, outer_bits, C_null(rhs_llty)); - let val = self.trans_scalar_binop(bx, op, lhs, rhs, input_ty); - - (val, of) - } - _ => { - bug!("Operator `{:?}` is not a checkable operator", op) - } - }; - - OperandValue::Pair(val, of) - } - - pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>) -> bool { - match *rvalue { - mir::Rvalue::Ref(..) | - mir::Rvalue::Len(..) | - mir::Rvalue::Cast(..) | // (*) - mir::Rvalue::BinaryOp(..) | - mir::Rvalue::CheckedBinaryOp(..) | - mir::Rvalue::UnaryOp(..) | - mir::Rvalue::Discriminant(..) | - mir::Rvalue::NullaryOp(..) | - mir::Rvalue::Use(..) => // (*) - true, - mir::Rvalue::Repeat(..) | - mir::Rvalue::Aggregate(..) => { - let ty = rvalue.ty(self.mir, self.cx.tcx); - let ty = self.monomorphize(&ty); - self.cx.layout_of(ty).is_zst() - } - } - - // (*) this is only true if the type is suitable - } -} - -#[derive(Copy, Clone)] -enum OverflowOp { - Add, Sub, Mul -} - -fn get_overflow_intrinsic(oop: OverflowOp, bx: &Builder, ty: Ty) -> ValueRef { - use syntax::ast::IntTy::*; - use syntax::ast::UintTy::*; - use rustc::ty::{TyInt, TyUint}; - - let tcx = bx.tcx(); - - let new_sty = match ty.sty { - TyInt(Isize) => match &tcx.sess.target.target.target_pointer_width[..] { - "16" => TyInt(I16), - "32" => TyInt(I32), - "64" => TyInt(I64), - _ => panic!("unsupported target word size") - }, - TyUint(Usize) => match &tcx.sess.target.target.target_pointer_width[..] { - "16" => TyUint(U16), - "32" => TyUint(U32), - "64" => TyUint(U64), - _ => panic!("unsupported target word size") - }, - ref t @ TyUint(_) | ref t @ TyInt(_) => t.clone(), - _ => panic!("tried to get overflow intrinsic for op applied to non-int type") - }; - - let name = match oop { - OverflowOp::Add => match new_sty { - TyInt(I8) => "llvm.sadd.with.overflow.i8", - TyInt(I16) => "llvm.sadd.with.overflow.i16", - TyInt(I32) => "llvm.sadd.with.overflow.i32", - TyInt(I64) => "llvm.sadd.with.overflow.i64", - TyInt(I128) => "llvm.sadd.with.overflow.i128", - - TyUint(U8) => "llvm.uadd.with.overflow.i8", - TyUint(U16) => "llvm.uadd.with.overflow.i16", - TyUint(U32) => "llvm.uadd.with.overflow.i32", - TyUint(U64) => "llvm.uadd.with.overflow.i64", - TyUint(U128) => "llvm.uadd.with.overflow.i128", - - _ => unreachable!(), - }, - OverflowOp::Sub => match new_sty { - TyInt(I8) => "llvm.ssub.with.overflow.i8", - TyInt(I16) => "llvm.ssub.with.overflow.i16", - TyInt(I32) => "llvm.ssub.with.overflow.i32", - TyInt(I64) => "llvm.ssub.with.overflow.i64", - TyInt(I128) => "llvm.ssub.with.overflow.i128", - - TyUint(U8) => "llvm.usub.with.overflow.i8", - TyUint(U16) => "llvm.usub.with.overflow.i16", - TyUint(U32) => "llvm.usub.with.overflow.i32", - TyUint(U64) => "llvm.usub.with.overflow.i64", - TyUint(U128) => "llvm.usub.with.overflow.i128", - - _ => unreachable!(), - }, - OverflowOp::Mul => match new_sty { - TyInt(I8) => "llvm.smul.with.overflow.i8", - TyInt(I16) => "llvm.smul.with.overflow.i16", - TyInt(I32) => "llvm.smul.with.overflow.i32", - TyInt(I64) => "llvm.smul.with.overflow.i64", - TyInt(I128) => "llvm.smul.with.overflow.i128", - - TyUint(U8) => "llvm.umul.with.overflow.i8", - TyUint(U16) => "llvm.umul.with.overflow.i16", - TyUint(U32) => "llvm.umul.with.overflow.i32", - TyUint(U64) => "llvm.umul.with.overflow.i64", - TyUint(U128) => "llvm.umul.with.overflow.i128", - - _ => unreachable!(), - }, - }; - - bx.cx.get_intrinsic(&name) -} - -fn cast_int_to_float(bx: &Builder, - signed: bool, - x: ValueRef, - int_ty: Type, - float_ty: Type) -> ValueRef { - // Most integer types, even i128, fit into [-f32::MAX, f32::MAX] after rounding. - // It's only u128 -> f32 that can cause overflows (i.e., should yield infinity). - // LLVM's uitofp produces undef in those cases, so we manually check for that case. - let is_u128_to_f32 = !signed && int_ty.int_width() == 128 && float_ty.float_width() == 32; - if is_u128_to_f32 { - // All inputs greater or equal to (f32::MAX + 0.5 ULP) are rounded to infinity, - // and for everything else LLVM's uitofp works just fine. - use rustc_apfloat::ieee::Single; - use rustc_apfloat::Float; - const MAX_F32_PLUS_HALF_ULP: u128 = ((1 << (Single::PRECISION + 1)) - 1) - << (Single::MAX_EXP - Single::PRECISION as i16); - let max = C_uint_big(int_ty, MAX_F32_PLUS_HALF_ULP); - let overflow = bx.icmp(llvm::IntUGE, x, max); - let infinity_bits = C_u32(bx.cx, ieee::Single::INFINITY.to_bits() as u32); - let infinity = consts::bitcast(infinity_bits, float_ty); - bx.select(overflow, infinity, bx.uitofp(x, float_ty)) - } else { - if signed { - bx.sitofp(x, float_ty) - } else { - bx.uitofp(x, float_ty) - } - } -} - -fn cast_float_to_int(bx: &Builder, - signed: bool, - x: ValueRef, - float_ty: Type, - int_ty: Type) -> ValueRef { - let fptosui_result = if signed { - bx.fptosi(x, int_ty) - } else { - bx.fptoui(x, int_ty) - }; - - if !bx.sess().opts.debugging_opts.saturating_float_casts { - return fptosui_result; - } - // LLVM's fpto[su]i returns undef when the input x is infinite, NaN, or does not fit into the - // destination integer type after rounding towards zero. This `undef` value can cause UB in - // safe code (see issue #10184), so we implement a saturating conversion on top of it: - // Semantically, the mathematical value of the input is rounded towards zero to the next - // mathematical integer, and then the result is clamped into the range of the destination - // integer type. Positive and negative infinity are mapped to the maximum and minimum value of - // the destination integer type. NaN is mapped to 0. - // - // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to - // a value representable in int_ty. - // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits. - // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two. - // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly - // representable. Note that this only works if float_ty's exponent range is sufficiently large. - // f16 or 256 bit integers would break this property. Right now the smallest float type is f32 - // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127. - // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because - // we're rounding towards zero, we just get float_ty::MAX (which is always an integer). - // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX. - fn compute_clamp_bounds(signed: bool, int_ty: Type) -> (u128, u128) { - let rounded_min = F::from_i128_r(int_min(signed, int_ty), Round::TowardZero); - assert_eq!(rounded_min.status, Status::OK); - let rounded_max = F::from_u128_r(int_max(signed, int_ty), Round::TowardZero); - assert!(rounded_max.value.is_finite()); - (rounded_min.value.to_bits(), rounded_max.value.to_bits()) - } - fn int_max(signed: bool, int_ty: Type) -> u128 { - let shift_amount = 128 - int_ty.int_width(); - if signed { - i128::MAX as u128 >> shift_amount - } else { - u128::MAX >> shift_amount - } - } - fn int_min(signed: bool, int_ty: Type) -> i128 { - if signed { - i128::MIN >> (128 - int_ty.int_width()) - } else { - 0 - } - } - let float_bits_to_llval = |bits| { - let bits_llval = match float_ty.float_width() { - 32 => C_u32(bx.cx, bits as u32), - 64 => C_u64(bx.cx, bits as u64), - n => bug!("unsupported float width {}", n), - }; - consts::bitcast(bits_llval, float_ty) - }; - let (f_min, f_max) = match float_ty.float_width() { - 32 => compute_clamp_bounds::(signed, int_ty), - 64 => compute_clamp_bounds::(signed, int_ty), - n => bug!("unsupported float width {}", n), - }; - let f_min = float_bits_to_llval(f_min); - let f_max = float_bits_to_llval(f_max); - // To implement saturation, we perform the following steps: - // - // 1. Cast x to an integer with fpto[su]i. This may result in undef. - // 2. Compare x to f_min and f_max, and use the comparison results to select: - // a) int_ty::MIN if x < f_min or x is NaN - // b) int_ty::MAX if x > f_max - // c) the result of fpto[su]i otherwise - // 3. If x is NaN, return 0.0, otherwise return the result of step 2. - // - // This avoids resulting undef because values in range [f_min, f_max] by definition fit into the - // destination type. It creates an undef temporary, but *producing* undef is not UB. Our use of - // undef does not introduce any non-determinism either. - // More importantly, the above procedure correctly implements saturating conversion. - // Proof (sketch): - // If x is NaN, 0 is returned by definition. - // Otherwise, x is finite or infinite and thus can be compared with f_min and f_max. - // This yields three cases to consider: - // (1) if x in [f_min, f_max], the result of fpto[su]i is returned, which agrees with - // saturating conversion for inputs in that range. - // (2) if x > f_max, then x is larger than int_ty::MAX. This holds even if f_max is rounded - // (i.e., if f_max < int_ty::MAX) because in those cases, nextUp(f_max) is already larger - // than int_ty::MAX. Because x is larger than int_ty::MAX, the return value of int_ty::MAX - // is correct. - // (3) if x < f_min, then x is smaller than int_ty::MIN. As shown earlier, f_min exactly equals - // int_ty::MIN and therefore the return value of int_ty::MIN is correct. - // QED. - - // Step 1 was already performed above. - - // Step 2: We use two comparisons and two selects, with %s1 being the result: - // %less_or_nan = fcmp ult %x, %f_min - // %greater = fcmp olt %x, %f_max - // %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result - // %s1 = select %greater, int_ty::MAX, %s0 - // Note that %less_or_nan uses an *unordered* comparison. This comparison is true if the - // operands are not comparable (i.e., if x is NaN). The unordered comparison ensures that s1 - // becomes int_ty::MIN if x is NaN. - // Performance note: Unordered comparison can be lowered to a "flipped" comparison and a - // negation, and the negation can be merged into the select. Therefore, it not necessarily any - // more expensive than a ordered ("normal") comparison. Whether these optimizations will be - // performed is ultimately up to the backend, but at least x86 does perform them. - let less_or_nan = bx.fcmp(llvm::RealULT, x, f_min); - let greater = bx.fcmp(llvm::RealOGT, x, f_max); - let int_max = C_uint_big(int_ty, int_max(signed, int_ty)); - let int_min = C_uint_big(int_ty, int_min(signed, int_ty) as u128); - let s0 = bx.select(less_or_nan, int_min, fptosui_result); - let s1 = bx.select(greater, int_max, s0); - - // Step 3: NaN replacement. - // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN. - // Therefore we only need to execute this step for signed integer types. - if signed { - // LLVM has no isNaN predicate, so we use (x == x) instead - bx.select(bx.fcmp(llvm::RealOEQ, x, x), s1, C_uint(int_ty, 0)) - } else { - s1 - } -} diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs deleted file mode 100644 index 579b07929a2..00000000000 --- a/src/librustc_trans/mir/statement.rs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use rustc::mir; - -use asm; -use builder::Builder; - -use super::FunctionCx; -use super::LocalRef; - -impl<'a, 'tcx> FunctionCx<'a, 'tcx> { - pub fn trans_statement(&mut self, - bx: Builder<'a, 'tcx>, - statement: &mir::Statement<'tcx>) - -> Builder<'a, 'tcx> { - debug!("trans_statement(statement={:?})", statement); - - self.set_debug_loc(&bx, statement.source_info); - match statement.kind { - mir::StatementKind::Assign(ref place, ref rvalue) => { - if let mir::Place::Local(index) = *place { - match self.locals[index] { - LocalRef::Place(tr_dest) => { - self.trans_rvalue(bx, tr_dest, rvalue) - } - LocalRef::Operand(None) => { - let (bx, operand) = self.trans_rvalue_operand(bx, rvalue); - self.locals[index] = LocalRef::Operand(Some(operand)); - bx - } - LocalRef::Operand(Some(op)) => { - if !op.layout.is_zst() { - span_bug!(statement.source_info.span, - "operand {:?} already assigned", - rvalue); - } - - // If the type is zero-sized, it's already been set here, - // but we still need to make sure we translate the operand - self.trans_rvalue_operand(bx, rvalue).0 - } - } - } else { - let tr_dest = self.trans_place(&bx, place); - self.trans_rvalue(bx, tr_dest, rvalue) - } - } - mir::StatementKind::SetDiscriminant{ref place, variant_index} => { - self.trans_place(&bx, place) - .trans_set_discr(&bx, variant_index); - bx - } - mir::StatementKind::StorageLive(local) => { - if let LocalRef::Place(tr_place) = self.locals[local] { - tr_place.storage_live(&bx); - } - bx - } - mir::StatementKind::StorageDead(local) => { - if let LocalRef::Place(tr_place) = self.locals[local] { - tr_place.storage_dead(&bx); - } - bx - } - mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => { - let outputs = outputs.iter().map(|output| { - self.trans_place(&bx, output) - }).collect(); - - let input_vals = inputs.iter().map(|input| { - self.trans_operand(&bx, input).immediate() - }).collect(); - - asm::trans_inline_asm(&bx, asm, outputs, input_vals); - bx - } - mir::StatementKind::EndRegion(_) | - mir::StatementKind::Validate(..) | - mir::StatementKind::UserAssertTy(..) | - mir::StatementKind::Nop => bx, - } - } -} diff --git a/src/librustc_trans/time_graph.rs b/src/librustc_trans/time_graph.rs deleted file mode 100644 index a8502682a80..00000000000 --- a/src/librustc_trans/time_graph.rs +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::collections::HashMap; -use std::fs::File; -use std::io::prelude::*; -use std::marker::PhantomData; -use std::mem; -use std::sync::{Arc, Mutex}; -use std::time::Instant; - -const OUTPUT_WIDTH_IN_PX: u64 = 1000; -const TIME_LINE_HEIGHT_IN_PX: u64 = 20; -const TIME_LINE_HEIGHT_STRIDE_IN_PX: usize = 30; - -#[derive(Clone)] -struct Timing { - start: Instant, - end: Instant, - work_package_kind: WorkPackageKind, - name: String, - events: Vec<(String, Instant)>, -} - -#[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)] -pub struct TimelineId(pub usize); - -#[derive(Clone)] -struct PerThread { - timings: Vec, - open_work_package: Option<(Instant, WorkPackageKind, String)>, -} - -#[derive(Clone)] -pub struct TimeGraph { - data: Arc>>, -} - -#[derive(Clone, Copy)] -pub struct WorkPackageKind(pub &'static [&'static str]); - -pub struct Timeline { - token: Option, -} - -struct RaiiToken { - graph: TimeGraph, - timeline: TimelineId, - events: Vec<(String, Instant)>, - // The token must not be Send: - _marker: PhantomData<*const ()> -} - - -impl Drop for RaiiToken { - fn drop(&mut self) { - self.graph.end(self.timeline, mem::replace(&mut self.events, Vec::new())); - } -} - -impl TimeGraph { - pub fn new() -> TimeGraph { - TimeGraph { - data: Arc::new(Mutex::new(HashMap::new())) - } - } - - pub fn start(&self, - timeline: TimelineId, - work_package_kind: WorkPackageKind, - name: &str) -> Timeline { - { - let mut table = self.data.lock().unwrap(); - - let data = table.entry(timeline).or_insert(PerThread { - timings: Vec::new(), - open_work_package: None, - }); - - assert!(data.open_work_package.is_none()); - data.open_work_package = Some((Instant::now(), work_package_kind, name.to_string())); - } - - Timeline { - token: Some(RaiiToken { - graph: self.clone(), - timeline, - events: Vec::new(), - _marker: PhantomData, - }), - } - } - - fn end(&self, timeline: TimelineId, events: Vec<(String, Instant)>) { - let end = Instant::now(); - - let mut table = self.data.lock().unwrap(); - let data = table.get_mut(&timeline).unwrap(); - - if let Some((start, work_package_kind, name)) = data.open_work_package.take() { - data.timings.push(Timing { - start, - end, - work_package_kind, - name, - events, - }); - } else { - bug!("end timing without start?") - } - } - - pub fn dump(&self, output_filename: &str) { - let table = self.data.lock().unwrap(); - - for data in table.values() { - assert!(data.open_work_package.is_none()); - } - - let mut threads: Vec = - table.values().map(|data| data.clone()).collect(); - - threads.sort_by_key(|timeline| timeline.timings[0].start); - - let earliest_instant = threads[0].timings[0].start; - let latest_instant = threads.iter() - .map(|timeline| timeline.timings - .last() - .unwrap() - .end) - .max() - .unwrap(); - let max_distance = distance(earliest_instant, latest_instant); - - let mut file = File::create(format!("{}.html", output_filename)).unwrap(); - - writeln!(file, " - - - - - -
- ", - total_height = threads.len() * TIME_LINE_HEIGHT_STRIDE_IN_PX, - width = OUTPUT_WIDTH_IN_PX, - ).unwrap(); - - let mut color = 0; - for (line_index, thread) in threads.iter().enumerate() { - let line_top = line_index * TIME_LINE_HEIGHT_STRIDE_IN_PX; - - for span in &thread.timings { - let start = distance(earliest_instant, span.start); - let end = distance(earliest_instant, span.end); - - let start = normalize(start, max_distance, OUTPUT_WIDTH_IN_PX); - let end = normalize(end, max_distance, OUTPUT_WIDTH_IN_PX); - - let colors = span.work_package_kind.0; - - writeln!(file, "{}", - color, - line_top, - start, - end - start, - TIME_LINE_HEIGHT_IN_PX, - colors[color % colors.len()], - span.name, - ).unwrap(); - - color += 1; - } - } - - writeln!(file, " -
- ").unwrap(); - - let mut idx = 0; - for thread in threads.iter() { - for timing in &thread.timings { - let colors = timing.work_package_kind.0; - let height = TIME_LINE_HEIGHT_STRIDE_IN_PX * timing.events.len(); - writeln!(file, "
", - idx, - colors[idx % colors.len()], - height).unwrap(); - idx += 1; - let max = distance(timing.start, timing.end); - for (i, &(ref event, time)) in timing.events.iter().enumerate() { - let i = i as u64; - let time = distance(timing.start, time); - let at = normalize(time, max, OUTPUT_WIDTH_IN_PX); - writeln!(file, "{}", - at, - TIME_LINE_HEIGHT_IN_PX * i, - event).unwrap(); - } - writeln!(file, "
").unwrap(); - } - } - - writeln!(file, " - - - ").unwrap(); - } -} - -impl Timeline { - pub fn noop() -> Timeline { - Timeline { token: None } - } - - /// Record an event which happened at this moment on this timeline. - /// - /// Events are displayed in the eventual HTML output where you can click on - /// a particular timeline and it'll expand to all of the events that - /// happened on that timeline. This can then be used to drill into a - /// particular timeline and see what events are happening and taking the - /// most time. - pub fn record(&mut self, name: &str) { - if let Some(ref mut token) = self.token { - token.events.push((name.to_string(), Instant::now())); - } - } -} - -fn distance(zero: Instant, x: Instant) -> u64 { - - let duration = x.duration_since(zero); - (duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64) // / div -} - -fn normalize(distance: u64, max: u64, max_pixels: u64) -> u64 { - (max_pixels * distance) / max -} - diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs deleted file mode 100644 index d19b5af2527..00000000000 --- a/src/librustc_trans/trans_item.rs +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Walks the crate looking for items/impl-items/trait-items that have -//! either a `rustc_symbol_name` or `rustc_item_path` attribute and -//! generates an error giving, respectively, the symbol name or -//! item-path. This is used for unit testing the code that generates -//! paths etc in all kinds of annoying scenarios. - -use asm; -use attributes; -use base; -use consts; -use context::CodegenCx; -use declare; -use llvm; -use monomorphize::Instance; -use type_of::LayoutLlvmExt; -use rustc::hir; -use rustc::hir::def::Def; -use rustc::hir::def_id::DefId; -use rustc::mir::mono::{Linkage, Visibility}; -use rustc::ty::TypeFoldable; -use rustc::ty::layout::LayoutOf; -use syntax::attr; -use std::fmt; - -pub use rustc::mir::mono::MonoItem; - -pub use rustc_mir::monomorphize::item::*; -pub use rustc_mir::monomorphize::item::MonoItemExt as BaseMonoItemExt; - -pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { - fn define(&self, cx: &CodegenCx<'a, 'tcx>) { - debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}", - self.to_string(cx.tcx), - self.to_raw_string(), - cx.codegen_unit.name()); - - match *self.as_mono_item() { - MonoItem::Static(def_id) => { - let tcx = cx.tcx; - let is_mutable = match tcx.describe_def(def_id) { - Some(Def::Static(_, is_mutable)) => is_mutable, - Some(other) => { - bug!("Expected Def::Static, found {:?}", other) - } - None => { - bug!("Expected Def::Static for {:?}, found nothing", def_id) - } - }; - let attrs = tcx.get_attrs(def_id); - - consts::trans_static(&cx, def_id, is_mutable, &attrs); - } - MonoItem::GlobalAsm(node_id) => { - let item = cx.tcx.hir.expect_item(node_id); - if let hir::ItemGlobalAsm(ref ga) = item.node { - asm::trans_global_asm(cx, ga); - } else { - span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") - } - } - MonoItem::Fn(instance) => { - base::trans_instance(&cx, instance); - } - } - - debug!("END IMPLEMENTING '{} ({})' in cgu {}", - self.to_string(cx.tcx), - self.to_raw_string(), - cx.codegen_unit.name()); - } - - fn predefine(&self, - cx: &CodegenCx<'a, 'tcx>, - linkage: Linkage, - visibility: Visibility) { - debug!("BEGIN PREDEFINING '{} ({})' in cgu {}", - self.to_string(cx.tcx), - self.to_raw_string(), - cx.codegen_unit.name()); - - let symbol_name = self.symbol_name(cx.tcx).as_str(); - - debug!("symbol {}", &symbol_name); - - match *self.as_mono_item() { - MonoItem::Static(def_id) => { - predefine_static(cx, def_id, linkage, visibility, &symbol_name); - } - MonoItem::Fn(instance) => { - predefine_fn(cx, instance, linkage, visibility, &symbol_name); - } - MonoItem::GlobalAsm(..) => {} - } - - debug!("END PREDEFINING '{} ({})' in cgu {}", - self.to_string(cx.tcx), - self.to_raw_string(), - cx.codegen_unit.name()); - } - - fn to_raw_string(&self) -> String { - match *self.as_mono_item() { - MonoItem::Fn(instance) => { - format!("Fn({:?}, {})", - instance.def, - instance.substs.as_ptr() as usize) - } - MonoItem::Static(id) => { - format!("Static({:?})", id) - } - MonoItem::GlobalAsm(id) => { - format!("GlobalAsm({:?})", id) - } - } - } -} - -impl<'a, 'tcx> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {} - -fn predefine_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - def_id: DefId, - linkage: Linkage, - visibility: Visibility, - symbol_name: &str) { - let instance = Instance::mono(cx.tcx, def_id); - let ty = instance.ty(cx.tcx); - let llty = cx.layout_of(ty).llvm_type(cx); - - let g = declare::define_global(cx, symbol_name, llty).unwrap_or_else(|| { - cx.sess().span_fatal(cx.tcx.def_span(def_id), - &format!("symbol `{}` is already defined", symbol_name)) - }); - - unsafe { - llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage)); - llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility)); - } - - cx.instances.borrow_mut().insert(instance, g); - cx.statics.borrow_mut().insert(g, def_id); -} - -fn predefine_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - instance: Instance<'tcx>, - linkage: Linkage, - visibility: Visibility, - symbol_name: &str) { - assert!(!instance.substs.needs_infer() && - !instance.substs.has_param_types()); - - let mono_ty = instance.ty(cx.tcx); - let attrs = instance.def.attrs(cx.tcx); - let lldecl = declare::declare_fn(cx, symbol_name, mono_ty); - unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) }; - base::set_link_section(cx, lldecl, &attrs); - if linkage == Linkage::LinkOnceODR || - linkage == Linkage::WeakODR { - llvm::SetUniqueComdat(cx.llmod, lldecl); - } - - // If we're compiling the compiler-builtins crate, e.g. the equivalent of - // compiler-rt, then we want to implicitly compile everything with hidden - // visibility as we're going to link this object all over the place but - // don't want the symbols to get exported. - if linkage != Linkage::Internal && linkage != Linkage::Private && - attr::contains_name(cx.tcx.hir.krate_attrs(), "compiler_builtins") { - unsafe { - llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden); - } - } else { - unsafe { - llvm::LLVMRustSetVisibility(lldecl, base::visibility_to_llvm(visibility)); - } - } - - debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance); - if instance.def.is_inline(cx.tcx) { - attributes::inline(lldecl, attributes::InlineAttr::Hint); - } - attributes::from_fn_attrs(cx, lldecl, instance.def.def_id()); - - cx.instances.borrow_mut().insert(instance, lldecl); -} diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs deleted file mode 100644 index a77acc4f175..00000000000 --- a/src/librustc_trans/type_.rs +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_upper_case_globals)] - -use llvm; -use llvm::{ContextRef, TypeRef, Bool, False, True, TypeKind}; -use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128}; - -use context::CodegenCx; - -use syntax::ast; -use rustc::ty::layout::{self, Align, Size}; - -use std::ffi::CString; -use std::fmt; -use std::mem; -use std::ptr; - -use libc::c_uint; - -#[derive(Clone, Copy, PartialEq)] -#[repr(C)] -pub struct Type { - rf: TypeRef -} - -impl fmt::Debug for Type { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(&llvm::build_string(|s| unsafe { - llvm::LLVMRustWriteTypeToString(self.to_ref(), s); - }).expect("non-UTF8 type description from LLVM")) - } -} - -macro_rules! ty { - ($e:expr) => ( Type::from_ref(unsafe { $e })) -} - -/// Wrapper for LLVM TypeRef -impl Type { - #[inline(always)] - pub fn from_ref(r: TypeRef) -> Type { - Type { - rf: r - } - } - - #[inline(always)] // So it doesn't kill --opt-level=0 builds of the compiler - pub fn to_ref(&self) -> TypeRef { - self.rf - } - - pub fn to_ref_slice(slice: &[Type]) -> &[TypeRef] { - unsafe { mem::transmute(slice) } - } - - pub fn void(cx: &CodegenCx) -> Type { - ty!(llvm::LLVMVoidTypeInContext(cx.llcx)) - } - - pub fn metadata(cx: &CodegenCx) -> Type { - ty!(llvm::LLVMRustMetadataTypeInContext(cx.llcx)) - } - - pub fn i1(cx: &CodegenCx) -> Type { - ty!(llvm::LLVMInt1TypeInContext(cx.llcx)) - } - - pub fn i8(cx: &CodegenCx) -> Type { - ty!(llvm::LLVMInt8TypeInContext(cx.llcx)) - } - - pub fn i8_llcx(llcx: ContextRef) -> Type { - ty!(llvm::LLVMInt8TypeInContext(llcx)) - } - - pub fn i16(cx: &CodegenCx) -> Type { - ty!(llvm::LLVMInt16TypeInContext(cx.llcx)) - } - - pub fn i32(cx: &CodegenCx) -> Type { - ty!(llvm::LLVMInt32TypeInContext(cx.llcx)) - } - - pub fn i64(cx: &CodegenCx) -> Type { - ty!(llvm::LLVMInt64TypeInContext(cx.llcx)) - } - - pub fn i128(cx: &CodegenCx) -> Type { - ty!(llvm::LLVMIntTypeInContext(cx.llcx, 128)) - } - - // Creates an integer type with the given number of bits, e.g. i24 - pub fn ix(cx: &CodegenCx, num_bits: u64) -> Type { - ty!(llvm::LLVMIntTypeInContext(cx.llcx, num_bits as c_uint)) - } - - pub fn f32(cx: &CodegenCx) -> Type { - ty!(llvm::LLVMFloatTypeInContext(cx.llcx)) - } - - pub fn f64(cx: &CodegenCx) -> Type { - ty!(llvm::LLVMDoubleTypeInContext(cx.llcx)) - } - - pub fn bool(cx: &CodegenCx) -> Type { - Type::i8(cx) - } - - pub fn char(cx: &CodegenCx) -> Type { - Type::i32(cx) - } - - pub fn i8p(cx: &CodegenCx) -> Type { - Type::i8(cx).ptr_to() - } - - pub fn i8p_llcx(llcx: ContextRef) -> Type { - Type::i8_llcx(llcx).ptr_to() - } - - pub fn isize(cx: &CodegenCx) -> Type { - match &cx.tcx.sess.target.target.target_pointer_width[..] { - "16" => Type::i16(cx), - "32" => Type::i32(cx), - "64" => Type::i64(cx), - tws => bug!("Unsupported target word size for int: {}", tws), - } - } - - pub fn c_int(cx: &CodegenCx) -> Type { - match &cx.tcx.sess.target.target.target_c_int_width[..] { - "16" => Type::i16(cx), - "32" => Type::i32(cx), - "64" => Type::i64(cx), - width => bug!("Unsupported target_c_int_width: {}", width), - } - } - - pub fn int_from_ty(cx: &CodegenCx, t: ast::IntTy) -> Type { - match t { - ast::IntTy::Isize => cx.isize_ty, - ast::IntTy::I8 => Type::i8(cx), - ast::IntTy::I16 => Type::i16(cx), - ast::IntTy::I32 => Type::i32(cx), - ast::IntTy::I64 => Type::i64(cx), - ast::IntTy::I128 => Type::i128(cx), - } - } - - pub fn uint_from_ty(cx: &CodegenCx, t: ast::UintTy) -> Type { - match t { - ast::UintTy::Usize => cx.isize_ty, - ast::UintTy::U8 => Type::i8(cx), - ast::UintTy::U16 => Type::i16(cx), - ast::UintTy::U32 => Type::i32(cx), - ast::UintTy::U64 => Type::i64(cx), - ast::UintTy::U128 => Type::i128(cx), - } - } - - pub fn float_from_ty(cx: &CodegenCx, t: ast::FloatTy) -> Type { - match t { - ast::FloatTy::F32 => Type::f32(cx), - ast::FloatTy::F64 => Type::f64(cx), - } - } - - pub fn func(args: &[Type], ret: &Type) -> Type { - let slice: &[TypeRef] = Type::to_ref_slice(args); - ty!(llvm::LLVMFunctionType(ret.to_ref(), slice.as_ptr(), - args.len() as c_uint, False)) - } - - pub fn variadic_func(args: &[Type], ret: &Type) -> Type { - let slice: &[TypeRef] = Type::to_ref_slice(args); - ty!(llvm::LLVMFunctionType(ret.to_ref(), slice.as_ptr(), - args.len() as c_uint, True)) - } - - pub fn struct_(cx: &CodegenCx, els: &[Type], packed: bool) -> Type { - let els: &[TypeRef] = Type::to_ref_slice(els); - ty!(llvm::LLVMStructTypeInContext(cx.llcx, els.as_ptr(), - els.len() as c_uint, - packed as Bool)) - } - - pub fn named_struct(cx: &CodegenCx, name: &str) -> Type { - let name = CString::new(name).unwrap(); - ty!(llvm::LLVMStructCreateNamed(cx.llcx, name.as_ptr())) - } - - - pub fn array(ty: &Type, len: u64) -> Type { - ty!(llvm::LLVMRustArrayType(ty.to_ref(), len)) - } - - pub fn vector(ty: &Type, len: u64) -> Type { - ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint)) - } - - pub fn kind(&self) -> TypeKind { - unsafe { - llvm::LLVMRustGetTypeKind(self.to_ref()) - } - } - - pub fn set_struct_body(&mut self, els: &[Type], packed: bool) { - let slice: &[TypeRef] = Type::to_ref_slice(els); - unsafe { - llvm::LLVMStructSetBody(self.to_ref(), slice.as_ptr(), - els.len() as c_uint, packed as Bool) - } - } - - pub fn ptr_to(&self) -> Type { - ty!(llvm::LLVMPointerType(self.to_ref(), 0)) - } - - pub fn element_type(&self) -> Type { - unsafe { - Type::from_ref(llvm::LLVMGetElementType(self.to_ref())) - } - } - - /// Return the number of elements in `self` if it is a LLVM vector type. - pub fn vector_length(&self) -> usize { - unsafe { - llvm::LLVMGetVectorSize(self.to_ref()) as usize - } - } - - pub fn func_params(&self) -> Vec { - unsafe { - let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as usize; - let mut args = vec![Type { rf: ptr::null_mut() }; n_args]; - llvm::LLVMGetParamTypes(self.to_ref(), - args.as_mut_ptr() as *mut TypeRef); - args - } - } - - pub fn float_width(&self) -> usize { - match self.kind() { - Float => 32, - Double => 64, - X86_FP80 => 80, - FP128 | PPC_FP128 => 128, - _ => bug!("llvm_float_width called on a non-float type") - } - } - - /// Retrieve the bit width of the integer type `self`. - pub fn int_width(&self) -> u64 { - unsafe { - llvm::LLVMGetIntTypeWidth(self.to_ref()) as u64 - } - } - - pub fn from_integer(cx: &CodegenCx, i: layout::Integer) -> Type { - use rustc::ty::layout::Integer::*; - match i { - I8 => Type::i8(cx), - I16 => Type::i16(cx), - I32 => Type::i32(cx), - I64 => Type::i64(cx), - I128 => Type::i128(cx), - } - } - - /// Return a LLVM type that has at most the required alignment, - /// as a conservative approximation for unknown pointee types. - pub fn pointee_for_abi_align(cx: &CodegenCx, align: Align) -> Type { - // FIXME(eddyb) We could find a better approximation if ity.align < align. - let ity = layout::Integer::approximate_abi_align(cx, align); - Type::from_integer(cx, ity) - } - - /// Return a LLVM type that has at most the required alignment, - /// and exactly the required size, as a best-effort padding array. - pub fn padding_filler(cx: &CodegenCx, size: Size, align: Align) -> Type { - let unit = layout::Integer::approximate_abi_align(cx, align); - let size = size.bytes(); - let unit_size = unit.size().bytes(); - assert_eq!(size % unit_size, 0); - Type::array(&Type::from_integer(cx, unit), size / unit_size) - } - - pub fn x86_mmx(cx: &CodegenCx) -> Type { - ty!(llvm::LLVMX86MMXTypeInContext(cx.llcx)) - } -} diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs deleted file mode 100644 index 32d26052aff..00000000000 --- a/src/librustc_trans/type_of.rs +++ /dev/null @@ -1,506 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use abi::{FnType, FnTypeExt}; -use common::*; -use rustc::hir; -use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout}; -use rustc_target::spec::PanicStrategy; -use trans_item::DefPathBasedNames; -use type_::Type; - -use std::fmt::Write; - -fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - layout: TyLayout<'tcx>, - defer: &mut Option<(Type, TyLayout<'tcx>)>) - -> Type { - match layout.abi { - layout::Abi::Scalar(_) => bug!("handled elsewhere"), - layout::Abi::Vector { ref element, count } => { - // LLVM has a separate type for 64-bit SIMD vectors on X86 called - // `x86_mmx` which is needed for some SIMD operations. As a bit of a - // hack (all SIMD definitions are super unstable anyway) we - // recognize any one-element SIMD vector as "this should be an - // x86_mmx" type. In general there shouldn't be a need for other - // one-element SIMD vectors, so it's assumed this won't clash with - // much else. - let use_x86_mmx = count == 1 && layout.size.bits() == 64 && - (cx.sess().target.target.arch == "x86" || - cx.sess().target.target.arch == "x86_64"); - if use_x86_mmx { - return Type::x86_mmx(cx) - } else { - let element = layout.scalar_llvm_type_at(cx, element, Size::from_bytes(0)); - return Type::vector(&element, count); - } - } - layout::Abi::ScalarPair(..) => { - return Type::struct_(cx, &[ - layout.scalar_pair_element_llvm_type(cx, 0), - layout.scalar_pair_element_llvm_type(cx, 1), - ], false); - } - layout::Abi::Uninhabited | - layout::Abi::Aggregate { .. } => {} - } - - let name = match layout.ty.sty { - ty::TyClosure(..) | - ty::TyGenerator(..) | - ty::TyAdt(..) | - // FIXME(eddyb) producing readable type names for trait objects can result - // in problematically distinct types due to HRTB and subtyping (see #47638). - // ty::TyDynamic(..) | - ty::TyForeign(..) | - ty::TyStr => { - let mut name = String::with_capacity(32); - let printer = DefPathBasedNames::new(cx.tcx, true, true); - printer.push_type_name(layout.ty, &mut name); - match (&layout.ty.sty, &layout.variants) { - (&ty::TyAdt(def, _), &layout::Variants::Single { index }) => { - if def.is_enum() && !def.variants.is_empty() { - write!(&mut name, "::{}", def.variants[index].name).unwrap(); - } - } - _ => {} - } - Some(name) - } - _ => None - }; - - match layout.fields { - layout::FieldPlacement::Union(_) => { - let fill = Type::padding_filler(cx, layout.size, layout.align); - let packed = false; - match name { - None => { - Type::struct_(cx, &[fill], packed) - } - Some(ref name) => { - let mut llty = Type::named_struct(cx, name); - llty.set_struct_body(&[fill], packed); - llty - } - } - } - layout::FieldPlacement::Array { count, .. } => { - Type::array(&layout.field(cx, 0).llvm_type(cx), count) - } - layout::FieldPlacement::Arbitrary { .. } => { - match name { - None => { - let (llfields, packed) = struct_llfields(cx, layout); - Type::struct_(cx, &llfields, packed) - } - Some(ref name) => { - let llty = Type::named_struct(cx, name); - *defer = Some((llty, layout)); - llty - } - } - } - } -} - -fn struct_llfields<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - layout: TyLayout<'tcx>) - -> (Vec, bool) { - debug!("struct_llfields: {:#?}", layout); - let field_count = layout.fields.count(); - - let mut packed = false; - let mut offset = Size::from_bytes(0); - let mut prev_align = layout.align; - let mut result: Vec = Vec::with_capacity(1 + field_count * 2); - for i in layout.fields.index_by_increasing_offset() { - let field = layout.field(cx, i); - packed |= layout.align.abi() < field.align.abi(); - - let target_offset = layout.fields.offset(i as usize); - debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?}", - i, field, offset, target_offset); - assert!(target_offset >= offset); - let padding = target_offset - offset; - let padding_align = layout.align.min(prev_align).min(field.align); - assert_eq!(offset.abi_align(padding_align) + padding, target_offset); - result.push(Type::padding_filler(cx, padding, padding_align)); - debug!(" padding before: {:?}", padding); - - result.push(field.llvm_type(cx)); - offset = target_offset + field.size; - prev_align = field.align; - } - if !layout.is_unsized() && field_count > 0 { - if offset > layout.size { - bug!("layout: {:#?} stride: {:?} offset: {:?}", - layout, layout.size, offset); - } - let padding = layout.size - offset; - let padding_align = layout.align.min(prev_align); - assert_eq!(offset.abi_align(padding_align) + padding, layout.size); - debug!("struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}", - padding, offset, layout.size); - result.push(Type::padding_filler(cx, padding, padding_align)); - assert!(result.len() == 1 + field_count * 2); - } else { - debug!("struct_llfields: offset: {:?} stride: {:?}", - offset, layout.size); - } - - (result, packed) -} - -impl<'a, 'tcx> CodegenCx<'a, 'tcx> { - pub fn align_of(&self, ty: Ty<'tcx>) -> Align { - self.layout_of(ty).align - } - - pub fn size_of(&self, ty: Ty<'tcx>) -> Size { - self.layout_of(ty).size - } - - pub fn size_and_align_of(&self, ty: Ty<'tcx>) -> (Size, Align) { - self.layout_of(ty).size_and_align() - } -} - -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum PointerKind { - /// Most general case, we know no restrictions to tell LLVM. - Shared, - - /// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`. - Frozen, - - /// `&mut T`, when we know `noalias` is safe for LLVM. - UniqueBorrowed, - - /// `Box`, unlike `UniqueBorrowed`, it also has `noalias` on returns. - UniqueOwned -} - -#[derive(Copy, Clone)] -pub struct PointeeInfo { - pub size: Size, - pub align: Align, - pub safe: Option, -} - -pub trait LayoutLlvmExt<'tcx> { - fn is_llvm_immediate(&self) -> bool; - fn is_llvm_scalar_pair<'a>(&self) -> bool; - fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Type; - fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Type; - fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, - scalar: &layout::Scalar, offset: Size) -> Type; - fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>, - index: usize) -> Type; - fn llvm_field_index(&self, index: usize) -> u64; - fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) - -> Option; -} - -impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { - fn is_llvm_immediate(&self) -> bool { - match self.abi { - layout::Abi::Scalar(_) | - layout::Abi::Vector { .. } => true, - layout::Abi::ScalarPair(..) => false, - layout::Abi::Uninhabited | - layout::Abi::Aggregate { .. } => self.is_zst() - } - } - - fn is_llvm_scalar_pair<'a>(&self) -> bool { - match self.abi { - layout::Abi::ScalarPair(..) => true, - layout::Abi::Uninhabited | - layout::Abi::Scalar(_) | - layout::Abi::Vector { .. } | - layout::Abi::Aggregate { .. } => false - } - } - - /// Get the LLVM type corresponding to a Rust type, i.e. `rustc::ty::Ty`. - /// The pointee type of the pointer in `PlaceRef` is always this type. - /// For sized types, it is also the right LLVM type for an `alloca` - /// containing a value of that type, and most immediates (except `bool`). - /// Unsized types, however, are represented by a "minimal unit", e.g. - /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this - /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`. - /// If the type is an unsized struct, the regular layout is generated, - /// with the inner-most trailing unsized field using the "minimal unit" - /// of that field's type - this is useful for taking the address of - /// that field and ensuring the struct has the right alignment. - fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { - if let layout::Abi::Scalar(ref scalar) = self.abi { - // Use a different cache for scalars because pointers to DSTs - // can be either fat or thin (data pointers of fat pointers). - if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) { - return llty; - } - let llty = match self.ty.sty { - ty::TyRef(_, ty, _) | - ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => { - cx.layout_of(ty).llvm_type(cx).ptr_to() - } - ty::TyAdt(def, _) if def.is_box() => { - cx.layout_of(self.ty.boxed_ty()).llvm_type(cx).ptr_to() - } - ty::TyFnPtr(sig) => { - let sig = cx.tcx.normalize_erasing_late_bound_regions( - ty::ParamEnv::reveal_all(), - &sig, - ); - FnType::new(cx, sig, &[]).llvm_type(cx).ptr_to() - } - _ => self.scalar_llvm_type_at(cx, scalar, Size::from_bytes(0)) - }; - cx.scalar_lltypes.borrow_mut().insert(self.ty, llty); - return llty; - } - - - // Check the cache. - let variant_index = match self.variants { - layout::Variants::Single { index } => Some(index), - _ => None - }; - if let Some(&llty) = cx.lltypes.borrow().get(&(self.ty, variant_index)) { - return llty; - } - - debug!("llvm_type({:#?})", self); - - assert!(!self.ty.has_escaping_regions(), "{:?} has escaping regions", self.ty); - - // Make sure lifetimes are erased, to avoid generating distinct LLVM - // types for Rust types that only differ in the choice of lifetimes. - let normal_ty = cx.tcx.erase_regions(&self.ty); - - let mut defer = None; - let llty = if self.ty != normal_ty { - let mut layout = cx.layout_of(normal_ty); - if let Some(v) = variant_index { - layout = layout.for_variant(cx, v); - } - layout.llvm_type(cx) - } else { - uncached_llvm_type(cx, *self, &mut defer) - }; - debug!("--> mapped {:#?} to llty={:?}", self, llty); - - cx.lltypes.borrow_mut().insert((self.ty, variant_index), llty); - - if let Some((mut llty, layout)) = defer { - let (llfields, packed) = struct_llfields(cx, layout); - llty.set_struct_body(&llfields, packed) - } - - llty - } - - fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { - if let layout::Abi::Scalar(ref scalar) = self.abi { - if scalar.is_bool() { - return Type::i1(cx); - } - } - self.llvm_type(cx) - } - - fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, - scalar: &layout::Scalar, offset: Size) -> Type { - match scalar.value { - layout::Int(i, _) => Type::from_integer(cx, i), - layout::F32 => Type::f32(cx), - layout::F64 => Type::f64(cx), - layout::Pointer => { - // If we know the alignment, pick something better than i8. - let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) { - Type::pointee_for_abi_align(cx, pointee.align) - } else { - Type::i8(cx) - }; - pointee.ptr_to() - } - } - } - - fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>, - index: usize) -> Type { - // HACK(eddyb) special-case fat pointers until LLVM removes - // pointee types, to avoid bitcasting every `OperandRef::deref`. - match self.ty.sty { - ty::TyRef(..) | - ty::TyRawPtr(_) => { - return self.field(cx, index).llvm_type(cx); - } - ty::TyAdt(def, _) if def.is_box() => { - let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty()); - return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index); - } - _ => {} - } - - let (a, b) = match self.abi { - layout::Abi::ScalarPair(ref a, ref b) => (a, b), - _ => bug!("TyLayout::scalar_pair_element_llty({:?}): not applicable", self) - }; - let scalar = [a, b][index]; - - // Make sure to return the same type `immediate_llvm_type` would, - // to avoid dealing with two types and the associated conversions. - // This means that `(bool, bool)` is represented as `{i1, i1}`, - // both in memory and as an immediate, while `bool` is typically - // `i8` in memory and only `i1` when immediate. While we need to - // load/store `bool` as `i8` to avoid crippling LLVM optimizations, - // `i1` in a LLVM aggregate is valid and mostly equivalent to `i8`. - if scalar.is_bool() { - return Type::i1(cx); - } - - let offset = if index == 0 { - Size::from_bytes(0) - } else { - a.value.size(cx).abi_align(b.value.align(cx)) - }; - self.scalar_llvm_type_at(cx, scalar, offset) - } - - fn llvm_field_index(&self, index: usize) -> u64 { - match self.abi { - layout::Abi::Scalar(_) | - layout::Abi::ScalarPair(..) => { - bug!("TyLayout::llvm_field_index({:?}): not applicable", self) - } - _ => {} - } - match self.fields { - layout::FieldPlacement::Union(_) => { - bug!("TyLayout::llvm_field_index({:?}): not applicable", self) - } - - layout::FieldPlacement::Array { .. } => { - index as u64 - } - - layout::FieldPlacement::Arbitrary { .. } => { - 1 + (self.fields.memory_index(index) as u64) * 2 - } - } - } - - fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) - -> Option { - if let Some(&pointee) = cx.pointee_infos.borrow().get(&(self.ty, offset)) { - return pointee; - } - - let mut result = None; - match self.ty.sty { - ty::TyRawPtr(mt) if offset.bytes() == 0 => { - let (size, align) = cx.size_and_align_of(mt.ty); - result = Some(PointeeInfo { - size, - align, - safe: None - }); - } - - ty::TyRef(_, ty, mt) if offset.bytes() == 0 => { - let (size, align) = cx.size_and_align_of(ty); - - let kind = match mt { - hir::MutImmutable => if cx.type_is_freeze(ty) { - PointerKind::Frozen - } else { - PointerKind::Shared - }, - hir::MutMutable => { - if cx.tcx.sess.opts.debugging_opts.mutable_noalias || - cx.tcx.sess.panic_strategy() == PanicStrategy::Abort { - PointerKind::UniqueBorrowed - } else { - PointerKind::Shared - } - } - }; - - result = Some(PointeeInfo { - size, - align, - safe: Some(kind) - }); - } - - _ => { - let mut data_variant = match self.variants { - layout::Variants::NicheFilling { dataful_variant, .. } => { - // Only the niche itself is always initialized, - // so only check for a pointer at its offset. - // - // If the niche is a pointer, it's either valid - // (according to its type), or null (which the - // niche field's scalar validity range encodes). - // This allows using `dereferenceable_or_null` - // for e.g. `Option<&T>`, and this will continue - // to work as long as we don't start using more - // niches than just null (e.g. the first page - // of the address space, or unaligned pointers). - if self.fields.offset(0) == offset { - Some(self.for_variant(cx, dataful_variant)) - } else { - None - } - } - _ => Some(*self) - }; - - if let Some(variant) = data_variant { - // We're not interested in any unions. - if let layout::FieldPlacement::Union(_) = variant.fields { - data_variant = None; - } - } - - if let Some(variant) = data_variant { - let ptr_end = offset + layout::Pointer.size(cx); - for i in 0..variant.fields.count() { - let field_start = variant.fields.offset(i); - if field_start <= offset { - let field = variant.field(cx, i); - if ptr_end <= field_start + field.size { - // We found the right field, look inside it. - result = field.pointee_info_at(cx, offset - field_start); - break; - } - } - } - } - - // FIXME(eddyb) This should be for `ptr::Unique`, not `Box`. - if let Some(ref mut pointee) = result { - if let ty::TyAdt(def, _) = self.ty.sty { - if def.is_box() && offset.bytes() == 0 { - pointee.safe = Some(PointerKind::UniqueOwned); - } - } - } - } - } - - cx.pointee_infos.borrow_mut().insert((self.ty, offset), result); - result - } -} diff --git a/src/librustc_trans/value.rs b/src/librustc_trans/value.rs deleted file mode 100644 index 287ad87caac..00000000000 --- a/src/librustc_trans/value.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use llvm; - -use std::fmt; - -#[derive(Copy, Clone, PartialEq)] -pub struct Value(pub llvm::ValueRef); - -impl fmt::Debug for Value { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(&llvm::build_string(|s| unsafe { - llvm::LLVMRustWriteValueToString(self.0, s); - }).expect("nun-UTF8 value description from LLVM")) - } -} diff --git a/src/librustc_trans_utils/Cargo.toml b/src/librustc_trans_utils/Cargo.toml deleted file mode 100644 index 323d9d1ceda..00000000000 --- a/src/librustc_trans_utils/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_trans_utils" -version = "0.0.0" - -[lib] -name = "rustc_trans_utils" -path = "lib.rs" -crate-type = ["dylib"] -test = false - -[dependencies] -ar = "0.3.0" -flate2 = "1.0" -log = "0.4" - -syntax = { path = "../libsyntax" } -syntax_pos = { path = "../libsyntax_pos" } -rustc = { path = "../librustc" } -rustc_target = { path = "../librustc_target" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_mir = { path = "../librustc_mir" } -rustc_incremental = { path = "../librustc_incremental" } diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs deleted file mode 100644 index b91f4e4dffb..00000000000 --- a/src/librustc_trans_utils/lib.rs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! # Note -//! -//! This API is completely unstable and subject to change. - -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/")] - -#![feature(box_patterns)] -#![feature(box_syntax)] -#![feature(custom_attribute)] -#![allow(unused_attributes)] -#![feature(quote)] -#![feature(rustc_diagnostic_macros)] - -extern crate ar; -extern crate flate2; -#[macro_use] -extern crate log; - -#[macro_use] -extern crate rustc; -extern crate rustc_target; -extern crate rustc_mir; -extern crate rustc_incremental; -extern crate syntax; -extern crate syntax_pos; -#[macro_use] extern crate rustc_data_structures; - -pub extern crate rustc as __rustc; - -use rustc::ty::TyCtxt; - -pub mod link; -pub mod trans_crate; -pub mod symbol_names; -pub mod symbol_names_test; - -/// check for the #[rustc_error] annotation, which forces an -/// error in trans. This is used to write compile-fail tests -/// that actually test that compilation succeeds without -/// reporting an error. -pub fn check_for_rustc_errors_attr(tcx: TyCtxt) { - if let Some((id, span, _)) = *tcx.sess.entry_fn.borrow() { - let main_def_id = tcx.hir.local_def_id(id); - - if tcx.has_attr(main_def_id, "rustc_error") { - tcx.sess.span_fatal(span, "compilation successful"); - } - } -} - -__build_diagnostic_array! { librustc_trans_utils, DIAGNOSTICS } diff --git a/src/librustc_trans_utils/link.rs b/src/librustc_trans_utils/link.rs deleted file mode 100644 index aabe931d79c..00000000000 --- a/src/librustc_trans_utils/link.rs +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use rustc::session::config::{self, OutputFilenames, Input, OutputType}; -use rustc::session::Session; -use rustc::middle::cstore::{self, LinkMeta}; -use rustc::hir::svh::Svh; -use std::path::{Path, PathBuf}; -use syntax::{ast, attr}; -use syntax_pos::Span; - -pub fn out_filename(sess: &Session, - crate_type: config::CrateType, - outputs: &OutputFilenames, - crate_name: &str) - -> PathBuf { - let default_filename = filename_for_input(sess, crate_type, crate_name, outputs); - let out_filename = outputs.outputs.get(&OutputType::Exe) - .and_then(|s| s.to_owned()) - .or_else(|| outputs.single_output_file.clone()) - .unwrap_or(default_filename); - - check_file_is_writeable(&out_filename, sess); - - out_filename -} - -// Make sure files are writeable. Mac, FreeBSD, and Windows system linkers -// check this already -- however, the Linux linker will happily overwrite a -// read-only file. We should be consistent. -pub fn check_file_is_writeable(file: &Path, sess: &Session) { - if !is_writeable(file) { - sess.fatal(&format!("output file {} is not writeable -- check its \ - permissions", file.display())); - } -} - -fn is_writeable(p: &Path) -> bool { - match p.metadata() { - Err(..) => true, - Ok(m) => !m.permissions().readonly() - } -} - -pub fn build_link_meta(crate_hash: Svh) -> LinkMeta { - let r = LinkMeta { - crate_hash, - }; - info!("{:?}", r); - return r; -} - -pub fn find_crate_name(sess: Option<&Session>, - attrs: &[ast::Attribute], - input: &Input) -> String { - let validate = |s: String, span: Option| { - cstore::validate_crate_name(sess, &s, span); - s - }; - - // Look in attributes 100% of the time to make sure the attribute is marked - // as used. After doing this, however, we still prioritize a crate name from - // the command line over one found in the #[crate_name] attribute. If we - // find both we ensure that they're the same later on as well. - let attr_crate_name = attr::find_by_name(attrs, "crate_name") - .and_then(|at| at.value_str().map(|s| (at, s))); - - if let Some(sess) = sess { - if let Some(ref s) = sess.opts.crate_name { - if let Some((attr, name)) = attr_crate_name { - if name != &**s { - let msg = format!("--crate-name and #[crate_name] are \ - required to match, but `{}` != `{}`", - s, name); - sess.span_err(attr.span, &msg); - } - } - return validate(s.clone(), None); - } - } - - if let Some((attr, s)) = attr_crate_name { - return validate(s.to_string(), Some(attr.span)); - } - if let Input::File(ref path) = *input { - if let Some(s) = path.file_stem().and_then(|s| s.to_str()) { - if s.starts_with("-") { - let msg = format!("crate names cannot start with a `-`, but \ - `{}` has a leading hyphen", s); - if let Some(sess) = sess { - sess.err(&msg); - } - } else { - return validate(s.replace("-", "_"), None); - } - } - } - - "rust_out".to_string() -} - -pub fn filename_for_input(sess: &Session, - crate_type: config::CrateType, - crate_name: &str, - outputs: &OutputFilenames) -> PathBuf { - let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename); - - match crate_type { - config::CrateTypeRlib => { - outputs.out_directory.join(&format!("lib{}.rlib", libname)) - } - config::CrateTypeCdylib | - config::CrateTypeProcMacro | - config::CrateTypeDylib => { - let (prefix, suffix) = (&sess.target.target.options.dll_prefix, - &sess.target.target.options.dll_suffix); - outputs.out_directory.join(&format!("{}{}{}", prefix, libname, - suffix)) - } - config::CrateTypeStaticlib => { - let (prefix, suffix) = (&sess.target.target.options.staticlib_prefix, - &sess.target.target.options.staticlib_suffix); - outputs.out_directory.join(&format!("{}{}{}", prefix, libname, - suffix)) - } - config::CrateTypeExecutable => { - let suffix = &sess.target.target.options.exe_suffix; - let out_filename = outputs.path(OutputType::Exe); - if suffix.is_empty() { - out_filename.to_path_buf() - } else { - out_filename.with_extension(&suffix[1..]) - } - } - } -} - -/// Returns default crate type for target -/// -/// Default crate type is used when crate type isn't provided neither -/// through cmd line arguments nor through crate attributes -/// -/// It is CrateTypeExecutable for all platforms but iOS as there is no -/// way to run iOS binaries anyway without jailbreaking and -/// interaction with Rust code through static library is the only -/// option for now -pub fn default_output_for_target(sess: &Session) -> config::CrateType { - if !sess.target.target.options.executables { - config::CrateTypeStaticlib - } else { - config::CrateTypeExecutable - } -} - -/// Checks if target supports crate_type as output -pub fn invalid_output_for_target(sess: &Session, - crate_type: config::CrateType) -> bool { - match crate_type { - config::CrateTypeCdylib | - config::CrateTypeDylib | - config::CrateTypeProcMacro => { - if !sess.target.target.options.dynamic_linking { - return true - } - if sess.crt_static() && !sess.target.target.options.crt_static_allows_dylibs { - return true - } - } - _ => {} - } - if sess.target.target.options.only_cdylib { - match crate_type { - config::CrateTypeProcMacro | config::CrateTypeDylib => return true, - _ => {} - } - } - if !sess.target.target.options.executables { - if crate_type == config::CrateTypeExecutable { - return true - } - } - - false -} diff --git a/src/librustc_trans_utils/symbol_names.rs b/src/librustc_trans_utils/symbol_names.rs deleted file mode 100644 index be5bff60805..00000000000 --- a/src/librustc_trans_utils/symbol_names.rs +++ /dev/null @@ -1,435 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The Rust Linkage Model and Symbol Names -//! ======================================= -//! -//! The semantic model of Rust linkage is, broadly, that "there's no global -//! namespace" between crates. Our aim is to preserve the illusion of this -//! model despite the fact that it's not *quite* possible to implement on -//! modern linkers. We initially didn't use system linkers at all, but have -//! been convinced of their utility. -//! -//! There are a few issues to handle: -//! -//! - Linkers operate on a flat namespace, so we have to flatten names. -//! We do this using the C++ namespace-mangling technique. Foo::bar -//! symbols and such. -//! -//! - Symbols for distinct items with the same *name* need to get different -//! linkage-names. Examples of this are monomorphizations of functions or -//! items within anonymous scopes that end up having the same path. -//! -//! - Symbols in different crates but with same names "within" the crate need -//! to get different linkage-names. -//! -//! - Symbol names should be deterministic: Two consecutive runs of the -//! compiler over the same code base should produce the same symbol names for -//! the same items. -//! -//! - Symbol names should not depend on any global properties of the code base, -//! so that small modifications to the code base do not result in all symbols -//! changing. In previous versions of the compiler, symbol names incorporated -//! the SVH (Stable Version Hash) of the crate. This scheme turned out to be -//! infeasible when used in conjunction with incremental compilation because -//! small code changes would invalidate all symbols generated previously. -//! -//! - Even symbols from different versions of the same crate should be able to -//! live next to each other without conflict. -//! -//! In order to fulfill the above requirements the following scheme is used by -//! the compiler: -//! -//! The main tool for avoiding naming conflicts is the incorporation of a 64-bit -//! hash value into every exported symbol name. Anything that makes a difference -//! to the symbol being named, but does not show up in the regular path needs to -//! be fed into this hash: -//! -//! - Different monomorphizations of the same item have the same path but differ -//! in their concrete type parameters, so these parameters are part of the -//! data being digested for the symbol hash. -//! -//! - Rust allows items to be defined in anonymous scopes, such as in -//! `fn foo() { { fn bar() {} } { fn bar() {} } }`. Both `bar` functions have -//! the path `foo::bar`, since the anonymous scopes do not contribute to the -//! path of an item. The compiler already handles this case via so-called -//! disambiguating `DefPaths` which use indices to distinguish items with the -//! same name. The DefPaths of the functions above are thus `foo[0]::bar[0]` -//! and `foo[0]::bar[1]`. In order to incorporate this disambiguation -//! information into the symbol name too, these indices are fed into the -//! symbol hash, so that the above two symbols would end up with different -//! hash values. -//! -//! The two measures described above suffice to avoid intra-crate conflicts. In -//! order to also avoid inter-crate conflicts two more measures are taken: -//! -//! - The name of the crate containing the symbol is prepended to the symbol -//! name, i.e. symbols are "crate qualified". For example, a function `foo` in -//! module `bar` in crate `baz` would get a symbol name like -//! `baz::bar::foo::{hash}` instead of just `bar::foo::{hash}`. This avoids -//! simple conflicts between functions from different crates. -//! -//! - In order to be able to also use symbols from two versions of the same -//! crate (which naturally also have the same name), a stronger measure is -//! required: The compiler accepts an arbitrary "disambiguator" value via the -//! `-C metadata` commandline argument. This disambiguator is then fed into -//! the symbol hash of every exported item. Consequently, the symbols in two -//! identical crates but with different disambiguators are not in conflict -//! with each other. This facility is mainly intended to be used by build -//! tools like Cargo. -//! -//! A note on symbol name stability -//! ------------------------------- -//! Previous versions of the compiler resorted to feeding NodeIds into the -//! symbol hash in order to disambiguate between items with the same path. The -//! current version of the name generation algorithm takes great care not to do -//! that, since NodeIds are notoriously unstable: A small change to the -//! code base will offset all NodeIds after the change and thus, much as using -//! the SVH in the hash, invalidate an unbounded number of symbol names. This -//! makes re-using previously compiled code for incremental compilation -//! virtually impossible. Thus, symbol hash generation exclusively relies on -//! DefPaths which are much more robust in the face of changes to the code base. - -use rustc::middle::weak_lang_items; -use rustc_mir::monomorphize::Instance; -use rustc_mir::monomorphize::item::{MonoItem, MonoItemExt, InstantiationMode}; -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; -use rustc::hir::map as hir_map; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::ty::fold::TypeVisitor; -use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; -use rustc::ty::maps::Providers; -use rustc::ty::subst::Substs; -use rustc::hir::map::definitions::DefPathData; -use rustc::util::common::record_time; - -use syntax::attr; -use syntax_pos::symbol::Symbol; - -use std::fmt::Write; - -pub fn provide(providers: &mut Providers) { - *providers = Providers { - def_symbol_name, - symbol_name, - - ..*providers - }; -} - -fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - - // the DefId of the item this name is for - def_id: DefId, - - // instance this name will be for - instance: Instance<'tcx>, - - // type of the item, without any generic - // parameters substituted; this is - // included in the hash as a kind of - // safeguard. - item_type: Ty<'tcx>, - - // values for generic type parameters, - // if any. - substs: &'tcx Substs<'tcx>) - -> u64 { - debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs); - - let mut hasher = ty::util::TypeIdHasher::::new(tcx); - - record_time(&tcx.sess.perf_stats.symbol_hash_time, || { - // the main symbol name is not necessarily unique; hash in the - // compiler's internal def-path, guaranteeing each symbol has a - // truly unique path - hasher.hash(tcx.def_path_hash(def_id)); - - // Include the main item-type. Note that, in this case, the - // assertions about `needs_subst` may not hold, but this item-type - // ought to be the same for every reference anyway. - assert!(!item_type.has_erasable_regions()); - hasher.visit_ty(item_type); - - // If this is a function, we hash the signature as well. - // This is not *strictly* needed, but it may help in some - // situations, see the `run-make/a-b-a-linker-guard` test. - if let ty::TyFnDef(..) = item_type.sty { - item_type.fn_sig(tcx).visit_with(&mut hasher); - } - - // also include any type parameters (for generic items) - assert!(!substs.has_erasable_regions()); - assert!(!substs.needs_subst()); - substs.visit_with(&mut hasher); - - let is_generic = substs.types().next().is_some(); - let avoid_cross_crate_conflicts = - // If this is an instance of a generic function, we also hash in - // the ID of the instantiating crate. This avoids symbol conflicts - // in case the same instances is emitted in two crates of the same - // project. - is_generic || - - // If we're dealing with an instance of a function that's inlined from - // another crate but we're marking it as globally shared to our - // compliation (aka we're not making an internal copy in each of our - // codegen units) then this symbol may become an exported (but hidden - // visibility) symbol. This means that multiple crates may do the same - // and we want to be sure to avoid any symbol conflicts here. - match MonoItem::Fn(instance).instantiation_mode(tcx) { - InstantiationMode::GloballyShared { may_conflict: true } => true, - _ => false, - }; - - if avoid_cross_crate_conflicts { - let instantiating_crate = if is_generic { - if !def_id.is_local() && tcx.share_generics() { - // If we are re-using a monomorphization from another crate, - // we have to compute the symbol hash accordingly. - let upstream_monomorphizations = - tcx.upstream_monomorphizations_for(def_id); - - upstream_monomorphizations.and_then(|monos| monos.get(&substs) - .cloned()) - .unwrap_or(LOCAL_CRATE) - } else { - LOCAL_CRATE - } - } else { - LOCAL_CRATE - }; - - hasher.hash(&tcx.original_crate_name(instantiating_crate).as_str()[..]); - hasher.hash(&tcx.crate_disambiguator(instantiating_crate)); - } - }); - - // 64 bits should be enough to avoid collisions. - hasher.finish() -} - -fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> ty::SymbolName -{ - let mut buffer = SymbolPathBuffer::new(); - item_path::with_forced_absolute_paths(|| { - tcx.push_item_path(&mut buffer, def_id); - }); - buffer.into_interned() -} - -fn symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) - -> ty::SymbolName -{ - ty::SymbolName { name: Symbol::intern(&compute_symbol_name(tcx, instance)).as_interned_str() } -} - -fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) - -> String -{ - let def_id = instance.def_id(); - let substs = instance.substs; - - debug!("symbol_name(def_id={:?}, substs={:?})", - def_id, substs); - - let node_id = tcx.hir.as_local_node_id(def_id); - - if let Some(id) = node_id { - if *tcx.sess.plugin_registrar_fn.get() == Some(id) { - let disambiguator = tcx.sess.local_crate_disambiguator(); - return tcx.sess.generate_plugin_registrar_symbol(disambiguator); - } - if *tcx.sess.derive_registrar_fn.get() == Some(id) { - let disambiguator = tcx.sess.local_crate_disambiguator(); - return tcx.sess.generate_derive_registrar_symbol(disambiguator); - } - } - - // FIXME(eddyb) Precompute a custom symbol name based on attributes. - let attrs = tcx.get_attrs(def_id); - let is_foreign = if let Some(id) = node_id { - match tcx.hir.get(id) { - hir_map::NodeForeignItem(_) => true, - _ => false - } - } else { - tcx.is_foreign_item(def_id) - }; - - if let Some(name) = weak_lang_items::link_name(&attrs) { - return name.to_string(); - } - - if is_foreign { - if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "link_name") { - return name.to_string(); - } - // Don't mangle foreign items. - return tcx.item_name(def_id).to_string(); - } - - if let Some(name) = tcx.trans_fn_attrs(def_id).export_name { - // Use provided name - return name.to_string(); - } - - if attr::contains_name(&attrs, "no_mangle") { - // Don't mangle - return tcx.item_name(def_id).to_string(); - } - - // We want to compute the "type" of this item. Unfortunately, some - // kinds of items (e.g., closures) don't have an entry in the - // item-type array. So walk back up the find the closest parent - // that DOES have an entry. - let mut ty_def_id = def_id; - let instance_ty; - loop { - let key = tcx.def_key(ty_def_id); - match key.disambiguated_data.data { - DefPathData::TypeNs(_) | - DefPathData::ValueNs(_) => { - instance_ty = tcx.type_of(ty_def_id); - break; - } - _ => { - // if we're making a symbol for something, there ought - // to be a value or type-def or something in there - // *somewhere* - ty_def_id.index = key.parent.unwrap_or_else(|| { - bug!("finding type for {:?}, encountered def-id {:?} with no \ - parent", def_id, ty_def_id); - }); - } - } - } - - // Erase regions because they may not be deterministic when hashed - // and should not matter anyhow. - let instance_ty = tcx.erase_regions(&instance_ty); - - let hash = get_symbol_hash(tcx, def_id, instance, instance_ty, substs); - - SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)).finish(hash) -} - -// Follow C++ namespace-mangling style, see -// http://en.wikipedia.org/wiki/Name_mangling for more info. -// -// It turns out that on macOS you can actually have arbitrary symbols in -// function names (at least when given to LLVM), but this is not possible -// when using unix's linker. Perhaps one day when we just use a linker from LLVM -// we won't need to do this name mangling. The problem with name mangling is -// that it seriously limits the available characters. For example we can't -// have things like &T in symbol names when one would theoretically -// want them for things like impls of traits on that type. -// -// To be able to work on all platforms and get *some* reasonable output, we -// use C++ name-mangling. -struct SymbolPathBuffer { - result: String, - temp_buf: String -} - -impl SymbolPathBuffer { - fn new() -> Self { - let mut result = SymbolPathBuffer { - result: String::with_capacity(64), - temp_buf: String::with_capacity(16) - }; - result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested - result - } - - fn from_interned(symbol: ty::SymbolName) -> Self { - let mut result = SymbolPathBuffer { - result: String::with_capacity(64), - temp_buf: String::with_capacity(16) - }; - result.result.push_str(&symbol.name.as_str()); - result - } - - fn into_interned(self) -> ty::SymbolName { - ty::SymbolName { name: Symbol::intern(&self.result).as_interned_str() } - } - - fn finish(mut self, hash: u64) -> String { - // E = end name-sequence - let _ = write!(self.result, "17h{:016x}E", hash); - self.result - } -} - -impl ItemPathBuffer for SymbolPathBuffer { - fn root_mode(&self) -> &RootMode { - const ABSOLUTE: &'static RootMode = &RootMode::Absolute; - ABSOLUTE - } - - fn push(&mut self, text: &str) { - self.temp_buf.clear(); - let need_underscore = sanitize(&mut self.temp_buf, text); - let _ = write!(self.result, "{}", self.temp_buf.len() + (need_underscore as usize)); - if need_underscore { - self.result.push('_'); - } - self.result.push_str(&self.temp_buf); - } -} - -// Name sanitation. LLVM will happily accept identifiers with weird names, but -// gas doesn't! -// gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $ -// -// returns true if an underscore must be added at the start -pub fn sanitize(result: &mut String, s: &str) -> bool { - for c in s.chars() { - match c { - // Escape these with $ sequences - '@' => result.push_str("$SP$"), - '*' => result.push_str("$BP$"), - '&' => result.push_str("$RF$"), - '<' => result.push_str("$LT$"), - '>' => result.push_str("$GT$"), - '(' => result.push_str("$LP$"), - ')' => result.push_str("$RP$"), - ',' => result.push_str("$C$"), - - // '.' doesn't occur in types and functions, so reuse it - // for ':' and '-' - '-' | ':' => result.push('.'), - - // These are legal symbols - 'a' ... 'z' - | 'A' ... 'Z' - | '0' ... '9' - | '_' | '.' | '$' => result.push(c), - - _ => { - result.push('$'); - for c in c.escape_unicode().skip(1) { - match c { - '{' => {}, - '}' => result.push('$'), - c => result.push(c), - } - } - } - } - } - - // Underscore-qualify anything that didn't start as an ident. - !result.is_empty() && - result.as_bytes()[0] != '_' as u8 && - ! (result.as_bytes()[0] as char).is_xid_start() -} diff --git a/src/librustc_trans_utils/symbol_names_test.rs b/src/librustc_trans_utils/symbol_names_test.rs deleted file mode 100644 index 47bbd67fb5c..00000000000 --- a/src/librustc_trans_utils/symbol_names_test.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Walks the crate looking for items/impl-items/trait-items that have -//! either a `rustc_symbol_name` or `rustc_item_path` attribute and -//! generates an error giving, respectively, the symbol name or -//! item-path. This is used for unit testing the code that generates -//! paths etc in all kinds of annoying scenarios. - -use rustc::hir; -use rustc::ty::TyCtxt; -use syntax::ast; - -use rustc_mir::monomorphize::Instance; - -const SYMBOL_NAME: &'static str = "rustc_symbol_name"; -const ITEM_PATH: &'static str = "rustc_item_path"; - -pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - // if the `rustc_attrs` feature is not enabled, then the - // attributes we are interested in cannot be present anyway, so - // skip the walk. - if !tcx.features().rustc_attrs { - return; - } - - tcx.dep_graph.with_ignore(|| { - let mut visitor = SymbolNamesTest { tcx: tcx }; - tcx.hir.krate().visit_all_item_likes(&mut visitor); - }) -} - -struct SymbolNamesTest<'a, 'tcx:'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, -} - -impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { - fn process_attrs(&mut self, - node_id: ast::NodeId) { - let tcx = self.tcx; - let def_id = tcx.hir.local_def_id(node_id); - for attr in tcx.get_attrs(def_id).iter() { - if attr.check_name(SYMBOL_NAME) { - // for now, can only use on monomorphic names - let instance = Instance::mono(tcx, def_id); - let name = self.tcx.symbol_name(instance); - tcx.sess.span_err(attr.span, &format!("symbol-name({})", name)); - } else if attr.check_name(ITEM_PATH) { - let path = tcx.item_path_str(def_id); - tcx.sess.span_err(attr.span, &format!("item-path({})", path)); - } - - // (*) The formatting of `tag({})` is chosen so that tests can elect - // to test the entirety of the string, if they choose, or else just - // some subset. - } - } -} - -impl<'a, 'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for SymbolNamesTest<'a, 'tcx> { - fn visit_item(&mut self, item: &'tcx hir::Item) { - self.process_attrs(item.id); - } - - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { - self.process_attrs(trait_item.id); - } - - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { - self.process_attrs(impl_item.id); - } -} diff --git a/src/librustc_trans_utils/trans_crate.rs b/src/librustc_trans_utils/trans_crate.rs deleted file mode 100644 index 7b585d1060f..00000000000 --- a/src/librustc_trans_utils/trans_crate.rs +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The Rust compiler. -//! -//! # Note -//! -//! This API is completely unstable and subject to change. - -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] - -#![feature(box_syntax)] - -use std::any::Any; -use std::io::prelude::*; -use std::io::{self, Cursor}; -use std::fs::File; -use std::path::Path; -use std::sync::mpsc; - -use rustc_data_structures::owning_ref::OwningRef; -use rustc_data_structures::sync::Lrc; -use ar::{Archive, Builder, Header}; -use flate2::Compression; -use flate2::write::DeflateEncoder; - -use syntax::symbol::Symbol; -use rustc::hir::def_id::LOCAL_CRATE; -use rustc::session::{Session, CompileIncomplete}; -use rustc::session::config::{CrateType, OutputFilenames, PrintRequest}; -use rustc::ty::TyCtxt; -use rustc::ty::maps::Providers; -use rustc::middle::cstore::EncodedMetadata; -use rustc::middle::cstore::MetadataLoader; -use rustc::dep_graph::DepGraph; -use rustc_target::spec::Target; -use rustc_data_structures::fx::FxHashMap; -use rustc_mir::monomorphize::collector; -use link::{build_link_meta, out_filename}; - -pub use rustc_data_structures::sync::MetadataRef; - -pub trait TransCrate { - fn init(&self, _sess: &Session) {} - fn print(&self, _req: PrintRequest, _sess: &Session) {} - fn target_features(&self, _sess: &Session) -> Vec { vec![] } - fn print_passes(&self) {} - fn print_version(&self) {} - fn diagnostics(&self) -> &[(&'static str, &'static str)] { &[] } - - fn metadata_loader(&self) -> Box; - fn provide(&self, _providers: &mut Providers); - fn provide_extern(&self, _providers: &mut Providers); - fn trans_crate<'a, 'tcx>( - &self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - rx: mpsc::Receiver> - ) -> Box; - - /// This is called on the returned `Box` from `trans_crate` - /// - /// # Panics - /// - /// Panics when the passed `Box` was not returned by `trans_crate`. - fn join_trans_and_link( - &self, - trans: Box, - sess: &Session, - dep_graph: &DepGraph, - outputs: &OutputFilenames, - ) -> Result<(), CompileIncomplete>; -} - -pub struct DummyTransCrate; - -impl TransCrate for DummyTransCrate { - fn metadata_loader(&self) -> Box { - box DummyMetadataLoader(()) - } - - fn provide(&self, _providers: &mut Providers) { - bug!("DummyTransCrate::provide"); - } - - fn provide_extern(&self, _providers: &mut Providers) { - bug!("DummyTransCrate::provide_extern"); - } - - fn trans_crate<'a, 'tcx>( - &self, - _tcx: TyCtxt<'a, 'tcx, 'tcx>, - _rx: mpsc::Receiver> - ) -> Box { - bug!("DummyTransCrate::trans_crate"); - } - - fn join_trans_and_link( - &self, - _trans: Box, - _sess: &Session, - _dep_graph: &DepGraph, - _outputs: &OutputFilenames, - ) -> Result<(), CompileIncomplete> { - bug!("DummyTransCrate::join_trans_and_link"); - } -} - -pub struct DummyMetadataLoader(()); - -impl MetadataLoader for DummyMetadataLoader { - fn get_rlib_metadata( - &self, - _target: &Target, - _filename: &Path - ) -> Result { - bug!("DummyMetadataLoader::get_rlib_metadata"); - } - - fn get_dylib_metadata( - &self, - _target: &Target, - _filename: &Path - ) -> Result { - bug!("DummyMetadataLoader::get_dylib_metadata"); - } -} - -pub struct NoLlvmMetadataLoader; - -impl MetadataLoader for NoLlvmMetadataLoader { - fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result { - let file = File::open(filename) - .map_err(|e| format!("metadata file open err: {:?}", e))?; - let mut archive = Archive::new(file); - - while let Some(entry_result) = archive.next_entry() { - let mut entry = entry_result - .map_err(|e| format!("metadata section read err: {:?}", e))?; - if entry.header().identifier() == "rust.metadata.bin" { - let mut buf = Vec::new(); - io::copy(&mut entry, &mut buf).unwrap(); - let buf: OwningRef, [u8]> = OwningRef::new(buf).into(); - return Ok(rustc_erase_owner!(buf.map_owner_box())); - } - } - - Err("Couldn't find metadata section".to_string()) - } - - fn get_dylib_metadata( - &self, - _target: &Target, - _filename: &Path, - ) -> Result { - // FIXME: Support reading dylibs from llvm enabled rustc - self.get_rlib_metadata(_target, _filename) - } -} - -pub struct MetadataOnlyTransCrate(()); -pub struct OngoingCrateTranslation { - metadata: EncodedMetadata, - metadata_version: Vec, - crate_name: Symbol, -} - -impl MetadataOnlyTransCrate { - pub fn new() -> Box { - box MetadataOnlyTransCrate(()) - } -} - -impl TransCrate for MetadataOnlyTransCrate { - fn init(&self, sess: &Session) { - for cty in sess.opts.crate_types.iter() { - match *cty { - CrateType::CrateTypeRlib | CrateType::CrateTypeDylib | - CrateType::CrateTypeExecutable => {}, - _ => { - sess.parse_sess.span_diagnostic.warn( - &format!("LLVM unsupported, so output type {} is not supported", cty) - ); - }, - } - } - } - - fn metadata_loader(&self) -> Box { - box NoLlvmMetadataLoader - } - - fn provide(&self, providers: &mut Providers) { - ::symbol_names::provide(providers); - - providers.target_features_whitelist = |_tcx, _cnum| { - Lrc::new(FxHashMap()) // Just a dummy - }; - } - fn provide_extern(&self, _providers: &mut Providers) {} - - fn trans_crate<'a, 'tcx>( - &self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - _rx: mpsc::Receiver> - ) -> Box { - use rustc_mir::monomorphize::item::MonoItem; - - ::check_for_rustc_errors_attr(tcx); - ::symbol_names_test::report_symbol_names(tcx); - ::rustc_incremental::assert_dep_graph(tcx); - ::rustc_incremental::assert_module_sources::assert_module_sources(tcx); - ::rustc_mir::monomorphize::assert_symbols_are_distinct(tcx, - collector::collect_crate_mono_items( - tcx, - collector::MonoItemCollectionMode::Eager - ).0.iter() - ); - ::rustc::middle::dependency_format::calculate(tcx); - let _ = tcx.link_args(LOCAL_CRATE); - let _ = tcx.native_libraries(LOCAL_CRATE); - for trans_item in - collector::collect_crate_mono_items( - tcx, - collector::MonoItemCollectionMode::Eager - ).0 { - match trans_item { - MonoItem::Fn(inst) => { - let def_id = inst.def_id(); - if def_id.is_local() { - let _ = inst.def.is_inline(tcx); - let _ = tcx.trans_fn_attrs(def_id); - } - } - _ => {} - } - } - tcx.sess.abort_if_errors(); - - let link_meta = build_link_meta(tcx.crate_hash(LOCAL_CRATE)); - let metadata = tcx.encode_metadata(&link_meta); - - box OngoingCrateTranslation { - metadata: metadata, - metadata_version: tcx.metadata_encoding_version().to_vec(), - crate_name: tcx.crate_name(LOCAL_CRATE), - } - } - - fn join_trans_and_link( - &self, - trans: Box, - sess: &Session, - _dep_graph: &DepGraph, - outputs: &OutputFilenames, - ) -> Result<(), CompileIncomplete> { - let trans = trans.downcast::() - .expect("Expected MetadataOnlyTransCrate's OngoingCrateTranslation, found Box"); - for &crate_type in sess.opts.crate_types.iter() { - if crate_type != CrateType::CrateTypeRlib && crate_type != CrateType::CrateTypeDylib { - continue; - } - let output_name = - out_filename(sess, crate_type, &outputs, &trans.crate_name.as_str()); - let mut compressed = trans.metadata_version.clone(); - let metadata = if crate_type == CrateType::CrateTypeDylib { - DeflateEncoder::new(&mut compressed, Compression::fast()) - .write_all(&trans.metadata.raw_data) - .unwrap(); - &compressed - } else { - &trans.metadata.raw_data - }; - let mut builder = Builder::new(File::create(&output_name).unwrap()); - let header = Header::new("rust.metadata.bin".to_string(), metadata.len() as u64); - builder.append(&header, Cursor::new(metadata)).unwrap(); - } - - sess.abort_if_errors(); - if !sess.opts.crate_types.contains(&CrateType::CrateTypeRlib) - && !sess.opts.crate_types.contains(&CrateType::CrateTypeDylib) - { - sess.fatal("Executables are not supported by the metadata-only backend."); - } - Ok(()) - } -} diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 97e4a35ea47..feb26e76162 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -72,7 +72,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(def_id)), fty); } -/// Remember to add all intrinsics here, in librustc_trans/trans/intrinsic.rs, +/// Remember to add all intrinsics here, in librustc_codegen_llvm/intrinsic.rs, /// and in libcore/intrinsics.rs pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::ForeignItem) { diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 23081b87d26..2dd22058d76 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -665,7 +665,7 @@ enum Op { /// `PartialEq` is not applicable. /// /// Reason #2 is the killer. I tried for a while to always use -/// overloaded logic and just check the types in constants/trans after +/// overloaded logic and just check the types in constants/codegen after /// the fact, and it worked fine, except for SIMD types. -nmatsakis fn is_builtin_binop(lhs: Ty, rhs: Ty, op: hir::BinOp) -> bool { match BinOpCategory::from(op) { diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 2f08a54e10f..735ebbfcb3d 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -9,7 +9,7 @@ // except according to those terms. //! Check properties that are required by built-in traits and set -//! up data structures required by type-checking/translation. +//! up data structures required by type-checking/codegen. use rustc::infer::outlives::env::OutlivesEnvironment; use rustc::middle::region; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index c2dde2d2e01..157f3ab76ca 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -48,7 +48,7 @@ use syntax::symbol::{Symbol, keywords}; use syntax::feature_gate; use syntax_pos::{Span, DUMMY_SP}; -use rustc::hir::{self, map as hir_map, TransFnAttrs, TransFnAttrFlags, Unsafety}; +use rustc::hir::{self, map as hir_map, CodegenFnAttrs, CodegenFnAttrFlags, Unsafety}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; @@ -75,7 +75,7 @@ pub fn provide(providers: &mut Providers) { impl_trait_ref, impl_polarity, is_foreign_item, - trans_fn_attrs, + codegen_fn_attrs, ..*providers }; } @@ -1800,33 +1800,33 @@ fn linkage_by_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, name: & } } -fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAttrs { +fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> CodegenFnAttrs { let attrs = tcx.get_attrs(id); - let mut trans_fn_attrs = TransFnAttrs::new(); + let mut codegen_fn_attrs = CodegenFnAttrs::new(); let whitelist = tcx.target_features_whitelist(LOCAL_CRATE); let mut inline_span = None; for attr in attrs.iter() { if attr.check_name("cold") { - trans_fn_attrs.flags |= TransFnAttrFlags::COLD; + codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD; } else if attr.check_name("allocator") { - trans_fn_attrs.flags |= TransFnAttrFlags::ALLOCATOR; + codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR; } else if attr.check_name("unwind") { - trans_fn_attrs.flags |= TransFnAttrFlags::UNWIND; + codegen_fn_attrs.flags |= CodegenFnAttrFlags::UNWIND; } else if attr.check_name("rustc_allocator_nounwind") { - trans_fn_attrs.flags |= TransFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND; + codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND; } else if attr.check_name("naked") { - trans_fn_attrs.flags |= TransFnAttrFlags::NAKED; + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED; } else if attr.check_name("no_mangle") { - trans_fn_attrs.flags |= TransFnAttrFlags::NO_MANGLE; + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; } else if attr.check_name("rustc_std_internal_symbol") { - trans_fn_attrs.flags |= TransFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; + codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; } else if attr.check_name("no_debug") { - trans_fn_attrs.flags |= TransFnAttrFlags::NO_DEBUG; + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_DEBUG; } else if attr.check_name("inline") { - trans_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { + codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { if attr.path != "inline" { return ia; } @@ -1862,7 +1862,7 @@ fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAt }); } else if attr.check_name("export_name") { if let s @ Some(_) = attr.value_str() { - trans_fn_attrs.export_name = s; + codegen_fn_attrs.export_name = s; } else { struct_span_err!(tcx.sess, attr.span, E0558, "export_name attribute has invalid format") @@ -1875,10 +1875,10 @@ fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAt `unsafe` function"; tcx.sess.span_err(attr.span, msg); } - from_target_feature(tcx, id, attr, &whitelist, &mut trans_fn_attrs.target_features); + from_target_feature(tcx, id, attr, &whitelist, &mut codegen_fn_attrs.target_features); } else if attr.check_name("linkage") { if let Some(val) = attr.value_str() { - trans_fn_attrs.linkage = Some(linkage_by_name(tcx, id, &val.as_str())); + codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, id, &val.as_str())); } } } @@ -1887,8 +1887,8 @@ fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAt // purpose functions as they wouldn't have the right target features // enabled. For that reason we also forbid #[inline(always)] as it can't be // respected. - if trans_fn_attrs.target_features.len() > 0 { - if trans_fn_attrs.inline == InlineAttr::Always { + if codegen_fn_attrs.target_features.len() > 0 { + if codegen_fn_attrs.inline == InlineAttr::Always { if let Some(span) = inline_span { tcx.sess.span_err(span, "cannot use #[inline(always)] with \ #[target_feature]"); @@ -1896,5 +1896,5 @@ fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAt } } - trans_fn_attrs + codegen_fn_attrs } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index e3f7ff5cb3f..99744d5b4b6 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1179,7 +1179,7 @@ extern "rust-intrinsic" { ``` Please check you didn't make a mistake in the function's name. All intrinsic -functions are defined in librustc_trans/trans/intrinsic.rs and in +functions are defined in librustc_codegen_llvm/intrinsic.rs and in libcore/intrinsics.rs in the Rust source code. Example: ``` @@ -1209,7 +1209,7 @@ fn main() { ``` Please check you didn't make a mistake in the function's name. All intrinsic -functions are defined in librustc_trans/trans/intrinsic.rs and in +functions are defined in librustc_codegen_llvm/intrinsic.rs and in libcore/intrinsics.rs in the Rust source code. Example: ``` diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index c9a80d47791..90889890e0b 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -219,19 +219,19 @@ pub fn run_core(search_paths: SearchPaths, let mut sess = session::build_session_( sessopts, cpath, diagnostic_handler, codemap, ); - let trans = rustc_driver::get_trans(&sess); - let cstore = Rc::new(CStore::new(trans.metadata_loader())); + let codegen_backend = rustc_driver::get_codegen_backend(&sess); + let cstore = Rc::new(CStore::new(codegen_backend.metadata_loader())); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs)); - target_features::add_configuration(&mut cfg, &sess, &*trans); + target_features::add_configuration(&mut cfg, &sess, &*codegen_backend); sess.parse_sess.config = cfg; let control = &driver::CompileController::basic(); let krate = panictry!(driver::phase_1_parse_input(control, &sess, &input)); - let name = ::rustc_trans_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input); + let name = ::rustc_codegen_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input); let mut crate_loader = CrateLoader::new(&sess, &cstore, &name); @@ -279,7 +279,7 @@ pub fn run_core(search_paths: SearchPaths, let resolver = RefCell::new(resolver); - abort_on_err(driver::phase_3_run_analysis_passes(&*trans, + abort_on_err(driver::phase_3_run_analysis_passes(&*codegen_backend, control, &sess, &*cstore, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index a14a27d5d61..3ce95c78a90 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -33,7 +33,7 @@ extern crate getopts; extern crate env_logger; extern crate rustc; extern crate rustc_data_structures; -extern crate rustc_trans_utils; +extern crate rustc_codegen_utils; extern crate rustc_driver; extern crate rustc_resolve; extern crate rustc_lint; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 7be7ce313fc..f507d0dc09d 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -95,12 +95,12 @@ pub fn run(input_path: &Path, let mut sess = session::build_session_( sessopts, Some(input_path.to_owned()), handler, codemap.clone(), ); - let trans = rustc_driver::get_trans(&sess); - let cstore = CStore::new(trans.metadata_loader()); + let codegen_backend = rustc_driver::get_codegen_backend(&sess); + let cstore = CStore::new(codegen_backend.metadata_loader()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); - target_features::add_configuration(&mut cfg, &sess, &*trans); + target_features::add_configuration(&mut cfg, &sess, &*codegen_backend); sess.parse_sess.config = cfg; let krate = panictry!(driver::phase_1_parse_input(&driver::CompileController::basic(), @@ -120,7 +120,7 @@ pub fn run(input_path: &Path, }; let crate_name = crate_name.unwrap_or_else(|| { - ::rustc_trans_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input) + ::rustc_codegen_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input) }); let mut opts = scrape_test_config(hir_forest.krate()); opts.display_warnings |= display_warnings; @@ -273,8 +273,8 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, let mut sess = session::build_session_( sessopts, None, diagnostic_handler, codemap, ); - let trans = rustc_driver::get_trans(&sess); - let cstore = CStore::new(trans.metadata_loader()); + let codegen_backend = rustc_driver::get_codegen_backend(&sess); + let cstore = CStore::new(codegen_backend.metadata_loader()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let outdir = Mutex::new(TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir")); @@ -282,7 +282,7 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, let mut control = driver::CompileController::basic(); let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); - target_features::add_configuration(&mut cfg, &sess, &*trans); + target_features::add_configuration(&mut cfg, &sess, &*codegen_backend); sess.parse_sess.config = cfg; let out = Some(outdir.lock().unwrap().path().to_path_buf()); @@ -293,7 +293,7 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, let res = panic::catch_unwind(AssertUnwindSafe(|| { driver::compile_input( - trans, + codegen_backend, &sess, &cstore, &None, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index f1229520c77..d247b5402ef 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -839,7 +839,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_partition_translated", Whitelisted, Gated(Stability::Unstable, + ("rustc_partition_codegened", Whitelisted, Gated(Stability::Unstable, "rustc_attrs", "this attribute \ is just used for rustc unit tests \ @@ -938,7 +938,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG // FIXME: #14408 whitelist docs since rustdoc looks at them ("doc", Whitelisted, Ungated), - // FIXME: #14406 these are processed in trans, which happens after the + // FIXME: #14406 these are processed in codegen, which happens after the // lint pass ("cold", Whitelisted, Ungated), ("naked", Whitelisted, Gated(Stability::Unstable, diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 6b155b6596d..f29cc75664d 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -79,7 +79,7 @@ struct Context<'a, 'b: 'a> { /// final generated static argument array. We record the starting indices /// corresponding to each positional argument, and number of references /// consumed so far for each argument, to facilitate correct `Position` - /// mapping in `trans_piece`. In effect this can be seen as a "flattened" + /// mapping in `build_piece`. In effect this can be seen as a "flattened" /// version of `arg_unique_types`. /// /// Again with the example described above in docstring for `args`: @@ -108,7 +108,7 @@ struct Context<'a, 'b: 'a> { /// Current position of the implicit positional arg pointer, as if it /// still existed in this phase of processing. - /// Used only for `all_pieces_simple` tracking in `trans_piece`. + /// Used only for `all_pieces_simple` tracking in `build_piece`. curarg: usize, /// Keep track of invalid references to positional arguments invalid_refs: Vec, @@ -373,7 +373,7 @@ impl<'a, 'b> Context<'a, 'b> { ecx.std_path(&["fmt", "rt", "v1", s]) } - fn trans_count(&self, c: parse::Count) -> P { + fn build_count(&self, c: parse::Count) -> P { let sp = self.macsp; let count = |c, arg| { let mut path = Context::rtpath(self.ecx, "Count"); @@ -401,17 +401,17 @@ impl<'a, 'b> Context<'a, 'b> { } } - /// Translate the accumulated string literals to a literal expression - fn trans_literal_string(&mut self) -> P { + /// Build a literal expression from the accumulated string literals + fn build_literal_string(&mut self) -> P { let sp = self.fmtsp; let s = Symbol::intern(&self.literal); self.literal.clear(); self.ecx.expr_str(sp, s) } - /// Translate a `parse::Piece` to a static `rt::Argument` or append + /// Build a static `rt::Argument` from a `parse::Piece` or append /// to the `literal` string. - fn trans_piece(&mut self, + fn build_piece(&mut self, piece: &parse::Piece, arg_index_consumed: &mut Vec) -> Option> { @@ -422,7 +422,7 @@ impl<'a, 'b> Context<'a, 'b> { None } parse::NextArgument(ref arg) => { - // Translate the position + // Build the position let pos = { let pos = |c, arg| { let mut path = Context::rtpath(self.ecx, "Position"); @@ -486,7 +486,7 @@ impl<'a, 'b> Context<'a, 'b> { self.all_pieces_simple = false; } - // Translate the format + // Build the format let fill = self.ecx.expr_lit(sp, ast::LitKind::Char(fill)); let align = |name| { let mut p = Context::rtpath(self.ecx, "Alignment"); @@ -501,8 +501,8 @@ impl<'a, 'b> Context<'a, 'b> { }; let align = self.ecx.expr_path(align); let flags = self.ecx.expr_u32(sp, arg.format.flags); - let prec = self.trans_count(arg.format.precision); - let width = self.trans_count(arg.format.width); + let prec = self.build_count(arg.format.precision); + let width = self.build_count(arg.format.width); let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "FormatSpec")); let fmt = self.ecx.expr_struct(sp, @@ -759,8 +759,8 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, let mut arg_index_consumed = vec![0usize; cx.arg_index_map.len()]; for piece in pieces { - if let Some(piece) = cx.trans_piece(&piece, &mut arg_index_consumed) { - let s = cx.trans_literal_string(); + if let Some(piece) = cx.build_piece(&piece, &mut arg_index_consumed) { + let s = cx.build_literal_string(); cx.str_pieces.push(s); cx.pieces.push(piece); } @@ -776,7 +776,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, return DummyResult::raw_expr(sp); } if !cx.literal.is_empty() { - let s = cx.trans_literal_string(); + let s = cx.build_literal_string(); cx.str_pieces.push(s); } diff --git a/src/libsyntax_ext/format_foreign.rs b/src/libsyntax_ext/format_foreign.rs index 2b8603c75a5..0dd8f0c55d8 100644 --- a/src/libsyntax_ext/format_foreign.rs +++ b/src/libsyntax_ext/format_foreign.rs @@ -697,7 +697,7 @@ pub mod printf { /// Check that the translations are what we expect. #[test] - fn test_trans() { + fn test_translation() { assert_eq_pnsat!("%c", Some("{}")); assert_eq_pnsat!("%d", Some("{}")); assert_eq_pnsat!("%u", Some("{}")); @@ -900,7 +900,7 @@ pub mod shell { } #[test] - fn test_trans() { + fn test_translation() { assert_eq_pnsat!("$0", Some("{0}")); assert_eq_pnsat!("$9", Some("{9}")); assert_eq_pnsat!("$1", Some("{1}")); diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs index f01a0aacb0a..642aa0e5b12 100644 --- a/src/libsyntax_ext/global_asm.rs +++ b/src/libsyntax_ext/global_asm.rs @@ -14,7 +14,7 @@ /// "file-scoped", or "module-level" assembly. These synonyms /// all correspond to LLVM's module-level inline assembly instruction. /// -/// For example, `global_asm!("some assembly here")` translates to +/// For example, `global_asm!("some assembly here")` codegens to /// LLVM's `module asm "some assembly here"`. All of LLVM's caveats /// therefore apply. diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 3b400b879eb..d5410feb254 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -388,7 +388,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.FunctionSections = FunctionSections; if (TrapUnreachable) { - // Tell LLVM to translate `unreachable` into an explicit trap instruction. + // Tell LLVM to codegen `unreachable` into an explicit trap instruction. // This limits the extent of possible undefined behavior in some cases, as // it prevents control flow from "falling through" into whatever code // happens to be laid out next in memory. diff --git a/src/test/codegen-units/item-collection/cross-crate-closures.rs b/src/test/codegen-units/item-collection/cross-crate-closures.rs index 320be278198..a26604d3ce9 100644 --- a/src/test/codegen-units/item-collection/cross-crate-closures.rs +++ b/src/test/codegen-units/item-collection/cross-crate-closures.rs @@ -9,12 +9,12 @@ // except according to those terms. // In the current version of the collector that still has to support -// legacy-trans, closures do not generate their own TransItems, so we are -// ignoring this test until MIR trans has taken over completely +// legacy-codegen, closures do not generate their own MonoItems, so we are +// ignoring this test until MIR codegen has taken over completely // ignore-test // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] #![feature(start)] @@ -22,16 +22,16 @@ // aux-build:cgu_extern_closures.rs extern crate cgu_extern_closures; -//~ TRANS_ITEM fn cross_crate_closures::start[0] +//~ MONO_ITEM fn cross_crate_closures::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ TRANS_ITEM fn cgu_extern_closures::inlined_fn[0] - //~ TRANS_ITEM fn cgu_extern_closures::inlined_fn[0]::{{closure}}[0] + //~ MONO_ITEM fn cgu_extern_closures::inlined_fn[0] + //~ MONO_ITEM fn cgu_extern_closures::inlined_fn[0]::{{closure}}[0] let _ = cgu_extern_closures::inlined_fn(1, 2); - //~ TRANS_ITEM fn cgu_extern_closures::inlined_fn_generic[0] - //~ TRANS_ITEM fn cgu_extern_closures::inlined_fn_generic[0]::{{closure}}[0] + //~ MONO_ITEM fn cgu_extern_closures::inlined_fn_generic[0] + //~ MONO_ITEM fn cgu_extern_closures::inlined_fn_generic[0]::{{closure}}[0] let _ = cgu_extern_closures::inlined_fn_generic(3, 4, 5i32); // Nothing should be generated for this call, we just link to the instance @@ -41,4 +41,4 @@ fn start(_: isize, _: *const *const u8) -> isize { 0 } -//~ TRANS_ITEM drop-glue i8 +//~ MONO_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs b/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs index bcb3b7b1dad..aa33c25da9a 100644 --- a/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs +++ b/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] #![feature(start)] @@ -17,15 +17,15 @@ // aux-build:cgu_generic_function.rs extern crate cgu_generic_function; -//~ TRANS_ITEM fn cross_crate_generic_functions::start[0] +//~ MONO_ITEM fn cross_crate_generic_functions::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ TRANS_ITEM fn cgu_generic_function::bar[0] - //~ TRANS_ITEM fn cgu_generic_function::foo[0] + //~ MONO_ITEM fn cgu_generic_function::bar[0] + //~ MONO_ITEM fn cgu_generic_function::foo[0] let _ = cgu_generic_function::foo(1u32); - //~ TRANS_ITEM fn cgu_generic_function::bar[0] - //~ TRANS_ITEM fn cgu_generic_function::foo[0] + //~ MONO_ITEM fn cgu_generic_function::bar[0] + //~ MONO_ITEM fn cgu_generic_function::foo[0] let _ = cgu_generic_function::foo(2u64); // This should not introduce a codegen item diff --git a/src/test/codegen-units/item-collection/cross-crate-trait-method.rs b/src/test/codegen-units/item-collection/cross-crate-trait-method.rs index 910ae000848..7a16b22a023 100644 --- a/src/test/codegen-units/item-collection/cross-crate-trait-method.rs +++ b/src/test/codegen-units/item-collection/cross-crate-trait-method.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] #![feature(start)] @@ -19,7 +19,7 @@ extern crate cgu_export_trait_method; use cgu_export_trait_method::Trait; -//~ TRANS_ITEM fn cross_crate_trait_method::start[0] +//~ MONO_ITEM fn cross_crate_trait_method::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { // The object code of these methods is contained in the external crate, so @@ -30,31 +30,31 @@ fn start(_: isize, _: *const *const u8) -> isize { // Currently, no object code is generated for trait methods with default // implemenations, unless they are actually called from somewhere. Therefore // we cannot import the implementations and have to create our own inline. - //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl[0] + //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl[0] let _ = Trait::with_default_impl(0u32); - //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl[0] + //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl[0] let _ = Trait::with_default_impl('c'); - //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] + //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] let _ = Trait::with_default_impl_generic(0u32, "abc"); - //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] + //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] let _ = Trait::with_default_impl_generic(0u32, false); - //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] + //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] let _ = Trait::with_default_impl_generic('x', 1i16); - //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] + //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] let _ = Trait::with_default_impl_generic('y', 0i32); - //~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[1]::without_default_impl_generic[0] + //~ MONO_ITEM fn cgu_export_trait_method::{{impl}}[1]::without_default_impl_generic[0] let _: (u32, char) = Trait::without_default_impl_generic('c'); - //~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[1]::without_default_impl_generic[0] + //~ MONO_ITEM fn cgu_export_trait_method::{{impl}}[1]::without_default_impl_generic[0] let _: (u32, bool) = Trait::without_default_impl_generic(false); - //~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[0]::without_default_impl_generic[0] + //~ MONO_ITEM fn cgu_export_trait_method::{{impl}}[0]::without_default_impl_generic[0] let _: (char, char) = Trait::without_default_impl_generic('c'); - //~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[0]::without_default_impl_generic[0] + //~ MONO_ITEM fn cgu_export_trait_method::{{impl}}[0]::without_default_impl_generic[0] let _: (char, bool) = Trait::without_default_impl_generic(false); 0 diff --git a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs index 52af8165032..49e4b8d43c1 100644 --- a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs +++ b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs @@ -9,24 +9,24 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager // compile-flags:-Zinline-in-all-cgus #![feature(start)] -//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ drop_in_place_intrinsic0[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ drop_in_place_intrinsic0[Internal] struct StructWithDtor(u32); impl Drop for StructWithDtor { - //~ TRANS_ITEM fn drop_in_place_intrinsic::{{impl}}[0]::drop[0] + //~ MONO_ITEM fn drop_in_place_intrinsic::{{impl}}[0]::drop[0] fn drop(&mut self) {} } -//~ TRANS_ITEM fn drop_in_place_intrinsic::start[0] +//~ MONO_ITEM fn drop_in_place_intrinsic::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]; 2]> @@ drop_in_place_intrinsic0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]; 2]> @@ drop_in_place_intrinsic0[Internal] let x = [StructWithDtor(0), StructWithDtor(1)]; drop_slice_in_place(&x); @@ -34,13 +34,13 @@ fn start(_: isize, _: *const *const u8) -> isize { 0 } -//~ TRANS_ITEM fn drop_in_place_intrinsic::drop_slice_in_place[0] +//~ MONO_ITEM fn drop_in_place_intrinsic::drop_slice_in_place[0] fn drop_slice_in_place(x: &[StructWithDtor]) { unsafe { // This is the interesting thing in this test case: Normally we would // not have drop-glue for the unsized [StructWithDtor]. This has to be // generated though when the drop_in_place() intrinsic is used. - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]]> @@ drop_in_place_intrinsic0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]]> @@ drop_in_place_intrinsic0[Internal] ::std::ptr::drop_in_place(x as *const _ as *mut [StructWithDtor]); } } diff --git a/src/test/codegen-units/item-collection/function-as-argument.rs b/src/test/codegen-units/item-collection/function-as-argument.rs index 65707c1aa4d..9a88336d1e5 100644 --- a/src/test/codegen-units/item-collection/function-as-argument.rs +++ b/src/test/codegen-units/item-collection/function-as-argument.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] #![feature(start)] @@ -24,26 +24,26 @@ fn take_fn_pointer(f: fn(T1, T2), x: T1, y: T2) { (f)(x, y) } -//~ TRANS_ITEM fn function_as_argument::start[0] +//~ MONO_ITEM fn function_as_argument::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ TRANS_ITEM fn function_as_argument::take_fn_once[0] - //~ TRANS_ITEM fn function_as_argument::function[0] - //~ TRANS_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] + //~ MONO_ITEM fn function_as_argument::take_fn_once[0] + //~ MONO_ITEM fn function_as_argument::function[0] + //~ MONO_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] take_fn_once(function, 0u32, "abc"); - //~ TRANS_ITEM fn function_as_argument::take_fn_once[0] - //~ TRANS_ITEM fn function_as_argument::function[0] - //~ TRANS_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] + //~ MONO_ITEM fn function_as_argument::take_fn_once[0] + //~ MONO_ITEM fn function_as_argument::function[0] + //~ MONO_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] take_fn_once(function, 'c', 0f64); - //~ TRANS_ITEM fn function_as_argument::take_fn_pointer[0] - //~ TRANS_ITEM fn function_as_argument::function[0] + //~ MONO_ITEM fn function_as_argument::take_fn_pointer[0] + //~ MONO_ITEM fn function_as_argument::function[0] take_fn_pointer(function, 0i32, ()); - //~ TRANS_ITEM fn function_as_argument::take_fn_pointer[0] - //~ TRANS_ITEM fn function_as_argument::function[0] + //~ MONO_ITEM fn function_as_argument::take_fn_pointer[0] + //~ MONO_ITEM fn function_as_argument::function[0] take_fn_pointer(function, 0f32, 0i64); 0 diff --git a/src/test/codegen-units/item-collection/generic-drop-glue.rs b/src/test/codegen-units/item-collection/generic-drop-glue.rs index d3d9aa3aefc..aad32d1eb7c 100644 --- a/src/test/codegen-units/item-collection/generic-drop-glue.rs +++ b/src/test/codegen-units/item-collection/generic-drop-glue.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager // compile-flags:-Zinline-in-all-cgus #![deny(dead_code)] @@ -47,22 +47,22 @@ enum EnumNoDrop { struct NonGenericNoDrop(i32); struct NonGenericWithDrop(i32); -//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ generic_drop_glue0[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ generic_drop_glue0[Internal] impl Drop for NonGenericWithDrop { - //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[2]::drop[0] + //~ MONO_ITEM fn generic_drop_glue::{{impl}}[2]::drop[0] fn drop(&mut self) {} } -//~ TRANS_ITEM fn generic_drop_glue::start[0] +//~ MONO_ITEM fn generic_drop_glue::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue0[Internal] - //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue0[Internal] + //~ MONO_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0] let _ = StructWithDrop { x: 0i8, y: 'a' }.x; - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue0[Internal] - //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]> + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue0[Internal] + //~ MONO_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]> let _ = StructWithDrop { x: "&str", y: NonGenericNoDrop(0) }.y; // Should produce no drop glue @@ -70,18 +70,18 @@ fn start(_: isize, _: *const *const u8) -> isize { // This is supposed to generate drop-glue because it contains a field that // needs to be dropped. - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue0[Internal] let _ = StructNoDrop { x: NonGenericWithDrop(0), y: 0f64 }.y; - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue0[Internal] - //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue0[Internal] + //~ MONO_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0] let _ = match EnumWithDrop::A::(0) { EnumWithDrop::A(x) => x, EnumWithDrop::B(x) => x as i32 }; - //~TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue0[Internal] - //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0] + //~MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue0[Internal] + //~ MONO_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0] let _ = match EnumWithDrop::B::(1.0) { EnumWithDrop::A(x) => x, EnumWithDrop::B(x) => x as f64 diff --git a/src/test/codegen-units/item-collection/generic-functions.rs b/src/test/codegen-units/item-collection/generic-functions.rs index 8efe4b2762a..402d19f9996 100644 --- a/src/test/codegen-units/item-collection/generic-functions.rs +++ b/src/test/codegen-units/item-collection/generic-functions.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] #![feature(start)] @@ -27,39 +27,39 @@ fn foo3(a: T1, b: T2, c: T3) -> (T1, T2, T3) { } // This function should be instantiated even if no used -//~ TRANS_ITEM fn generic_functions::lifetime_only[0] +//~ MONO_ITEM fn generic_functions::lifetime_only[0] pub fn lifetime_only<'a>(a: &'a u32) -> &'a u32 { a } -//~ TRANS_ITEM fn generic_functions::start[0] +//~ MONO_ITEM fn generic_functions::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ TRANS_ITEM fn generic_functions::foo1[0] + //~ MONO_ITEM fn generic_functions::foo1[0] let _ = foo1(2i32); - //~ TRANS_ITEM fn generic_functions::foo1[0] + //~ MONO_ITEM fn generic_functions::foo1[0] let _ = foo1(2i64); - //~ TRANS_ITEM fn generic_functions::foo1[0]<&str> + //~ MONO_ITEM fn generic_functions::foo1[0]<&str> let _ = foo1("abc"); - //~ TRANS_ITEM fn generic_functions::foo1[0] + //~ MONO_ITEM fn generic_functions::foo1[0] let _ = foo1('v'); - //~ TRANS_ITEM fn generic_functions::foo2[0] + //~ MONO_ITEM fn generic_functions::foo2[0] let _ = foo2(2i32, 2i32); - //~ TRANS_ITEM fn generic_functions::foo2[0] + //~ MONO_ITEM fn generic_functions::foo2[0] let _ = foo2(2i64, "abc"); - //~ TRANS_ITEM fn generic_functions::foo2[0]<&str, usize> + //~ MONO_ITEM fn generic_functions::foo2[0]<&str, usize> let _ = foo2("a", 2usize); - //~ TRANS_ITEM fn generic_functions::foo2[0] + //~ MONO_ITEM fn generic_functions::foo2[0] let _ = foo2('v', ()); - //~ TRANS_ITEM fn generic_functions::foo3[0] + //~ MONO_ITEM fn generic_functions::foo3[0] let _ = foo3(2i32, 2i32, 2i32); - //~ TRANS_ITEM fn generic_functions::foo3[0] + //~ MONO_ITEM fn generic_functions::foo3[0] let _ = foo3(2i64, "abc", 'c'); - //~ TRANS_ITEM fn generic_functions::foo3[0] + //~ MONO_ITEM fn generic_functions::foo3[0] let _ = foo3(0i16, "a", 2usize); - //~ TRANS_ITEM fn generic_functions::foo3[0] + //~ MONO_ITEM fn generic_functions::foo3[0] let _ = foo3('v', (), ()); 0 diff --git a/src/test/codegen-units/item-collection/generic-impl.rs b/src/test/codegen-units/item-collection/generic-impl.rs index d1ee8ee624c..07e51a1e947 100644 --- a/src/test/codegen-units/item-collection/generic-impl.rs +++ b/src/test/codegen-units/item-collection/generic-impl.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] #![feature(start)] @@ -41,41 +41,41 @@ pub struct LifeTimeOnly<'a> { impl<'a> LifeTimeOnly<'a> { - //~ TRANS_ITEM fn generic_impl::{{impl}}[1]::foo[0] + //~ MONO_ITEM fn generic_impl::{{impl}}[1]::foo[0] pub fn foo(&self) {} - //~ TRANS_ITEM fn generic_impl::{{impl}}[1]::bar[0] + //~ MONO_ITEM fn generic_impl::{{impl}}[1]::bar[0] pub fn bar(&'a self) {} - //~ TRANS_ITEM fn generic_impl::{{impl}}[1]::baz[0] + //~ MONO_ITEM fn generic_impl::{{impl}}[1]::baz[0] pub fn baz<'b>(&'b self) {} pub fn non_instantiated(&self) {} } -//~ TRANS_ITEM fn generic_impl::start[0] +//~ MONO_ITEM fn generic_impl::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0] - //~ TRANS_ITEM fn generic_impl::id[0] - //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0] + //~ MONO_ITEM fn generic_impl::{{impl}}[0]::new[0] + //~ MONO_ITEM fn generic_impl::id[0] + //~ MONO_ITEM fn generic_impl::{{impl}}[0]::get[0] let _ = Struct::new(0i32).get(0i16); - //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0] - //~ TRANS_ITEM fn generic_impl::id[0] - //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0] + //~ MONO_ITEM fn generic_impl::{{impl}}[0]::new[0] + //~ MONO_ITEM fn generic_impl::id[0] + //~ MONO_ITEM fn generic_impl::{{impl}}[0]::get[0] let _ = Struct::new(0i64).get(0i16); - //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0] - //~ TRANS_ITEM fn generic_impl::id[0] - //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0] + //~ MONO_ITEM fn generic_impl::{{impl}}[0]::new[0] + //~ MONO_ITEM fn generic_impl::id[0] + //~ MONO_ITEM fn generic_impl::{{impl}}[0]::get[0] let _ = Struct::new('c').get(0i16); - //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0]<&str> - //~ TRANS_ITEM fn generic_impl::id[0]<&str> - //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0], i16> + //~ MONO_ITEM fn generic_impl::{{impl}}[0]::new[0]<&str> + //~ MONO_ITEM fn generic_impl::id[0]<&str> + //~ MONO_ITEM fn generic_impl::{{impl}}[0]::get[0], i16> let _ = Struct::new(Struct::new("str")).get(0i16); - //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0]> - //~ TRANS_ITEM fn generic_impl::id[0]> + //~ MONO_ITEM fn generic_impl::{{impl}}[0]::new[0]> + //~ MONO_ITEM fn generic_impl::id[0]> let _ = (Struct::new(Struct::new("str")).f)(Struct::new("str")); 0 diff --git a/src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs b/src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs index c07d26c3f8d..6d65c0d3aa8 100644 --- a/src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs +++ b/src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] #![feature(start)] @@ -22,14 +22,14 @@ trait SomeTrait { // discovered. pub fn generic_function(x: T) -> (T, i32) { impl SomeTrait for i64 { - //~ TRANS_ITEM fn impl_in_non_instantiated_generic::generic_function[0]::{{impl}}[0]::foo[0] + //~ MONO_ITEM fn impl_in_non_instantiated_generic::generic_function[0]::{{impl}}[0]::foo[0] fn foo(&self) {} } (x, 0) } -//~ TRANS_ITEM fn impl_in_non_instantiated_generic::start[0] +//~ MONO_ITEM fn impl_in_non_instantiated_generic::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { 0i64.foo(); diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs index 2e1138ef128..5c6201da252 100644 --- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs +++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager // compile-flags:-Zinline-in-all-cgus #![deny(dead_code)] @@ -29,20 +29,20 @@ impl Trait for Struct { fn bar(&self) {} } -//~ TRANS_ITEM fn instantiation_through_vtable::start[0] +//~ MONO_ITEM fn instantiation_through_vtable::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { let s1 = Struct { _a: 0u32 }; - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ instantiation_through_vtable0[Internal] - //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] - //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ instantiation_through_vtable0[Internal] + //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] + //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] let _ = &s1 as &Trait; let s1 = Struct { _a: 0u64 }; - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ instantiation_through_vtable0[Internal] - //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] - //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ instantiation_through_vtable0[Internal] + //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] + //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] let _ = &s1 as &Trait; 0 diff --git a/src/test/codegen-units/item-collection/items-within-generic-items.rs b/src/test/codegen-units/item-collection/items-within-generic-items.rs index 04b54de3ce2..f9813063831 100644 --- a/src/test/codegen-units/item-collection/items-within-generic-items.rs +++ b/src/test/codegen-units/item-collection/items-within-generic-items.rs @@ -9,19 +9,19 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] #![feature(start)] fn generic_fn(a: T) -> (T, i32) { - //~ TRANS_ITEM fn items_within_generic_items::generic_fn[0]::nested_fn[0] + //~ MONO_ITEM fn items_within_generic_items::generic_fn[0]::nested_fn[0] fn nested_fn(a: i32) -> i32 { a + 1 } let x = { - //~ TRANS_ITEM fn items_within_generic_items::generic_fn[0]::nested_fn[1] + //~ MONO_ITEM fn items_within_generic_items::generic_fn[0]::nested_fn[1] fn nested_fn(a: i32) -> i32 { a + 2 } @@ -32,14 +32,14 @@ fn generic_fn(a: T) -> (T, i32) { return (a, x + nested_fn(0)); } -//~ TRANS_ITEM fn items_within_generic_items::start[0] +//~ MONO_ITEM fn items_within_generic_items::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ TRANS_ITEM fn items_within_generic_items::generic_fn[0] + //~ MONO_ITEM fn items_within_generic_items::generic_fn[0] let _ = generic_fn(0i64); - //~ TRANS_ITEM fn items_within_generic_items::generic_fn[0] + //~ MONO_ITEM fn items_within_generic_items::generic_fn[0] let _ = generic_fn(0u16); - //~ TRANS_ITEM fn items_within_generic_items::generic_fn[0] + //~ MONO_ITEM fn items_within_generic_items::generic_fn[0] let _ = generic_fn(0i8); 0 diff --git a/src/test/codegen-units/item-collection/non-generic-closures.rs b/src/test/codegen-units/item-collection/non-generic-closures.rs index f0121d56cec..77ada23de71 100644 --- a/src/test/codegen-units/item-collection/non-generic-closures.rs +++ b/src/test/codegen-units/item-collection/non-generic-closures.rs @@ -9,51 +9,51 @@ // except according to those terms. // In the current version of the collector that still has to support -// legacy-trans, closures do not generate their own TransItems, so we are -// ignoring this test until MIR trans has taken over completely +// legacy-codegen, closures do not generate their own MonoItems, so we are +// ignoring this test until MIR codegen has taken over completely // ignore-test // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] #![feature(start)] -//~ TRANS_ITEM fn non_generic_closures::temporary[0] +//~ MONO_ITEM fn non_generic_closures::temporary[0] fn temporary() { - //~ TRANS_ITEM fn non_generic_closures::temporary[0]::{{closure}}[0] + //~ MONO_ITEM fn non_generic_closures::temporary[0]::{{closure}}[0] (|a: u32| { let _ = a; })(4); } -//~ TRANS_ITEM fn non_generic_closures::assigned_to_variable_but_not_executed[0] +//~ MONO_ITEM fn non_generic_closures::assigned_to_variable_but_not_executed[0] fn assigned_to_variable_but_not_executed() { - //~ TRANS_ITEM fn non_generic_closures::assigned_to_variable_but_not_executed[0]::{{closure}}[0] + //~ MONO_ITEM fn non_generic_closures::assigned_to_variable_but_not_executed[0]::{{closure}}[0] let _x = |a: i16| { let _ = a + 1; }; } -//~ TRANS_ITEM fn non_generic_closures::assigned_to_variable_executed_directly[0] +//~ MONO_ITEM fn non_generic_closures::assigned_to_variable_executed_directly[0] fn assigned_to_variable_executed_indirectly() { - //~ TRANS_ITEM fn non_generic_closures::assigned_to_variable_executed_directly[0]::{{closure}}[0] + //~ MONO_ITEM fn non_generic_closures::assigned_to_variable_executed_directly[0]::{{closure}}[0] let f = |a: i32| { let _ = a + 2; }; run_closure(&f); } -//~ TRANS_ITEM fn non_generic_closures::assigned_to_variable_executed_indirectly[0] +//~ MONO_ITEM fn non_generic_closures::assigned_to_variable_executed_indirectly[0] fn assigned_to_variable_executed_directly() { - //~ TRANS_ITEM fn non_generic_closures::assigned_to_variable_executed_indirectly[0]::{{closure}}[0] + //~ MONO_ITEM fn non_generic_closures::assigned_to_variable_executed_indirectly[0]::{{closure}}[0] let f = |a: i64| { let _ = a + 3; }; f(4); } -//~ TRANS_ITEM fn non_generic_closures::start[0] +//~ MONO_ITEM fn non_generic_closures::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { temporary(); @@ -64,7 +64,7 @@ fn start(_: isize, _: *const *const u8) -> isize { 0 } -//~ TRANS_ITEM fn non_generic_closures::run_closure[0] +//~ MONO_ITEM fn non_generic_closures::run_closure[0] fn run_closure(f: &Fn(i32)) { f(3); } diff --git a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs index bf084aa96ea..6ca24aa5b4b 100644 --- a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs +++ b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs @@ -9,19 +9,19 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager // compile-flags:-Zinline-in-all-cgus #![deny(dead_code)] #![feature(start)] -//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ non_generic_drop_glue0[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ non_generic_drop_glue0[Internal] struct StructWithDrop { x: i32 } impl Drop for StructWithDrop { - //~ TRANS_ITEM fn non_generic_drop_glue::{{impl}}[0]::drop[0] + //~ MONO_ITEM fn non_generic_drop_glue::{{impl}}[0]::drop[0] fn drop(&mut self) {} } @@ -29,13 +29,13 @@ struct StructNoDrop { x: i32 } -//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ non_generic_drop_glue0[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ non_generic_drop_glue0[Internal] enum EnumWithDrop { A(i32) } impl Drop for EnumWithDrop { - //~ TRANS_ITEM fn non_generic_drop_glue::{{impl}}[1]::drop[0] + //~ MONO_ITEM fn non_generic_drop_glue::{{impl}}[1]::drop[0] fn drop(&mut self) {} } @@ -43,7 +43,7 @@ enum EnumNoDrop { A(i32) } -//~ TRANS_ITEM fn non_generic_drop_glue::start[0] +//~ MONO_ITEM fn non_generic_drop_glue::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { let _ = StructWithDrop { x: 0 }.x; diff --git a/src/test/codegen-units/item-collection/non-generic-functions.rs b/src/test/codegen-units/item-collection/non-generic-functions.rs index 8c487db5c96..38d08c8a6ed 100644 --- a/src/test/codegen-units/item-collection/non-generic-functions.rs +++ b/src/test/codegen-units/item-collection/non-generic-functions.rs @@ -9,29 +9,29 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] #![feature(start)] -//~ TRANS_ITEM fn non_generic_functions::foo[0] +//~ MONO_ITEM fn non_generic_functions::foo[0] fn foo() { { - //~ TRANS_ITEM fn non_generic_functions::foo[0]::foo[0] + //~ MONO_ITEM fn non_generic_functions::foo[0]::foo[0] fn foo() {} foo(); } { - //~ TRANS_ITEM fn non_generic_functions::foo[0]::foo[1] + //~ MONO_ITEM fn non_generic_functions::foo[0]::foo[1] fn foo() {} foo(); } } -//~ TRANS_ITEM fn non_generic_functions::bar[0] +//~ MONO_ITEM fn non_generic_functions::bar[0] fn bar() { - //~ TRANS_ITEM fn non_generic_functions::bar[0]::baz[0] + //~ MONO_ITEM fn non_generic_functions::bar[0]::baz[0] fn baz() {} baz(); } @@ -39,38 +39,38 @@ fn bar() { struct Struct { _x: i32 } impl Struct { - //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::foo[0] + //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::foo[0] fn foo() { { - //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::foo[0]::foo[0] + //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::foo[0]::foo[0] fn foo() {} foo(); } { - //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::foo[0]::foo[1] + //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::foo[0]::foo[1] fn foo() {} foo(); } } - //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::bar[0] + //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::bar[0] fn bar(&self) { { - //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::bar[0]::foo[0] + //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::bar[0]::foo[0] fn foo() {} foo(); } { - //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::bar[0]::foo[1] + //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::bar[0]::foo[1] fn foo() {} foo(); } } } -//~ TRANS_ITEM fn non_generic_functions::start[0] +//~ MONO_ITEM fn non_generic_functions::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { foo(); diff --git a/src/test/codegen-units/item-collection/overloaded-operators.rs b/src/test/codegen-units/item-collection/overloaded-operators.rs index 05848a727e9..dae6ef83551 100644 --- a/src/test/codegen-units/item-collection/overloaded-operators.rs +++ b/src/test/codegen-units/item-collection/overloaded-operators.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] #![crate_type="lib"] @@ -23,7 +23,7 @@ pub struct Indexable { impl Index for Indexable { type Output = u8; - //~ TRANS_ITEM fn overloaded_operators::{{impl}}[0]::index[0] + //~ MONO_ITEM fn overloaded_operators::{{impl}}[0]::index[0] fn index(&self, index: usize) -> &Self::Output { if index >= 3 { &self.data[0] @@ -34,7 +34,7 @@ impl Index for Indexable { } impl IndexMut for Indexable { - //~ TRANS_ITEM fn overloaded_operators::{{impl}}[1]::index_mut[0] + //~ MONO_ITEM fn overloaded_operators::{{impl}}[1]::index_mut[0] fn index_mut(&mut self, index: usize) -> &mut Self::Output { if index >= 3 { &mut self.data[0] @@ -45,8 +45,8 @@ impl IndexMut for Indexable { } -//~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::eq[0] -//~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::ne[0] +//~ MONO_ITEM fn overloaded_operators::{{impl}}[4]::eq[0] +//~ MONO_ITEM fn overloaded_operators::{{impl}}[4]::ne[0] #[derive(PartialEq)] pub struct Equatable(u32); @@ -54,7 +54,7 @@ pub struct Equatable(u32); impl Add for Equatable { type Output = u32; - //~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::add[0] + //~ MONO_ITEM fn overloaded_operators::{{impl}}[2]::add[0] fn add(self, rhs: u32) -> u32 { self.0 + rhs } @@ -63,7 +63,7 @@ impl Add for Equatable { impl Deref for Equatable { type Target = u32; - //~ TRANS_ITEM fn overloaded_operators::{{impl}}[3]::deref[0] + //~ MONO_ITEM fn overloaded_operators::{{impl}}[3]::deref[0] fn deref(&self) -> &Self::Target { &self.0 } diff --git a/src/test/codegen-units/item-collection/static-init.rs b/src/test/codegen-units/item-collection/static-init.rs index 5ff7c3480b1..f36c4903458 100644 --- a/src/test/codegen-units/item-collection/static-init.rs +++ b/src/test/codegen-units/item-collection/static-init.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager // ignore-tidy-linelength #![feature(start)] @@ -17,12 +17,11 @@ pub static FN : fn() = foo::; pub fn foo() { } -//~ TRANS_ITEM fn static_init::foo[0] -//~ TRANS_ITEM static static_init::FN[0] +//~ MONO_ITEM fn static_init::foo[0] +//~ MONO_ITEM static static_init::FN[0] -//~ TRANS_ITEM fn static_init::start[0] +//~ MONO_ITEM fn static_init::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { 0 } - diff --git a/src/test/codegen-units/item-collection/statics-and-consts.rs b/src/test/codegen-units/item-collection/statics-and-consts.rs index 11df1da3a78..883809ff059 100644 --- a/src/test/codegen-units/item-collection/statics-and-consts.rs +++ b/src/test/codegen-units/item-collection/statics-and-consts.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] #![feature(start)] @@ -48,7 +48,7 @@ fn foo() { }; } -//~ TRANS_ITEM fn statics_and_consts::start[0] +//~ MONO_ITEM fn statics_and_consts::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { foo(); @@ -57,9 +57,9 @@ fn start(_: isize, _: *const *const u8) -> isize { 0 } -//~ TRANS_ITEM static statics_and_consts::STATIC1[0] +//~ MONO_ITEM static statics_and_consts::STATIC1[0] -//~ TRANS_ITEM fn statics_and_consts::foo[0] -//~ TRANS_ITEM static statics_and_consts::foo[0]::STATIC2[0] -//~ TRANS_ITEM static statics_and_consts::foo[0]::STATIC2[1] -//~ TRANS_ITEM static statics_and_consts::foo[0]::STATIC2[2] +//~ MONO_ITEM fn statics_and_consts::foo[0] +//~ MONO_ITEM static statics_and_consts::foo[0]::STATIC2[0] +//~ MONO_ITEM static statics_and_consts::foo[0]::STATIC2[1] +//~ MONO_ITEM static statics_and_consts::foo[0]::STATIC2[2] diff --git a/src/test/codegen-units/item-collection/trait-implementations.rs b/src/test/codegen-units/item-collection/trait-implementations.rs index 8eb33dd647f..f85486b5d34 100644 --- a/src/test/codegen-units/item-collection/trait-implementations.rs +++ b/src/test/codegen-units/item-collection/trait-implementations.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] #![feature(start)] @@ -21,7 +21,7 @@ pub trait SomeTrait { impl SomeTrait for i64 { - //~ TRANS_ITEM fn trait_implementations::{{impl}}[0]::foo[0] + //~ MONO_ITEM fn trait_implementations::{{impl}}[0]::foo[0] fn foo(&self) {} fn bar(&self, _: T) {} @@ -29,7 +29,7 @@ impl SomeTrait for i64 { impl SomeTrait for i32 { - //~ TRANS_ITEM fn trait_implementations::{{impl}}[1]::foo[0] + //~ MONO_ITEM fn trait_implementations::{{impl}}[1]::foo[0] fn foo(&self) {} fn bar(&self, _: T) {} @@ -43,7 +43,7 @@ pub trait SomeGenericTrait { // Concrete impl of generic trait impl SomeGenericTrait for f64 { - //~ TRANS_ITEM fn trait_implementations::{{impl}}[2]::foo[0] + //~ MONO_ITEM fn trait_implementations::{{impl}}[2]::foo[0] fn foo(&self, _: u32) {} fn bar(&self, _: u32, _: T2) {} @@ -56,28 +56,28 @@ impl SomeGenericTrait for f32 { fn bar(&self, _: T, _: T2) {} } -//~ TRANS_ITEM fn trait_implementations::start[0] +//~ MONO_ITEM fn trait_implementations::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ TRANS_ITEM fn trait_implementations::{{impl}}[1]::bar[0] + //~ MONO_ITEM fn trait_implementations::{{impl}}[1]::bar[0] 0i32.bar('x'); - //~ TRANS_ITEM fn trait_implementations::{{impl}}[2]::bar[0]<&str> + //~ MONO_ITEM fn trait_implementations::{{impl}}[2]::bar[0]<&str> 0f64.bar(0u32, "&str"); - //~ TRANS_ITEM fn trait_implementations::{{impl}}[2]::bar[0]<()> + //~ MONO_ITEM fn trait_implementations::{{impl}}[2]::bar[0]<()> 0f64.bar(0u32, ()); - //~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::foo[0] + //~ MONO_ITEM fn trait_implementations::{{impl}}[3]::foo[0] 0f32.foo('x'); - //~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::foo[0] + //~ MONO_ITEM fn trait_implementations::{{impl}}[3]::foo[0] 0f32.foo(-1i64); - //~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::bar[0] + //~ MONO_ITEM fn trait_implementations::{{impl}}[3]::bar[0] 0f32.bar(0u32, ()); - //~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::bar[0]<&str, &str> + //~ MONO_ITEM fn trait_implementations::{{impl}}[3]::bar[0]<&str, &str> 0f32.bar("&str", "&str"); 0 diff --git a/src/test/codegen-units/item-collection/trait-method-as-argument.rs b/src/test/codegen-units/item-collection/trait-method-as-argument.rs index 10b21630308..1f08f0f8060 100644 --- a/src/test/codegen-units/item-collection/trait-method-as-argument.rs +++ b/src/test/codegen-units/item-collection/trait-method-as-argument.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] #![feature(start)] @@ -37,33 +37,33 @@ fn take_foo_mut T>(mut f: F, arg: T) -> T { (f)(arg) } -//~ TRANS_ITEM fn trait_method_as_argument::start[0] +//~ MONO_ITEM fn trait_method_as_argument::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ TRANS_ITEM fn trait_method_as_argument::take_foo_once[0] u32> - //~ TRANS_ITEM fn trait_method_as_argument::{{impl}}[0]::foo[0] - //~ TRANS_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] u32, (u32)> + //~ MONO_ITEM fn trait_method_as_argument::take_foo_once[0] u32> + //~ MONO_ITEM fn trait_method_as_argument::{{impl}}[0]::foo[0] + //~ MONO_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] u32, (u32)> take_foo_once(Trait::foo, 0u32); - //~ TRANS_ITEM fn trait_method_as_argument::take_foo_once[0] char> - //~ TRANS_ITEM fn trait_method_as_argument::Trait[0]::foo[0] - //~ TRANS_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] char, (char)> + //~ MONO_ITEM fn trait_method_as_argument::take_foo_once[0] char> + //~ MONO_ITEM fn trait_method_as_argument::Trait[0]::foo[0] + //~ MONO_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] char, (char)> take_foo_once(Trait::foo, 'c'); - //~ TRANS_ITEM fn trait_method_as_argument::take_foo[0] u32> - //~ TRANS_ITEM fn core::ops[0]::function[0]::Fn[0]::call[0] u32, (u32)> + //~ MONO_ITEM fn trait_method_as_argument::take_foo[0] u32> + //~ MONO_ITEM fn core::ops[0]::function[0]::Fn[0]::call[0] u32, (u32)> take_foo(Trait::foo, 0u32); - //~ TRANS_ITEM fn trait_method_as_argument::take_foo[0] char> - //~ TRANS_ITEM fn core::ops[0]::function[0]::Fn[0]::call[0] char, (char)> + //~ MONO_ITEM fn trait_method_as_argument::take_foo[0] char> + //~ MONO_ITEM fn core::ops[0]::function[0]::Fn[0]::call[0] char, (char)> take_foo(Trait::foo, 'c'); - //~ TRANS_ITEM fn trait_method_as_argument::take_foo_mut[0] u32> - //~ TRANS_ITEM fn core::ops[0]::function[0]::FnMut[0]::call_mut[0] char, (char)> + //~ MONO_ITEM fn trait_method_as_argument::take_foo_mut[0] u32> + //~ MONO_ITEM fn core::ops[0]::function[0]::FnMut[0]::call_mut[0] char, (char)> take_foo_mut(Trait::foo, 0u32); - //~ TRANS_ITEM fn trait_method_as_argument::take_foo_mut[0] char> - //~ TRANS_ITEM fn core::ops[0]::function[0]::FnMut[0]::call_mut[0] u32, (u32)> + //~ MONO_ITEM fn trait_method_as_argument::take_foo_mut[0] char> + //~ MONO_ITEM fn core::ops[0]::function[0]::FnMut[0]::call_mut[0] u32, (u32)> take_foo_mut(Trait::foo, 'c'); 0 diff --git a/src/test/codegen-units/item-collection/trait-method-default-impl.rs b/src/test/codegen-units/item-collection/trait-method-default-impl.rs index a6ae3765b2e..b130747972e 100644 --- a/src/test/codegen-units/item-collection/trait-method-default-impl.rs +++ b/src/test/codegen-units/item-collection/trait-method-default-impl.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] #![feature(start)] @@ -24,7 +24,7 @@ impl SomeTrait for i8 { // For the non-generic foo(), we should generate a codegen-item even if it // is not called anywhere - //~ TRANS_ITEM fn trait_method_default_impl::SomeTrait[0]::foo[0] + //~ MONO_ITEM fn trait_method_default_impl::SomeTrait[0]::foo[0] } trait SomeGenericTrait { @@ -38,7 +38,7 @@ impl SomeGenericTrait for i32 { // For the non-generic foo(), we should generate a codegen-item even if it // is not called anywhere - //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::foo[0] + //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::foo[0] } // Non-generic impl of generic trait @@ -47,25 +47,25 @@ impl SomeGenericTrait for u32 { // since nothing is monomorphic here, nothing should be generated unless used somewhere. } -//~ TRANS_ITEM fn trait_method_default_impl::start[0] +//~ MONO_ITEM fn trait_method_default_impl::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ TRANS_ITEM fn trait_method_default_impl::SomeTrait[0]::bar[0] + //~ MONO_ITEM fn trait_method_default_impl::SomeTrait[0]::bar[0] let _ = 1i8.bar('c'); - //~ TRANS_ITEM fn trait_method_default_impl::SomeTrait[0]::bar[0] + //~ MONO_ITEM fn trait_method_default_impl::SomeTrait[0]::bar[0] let _ = 2i8.bar("&str"); - //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] + //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] 0i32.bar(0u64, 'c'); - //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] + //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] 0i32.bar(0u64, "&str"); - //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] + //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] 0u32.bar(0i8, &['c']); - //~ TRANS_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] + //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] 0u32.bar(0i16, ()); 0 diff --git a/src/test/codegen-units/item-collection/transitive-drop-glue.rs b/src/test/codegen-units/item-collection/transitive-drop-glue.rs index 57cd10187a2..d20213c109b 100644 --- a/src/test/codegen-units/item-collection/transitive-drop-glue.rs +++ b/src/test/codegen-units/item-collection/transitive-drop-glue.rs @@ -9,21 +9,21 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager // compile-flags:-Zinline-in-all-cgus #![deny(dead_code)] #![feature(start)] -//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue0[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue0[Internal] struct Root(Intermediate); -//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue0[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue0[Internal] struct Intermediate(Leaf); -//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue0[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue0[Internal] struct Leaf; impl Drop for Leaf { - //~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[0]::drop[0] + //~ MONO_ITEM fn transitive_drop_glue::{{impl}}[0]::drop[0] fn drop(&mut self) {} } @@ -35,21 +35,21 @@ impl Drop for LeafGen { fn drop(&mut self) {} } -//~ TRANS_ITEM fn transitive_drop_glue::start[0] +//~ MONO_ITEM fn transitive_drop_glue::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { let _ = Root(Intermediate(Leaf)); - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] - //~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] + //~ MONO_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0] let _ = RootGen(IntermediateGen(LeafGen(0u32))); - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] - //~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] + //~ MONO_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0] let _ = RootGen(IntermediateGen(LeafGen(0i16))); 0 diff --git a/src/test/codegen-units/item-collection/tuple-drop-glue.rs b/src/test/codegen-units/item-collection/tuple-drop-glue.rs index a5f2409b8ae..9e4cc6ea6f0 100644 --- a/src/test/codegen-units/item-collection/tuple-drop-glue.rs +++ b/src/test/codegen-units/item-collection/tuple-drop-glue.rs @@ -9,28 +9,28 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager // compile-flags:-Zinline-in-all-cgus #![deny(dead_code)] #![feature(start)] -//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ tuple_drop_glue0[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ tuple_drop_glue0[Internal] struct Dropped; impl Drop for Dropped { - //~ TRANS_ITEM fn tuple_drop_glue::{{impl}}[0]::drop[0] + //~ MONO_ITEM fn tuple_drop_glue::{{impl}}[0]::drop[0] fn drop(&mut self) {} } -//~ TRANS_ITEM fn tuple_drop_glue::start[0] +//~ MONO_ITEM fn tuple_drop_glue::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, tuple_drop_glue::Dropped[0])> @@ tuple_drop_glue0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, tuple_drop_glue::Dropped[0])> @@ tuple_drop_glue0[Internal] let x = (0u32, Dropped); - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(i16, (tuple_drop_glue::Dropped[0], bool))> @@ tuple_drop_glue0[Internal] - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(tuple_drop_glue::Dropped[0], bool)> @@ tuple_drop_glue0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(i16, (tuple_drop_glue::Dropped[0], bool))> @@ tuple_drop_glue0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(tuple_drop_glue::Dropped[0], bool)> @@ tuple_drop_glue0[Internal] let x = (0i16, (Dropped, true)); 0 diff --git a/src/test/codegen-units/item-collection/unreferenced-const-fn.rs b/src/test/codegen-units/item-collection/unreferenced-const-fn.rs index 59b25d8beca..c2ff846721c 100644 --- a/src/test/codegen-units/item-collection/unreferenced-const-fn.rs +++ b/src/test/codegen-units/item-collection/unreferenced-const-fn.rs @@ -9,9 +9,9 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=lazy +// compile-flags:-Zprint-mono-items=lazy -// NB: We do not expect *any* translation item to be generated here. +// NB: We do not expect *any* monomorphization to be generated here. #![feature(const_fn)] #![deny(dead_code)] diff --git a/src/test/codegen-units/item-collection/unreferenced-inline-function.rs b/src/test/codegen-units/item-collection/unreferenced-inline-function.rs index 75d41a38012..829b4fbf3c9 100644 --- a/src/test/codegen-units/item-collection/unreferenced-inline-function.rs +++ b/src/test/codegen-units/item-collection/unreferenced-inline-function.rs @@ -9,9 +9,9 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=lazy +// compile-flags:-Zprint-mono-items=lazy -// NB: We do not expect *any* translation item to be generated here. +// NB: We do not expect *any* monomorphization to be generated here. #![deny(dead_code)] #![crate_type = "rlib"] @@ -20,4 +20,3 @@ pub fn foo() -> bool { [1, 2] == [3, 4] } - diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs index 87d2581e1f8..adc0eb6c709 100644 --- a/src/test/codegen-units/item-collection/unsizing.rs +++ b/src/test/codegen-units/item-collection/unsizing.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager // compile-flags:-Zinline-in-all-cgus #![deny(dead_code)] @@ -54,19 +54,19 @@ struct Wrapper(*const T); impl, U: ?Sized> CoerceUnsized> for Wrapper {} -//~ TRANS_ITEM fn unsizing::start[0] +//~ MONO_ITEM fn unsizing::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { // simple case let bool_sized = &true; - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing0[Internal] - //~ TRANS_ITEM fn unsizing::{{impl}}[0]::foo[0] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing0[Internal] + //~ MONO_ITEM fn unsizing::{{impl}}[0]::foo[0] let _bool_unsized = bool_sized as &Trait; let char_sized = &'a'; - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing0[Internal] - //~ TRANS_ITEM fn unsizing::{{impl}}[1]::foo[0] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing0[Internal] + //~ MONO_ITEM fn unsizing::{{impl}}[1]::foo[0] let _char_unsized = char_sized as &Trait; // struct field @@ -75,14 +75,14 @@ fn start(_: isize, _: *const *const u8) -> isize { _b: 2, _c: 3.0f64 }; - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing0[Internal] - //~ TRANS_ITEM fn unsizing::{{impl}}[2]::foo[0] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing0[Internal] + //~ MONO_ITEM fn unsizing::{{impl}}[2]::foo[0] let _struct_unsized = struct_sized as &Struct; // custom coercion let wrapper_sized = Wrapper(&0u32); - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing0[Internal] - //~ TRANS_ITEM fn unsizing::{{impl}}[3]::foo[0] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing0[Internal] + //~ MONO_ITEM fn unsizing::{{impl}}[3]::foo[0] let _wrapper_sized = wrapper_sized as Wrapper; 0 diff --git a/src/test/codegen-units/item-collection/unused-traits-and-generics.rs b/src/test/codegen-units/item-collection/unused-traits-and-generics.rs index ce85c4fc13c..2edc7b211a1 100644 --- a/src/test/codegen-units/item-collection/unused-traits-and-generics.rs +++ b/src/test/codegen-units/item-collection/unused-traits-and-generics.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager +// compile-flags:-Zprint-mono-items=eager #![crate_type="lib"] #![deny(dead_code)] @@ -85,4 +85,4 @@ impl NonGeneric { } // Only the non-generic methods should be instantiated: -//~ TRANS_ITEM fn unused_traits_and_generics::{{impl}}[3]::foo[0] +//~ MONO_ITEM fn unused_traits_and_generics::{{impl}}[3]::foo[0] diff --git a/src/test/codegen-units/partitioning/extern-drop-glue.rs b/src/test/codegen-units/partitioning/extern-drop-glue.rs index da96c5e183d..cbad3a63884 100644 --- a/src/test/codegen-units/partitioning/extern-drop-glue.rs +++ b/src/test/codegen-units/partitioning/extern-drop-glue.rs @@ -12,7 +12,7 @@ // We specify -Z incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/extern-drop-glue +// compile-flags:-Zprint-mono-items=lazy -Zincremental=tmp/partitioning-tests/extern-drop-glue // compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] @@ -21,14 +21,14 @@ // aux-build:cgu_extern_drop_glue.rs extern crate cgu_extern_drop_glue; -//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue[Internal] extern_drop_glue-mod1[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue[Internal] extern_drop_glue-mod1[Internal] struct LocalStruct(cgu_extern_drop_glue::Struct); -//~ TRANS_ITEM fn extern_drop_glue::user[0] @@ extern_drop_glue[External] +//~ MONO_ITEM fn extern_drop_glue::user[0] @@ extern_drop_glue[External] pub fn user() { - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue[Internal] let _ = LocalStruct(cgu_extern_drop_glue::Struct(0)); } @@ -37,10 +37,10 @@ pub mod mod1 { struct LocalStruct(cgu_extern_drop_glue::Struct); - //~ TRANS_ITEM fn extern_drop_glue::mod1[0]::user[0] @@ extern_drop_glue-mod1[External] + //~ MONO_ITEM fn extern_drop_glue::mod1[0]::user[0] @@ extern_drop_glue-mod1[External] pub fn user() { - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue-mod1[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue-mod1[Internal] let _ = LocalStruct(cgu_extern_drop_glue::Struct(0)); } } diff --git a/src/test/codegen-units/partitioning/extern-generic.rs b/src/test/codegen-units/partitioning/extern-generic.rs index 140b43c85d5..a774376690a 100644 --- a/src/test/codegen-units/partitioning/extern-generic.rs +++ b/src/test/codegen-units/partitioning/extern-generic.rs @@ -11,7 +11,7 @@ // ignore-tidy-linelength // We specify -Z incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-trans-items=eager -Zincremental=tmp/partitioning-tests/extern-generic -Zshare-generics=y +// compile-flags:-Zprint-mono-items=eager -Zincremental=tmp/partitioning-tests/extern-generic -Zshare-generics=y #![allow(dead_code)] #![crate_type="lib"] @@ -19,7 +19,7 @@ // aux-build:cgu_generic_function.rs extern crate cgu_generic_function; -//~ TRANS_ITEM fn extern_generic::user[0] @@ extern_generic[Internal] +//~ MONO_ITEM fn extern_generic::user[0] @@ extern_generic[Internal] fn user() { let _ = cgu_generic_function::foo("abc"); } @@ -27,7 +27,7 @@ fn user() { mod mod1 { use cgu_generic_function; - //~ TRANS_ITEM fn extern_generic::mod1[0]::user[0] @@ extern_generic-mod1[Internal] + //~ MONO_ITEM fn extern_generic::mod1[0]::user[0] @@ extern_generic-mod1[Internal] fn user() { let _ = cgu_generic_function::foo("abc"); } @@ -35,7 +35,7 @@ mod mod1 { mod mod1 { use cgu_generic_function; - //~ TRANS_ITEM fn extern_generic::mod1[0]::mod1[0]::user[0] @@ extern_generic-mod1-mod1[Internal] + //~ MONO_ITEM fn extern_generic::mod1[0]::mod1[0]::user[0] @@ extern_generic-mod1-mod1[Internal] fn user() { let _ = cgu_generic_function::foo("abc"); } @@ -45,18 +45,18 @@ mod mod1 { mod mod2 { use cgu_generic_function; - //~ TRANS_ITEM fn extern_generic::mod2[0]::user[0] @@ extern_generic-mod2[Internal] + //~ MONO_ITEM fn extern_generic::mod2[0]::user[0] @@ extern_generic-mod2[Internal] fn user() { let _ = cgu_generic_function::foo("abc"); } } mod mod3 { - //~ TRANS_ITEM fn extern_generic::mod3[0]::non_user[0] @@ extern_generic-mod3[Internal] + //~ MONO_ITEM fn extern_generic::mod3[0]::non_user[0] @@ extern_generic-mod3[Internal] fn non_user() {} } // Make sure the two generic functions from the extern crate get instantiated // once for the current crate -//~ TRANS_ITEM fn cgu_generic_function::foo[0]<&str> @@ cgu_generic_function.volatile[External] -//~ TRANS_ITEM fn cgu_generic_function::bar[0]<&str> @@ cgu_generic_function.volatile[External] +//~ MONO_ITEM fn cgu_generic_function::foo[0]<&str> @@ cgu_generic_function.volatile[External] +//~ MONO_ITEM fn cgu_generic_function::bar[0]<&str> @@ cgu_generic_function.volatile[External] diff --git a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs index 01600c03ba2..4136557d800 100644 --- a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs +++ b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs @@ -11,7 +11,7 @@ // ignore-tidy-linelength // We specify -Z incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/inlining-from-extern-crate +// compile-flags:-Zprint-mono-items=lazy -Zincremental=tmp/partitioning-tests/inlining-from-extern-crate // compile-flags:-Zinline-in-all-cgus #![crate_type="lib"] @@ -22,28 +22,28 @@ extern crate cgu_explicit_inlining; // This test makes sure that items inlined from external crates are privately // instantiated in every codegen unit they are used in. -//~ TRANS_ITEM fn cgu_explicit_inlining::inlined[0] @@ inlining_from_extern_crate[Internal] inlining_from_extern_crate-mod1[Internal] -//~ TRANS_ITEM fn cgu_explicit_inlining::always_inlined[0] @@ inlining_from_extern_crate[Internal] inlining_from_extern_crate-mod2[Internal] +//~ MONO_ITEM fn cgu_explicit_inlining::inlined[0] @@ inlining_from_extern_crate[Internal] inlining_from_extern_crate-mod1[Internal] +//~ MONO_ITEM fn cgu_explicit_inlining::always_inlined[0] @@ inlining_from_extern_crate[Internal] inlining_from_extern_crate-mod2[Internal] -//~ TRANS_ITEM fn inlining_from_extern_crate::user[0] @@ inlining_from_extern_crate[External] +//~ MONO_ITEM fn inlining_from_extern_crate::user[0] @@ inlining_from_extern_crate[External] pub fn user() { cgu_explicit_inlining::inlined(); cgu_explicit_inlining::always_inlined(); - // does not generate a translation item in this crate + // does not generate a monomorphization in this crate cgu_explicit_inlining::never_inlined(); } pub mod mod1 { use cgu_explicit_inlining; - //~ TRANS_ITEM fn inlining_from_extern_crate::mod1[0]::user[0] @@ inlining_from_extern_crate-mod1[External] + //~ MONO_ITEM fn inlining_from_extern_crate::mod1[0]::user[0] @@ inlining_from_extern_crate-mod1[External] pub fn user() { cgu_explicit_inlining::inlined(); - // does not generate a translation item in this crate + // does not generate a monomorphization in this crate cgu_explicit_inlining::never_inlined(); } } @@ -51,12 +51,12 @@ pub mod mod1 { pub mod mod2 { use cgu_explicit_inlining; - //~ TRANS_ITEM fn inlining_from_extern_crate::mod2[0]::user[0] @@ inlining_from_extern_crate-mod2[External] + //~ MONO_ITEM fn inlining_from_extern_crate::mod2[0]::user[0] @@ inlining_from_extern_crate-mod2[External] pub fn user() { cgu_explicit_inlining::always_inlined(); - // does not generate a translation item in this crate + // does not generate a monomorphization in this crate cgu_explicit_inlining::never_inlined(); } } diff --git a/src/test/codegen-units/partitioning/local-drop-glue.rs b/src/test/codegen-units/partitioning/local-drop-glue.rs index f7c05285ed6..98729d99ea9 100644 --- a/src/test/codegen-units/partitioning/local-drop-glue.rs +++ b/src/test/codegen-units/partitioning/local-drop-glue.rs @@ -11,28 +11,28 @@ // ignore-tidy-linelength // We specify -Z incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/local-drop-glue +// compile-flags:-Zprint-mono-items=lazy -Zincremental=tmp/partitioning-tests/local-drop-glue // compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] #![crate_type="rlib"] -//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue[Internal] local_drop_glue-mod1[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue[Internal] local_drop_glue-mod1[Internal] struct Struct { _a: u32 } impl Drop for Struct { - //~ TRANS_ITEM fn local_drop_glue::{{impl}}[0]::drop[0] @@ local_drop_glue[External] + //~ MONO_ITEM fn local_drop_glue::{{impl}}[0]::drop[0] @@ local_drop_glue[External] fn drop(&mut self) {} } -//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue[Internal] struct Outer { _a: Struct } -//~ TRANS_ITEM fn local_drop_glue::user[0] @@ local_drop_glue[External] +//~ MONO_ITEM fn local_drop_glue::user[0] @@ local_drop_glue[External] pub fn user() { let _ = Outer { @@ -46,14 +46,14 @@ pub mod mod1 { use super::Struct; - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue-mod1[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue-mod1[Internal] struct Struct2 { _a: Struct, - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, local_drop_glue::Struct[0])> @@ local_drop_glue-mod1[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, local_drop_glue::Struct[0])> @@ local_drop_glue-mod1[Internal] _b: (u32, Struct), } - //~ TRANS_ITEM fn local_drop_glue::mod1[0]::user[0] @@ local_drop_glue-mod1[External] + //~ MONO_ITEM fn local_drop_glue::mod1[0]::user[0] @@ local_drop_glue-mod1[External] pub fn user() { let _ = Struct2 { diff --git a/src/test/codegen-units/partitioning/local-generic.rs b/src/test/codegen-units/partitioning/local-generic.rs index 33e3745502f..7c8ca20e1e3 100644 --- a/src/test/codegen-units/partitioning/local-generic.rs +++ b/src/test/codegen-units/partitioning/local-generic.rs @@ -11,18 +11,18 @@ // ignore-tidy-linelength // We specify -Z incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-trans-items=eager -Zincremental=tmp/partitioning-tests/local-generic +// compile-flags:-Zprint-mono-items=eager -Zincremental=tmp/partitioning-tests/local-generic #![allow(dead_code)] #![crate_type="lib"] -//~ TRANS_ITEM fn local_generic::generic[0] @@ local_generic.volatile[External] -//~ TRANS_ITEM fn local_generic::generic[0] @@ local_generic.volatile[External] -//~ TRANS_ITEM fn local_generic::generic[0] @@ local_generic.volatile[External] -//~ TRANS_ITEM fn local_generic::generic[0]<&str> @@ local_generic.volatile[External] +//~ MONO_ITEM fn local_generic::generic[0] @@ local_generic.volatile[External] +//~ MONO_ITEM fn local_generic::generic[0] @@ local_generic.volatile[External] +//~ MONO_ITEM fn local_generic::generic[0] @@ local_generic.volatile[External] +//~ MONO_ITEM fn local_generic::generic[0]<&str> @@ local_generic.volatile[External] pub fn generic(x: T) -> T { x } -//~ TRANS_ITEM fn local_generic::user[0] @@ local_generic[Internal] +//~ MONO_ITEM fn local_generic::user[0] @@ local_generic[Internal] fn user() { let _ = generic(0u32); } @@ -30,7 +30,7 @@ fn user() { mod mod1 { pub use super::generic; - //~ TRANS_ITEM fn local_generic::mod1[0]::user[0] @@ local_generic-mod1[Internal] + //~ MONO_ITEM fn local_generic::mod1[0]::user[0] @@ local_generic-mod1[Internal] fn user() { let _ = generic(0u64); } @@ -38,7 +38,7 @@ mod mod1 { mod mod1 { use super::generic; - //~ TRANS_ITEM fn local_generic::mod1[0]::mod1[0]::user[0] @@ local_generic-mod1-mod1[Internal] + //~ MONO_ITEM fn local_generic::mod1[0]::mod1[0]::user[0] @@ local_generic-mod1-mod1[Internal] fn user() { let _ = generic('c'); } @@ -48,7 +48,7 @@ mod mod1 { mod mod2 { use super::generic; - //~ TRANS_ITEM fn local_generic::mod2[0]::user[0] @@ local_generic-mod2[Internal] + //~ MONO_ITEM fn local_generic::mod2[0]::user[0] @@ local_generic-mod2[Internal] fn user() { let _ = generic("abc"); } diff --git a/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs index cf197301eec..747f768c11f 100644 --- a/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs +++ b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs @@ -11,7 +11,7 @@ // ignore-tidy-linelength // We specify -Z incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/local-inlining-but-not-all +// compile-flags:-Zprint-mono-items=lazy -Zincremental=tmp/partitioning-tests/local-inlining-but-not-all // compile-flags:-Zinline-in-all-cgus=no #![allow(dead_code)] @@ -19,7 +19,7 @@ mod inline { - //~ TRANS_ITEM fn local_inlining_but_not_all::inline[0]::inlined_function[0] @@ local_inlining_but_not_all-inline[External] + //~ MONO_ITEM fn local_inlining_but_not_all::inline[0]::inlined_function[0] @@ local_inlining_but_not_all-inline[External] #[inline] pub fn inlined_function() { @@ -30,7 +30,7 @@ mod inline { pub mod user1 { use super::inline; - //~ TRANS_ITEM fn local_inlining_but_not_all::user1[0]::foo[0] @@ local_inlining_but_not_all-user1[External] + //~ MONO_ITEM fn local_inlining_but_not_all::user1[0]::foo[0] @@ local_inlining_but_not_all-user1[External] pub fn foo() { inline::inlined_function(); } @@ -39,7 +39,7 @@ pub mod user1 { pub mod user2 { use super::inline; - //~ TRANS_ITEM fn local_inlining_but_not_all::user2[0]::bar[0] @@ local_inlining_but_not_all-user2[External] + //~ MONO_ITEM fn local_inlining_but_not_all::user2[0]::bar[0] @@ local_inlining_but_not_all-user2[External] pub fn bar() { inline::inlined_function(); } @@ -47,7 +47,7 @@ pub mod user2 { pub mod non_user { - //~ TRANS_ITEM fn local_inlining_but_not_all::non_user[0]::baz[0] @@ local_inlining_but_not_all-non_user[External] + //~ MONO_ITEM fn local_inlining_but_not_all::non_user[0]::baz[0] @@ local_inlining_but_not_all-non_user[External] pub fn baz() { } diff --git a/src/test/codegen-units/partitioning/local-inlining.rs b/src/test/codegen-units/partitioning/local-inlining.rs index 3502aa59fdc..f144f0d992b 100644 --- a/src/test/codegen-units/partitioning/local-inlining.rs +++ b/src/test/codegen-units/partitioning/local-inlining.rs @@ -11,7 +11,7 @@ // ignore-tidy-linelength // We specify -Z incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/local-inlining +// compile-flags:-Zprint-mono-items=lazy -Zincremental=tmp/partitioning-tests/local-inlining // compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] @@ -20,7 +20,7 @@ mod inline { // Important: This function should show up in all codegen units where it is inlined - //~ TRANS_ITEM fn local_inlining::inline[0]::inlined_function[0] @@ local_inlining-user1[Internal] local_inlining-user2[Internal] + //~ MONO_ITEM fn local_inlining::inline[0]::inlined_function[0] @@ local_inlining-user1[Internal] local_inlining-user2[Internal] #[inline(always)] pub fn inlined_function() { @@ -31,7 +31,7 @@ mod inline { pub mod user1 { use super::inline; - //~ TRANS_ITEM fn local_inlining::user1[0]::foo[0] @@ local_inlining-user1[External] + //~ MONO_ITEM fn local_inlining::user1[0]::foo[0] @@ local_inlining-user1[External] pub fn foo() { inline::inlined_function(); } @@ -40,7 +40,7 @@ pub mod user1 { pub mod user2 { use super::inline; - //~ TRANS_ITEM fn local_inlining::user2[0]::bar[0] @@ local_inlining-user2[External] + //~ MONO_ITEM fn local_inlining::user2[0]::bar[0] @@ local_inlining-user2[External] pub fn bar() { inline::inlined_function(); } @@ -48,7 +48,7 @@ pub mod user2 { pub mod non_user { - //~ TRANS_ITEM fn local_inlining::non_user[0]::baz[0] @@ local_inlining-non_user[External] + //~ MONO_ITEM fn local_inlining::non_user[0]::baz[0] @@ local_inlining-non_user[External] pub fn baz() { } diff --git a/src/test/codegen-units/partitioning/local-transitive-inlining.rs b/src/test/codegen-units/partitioning/local-transitive-inlining.rs index ed883954f3f..8637844a83d 100644 --- a/src/test/codegen-units/partitioning/local-transitive-inlining.rs +++ b/src/test/codegen-units/partitioning/local-transitive-inlining.rs @@ -11,7 +11,7 @@ // ignore-tidy-linelength // We specify -Z incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/local-transitive-inlining +// compile-flags:-Zprint-mono-items=lazy -Zincremental=tmp/partitioning-tests/local-transitive-inlining // compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] @@ -19,7 +19,7 @@ mod inline { - //~ TRANS_ITEM fn local_transitive_inlining::inline[0]::inlined_function[0] @@ local_transitive_inlining-indirect_user[Internal] + //~ MONO_ITEM fn local_transitive_inlining::inline[0]::inlined_function[0] @@ local_transitive_inlining-indirect_user[Internal] #[inline(always)] pub fn inlined_function() { @@ -30,7 +30,7 @@ mod inline { mod direct_user { use super::inline; - //~ TRANS_ITEM fn local_transitive_inlining::direct_user[0]::foo[0] @@ local_transitive_inlining-indirect_user[Internal] + //~ MONO_ITEM fn local_transitive_inlining::direct_user[0]::foo[0] @@ local_transitive_inlining-indirect_user[Internal] #[inline(always)] pub fn foo() { inline::inlined_function(); @@ -40,7 +40,7 @@ mod direct_user { pub mod indirect_user { use super::direct_user; - //~ TRANS_ITEM fn local_transitive_inlining::indirect_user[0]::bar[0] @@ local_transitive_inlining-indirect_user[External] + //~ MONO_ITEM fn local_transitive_inlining::indirect_user[0]::bar[0] @@ local_transitive_inlining-indirect_user[External] pub fn bar() { direct_user::foo(); } @@ -48,7 +48,7 @@ pub mod indirect_user { pub mod non_user { - //~ TRANS_ITEM fn local_transitive_inlining::non_user[0]::baz[0] @@ local_transitive_inlining-non_user[External] + //~ MONO_ITEM fn local_transitive_inlining::non_user[0]::baz[0] @@ local_transitive_inlining-non_user[External] pub fn baz() { } diff --git a/src/test/codegen-units/partitioning/methods-are-with-self-type.rs b/src/test/codegen-units/partitioning/methods-are-with-self-type.rs index aa01289de59..ff25a7194e0 100644 --- a/src/test/codegen-units/partitioning/methods-are-with-self-type.rs +++ b/src/test/codegen-units/partitioning/methods-are-with-self-type.rs @@ -16,7 +16,7 @@ // ignore-tidy-linelength // We specify -Z incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/methods-are-with-self-type +// compile-flags:-Zprint-mono-items=lazy -Zincremental=tmp/partitioning-tests/methods-are-with-self-type #![allow(dead_code)] #![feature(start)] @@ -31,10 +31,10 @@ mod mod1 { // Even though the impl is in `mod1`, the methods should end up in the // parent module, since that is where their self-type is. impl SomeType { - //~ TRANS_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[0]::method[0] @@ methods_are_with_self_type[External] + //~ MONO_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[0]::method[0] @@ methods_are_with_self_type[External] fn method(&self) {} - //~ TRANS_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[0]::associated_fn[0] @@ methods_are_with_self_type[External] + //~ MONO_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[0]::associated_fn[0] @@ methods_are_with_self_type[External] fn associated_fn() {} } @@ -64,25 +64,25 @@ mod type2 { pub struct Struct; } -//~ TRANS_ITEM fn methods_are_with_self_type::start[0] +//~ MONO_ITEM fn methods_are_with_self_type::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ TRANS_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[1]::method[0] @@ methods_are_with_self_type.volatile[WeakODR] + //~ MONO_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[1]::method[0] @@ methods_are_with_self_type.volatile[WeakODR] SomeGenericType(0u32, 0u64).method(); - //~ TRANS_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[1]::associated_fn[0] @@ methods_are_with_self_type.volatile[WeakODR] + //~ MONO_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[1]::associated_fn[0] @@ methods_are_with_self_type.volatile[WeakODR] SomeGenericType::associated_fn('c', "&str"); - //~ TRANS_ITEM fn methods_are_with_self_type::{{impl}}[0]::foo[0] @@ methods_are_with_self_type-type1.volatile[WeakODR] + //~ MONO_ITEM fn methods_are_with_self_type::{{impl}}[0]::foo[0] @@ methods_are_with_self_type-type1.volatile[WeakODR] type1::Struct.foo(); - //~ TRANS_ITEM fn methods_are_with_self_type::{{impl}}[0]::foo[0] @@ methods_are_with_self_type-type2.volatile[WeakODR] + //~ MONO_ITEM fn methods_are_with_self_type::{{impl}}[0]::foo[0] @@ methods_are_with_self_type-type2.volatile[WeakODR] type2::Struct.foo(); - //~ TRANS_ITEM fn methods_are_with_self_type::Trait[0]::default[0] @@ methods_are_with_self_type-type1.volatile[WeakODR] + //~ MONO_ITEM fn methods_are_with_self_type::Trait[0]::default[0] @@ methods_are_with_self_type-type1.volatile[WeakODR] type1::Struct.default(); - //~ TRANS_ITEM fn methods_are_with_self_type::Trait[0]::default[0] @@ methods_are_with_self_type-type2.volatile[WeakODR] + //~ MONO_ITEM fn methods_are_with_self_type::Trait[0]::default[0] @@ methods_are_with_self_type-type2.volatile[WeakODR] type2::Struct.default(); 0 } -//~ TRANS_ITEM drop-glue i8 +//~ MONO_ITEM drop-glue i8 diff --git a/src/test/codegen-units/partitioning/regular-modules.rs b/src/test/codegen-units/partitioning/regular-modules.rs index 9bdbc8b85e8..e1ec6f51b30 100644 --- a/src/test/codegen-units/partitioning/regular-modules.rs +++ b/src/test/codegen-units/partitioning/regular-modules.rs @@ -11,72 +11,72 @@ // ignore-tidy-linelength // We specify -Z incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-trans-items=eager -Zincremental=tmp/partitioning-tests/regular-modules +// compile-flags:-Zprint-mono-items=eager -Zincremental=tmp/partitioning-tests/regular-modules #![allow(dead_code)] #![crate_type="lib"] -//~ TRANS_ITEM fn regular_modules::foo[0] @@ regular_modules[Internal] +//~ MONO_ITEM fn regular_modules::foo[0] @@ regular_modules[Internal] fn foo() {} -//~ TRANS_ITEM fn regular_modules::bar[0] @@ regular_modules[Internal] +//~ MONO_ITEM fn regular_modules::bar[0] @@ regular_modules[Internal] fn bar() {} -//~ TRANS_ITEM static regular_modules::BAZ[0] @@ regular_modules[Internal] +//~ MONO_ITEM static regular_modules::BAZ[0] @@ regular_modules[Internal] static BAZ: u64 = 0; mod mod1 { - //~ TRANS_ITEM fn regular_modules::mod1[0]::foo[0] @@ regular_modules-mod1[Internal] + //~ MONO_ITEM fn regular_modules::mod1[0]::foo[0] @@ regular_modules-mod1[Internal] fn foo() {} - //~ TRANS_ITEM fn regular_modules::mod1[0]::bar[0] @@ regular_modules-mod1[Internal] + //~ MONO_ITEM fn regular_modules::mod1[0]::bar[0] @@ regular_modules-mod1[Internal] fn bar() {} - //~ TRANS_ITEM static regular_modules::mod1[0]::BAZ[0] @@ regular_modules-mod1[Internal] + //~ MONO_ITEM static regular_modules::mod1[0]::BAZ[0] @@ regular_modules-mod1[Internal] static BAZ: u64 = 0; mod mod1 { - //~ TRANS_ITEM fn regular_modules::mod1[0]::mod1[0]::foo[0] @@ regular_modules-mod1-mod1[Internal] + //~ MONO_ITEM fn regular_modules::mod1[0]::mod1[0]::foo[0] @@ regular_modules-mod1-mod1[Internal] fn foo() {} - //~ TRANS_ITEM fn regular_modules::mod1[0]::mod1[0]::bar[0] @@ regular_modules-mod1-mod1[Internal] + //~ MONO_ITEM fn regular_modules::mod1[0]::mod1[0]::bar[0] @@ regular_modules-mod1-mod1[Internal] fn bar() {} - //~ TRANS_ITEM static regular_modules::mod1[0]::mod1[0]::BAZ[0] @@ regular_modules-mod1-mod1[Internal] + //~ MONO_ITEM static regular_modules::mod1[0]::mod1[0]::BAZ[0] @@ regular_modules-mod1-mod1[Internal] static BAZ: u64 = 0; } mod mod2 { - //~ TRANS_ITEM fn regular_modules::mod1[0]::mod2[0]::foo[0] @@ regular_modules-mod1-mod2[Internal] + //~ MONO_ITEM fn regular_modules::mod1[0]::mod2[0]::foo[0] @@ regular_modules-mod1-mod2[Internal] fn foo() {} - //~ TRANS_ITEM fn regular_modules::mod1[0]::mod2[0]::bar[0] @@ regular_modules-mod1-mod2[Internal] + //~ MONO_ITEM fn regular_modules::mod1[0]::mod2[0]::bar[0] @@ regular_modules-mod1-mod2[Internal] fn bar() {} - //~ TRANS_ITEM static regular_modules::mod1[0]::mod2[0]::BAZ[0] @@ regular_modules-mod1-mod2[Internal] + //~ MONO_ITEM static regular_modules::mod1[0]::mod2[0]::BAZ[0] @@ regular_modules-mod1-mod2[Internal] static BAZ: u64 = 0; } } mod mod2 { - //~ TRANS_ITEM fn regular_modules::mod2[0]::foo[0] @@ regular_modules-mod2[Internal] + //~ MONO_ITEM fn regular_modules::mod2[0]::foo[0] @@ regular_modules-mod2[Internal] fn foo() {} - //~ TRANS_ITEM fn regular_modules::mod2[0]::bar[0] @@ regular_modules-mod2[Internal] + //~ MONO_ITEM fn regular_modules::mod2[0]::bar[0] @@ regular_modules-mod2[Internal] fn bar() {} - //~ TRANS_ITEM static regular_modules::mod2[0]::BAZ[0] @@ regular_modules-mod2[Internal] + //~ MONO_ITEM static regular_modules::mod2[0]::BAZ[0] @@ regular_modules-mod2[Internal] static BAZ: u64 = 0; mod mod1 { - //~ TRANS_ITEM fn regular_modules::mod2[0]::mod1[0]::foo[0] @@ regular_modules-mod2-mod1[Internal] + //~ MONO_ITEM fn regular_modules::mod2[0]::mod1[0]::foo[0] @@ regular_modules-mod2-mod1[Internal] fn foo() {} - //~ TRANS_ITEM fn regular_modules::mod2[0]::mod1[0]::bar[0] @@ regular_modules-mod2-mod1[Internal] + //~ MONO_ITEM fn regular_modules::mod2[0]::mod1[0]::bar[0] @@ regular_modules-mod2-mod1[Internal] fn bar() {} - //~ TRANS_ITEM static regular_modules::mod2[0]::mod1[0]::BAZ[0] @@ regular_modules-mod2-mod1[Internal] + //~ MONO_ITEM static regular_modules::mod2[0]::mod1[0]::BAZ[0] @@ regular_modules-mod2-mod1[Internal] static BAZ: u64 = 0; } mod mod2 { - //~ TRANS_ITEM fn regular_modules::mod2[0]::mod2[0]::foo[0] @@ regular_modules-mod2-mod2[Internal] + //~ MONO_ITEM fn regular_modules::mod2[0]::mod2[0]::foo[0] @@ regular_modules-mod2-mod2[Internal] fn foo() {} - //~ TRANS_ITEM fn regular_modules::mod2[0]::mod2[0]::bar[0] @@ regular_modules-mod2-mod2[Internal] + //~ MONO_ITEM fn regular_modules::mod2[0]::mod2[0]::bar[0] @@ regular_modules-mod2-mod2[Internal] fn bar() {} - //~ TRANS_ITEM static regular_modules::mod2[0]::mod2[0]::BAZ[0] @@ regular_modules-mod2-mod2[Internal] + //~ MONO_ITEM static regular_modules::mod2[0]::mod2[0]::BAZ[0] @@ regular_modules-mod2-mod2[Internal] static BAZ: u64 = 0; } } diff --git a/src/test/codegen-units/partitioning/shared-generics.rs b/src/test/codegen-units/partitioning/shared-generics.rs index d352609bfcb..880361fac2e 100644 --- a/src/test/codegen-units/partitioning/shared-generics.rs +++ b/src/test/codegen-units/partitioning/shared-generics.rs @@ -9,17 +9,17 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager -Zshare-generics=yes -Zincremental=tmp/partitioning-tests/shared-generics-exe +// compile-flags:-Zprint-mono-items=eager -Zshare-generics=yes -Zincremental=tmp/partitioning-tests/shared-generics-exe #![crate_type="rlib"] // aux-build:shared_generics_aux.rs extern crate shared_generics_aux; -//~ TRANS_ITEM fn shared_generics::foo[0] +//~ MONO_ITEM fn shared_generics::foo[0] pub fn foo() { - //~ TRANS_ITEM fn shared_generics_aux::generic_fn[0] @@ shared_generics_aux.volatile[External] + //~ MONO_ITEM fn shared_generics_aux::generic_fn[0] @@ shared_generics_aux.volatile[External] let _ = shared_generics_aux::generic_fn(0u16, 1u16); // This should not generate a monomorphization because it's already @@ -27,4 +27,4 @@ pub fn foo() { let _ = shared_generics_aux::generic_fn(0.0f32, 3.0f32); } -// TRANS_ITEM drop-glue i8 +// MONO_ITEM drop-glue i8 diff --git a/src/test/codegen-units/partitioning/statics.rs b/src/test/codegen-units/partitioning/statics.rs index 12ef34441ff..b6c1e5210da 100644 --- a/src/test/codegen-units/partitioning/statics.rs +++ b/src/test/codegen-units/partitioning/statics.rs @@ -11,38 +11,38 @@ // ignore-tidy-linelength // We specify -Z incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/statics +// compile-flags:-Zprint-mono-items=lazy -Zincremental=tmp/partitioning-tests/statics #![crate_type="rlib"] -//~ TRANS_ITEM static statics::FOO[0] @@ statics[Internal] +//~ MONO_ITEM static statics::FOO[0] @@ statics[Internal] static FOO: u32 = 0; -//~ TRANS_ITEM static statics::BAR[0] @@ statics[Internal] +//~ MONO_ITEM static statics::BAR[0] @@ statics[Internal] static BAR: u32 = 0; -//~ TRANS_ITEM fn statics::function[0] @@ statics[External] +//~ MONO_ITEM fn statics::function[0] @@ statics[External] pub fn function() { - //~ TRANS_ITEM static statics::function[0]::FOO[0] @@ statics[Internal] + //~ MONO_ITEM static statics::function[0]::FOO[0] @@ statics[Internal] static FOO: u32 = 0; - //~ TRANS_ITEM static statics::function[0]::BAR[0] @@ statics[Internal] + //~ MONO_ITEM static statics::function[0]::BAR[0] @@ statics[Internal] static BAR: u32 = 0; } pub mod mod1 { - //~ TRANS_ITEM static statics::mod1[0]::FOO[0] @@ statics-mod1[Internal] + //~ MONO_ITEM static statics::mod1[0]::FOO[0] @@ statics-mod1[Internal] static FOO: u32 = 0; - //~ TRANS_ITEM static statics::mod1[0]::BAR[0] @@ statics-mod1[Internal] + //~ MONO_ITEM static statics::mod1[0]::BAR[0] @@ statics-mod1[Internal] static BAR: u32 = 0; - //~ TRANS_ITEM fn statics::mod1[0]::function[0] @@ statics-mod1[External] + //~ MONO_ITEM fn statics::mod1[0]::function[0] @@ statics-mod1[External] pub fn function() { - //~ TRANS_ITEM static statics::mod1[0]::function[0]::FOO[0] @@ statics-mod1[Internal] + //~ MONO_ITEM static statics::mod1[0]::function[0]::FOO[0] @@ statics-mod1[Internal] static FOO: u32 = 0; - //~ TRANS_ITEM static statics::mod1[0]::function[0]::BAR[0] @@ statics-mod1[Internal] + //~ MONO_ITEM static statics::mod1[0]::function[0]::BAR[0] @@ statics-mod1[Internal] static BAR: u32 = 0; } } diff --git a/src/test/codegen-units/partitioning/vtable-through-const.rs b/src/test/codegen-units/partitioning/vtable-through-const.rs index d0acddda637..74533c1015b 100644 --- a/src/test/codegen-units/partitioning/vtable-through-const.rs +++ b/src/test/codegen-units/partitioning/vtable-through-const.rs @@ -12,7 +12,7 @@ // We specify -Z incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/vtable-through-const +// compile-flags:-Zprint-mono-items=lazy -Zincremental=tmp/partitioning-tests/vtable-through-const // compile-flags:-Zinline-in-all-cgus // This test case makes sure, that references made through constants are @@ -40,7 +40,7 @@ mod mod1 { fn id(x: T) -> T { x } - // These are referenced, so they produce trans-items (see start()) + // These are referenced, so they produce mono-items (see start()) pub const TRAIT1_REF: &'static Trait1 = &0u32 as &Trait1; pub const TRAIT1_GEN_REF: &'static Trait1Gen = &0u32 as &Trait1Gen; pub const ID_CHAR: fn(char) -> char = id::; @@ -64,34 +64,34 @@ mod mod1 { fn do_something_else(&self, x: T) -> T { x } } - // These are not referenced, so they do not produce trans-items + // These are not referenced, so they do not produce mono-items pub const TRAIT2_REF: &'static Trait2 = &0u32 as &Trait2; pub const TRAIT2_GEN_REF: &'static Trait2Gen = &0u32 as &Trait2Gen; pub const ID_I64: fn(i64) -> i64 = id::; } -//~ TRANS_ITEM fn vtable_through_const::start[0] +//~ MONO_ITEM fn vtable_through_const::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0] @@ vtable_through_const[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ vtable_through_const[Internal] // Since Trait1::do_something() is instantiated via its default implementation, // it is considered a generic and is instantiated here only because it is // referenced in this module. - //~ TRANS_ITEM fn vtable_through_const::mod1[0]::Trait1[0]::do_something_else[0] @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn vtable_through_const::mod1[0]::Trait1[0]::do_something_else[0] @@ vtable_through_const-mod1.volatile[External] // Although it is never used, Trait1::do_something_else() has to be // instantiated locally here too, otherwise the <&u32 as &Trait1> vtable // could not be fully constructed. - //~ TRANS_ITEM fn vtable_through_const::mod1[0]::Trait1[0]::do_something[0] @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn vtable_through_const::mod1[0]::Trait1[0]::do_something[0] @@ vtable_through_const-mod1.volatile[External] mod1::TRAIT1_REF.do_something(); // Same as above - //~ TRANS_ITEM fn vtable_through_const::mod1[0]::{{impl}}[1]::do_something[0] @@ vtable_through_const-mod1.volatile[External] - //~ TRANS_ITEM fn vtable_through_const::mod1[0]::{{impl}}[1]::do_something_else[0] @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn vtable_through_const::mod1[0]::{{impl}}[1]::do_something[0] @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn vtable_through_const::mod1[0]::{{impl}}[1]::do_something_else[0] @@ vtable_through_const-mod1.volatile[External] mod1::TRAIT1_GEN_REF.do_something(0u8); - //~ TRANS_ITEM fn vtable_through_const::mod1[0]::id[0] @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn vtable_through_const::mod1[0]::id[0] @@ vtable_through_const-mod1.volatile[External] mod1::ID_CHAR('x'); 0 diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs index 8bd759b6d37..f6a64bcba21 100644 --- a/src/test/compile-fail/const-err.rs +++ b/src/test/compile-fail/const-err.rs @@ -10,7 +10,7 @@ // compile-flags: -Zforce-overflow-checks=on -// these errors are not actually "const_err", they occur in trans/consts +// these errors are not actually "const_err", they occur in codegen/consts // and are unconditional warnings that can't be denied or allowed #![allow(exceeding_bitshifts)] diff --git a/src/test/compile-fail/const-eval-overflow2.rs b/src/test/compile-fail/const-eval-overflow2.rs index faa8c3039b7..7b5db7a4f6d 100644 --- a/src/test/compile-fail/const-eval-overflow2.rs +++ b/src/test/compile-fail/const-eval-overflow2.rs @@ -11,7 +11,7 @@ #![allow(unused_imports)] // Note: the relevant lint pass here runs before some of the constant -// evaluation below (e.g. that performed by trans and llvm), so if you +// evaluation below (e.g. that performed by codegen and llvm), so if you // change this warn to a deny, then the compiler will exit before // those errors are detected. diff --git a/src/test/compile-fail/const-eval-overflow2b.rs b/src/test/compile-fail/const-eval-overflow2b.rs index d827e680c5b..ce4dc72555d 100644 --- a/src/test/compile-fail/const-eval-overflow2b.rs +++ b/src/test/compile-fail/const-eval-overflow2b.rs @@ -11,7 +11,7 @@ #![allow(unused_imports)] // Note: the relevant lint pass here runs before some of the constant -// evaluation below (e.g. that performed by trans and llvm), so if you +// evaluation below (e.g. that performed by codegen and llvm), so if you // change this warn to a deny, then the compiler will exit before // those errors are detected. diff --git a/src/test/compile-fail/const-eval-overflow2c.rs b/src/test/compile-fail/const-eval-overflow2c.rs index 2fd46b038ef..88eb14a1330 100644 --- a/src/test/compile-fail/const-eval-overflow2c.rs +++ b/src/test/compile-fail/const-eval-overflow2c.rs @@ -11,7 +11,7 @@ #![allow(unused_imports)] // Note: the relevant lint pass here runs before some of the constant -// evaluation below (e.g. that performed by trans and llvm), so if you +// evaluation below (e.g. that performed by codegen and llvm), so if you // change this warn to a deny, then the compiler will exit before // those errors are detected. diff --git a/src/test/compile-fail/dep-graph-assoc-type-codegen.rs b/src/test/compile-fail/dep-graph-assoc-type-codegen.rs new file mode 100644 index 00000000000..c20cfbc7e23 --- /dev/null +++ b/src/test/compile-fail/dep-graph-assoc-type-codegen.rs @@ -0,0 +1,47 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that when a trait impl changes, fns whose body uses that trait +// must also be recompiled. + +// compile-flags: -Z query-dep-graph + +#![feature(rustc_attrs)] +#![allow(warnings)] + +fn main() { } + +pub trait Foo: Sized { + type T; + fn method(self) { } +} + +mod x { + use Foo; + + #[rustc_if_this_changed] + impl Foo for char { type T = char; } + + impl Foo for u32 { type T = u32; } +} + +mod y { + use Foo; + + #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + pub fn use_char_assoc() { + // Careful here: in the representation, ::T gets + // normalized away, so at a certain point we had no edge to + // codegen. (But now codegen just depends on typeck.) + let x: ::T = 'a'; + } + + pub fn take_foo(t: T) { } +} diff --git a/src/test/compile-fail/dep-graph-assoc-type-trans.rs b/src/test/compile-fail/dep-graph-assoc-type-trans.rs deleted file mode 100644 index 007a80008a8..00000000000 --- a/src/test/compile-fail/dep-graph-assoc-type-trans.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that when a trait impl changes, fns whose body uses that trait -// must also be recompiled. - -// compile-flags: -Z query-dep-graph - -#![feature(rustc_attrs)] -#![allow(warnings)] - -fn main() { } - -pub trait Foo: Sized { - type T; - fn method(self) { } -} - -mod x { - use Foo; - - #[rustc_if_this_changed] - impl Foo for char { type T = char; } - - impl Foo for u32 { type T = u32; } -} - -mod y { - use Foo; - - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - pub fn use_char_assoc() { - // Careful here: in the representation, ::T gets - // normalized away, so at a certain point we had no edge to - // trans. (But now trans just depends on typeck.) - let x: ::T = 'a'; - } - - pub fn take_foo(t: T) { } -} diff --git a/src/test/debuginfo/struct-with-destructor.rs b/src/test/debuginfo/struct-with-destructor.rs index af70b4a63fd..ab935a07d65 100644 --- a/src/test/debuginfo/struct-with-destructor.rs +++ b/src/test/debuginfo/struct-with-destructor.rs @@ -91,7 +91,7 @@ struct NestedOuter { // The compiler adds a 'destructed' boolean field to structs implementing Drop. This field is used -// at runtime to prevent drop() to be executed more than once (see middle::trans::adt). +// at runtime to prevent drop() to be executed more than once. // This field must be incorporated by the debug info generation. Otherwise the debugger assumes a // wrong size/layout for the struct. fn main() { diff --git a/src/test/debuginfo/var-captured-in-sendable-closure.rs b/src/test/debuginfo/var-captured-in-sendable-closure.rs index 120bbdd7ba9..9aeb3bc9133 100644 --- a/src/test/debuginfo/var-captured-in-sendable-closure.rs +++ b/src/test/debuginfo/var-captured-in-sendable-closure.rs @@ -72,7 +72,7 @@ fn main() { let constant2 = 6_usize; // The `self` argument of the following closure should be passed by value - // to FnOnce::call_once(self, args), which gets translated a bit differently + // to FnOnce::call_once(self, args), which gets codegened a bit differently // than the regular case. Let's make sure this is supported too. let immedate_env = move || { zzz(); // #break diff --git a/src/test/incremental/cache_file_headers.rs b/src/test/incremental/cache_file_headers.rs index feecfecd0b8..02ee06b4cf4 100644 --- a/src/test/incremental/cache_file_headers.rs +++ b/src/test/incremental/cache_file_headers.rs @@ -13,7 +13,7 @@ // different compiler version. This is tested by artificially forcing the // emission of a different compiler version in the header of rpass1 artifacts, // and then making sure that the only object file of the test program gets -// re-translated although the program stays unchanged. +// re-codegened although the program stays unchanged. // The `l33t haxx0r` Rust compiler is known to produce incr. comp. artifacts // that are outrageously incompatible with just about anything, even itself: @@ -23,7 +23,7 @@ // compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] -#![rustc_partition_translated(module="cache_file_headers", cfg="rpass2")] +#![rustc_partition_codegened(module="cache_file_headers", cfg="rpass2")] fn main() { // empty diff --git a/src/test/incremental/change_add_field/struct_point.rs b/src/test/incremental/change_add_field/struct_point.rs index da3b9e4d6d6..37d1a397303 100644 --- a/src/test/incremental/change_add_field/struct_point.rs +++ b/src/test/incremental/change_add_field/struct_point.rs @@ -22,14 +22,14 @@ #![allow(dead_code)] #![crate_type = "rlib"] -// These are expected to require translation. -#![rustc_partition_translated(module="struct_point-point", cfg="cfail2")] -#![rustc_partition_translated(module="struct_point-fn_with_type_in_sig", cfg="cfail2")] -#![rustc_partition_translated(module="struct_point-call_fn_with_type_in_sig", cfg="cfail2")] -#![rustc_partition_translated(module="struct_point-fn_with_type_in_body", cfg="cfail2")] -#![rustc_partition_translated(module="struct_point-fn_make_struct", cfg="cfail2")] -#![rustc_partition_translated(module="struct_point-fn_read_field", cfg="cfail2")] -#![rustc_partition_translated(module="struct_point-fn_write_field", cfg="cfail2")] +// These are expected to require codegen. +#![rustc_partition_codegened(module="struct_point-point", cfg="cfail2")] +#![rustc_partition_codegened(module="struct_point-fn_with_type_in_sig", cfg="cfail2")] +#![rustc_partition_codegened(module="struct_point-call_fn_with_type_in_sig", cfg="cfail2")] +#![rustc_partition_codegened(module="struct_point-fn_with_type_in_body", cfg="cfail2")] +#![rustc_partition_codegened(module="struct_point-fn_make_struct", cfg="cfail2")] +#![rustc_partition_codegened(module="struct_point-fn_read_field", cfg="cfail2")] +#![rustc_partition_codegened(module="struct_point-fn_write_field", cfg="cfail2")] #![rustc_partition_reused(module="struct_point-call_fn_with_type_in_body", cfg="cfail2")] diff --git a/src/test/incremental/change_private_fn/struct_point.rs b/src/test/incremental/change_private_fn/struct_point.rs index 63e137a7e0b..d1b8399dbda 100644 --- a/src/test/incremental/change_private_fn/struct_point.rs +++ b/src/test/incremental/change_private_fn/struct_point.rs @@ -20,7 +20,7 @@ #![allow(dead_code)] #![crate_type = "rlib"] -#![rustc_partition_translated(module="struct_point-point", cfg="cfail2")] +#![rustc_partition_codegened(module="struct_point-point", cfg="cfail2")] #![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="cfail2")] #![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="cfail2")] diff --git a/src/test/incremental/change_private_impl_method/struct_point.rs b/src/test/incremental/change_private_impl_method/struct_point.rs index 7f2dd81d0ea..cf6eefd61d7 100644 --- a/src/test/incremental/change_private_impl_method/struct_point.rs +++ b/src/test/incremental/change_private_impl_method/struct_point.rs @@ -20,7 +20,7 @@ #![allow(dead_code)] #![crate_type = "rlib"] -#![rustc_partition_translated(module="struct_point-point", cfg="cfail2")] +#![rustc_partition_codegened(module="struct_point-point", cfg="cfail2")] #![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="cfail2")] #![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="cfail2")] diff --git a/src/test/incremental/change_pub_inherent_method_body/struct_point.rs b/src/test/incremental/change_pub_inherent_method_body/struct_point.rs index 412fe72e4e4..a204fe27da6 100644 --- a/src/test/incremental/change_pub_inherent_method_body/struct_point.rs +++ b/src/test/incremental/change_pub_inherent_method_body/struct_point.rs @@ -19,7 +19,7 @@ #![feature(stmt_expr_attributes)] #![allow(dead_code)] -#![rustc_partition_translated(module="struct_point-point", cfg="cfail2")] +#![rustc_partition_codegened(module="struct_point-point", cfg="cfail2")] #![rustc_partition_reused(module="struct_point-fn_calls_changed_method", cfg="cfail2")] #![rustc_partition_reused(module="struct_point-fn_calls_another_method", cfg="cfail2")] diff --git a/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs b/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs index c82f4645caf..76c9dfce93d 100644 --- a/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs +++ b/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs @@ -19,9 +19,9 @@ #![feature(stmt_expr_attributes)] #![allow(dead_code)] -// These are expected to require translation. -#![rustc_partition_translated(module="struct_point-point", cfg="cfail2")] -#![rustc_partition_translated(module="struct_point-fn_calls_changed_method", cfg="cfail2")] +// These are expected to require codegen. +#![rustc_partition_codegened(module="struct_point-point", cfg="cfail2")] +#![rustc_partition_codegened(module="struct_point-fn_calls_changed_method", cfg="cfail2")] #![rustc_partition_reused(module="struct_point-fn_calls_another_method", cfg="cfail2")] #![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="cfail2")] diff --git a/src/test/incremental/change_symbol_export_status.rs b/src/test/incremental/change_symbol_export_status.rs index ab91a941a16..feb8026f501 100644 --- a/src/test/incremental/change_symbol_export_status.rs +++ b/src/test/incremental/change_symbol_export_status.rs @@ -14,7 +14,7 @@ #![feature(rustc_attrs)] #![allow(private_no_mangle_fns)] -#![rustc_partition_translated(module="change_symbol_export_status-mod1", cfg="rpass2")] +#![rustc_partition_codegened(module="change_symbol_export_status-mod1", cfg="rpass2")] #![rustc_partition_reused(module="change_symbol_export_status-mod2", cfg="rpass2")] // This test case makes sure that a change in symbol visibility is detected by diff --git a/src/test/incremental/commandline-args.rs b/src/test/incremental/commandline-args.rs index e29f2ec2a13..bb2f385e9c5 100644 --- a/src/test/incremental/commandline-args.rs +++ b/src/test/incremental/commandline-args.rs @@ -16,7 +16,7 @@ #![feature(rustc_attrs)] -#![rustc_partition_translated(module="commandline_args", cfg="rpass2")] +#![rustc_partition_codegened(module="commandline_args", cfg="rpass2")] #![rustc_partition_reused(module="commandline_args", cfg="rpass3")] // Between revisions 1 and 2, we are changing the debuginfo-level, which should diff --git a/src/test/incremental/inlined_hir_34991/main.rs b/src/test/incremental/inlined_hir_34991/main.rs index a150a8c4df7..baf4ae73932 100644 --- a/src/test/incremental/inlined_hir_34991/main.rs +++ b/src/test/incremental/inlined_hir_34991/main.rs @@ -10,7 +10,7 @@ // Regression test for #34991: an ICE occurred here because we inline // some of the vector routines and give them a local def-id `X`. This -// got hashed after trans (`Hir(X)`). When we load back up, we get an +// got hashed after codegen (`Hir(X)`). When we load back up, we get an // error because the `X` is remapped to the original def-id (in // libstd), and we can't hash a HIR node from std. diff --git a/src/test/incremental/issue-38222.rs b/src/test/incremental/issue-38222.rs index f890672aa8f..a19de6ef636 100644 --- a/src/test/incremental/issue-38222.rs +++ b/src/test/incremental/issue-38222.rs @@ -20,7 +20,7 @@ #![rustc_partition_reused(module="issue_38222-mod1", cfg="rpass2")] -// If trans had added a dependency edge to the Krate dep-node, nothing would +// If codegen had added a dependency edge to the Krate dep-node, nothing would // be re-used, so checking that this module was re-used is sufficient. #![rustc_partition_reused(module="issue_38222", cfg="rpass2")] diff --git a/src/test/incremental/issue-49595/issue_49595.rs b/src/test/incremental/issue-49595/issue_49595.rs index a5b0101c68f..dfa92d425f4 100644 --- a/src/test/incremental/issue-49595/issue_49595.rs +++ b/src/test/incremental/issue-49595/issue_49595.rs @@ -15,8 +15,8 @@ #![feature(rustc_attrs)] #![crate_type = "rlib"] -#![rustc_partition_translated(module="issue_49595-tests", cfg="cfail2")] -#![rustc_partition_translated(module="issue_49595-lit_test", cfg="cfail3")] +#![rustc_partition_codegened(module="issue_49595-tests", cfg="cfail2")] +#![rustc_partition_codegened(module="issue_49595-lit_test", cfg="cfail3")] mod tests { #[cfg_attr(not(cfail1), ignore)] diff --git a/src/test/incremental/remapped_paths_cc/main.rs b/src/test/incremental/remapped_paths_cc/main.rs index ce7f5792cea..cd66310dafe 100644 --- a/src/test/incremental/remapped_paths_cc/main.rs +++ b/src/test/incremental/remapped_paths_cc/main.rs @@ -20,7 +20,7 @@ #![rustc_partition_reused(module="main", cfg="rpass2")] #![rustc_partition_reused(module="main-some_mod", cfg="rpass2")] #![rustc_partition_reused(module="main", cfg="rpass3")] -#![rustc_partition_translated(module="main-some_mod", cfg="rpass3")] +#![rustc_partition_codegened(module="main-some_mod", cfg="rpass3")] extern crate extern_crate; diff --git a/src/test/incremental/spike-neg1.rs b/src/test/incremental/spike-neg1.rs index b00c68a184e..d4701b9a66e 100644 --- a/src/test/incremental/spike-neg1.rs +++ b/src/test/incremental/spike-neg1.rs @@ -9,7 +9,7 @@ // except according to those terms. // A variant of the first "spike" test that serves to test the -// `rustc_partition_reused` and `rustc_partition_translated` tests. +// `rustc_partition_reused` and `rustc_partition_codegened` tests. // Here we change and say that the `x` module will be reused (when in // fact it will not), and then indicate that the test itself // should-fail (because an error will be reported, and hence the diff --git a/src/test/incremental/spike-neg2.rs b/src/test/incremental/spike-neg2.rs index 472d11d7f90..da79237b1a6 100644 --- a/src/test/incremental/spike-neg2.rs +++ b/src/test/incremental/spike-neg2.rs @@ -9,8 +9,8 @@ // except according to those terms. // A variant of the first "spike" test that serves to test the -// `rustc_partition_reused` and `rustc_partition_translated` tests. -// Here we change and say that the `y` module will be translated (when +// `rustc_partition_reused` and `rustc_partition_codegened` tests. +// Here we change and say that the `y` module will be codegened (when // in fact it will not), and then indicate that the test itself // should-fail (because an error will be reported, and hence the // revision rpass2 will not compile, despite being named rpass). @@ -21,8 +21,8 @@ #![feature(rustc_attrs)] #![rustc_partition_reused(module="spike_neg2", cfg="rpass2")] -#![rustc_partition_translated(module="spike_neg2-x", cfg="rpass2")] -#![rustc_partition_translated(module="spike_neg2-y", cfg="rpass2")] // this is wrong! +#![rustc_partition_codegened(module="spike_neg2-x", cfg="rpass2")] +#![rustc_partition_codegened(module="spike_neg2-y", cfg="rpass2")] // this is wrong! mod x { pub struct X { diff --git a/src/test/incremental/spike.rs b/src/test/incremental/spike.rs index a820471b7d5..1756511dd37 100644 --- a/src/test/incremental/spike.rs +++ b/src/test/incremental/spike.rs @@ -18,7 +18,7 @@ #![feature(rustc_attrs)] #![rustc_partition_reused(module="spike", cfg="rpass2")] -#![rustc_partition_translated(module="spike-x", cfg="rpass2")] +#![rustc_partition_codegened(module="spike-x", cfg="rpass2")] #![rustc_partition_reused(module="spike-y", cfg="rpass2")] mod x { diff --git a/src/test/run-fail/mir_codegen_calls_converging_drops.rs b/src/test/run-fail/mir_codegen_calls_converging_drops.rs new file mode 100644 index 00000000000..9c851eb7346 --- /dev/null +++ b/src/test/run-fail/mir_codegen_calls_converging_drops.rs @@ -0,0 +1,34 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern:converging_fn called +// error-pattern:0 dropped +// error-pattern:exit + +struct Droppable(u8); +impl Drop for Droppable { + fn drop(&mut self) { + eprintln!("{} dropped", self.0); + } +} + +fn converging_fn() { + eprintln!("converging_fn called"); +} + +fn mir(d: Droppable) { + converging_fn(); +} + +fn main() { + let d = Droppable(0); + mir(d); + panic!("exit"); +} diff --git a/src/test/run-fail/mir_codegen_calls_converging_drops_2.rs b/src/test/run-fail/mir_codegen_calls_converging_drops_2.rs new file mode 100644 index 00000000000..6f105211556 --- /dev/null +++ b/src/test/run-fail/mir_codegen_calls_converging_drops_2.rs @@ -0,0 +1,38 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern:complex called +// error-pattern:dropped +// error-pattern:exit + +struct Droppable; +impl Drop for Droppable { + fn drop(&mut self) { + eprintln!("dropped"); + } +} + +// return value of this function is copied into the return slot +fn complex() -> u64 { + eprintln!("complex called"); + 42 +} + + +fn mir() -> u64 { + let x = Droppable; + return complex(); + drop(x); +} + +pub fn main() { + assert_eq!(mir(), 42); + panic!("exit"); +} diff --git a/src/test/run-fail/mir_codegen_calls_diverging.rs b/src/test/run-fail/mir_codegen_calls_diverging.rs new file mode 100644 index 00000000000..9dbf7de0d2d --- /dev/null +++ b/src/test/run-fail/mir_codegen_calls_diverging.rs @@ -0,0 +1,23 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern:diverging_fn called + +fn diverging_fn() -> ! { + panic!("diverging_fn called") +} + +fn mir() { + diverging_fn(); +} + +fn main() { + mir(); +} diff --git a/src/test/run-fail/mir_codegen_calls_diverging_drops.rs b/src/test/run-fail/mir_codegen_calls_diverging_drops.rs new file mode 100644 index 00000000000..f8fbe8f79cc --- /dev/null +++ b/src/test/run-fail/mir_codegen_calls_diverging_drops.rs @@ -0,0 +1,32 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern:diverging_fn called +// error-pattern:0 dropped + +struct Droppable(u8); +impl Drop for Droppable { + fn drop(&mut self) { + eprintln!("{} dropped", self.0); + } +} + +fn diverging_fn() -> ! { + panic!("diverging_fn called") +} + +fn mir(d: Droppable) { + diverging_fn(); +} + +fn main() { + let d = Droppable(0); + mir(d); +} diff --git a/src/test/run-fail/mir_codegen_no_landing_pads.rs b/src/test/run-fail/mir_codegen_no_landing_pads.rs new file mode 100644 index 00000000000..aded2739b10 --- /dev/null +++ b/src/test/run-fail/mir_codegen_no_landing_pads.rs @@ -0,0 +1,37 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z no-landing-pads -C codegen-units=1 +// error-pattern:converging_fn called +// ignore-cloudabi no std::process + +use std::io::{self, Write}; + +struct Droppable; +impl Drop for Droppable { + fn drop(&mut self) { + ::std::process::exit(1) + } +} + +fn converging_fn() { + panic!("converging_fn called") +} + +fn mir(d: Droppable) { + let x = Droppable; + converging_fn(); + drop(x); + drop(d); +} + +fn main() { + mir(Droppable); +} diff --git a/src/test/run-fail/mir_codegen_no_landing_pads_diverging.rs b/src/test/run-fail/mir_codegen_no_landing_pads_diverging.rs new file mode 100644 index 00000000000..d3a8613bbc4 --- /dev/null +++ b/src/test/run-fail/mir_codegen_no_landing_pads_diverging.rs @@ -0,0 +1,37 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z no-landing-pads -C codegen-units=1 +// error-pattern:diverging_fn called +// ignore-cloudabi no std::process + +use std::io::{self, Write}; + +struct Droppable; +impl Drop for Droppable { + fn drop(&mut self) { + ::std::process::exit(1) + } +} + +fn diverging_fn() -> ! { + panic!("diverging_fn called") +} + +fn mir(d: Droppable) { + let x = Droppable; + diverging_fn(); + drop(x); + drop(d); +} + +fn main() { + mir(Droppable); +} diff --git a/src/test/run-fail/mir_trans_calls_converging_drops.rs b/src/test/run-fail/mir_trans_calls_converging_drops.rs deleted file mode 100644 index 9c851eb7346..00000000000 --- a/src/test/run-fail/mir_trans_calls_converging_drops.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:converging_fn called -// error-pattern:0 dropped -// error-pattern:exit - -struct Droppable(u8); -impl Drop for Droppable { - fn drop(&mut self) { - eprintln!("{} dropped", self.0); - } -} - -fn converging_fn() { - eprintln!("converging_fn called"); -} - -fn mir(d: Droppable) { - converging_fn(); -} - -fn main() { - let d = Droppable(0); - mir(d); - panic!("exit"); -} diff --git a/src/test/run-fail/mir_trans_calls_converging_drops_2.rs b/src/test/run-fail/mir_trans_calls_converging_drops_2.rs deleted file mode 100644 index 6f105211556..00000000000 --- a/src/test/run-fail/mir_trans_calls_converging_drops_2.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:complex called -// error-pattern:dropped -// error-pattern:exit - -struct Droppable; -impl Drop for Droppable { - fn drop(&mut self) { - eprintln!("dropped"); - } -} - -// return value of this function is copied into the return slot -fn complex() -> u64 { - eprintln!("complex called"); - 42 -} - - -fn mir() -> u64 { - let x = Droppable; - return complex(); - drop(x); -} - -pub fn main() { - assert_eq!(mir(), 42); - panic!("exit"); -} diff --git a/src/test/run-fail/mir_trans_calls_diverging.rs b/src/test/run-fail/mir_trans_calls_diverging.rs deleted file mode 100644 index 9dbf7de0d2d..00000000000 --- a/src/test/run-fail/mir_trans_calls_diverging.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:diverging_fn called - -fn diverging_fn() -> ! { - panic!("diverging_fn called") -} - -fn mir() { - diverging_fn(); -} - -fn main() { - mir(); -} diff --git a/src/test/run-fail/mir_trans_calls_diverging_drops.rs b/src/test/run-fail/mir_trans_calls_diverging_drops.rs deleted file mode 100644 index f8fbe8f79cc..00000000000 --- a/src/test/run-fail/mir_trans_calls_diverging_drops.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:diverging_fn called -// error-pattern:0 dropped - -struct Droppable(u8); -impl Drop for Droppable { - fn drop(&mut self) { - eprintln!("{} dropped", self.0); - } -} - -fn diverging_fn() -> ! { - panic!("diverging_fn called") -} - -fn mir(d: Droppable) { - diverging_fn(); -} - -fn main() { - let d = Droppable(0); - mir(d); -} diff --git a/src/test/run-fail/mir_trans_no_landing_pads.rs b/src/test/run-fail/mir_trans_no_landing_pads.rs deleted file mode 100644 index aded2739b10..00000000000 --- a/src/test/run-fail/mir_trans_no_landing_pads.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: -Z no-landing-pads -C codegen-units=1 -// error-pattern:converging_fn called -// ignore-cloudabi no std::process - -use std::io::{self, Write}; - -struct Droppable; -impl Drop for Droppable { - fn drop(&mut self) { - ::std::process::exit(1) - } -} - -fn converging_fn() { - panic!("converging_fn called") -} - -fn mir(d: Droppable) { - let x = Droppable; - converging_fn(); - drop(x); - drop(d); -} - -fn main() { - mir(Droppable); -} diff --git a/src/test/run-fail/mir_trans_no_landing_pads_diverging.rs b/src/test/run-fail/mir_trans_no_landing_pads_diverging.rs deleted file mode 100644 index d3a8613bbc4..00000000000 --- a/src/test/run-fail/mir_trans_no_landing_pads_diverging.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: -Z no-landing-pads -C codegen-units=1 -// error-pattern:diverging_fn called -// ignore-cloudabi no std::process - -use std::io::{self, Write}; - -struct Droppable; -impl Drop for Droppable { - fn drop(&mut self) { - ::std::process::exit(1) - } -} - -fn diverging_fn() -> ! { - panic!("diverging_fn called") -} - -fn mir(d: Droppable) { - let x = Droppable; - diverging_fn(); - drop(x); - drop(d); -} - -fn main() { - mir(Droppable); -} diff --git a/src/test/run-fail/rhs-type.rs b/src/test/run-fail/rhs-type.rs index e16ce9c8edb..572b56d02ae 100644 --- a/src/test/run-fail/rhs-type.rs +++ b/src/test/run-fail/rhs-type.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Tests that trans treats the rhs of pth's decl +// Tests that codegen treats the rhs of pth's decl // as a _|_-typed thing, not a str-typed thing // error-pattern:bye diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs index e266b0f5e83..251fb78a985 100644 --- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs +++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs @@ -12,7 +12,7 @@ extern crate syntax; extern crate rustc; -extern crate rustc_trans_utils; +extern crate rustc_codegen_utils; use std::any::Any; use std::sync::mpsc; @@ -23,11 +23,11 @@ use rustc::ty::TyCtxt; use rustc::ty::maps::Providers; use rustc::middle::cstore::MetadataLoader; use rustc::dep_graph::DepGraph; -use rustc_trans_utils::trans_crate::{TransCrate, MetadataOnlyTransCrate}; +use rustc_codegen_utils::codegen_backend::{CodegenBackend, MetadataOnlyCodegenBackend}; -struct TheBackend(Box); +struct TheBackend(Box); -impl TransCrate for TheBackend { +impl CodegenBackend for TheBackend { fn metadata_loader(&self) -> Box { self.0.metadata_loader() } @@ -40,7 +40,7 @@ impl TransCrate for TheBackend { self.0.provide_extern(providers); } - fn trans_crate<'a, 'tcx>( + fn codegen_crate<'a, 'tcx>( &self, tcx: TyCtxt<'a, 'tcx, 'tcx>, _rx: mpsc::Receiver> @@ -50,18 +50,18 @@ impl TransCrate for TheBackend { Box::new(tcx.crate_name(LOCAL_CRATE) as Symbol) } - fn join_trans_and_link( + fn join_codegen_and_link( &self, - trans: Box, + ongoing_codegen: Box, sess: &Session, _dep_graph: &DepGraph, outputs: &OutputFilenames, ) -> Result<(), CompileIncomplete> { use std::io::Write; use rustc::session::config::CrateType; - use rustc_trans_utils::link::out_filename; - let crate_name = trans.downcast::() - .expect("in join_trans_and_link: trans is not a Symbol"); + use rustc_codegen_utils::link::out_filename; + let crate_name = ongoing_codegen.downcast::() + .expect("in join_codegen_and_link: ongoing_codegen is not a Symbol"); for &crate_type in sess.opts.crate_types.iter() { if crate_type != CrateType::CrateTypeExecutable { sess.fatal(&format!("Crate type is {:?}", crate_type)); @@ -75,8 +75,8 @@ impl TransCrate for TheBackend { } } -/// This is the entrypoint for a hot plugged rustc_trans +/// This is the entrypoint for a hot plugged rustc_codegen_llvm #[no_mangle] -pub fn __rustc_codegen_backend() -> Box { - Box::new(TheBackend(MetadataOnlyTransCrate::new())) +pub fn __rustc_codegen_backend() -> Box { + Box::new(TheBackend(MetadataOnlyCodegenBackend::new())) } diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs index e0db2627d85..403f4f79843 100644 --- a/src/test/run-make-fulldeps/issue-19371/foo.rs +++ b/src/test/run-make-fulldeps/issue-19371/foo.rs @@ -15,7 +15,7 @@ extern crate rustc_driver; extern crate rustc_lint; extern crate rustc_metadata; extern crate rustc_errors; -extern crate rustc_trans_utils; +extern crate rustc_codegen_utils; extern crate syntax; use rustc::session::{build_session, Session}; @@ -25,7 +25,7 @@ use rustc_driver::driver::{compile_input, CompileController}; use rustc_metadata::cstore::CStore; use rustc_errors::registry::Registry; use syntax::codemap::FileName; -use rustc_trans_utils::trans_crate::TransCrate; +use rustc_codegen_utils::codegen_backend::CodegenBackend; use std::path::PathBuf; use std::rc::Rc; @@ -52,7 +52,7 @@ fn main() { compile(src.to_string(), tmpdir.join("out"), sysroot.clone()); } -fn basic_sess(sysroot: PathBuf) -> (Session, Rc, Box) { +fn basic_sess(sysroot: PathBuf) -> (Session, Rc, Box) { let mut opts = basic_options(); opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]); opts.maybe_sysroot = Some(sysroot); @@ -62,19 +62,19 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc, Box) { let descriptions = Registry::new(&rustc::DIAGNOSTICS); let sess = build_session(opts, None, descriptions); - let trans = rustc_driver::get_trans(&sess); - let cstore = Rc::new(CStore::new(trans.metadata_loader())); + let codegen_backend = rustc_driver::get_codegen_backend(&sess); + let cstore = Rc::new(CStore::new(codegen_backend.metadata_loader())); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - (sess, cstore, trans) + (sess, cstore, codegen_backend) } fn compile(code: String, output: PathBuf, sysroot: PathBuf) { syntax::with_globals(|| { - let (sess, cstore, trans) = basic_sess(sysroot); + let (sess, cstore, codegen_backend) = basic_sess(sysroot); let control = CompileController::basic(); let input = Input::Str { name: FileName::Anon, input: code }; let _ = compile_input( - trans, + codegen_backend, &sess, &cstore, &None, diff --git a/src/test/run-make-fulldeps/issue-7349/Makefile b/src/test/run-make-fulldeps/issue-7349/Makefile index 50dc63b1deb..9658b99e3b0 100644 --- a/src/test/run-make-fulldeps/issue-7349/Makefile +++ b/src/test/run-make-fulldeps/issue-7349/Makefile @@ -1,7 +1,7 @@ -include ../tools.mk # Test to make sure that inner functions within a polymorphic outer function -# don't get re-translated when the outer function is monomorphized. The test +# don't get re-codegened when the outer function is monomorphized. The test # code monomorphizes the outer functions several times, but the magic constants # used in the inner functions should each appear only once in the generated IR. diff --git a/src/test/run-pass-fulldeps/compiler-calls.rs b/src/test/run-pass-fulldeps/compiler-calls.rs index 85aa92ce260..9aa4f42c8ac 100644 --- a/src/test/run-pass-fulldeps/compiler-calls.rs +++ b/src/test/run-pass-fulldeps/compiler-calls.rs @@ -18,7 +18,7 @@ extern crate getopts; extern crate rustc; extern crate rustc_driver; -extern crate rustc_trans_utils; +extern crate rustc_codegen_utils; extern crate syntax; extern crate rustc_errors as errors; @@ -26,7 +26,7 @@ use rustc::middle::cstore::CrateStore; use rustc::session::Session; use rustc::session::config::{self, Input}; use rustc_driver::{driver, CompilerCalls, Compilation}; -use rustc_trans_utils::trans_crate::TransCrate; +use rustc_codegen_utils::codegen_backend::CodegenBackend; use syntax::ast; use std::path::PathBuf; @@ -48,7 +48,7 @@ impl<'a> CompilerCalls<'a> for TestCalls { } fn late_callback(&mut self, - _: &TransCrate, + _: &CodegenBackend, _: &getopts::Matches, _: &Session, _: &CrateStore, diff --git a/src/test/run-pass/associated-types-region-erasure-issue-20582.rs b/src/test/run-pass/associated-types-region-erasure-issue-20582.rs index 16e49f146ab..40f352e2e1f 100644 --- a/src/test/run-pass/associated-types-region-erasure-issue-20582.rs +++ b/src/test/run-pass/associated-types-region-erasure-issue-20582.rs @@ -9,7 +9,7 @@ // except according to those terms. // Regression test for #20582. This test caused an ICE related to -// inconsistent region erasure in trans. +// inconsistent region erasure in codegen. // pretty-expanded FIXME #23616 diff --git a/src/test/run-pass/atomic-compare_exchange.rs b/src/test/run-pass/atomic-compare_exchange.rs index 1d9fa248e3d..2f33eb9ca40 100644 --- a/src/test/run-pass/atomic-compare_exchange.rs +++ b/src/test/run-pass/atomic-compare_exchange.rs @@ -15,7 +15,7 @@ use std::sync::atomic::Ordering::*; static ATOMIC: AtomicIsize = ATOMIC_ISIZE_INIT; fn main() { - // Make sure trans can emit all the intrinsics correctly + // Make sure codegen can emit all the intrinsics correctly ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok(); ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok(); ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok(); diff --git a/src/test/run-pass/codegen-object-shim.rs b/src/test/run-pass/codegen-object-shim.rs new file mode 100644 index 00000000000..5fbfef05e10 --- /dev/null +++ b/src/test/run-pass/codegen-object-shim.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + assert_eq!((ToString::to_string as fn(&(ToString+'static)) -> String)(&"foo"), + String::from("foo")); +} diff --git a/src/test/run-pass/codegen-tag-static-padding.rs b/src/test/run-pass/codegen-tag-static-padding.rs new file mode 100644 index 00000000000..ba01d51dc6a --- /dev/null +++ b/src/test/run-pass/codegen-tag-static-padding.rs @@ -0,0 +1,67 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// Issue #13186 + +// For simplicity of explanations assuming code is compiled for x86_64 +// Linux ABI. + +// Size of TestOption is 16, and alignment of TestOption is 8. +// Size of u8 is 1, and alignment of u8 is 1. +// So size of Request is 24, and alignment of Request must be 8: +// the maximum alignment of its fields. +// Last 7 bytes of Request struct are not occupied by any fields. + + + +enum TestOption { + TestNone, + TestSome(T), +} + +pub struct Request { + foo: TestOption, + bar: u8, +} + +fn default_instance() -> &'static Request { + static instance: Request = Request { + // LLVM does not allow to specify alignment of expressions, thus + // alignment of `foo` in constant is 1, not 8. + foo: TestOption::TestNone, + bar: 17, + // Space after last field is not occupied by any data, but it is + // reserved to make struct aligned properly. If compiler does + // not insert padding after last field when emitting constant, + // size of struct may be not equal to size of struct, and + // compiler crashes in internal assertion check. + }; + &instance +} + +fn non_default_instance() -> &'static Request { + static instance: Request = Request { + foo: TestOption::TestSome(0x1020304050607080), + bar: 19, + }; + &instance +} + +pub fn main() { + match default_instance() { + &Request { foo: TestOption::TestNone, bar: 17 } => {}, + _ => panic!(), + }; + match non_default_instance() { + &Request { foo: TestOption::TestSome(0x1020304050607080), bar: 19 } => {}, + _ => panic!(), + }; +} diff --git a/src/test/run-pass/compiletest-skip-codegen.rs b/src/test/run-pass/compiletest-skip-codegen.rs new file mode 100644 index 00000000000..d318b8fa44b --- /dev/null +++ b/src/test/run-pass/compiletest-skip-codegen.rs @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that with the `skip-codegen` option the test isn't executed. + +// skip-codegen + +fn main() { + unreachable!(); +} diff --git a/src/test/run-pass/compiletest-skip-trans.rs b/src/test/run-pass/compiletest-skip-trans.rs deleted file mode 100644 index d24a6506c2c..00000000000 --- a/src/test/run-pass/compiletest-skip-trans.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that with the `skip-trans` option the test isn't executed. - -// skip-trans - -fn main() { - unreachable!(); -} diff --git a/src/test/run-pass/conditional-compile.rs b/src/test/run-pass/conditional-compile.rs index c8e9cbdae1e..01bdcfeaefb 100644 --- a/src/test/run-pass/conditional-compile.rs +++ b/src/test/run-pass/conditional-compile.rs @@ -22,7 +22,7 @@ mod rustrt { #[cfg(bogus)] extern { // This symbol doesn't exist and would be a link error if this - // module was translated + // module was codegened pub fn bogus(); } diff --git a/src/test/run-pass/issue-18425.rs b/src/test/run-pass/issue-18425.rs index eb7e504ae14..797b3197182 100644 --- a/src/test/run-pass/issue-18425.rs +++ b/src/test/run-pass/issue-18425.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Check that trans doesn't ICE when translating an array repeat +// Check that codegen doesn't ICE when codegenning an array repeat // expression with a count of 1 and a non-Copy element type. // pretty-expanded FIXME #23616 diff --git a/src/test/run-pass/issue-18514.rs b/src/test/run-pass/issue-18514.rs index 2a1e55d867f..f8bebb4a40b 100644 --- a/src/test/run-pass/issue-18514.rs +++ b/src/test/run-pass/issue-18514.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that we don't ICE when translating a generic impl method from +// Test that we don't ICE when codegenning a generic impl method from // an extern crate that contains a match expression on a local // variable place where one of the match case bodies contains an // expression that autoderefs through an overloaded generic deref diff --git a/src/test/run-pass/issue-18652.rs b/src/test/run-pass/issue-18652.rs index cea0beaf5f0..1eddc34f5b1 100644 --- a/src/test/run-pass/issue-18652.rs +++ b/src/test/run-pass/issue-18652.rs @@ -9,7 +9,7 @@ // except according to those terms. // Tests multiple free variables being passed by value into an unboxed -// once closure as an optimization by trans. This used to hit an +// once closure as an optimization by codegen. This used to hit an // incorrect assert. fn main() { diff --git a/src/test/run-pass/issue-18661.rs b/src/test/run-pass/issue-18661.rs index 48d29095ec6..4287f449c6f 100644 --- a/src/test/run-pass/issue-18661.rs +++ b/src/test/run-pass/issue-18661.rs @@ -9,7 +9,7 @@ // except according to those terms. // Test that param substitutions from the correct environment are -// used when translating unboxed closure calls. +// used when codegenning unboxed closure calls. // pretty-expanded FIXME #23616 diff --git a/src/test/run-pass/issue-20644.rs b/src/test/run-pass/issue-20644.rs index 7cacc2e1146..65a67d0b41a 100644 --- a/src/test/run-pass/issue-20644.rs +++ b/src/test/run-pass/issue-20644.rs @@ -9,7 +9,7 @@ // except according to those terms. // A reduced version of the rustbook ice. The problem this encountered -// had to do with trans ignoring binders. +// had to do with codegen ignoring binders. // pretty-expanded FIXME #23616 // ignore-cloudabi no std::fs diff --git a/src/test/run-pass/issue-24085.rs b/src/test/run-pass/issue-24085.rs index fde32cb9023..b15ec2986c2 100644 --- a/src/test/run-pass/issue-24085.rs +++ b/src/test/run-pass/issue-24085.rs @@ -10,7 +10,7 @@ // Regression test for #24085. Errors were occurring in region // inference due to the requirement that `'a:b'`, which was getting -// incorrectly translated in connection with the closure below. +// incorrectly codegened in connection with the closure below. #[derive(Copy,Clone)] struct Path<'a:'b, 'b> { diff --git a/src/test/run-pass/issue-34569.rs b/src/test/run-pass/issue-34569.rs index 41d02e96cc2..5c7c5a2b3b9 100644 --- a/src/test/run-pass/issue-34569.rs +++ b/src/test/run-pass/issue-34569.rs @@ -12,7 +12,7 @@ // In this test we just want to make sure that the code below does not lead to // a debuginfo verification assertion during compilation. This was caused by the -// closure in the guard being translated twice due to how match expressions are +// closure in the guard being codegened twice due to how match expressions are // handled. // // See https://github.com/rust-lang/rust/issues/34569 for details. diff --git a/src/test/run-pass/issue-36381.rs b/src/test/run-pass/issue-36381.rs index 6cd991bd942..2694c98dd91 100644 --- a/src/test/run-pass/issue-36381.rs +++ b/src/test/run-pass/issue-36381.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Regression test for #36381. The trans collector was asserting that +// Regression test for #36381. The monomorphization collector was asserting that // there are no projection types, but the `<&str as // StreamOnce>::Position` projection contained a late-bound region, // and we don't currently normalize in that case until the function is diff --git a/src/test/run-pass/issue-38002.rs b/src/test/run-pass/issue-38002.rs index dd6ccec973f..4eb381b9eac 100644 --- a/src/test/run-pass/issue-38002.rs +++ b/src/test/run-pass/issue-38002.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Check that constant ADTs are translated OK, part k of N. +// Check that constant ADTs are codegened OK, part k of N. enum Bar { C diff --git a/src/test/run-pass/issue-5243.rs b/src/test/run-pass/issue-5243.rs index eda0eea7071..9bd13c4d3a0 100644 --- a/src/test/run-pass/issue-5243.rs +++ b/src/test/run-pass/issue-5243.rs @@ -9,7 +9,7 @@ // except according to those terms. // Check that merely having lifetime parameters is not -// enough for trans to consider this as non-monomorphic, +// enough for codegen to consider this as non-monomorphic, // which led to various assertions and failures in turn. // pretty-expanded FIXME #23616 diff --git a/src/test/run-pass/issue24687-embed-debuginfo/main.rs b/src/test/run-pass/issue24687-embed-debuginfo/main.rs index 7754e9c3ad7..abec252c74e 100644 --- a/src/test/run-pass/issue24687-embed-debuginfo/main.rs +++ b/src/test/run-pass/issue24687-embed-debuginfo/main.rs @@ -14,7 +14,7 @@ extern crate issue24687_lib as d; fn main() { - // Create a d, which has a destructor whose body will be trans'ed + // Create a d, which has a destructor whose body will be codegen'ed // into the generated code here, and thus the local debuginfo will // need references into the original source locations from // `importer` above. diff --git a/src/test/run-pass/method-two-trait-defer-resolution-2.rs b/src/test/run-pass/method-two-trait-defer-resolution-2.rs index cf9bc9bb56a..82d747b6c27 100644 --- a/src/test/run-pass/method-two-trait-defer-resolution-2.rs +++ b/src/test/run-pass/method-two-trait-defer-resolution-2.rs @@ -16,7 +16,7 @@ // whether `_1: MyCopy` or `_1 == Box`. However (and this is the // point of the test), we don't have to pick between the two impls -- // it is enough to know that `foo` comes from the `Foo` trait. We can -// translate the call as `Foo::foo(&x)` and let the specific impl get +// codegen the call as `Foo::foo(&x)` and let the specific impl get // chosen later. diff --git a/src/test/run-pass/mir_codegen_array.rs b/src/test/run-pass/mir_codegen_array.rs new file mode 100644 index 00000000000..b7f247012ce --- /dev/null +++ b/src/test/run-pass/mir_codegen_array.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn into_inner() -> [u64; 1024] { + let mut x = 10 + 20; + [x; 1024] +} + +fn main(){ + let x: &[u64] = &[30; 1024]; + assert_eq!(&into_inner()[..], x); +} diff --git a/src/test/run-pass/mir_codegen_array_2.rs b/src/test/run-pass/mir_codegen_array_2.rs new file mode 100644 index 00000000000..c7133fb0c0e --- /dev/null +++ b/src/test/run-pass/mir_codegen_array_2.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn into_inner(x: u64) -> [u64; 1024] { + [x; 2*4*8*16] +} + +fn main(){ + let x: &[u64] = &[42; 1024]; + assert_eq!(&into_inner(42)[..], x); +} diff --git a/src/test/run-pass/mir_codegen_call_converging.rs b/src/test/run-pass/mir_codegen_call_converging.rs new file mode 100644 index 00000000000..7d420bb86c6 --- /dev/null +++ b/src/test/run-pass/mir_codegen_call_converging.rs @@ -0,0 +1,26 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn converging_fn() -> u64 { + 43 +} + +fn mir() -> u64 { + let x; + loop { + x = converging_fn(); + break; + } + x +} + +fn main() { + assert_eq!(mir(), 43); +} diff --git a/src/test/run-pass/mir_codegen_calls.rs b/src/test/run-pass/mir_codegen_calls.rs new file mode 100644 index 00000000000..d02e3287bc3 --- /dev/null +++ b/src/test/run-pass/mir_codegen_calls.rs @@ -0,0 +1,200 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(fn_traits, test)] + +extern crate test; + +fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) { + // Test passing a number of arguments including a fat pointer. + // Also returning via an out pointer + fn callee(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) { + (a, b, c) + } + callee(a, b, c) +} + +fn test2(a: isize) -> isize { + // Test passing a single argument. + // Not using out pointer. + fn callee(a: isize) -> isize { + a + } + callee(a) +} + +#[derive(PartialEq, Eq, Debug)] +struct Foo; +impl Foo { + fn inherent_method(&self, a: isize) -> isize { a } +} + +fn test3(x: &Foo, a: isize) -> isize { + // Test calling inherent method + x.inherent_method(a) +} + +trait Bar { + fn extension_method(&self, a: isize) -> isize { a } +} +impl Bar for Foo {} + +fn test4(x: &Foo, a: isize) -> isize { + // Test calling extension method + x.extension_method(a) +} + +fn test5(x: &Bar, a: isize) -> isize { + // Test calling method on trait object + x.extension_method(a) +} + +fn test6(x: &T, a: isize) -> isize { + // Test calling extension method on generic callee + x.extension_method(a) +} + +trait One { + fn one() -> T; +} +impl One for isize { + fn one() -> isize { 1 } +} + +fn test7() -> isize { + // Test calling trait static method + ::one() +} + +struct Two; +impl Two { + fn two() -> isize { 2 } +} + +fn test8() -> isize { + // Test calling impl static method + Two::two() +} + +extern fn simple_extern(x: u32, y: (u32, u32)) -> u32 { + x + y.0 * y.1 +} + +fn test9() -> u32 { + simple_extern(41, (42, 43)) +} + +fn test_closure(f: &F, x: i32, y: i32) -> i32 + where F: Fn(i32, i32) -> i32 +{ + f(x, y) +} + +fn test_fn_object(f: &Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 { + f(x, y) +} + +fn test_fn_impl(f: &&Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 { + // This call goes through the Fn implementation for &Fn provided in + // core::ops::impls. It expands to a static Fn::call() that calls the + // Fn::call() implementation of the object shim underneath. + f(x, y) +} + +fn test_fn_direct_call(f: &F, x: i32, y: i32) -> i32 + where F: Fn(i32, i32) -> i32 +{ + f.call((x, y)) +} + +fn test_fn_const_call(f: &F) -> i32 + where F: Fn(i32, i32) -> i32 +{ + f.call((100, -1)) +} + +fn test_fn_nil_call(f: &F) -> i32 + where F: Fn() -> i32 +{ + f() +} + +fn test_fn_transmute_zst(x: ()) -> [(); 1] { + fn id(x: T) -> T {x} + + id(unsafe { + std::mem::transmute(x) + }) +} + +fn test_fn_ignored_pair() -> ((), ()) { + ((), ()) +} + +fn test_fn_ignored_pair_0() { + test_fn_ignored_pair().0 +} + +fn id(x: T) -> T { x } + +fn ignored_pair_named() -> (Foo, Foo) { + (Foo, Foo) +} + +fn test_fn_ignored_pair_named() -> (Foo, Foo) { + id(ignored_pair_named()) +} + +fn test_fn_nested_pair(x: &((f32, f32), u32)) -> (f32, f32) { + let y = *x; + let z = y.0; + (z.0, z.1) +} + +fn test_fn_const_arg_by_ref(mut a: [u64; 4]) -> u64 { + // Mutate the by-reference argument, which won't work with + // a non-immediate constant unless it's copied to the stack. + let a = test::black_box(&mut a); + a[0] += a[1]; + a[0] += a[2]; + a[0] += a[3]; + a[0] +} + +fn main() { + assert_eq!(test1(1, (2, 3), &[4, 5, 6]), (1, (2, 3), &[4, 5, 6][..])); + assert_eq!(test2(98), 98); + assert_eq!(test3(&Foo, 42), 42); + assert_eq!(test4(&Foo, 970), 970); + assert_eq!(test5(&Foo, 8576), 8576); + assert_eq!(test6(&Foo, 12367), 12367); + assert_eq!(test7(), 1); + assert_eq!(test8(), 2); + assert_eq!(test9(), 41 + 42 * 43); + + let r = 3; + let closure = |x: i32, y: i32| { r*(x + (y*2)) }; + assert_eq!(test_fn_const_call(&closure), 294); + assert_eq!(test_closure(&closure, 100, 1), 306); + let function_object = &closure as &Fn(i32, i32) -> i32; + assert_eq!(test_fn_object(function_object, 100, 2), 312); + assert_eq!(test_fn_impl(&function_object, 100, 3), 318); + assert_eq!(test_fn_direct_call(&closure, 100, 4), 324); + + assert_eq!(test_fn_nil_call(&(|| 42)), 42); + assert_eq!(test_fn_transmute_zst(()), [()]); + + assert_eq!(test_fn_ignored_pair_0(), ()); + assert_eq!(test_fn_ignored_pair_named(), (Foo, Foo)); + assert_eq!(test_fn_nested_pair(&((1.0, 2.0), 0)), (1.0, 2.0)); + + const ARRAY: [u64; 4] = [1, 2, 3, 4]; + assert_eq!(test_fn_const_arg_by_ref(ARRAY), 1 + 2 + 3 + 4); +} diff --git a/src/test/run-pass/mir_codegen_calls_variadic.rs b/src/test/run-pass/mir_codegen_calls_variadic.rs new file mode 100644 index 00000000000..7845c9426e2 --- /dev/null +++ b/src/test/run-pass/mir_codegen_calls_variadic.rs @@ -0,0 +1,31 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-wasm32-bare no libc to test ffi with + +#[link(name = "rust_test_helpers", kind = "static")] +extern { + fn rust_interesting_average(_: i64, ...) -> f64; +} + +fn test(a: i64, b: i64, c: i64, d: i64, e: i64, f: T, g: U) -> i64 { + unsafe { + rust_interesting_average(6, a, a as f64, + b, b as f64, + c, c as f64, + d, d as f64, + e, e as f64, + f, g) as i64 + } +} + +fn main(){ + assert_eq!(test(10, 20, 30, 40, 50, 60_i64, 60.0_f64), 70); +} diff --git a/src/test/run-pass/mir_codegen_critical_edge.rs b/src/test/run-pass/mir_codegen_critical_edge.rs new file mode 100644 index 00000000000..c742e71633f --- /dev/null +++ b/src/test/run-pass/mir_codegen_critical_edge.rs @@ -0,0 +1,52 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This code produces a CFG with critical edges that, if we don't +// handle properly, will cause invalid codegen. + +#![feature(rustc_attrs)] + +enum State { + Both, + Front, + Back +} + +pub struct Foo { + state: State, + a: A, + b: B +} + +impl Foo +where A: Iterator, B: Iterator +{ + // This is the function we care about + fn next(&mut self) -> Option { + match self.state { + State::Both => match self.a.next() { + elt @ Some(..) => elt, + None => { + self.state = State::Back; + self.b.next() + } + }, + State::Front => self.a.next(), + State::Back => self.b.next(), + } + } +} + +// Make sure we actually codegen a version of the function +pub fn do_stuff(mut f: Foo>, Box>>) { + let _x = f.next(); +} + +fn main() {} diff --git a/src/test/run-pass/mir_codegen_spike1.rs b/src/test/run-pass/mir_codegen_spike1.rs new file mode 100644 index 00000000000..27e1583af34 --- /dev/null +++ b/src/test/run-pass/mir_codegen_spike1.rs @@ -0,0 +1,21 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// A simple spike test for MIR version of codegen. + +fn sum(x: i32, y: i32) -> i32 { + x + y +} + +fn main() { + let x = sum(22, 44); + assert_eq!(x, 66); + println!("sum()={:?}", x); +} diff --git a/src/test/run-pass/mir_codegen_switch.rs b/src/test/run-pass/mir_codegen_switch.rs new file mode 100644 index 00000000000..b097bf46ad3 --- /dev/null +++ b/src/test/run-pass/mir_codegen_switch.rs @@ -0,0 +1,44 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Abc { + A(u8), + B(i8), + C, + D, +} + +fn foo(x: Abc) -> i32 { + match x { + Abc::C => 3, + Abc::D => 4, + Abc::B(_) => 2, + Abc::A(_) => 1, + } +} + +fn foo2(x: Abc) -> bool { + match x { + Abc::D => true, + _ => false + } +} + +fn main() { + assert_eq!(1, foo(Abc::A(42))); + assert_eq!(2, foo(Abc::B(-100))); + assert_eq!(3, foo(Abc::C)); + assert_eq!(4, foo(Abc::D)); + + assert_eq!(false, foo2(Abc::A(1))); + assert_eq!(false, foo2(Abc::B(2))); + assert_eq!(false, foo2(Abc::C)); + assert_eq!(true, foo2(Abc::D)); +} diff --git a/src/test/run-pass/mir_codegen_switchint.rs b/src/test/run-pass/mir_codegen_switchint.rs new file mode 100644 index 00000000000..537734596a5 --- /dev/null +++ b/src/test/run-pass/mir_codegen_switchint.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn foo(x: i8) -> i32 { + match x { + 1 => 0, + _ => 1, + } +} + +fn main() { + assert_eq!(foo(0), 1); + assert_eq!(foo(1), 0); +} diff --git a/src/test/run-pass/mir_overflow_off.rs b/src/test/run-pass/mir_overflow_off.rs index 0db1e7b4563..a2cfca01dac 100644 --- a/src/test/run-pass/mir_overflow_off.rs +++ b/src/test/run-pass/mir_overflow_off.rs @@ -10,7 +10,7 @@ // compile-flags: -Z force-overflow-checks=off -// Test that with MIR trans, overflow checks can be +// Test that with MIR codegen, overflow checks can be // turned off, even when they're from core::ops::*. use std::ops::*; diff --git a/src/test/run-pass/mir_trans_array.rs b/src/test/run-pass/mir_trans_array.rs deleted file mode 100644 index b7f247012ce..00000000000 --- a/src/test/run-pass/mir_trans_array.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn into_inner() -> [u64; 1024] { - let mut x = 10 + 20; - [x; 1024] -} - -fn main(){ - let x: &[u64] = &[30; 1024]; - assert_eq!(&into_inner()[..], x); -} diff --git a/src/test/run-pass/mir_trans_array_2.rs b/src/test/run-pass/mir_trans_array_2.rs deleted file mode 100644 index c7133fb0c0e..00000000000 --- a/src/test/run-pass/mir_trans_array_2.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn into_inner(x: u64) -> [u64; 1024] { - [x; 2*4*8*16] -} - -fn main(){ - let x: &[u64] = &[42; 1024]; - assert_eq!(&into_inner(42)[..], x); -} diff --git a/src/test/run-pass/mir_trans_call_converging.rs b/src/test/run-pass/mir_trans_call_converging.rs deleted file mode 100644 index 7d420bb86c6..00000000000 --- a/src/test/run-pass/mir_trans_call_converging.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn converging_fn() -> u64 { - 43 -} - -fn mir() -> u64 { - let x; - loop { - x = converging_fn(); - break; - } - x -} - -fn main() { - assert_eq!(mir(), 43); -} diff --git a/src/test/run-pass/mir_trans_calls.rs b/src/test/run-pass/mir_trans_calls.rs deleted file mode 100644 index d02e3287bc3..00000000000 --- a/src/test/run-pass/mir_trans_calls.rs +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(fn_traits, test)] - -extern crate test; - -fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) { - // Test passing a number of arguments including a fat pointer. - // Also returning via an out pointer - fn callee(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) { - (a, b, c) - } - callee(a, b, c) -} - -fn test2(a: isize) -> isize { - // Test passing a single argument. - // Not using out pointer. - fn callee(a: isize) -> isize { - a - } - callee(a) -} - -#[derive(PartialEq, Eq, Debug)] -struct Foo; -impl Foo { - fn inherent_method(&self, a: isize) -> isize { a } -} - -fn test3(x: &Foo, a: isize) -> isize { - // Test calling inherent method - x.inherent_method(a) -} - -trait Bar { - fn extension_method(&self, a: isize) -> isize { a } -} -impl Bar for Foo {} - -fn test4(x: &Foo, a: isize) -> isize { - // Test calling extension method - x.extension_method(a) -} - -fn test5(x: &Bar, a: isize) -> isize { - // Test calling method on trait object - x.extension_method(a) -} - -fn test6(x: &T, a: isize) -> isize { - // Test calling extension method on generic callee - x.extension_method(a) -} - -trait One { - fn one() -> T; -} -impl One for isize { - fn one() -> isize { 1 } -} - -fn test7() -> isize { - // Test calling trait static method - ::one() -} - -struct Two; -impl Two { - fn two() -> isize { 2 } -} - -fn test8() -> isize { - // Test calling impl static method - Two::two() -} - -extern fn simple_extern(x: u32, y: (u32, u32)) -> u32 { - x + y.0 * y.1 -} - -fn test9() -> u32 { - simple_extern(41, (42, 43)) -} - -fn test_closure(f: &F, x: i32, y: i32) -> i32 - where F: Fn(i32, i32) -> i32 -{ - f(x, y) -} - -fn test_fn_object(f: &Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 { - f(x, y) -} - -fn test_fn_impl(f: &&Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 { - // This call goes through the Fn implementation for &Fn provided in - // core::ops::impls. It expands to a static Fn::call() that calls the - // Fn::call() implementation of the object shim underneath. - f(x, y) -} - -fn test_fn_direct_call(f: &F, x: i32, y: i32) -> i32 - where F: Fn(i32, i32) -> i32 -{ - f.call((x, y)) -} - -fn test_fn_const_call(f: &F) -> i32 - where F: Fn(i32, i32) -> i32 -{ - f.call((100, -1)) -} - -fn test_fn_nil_call(f: &F) -> i32 - where F: Fn() -> i32 -{ - f() -} - -fn test_fn_transmute_zst(x: ()) -> [(); 1] { - fn id(x: T) -> T {x} - - id(unsafe { - std::mem::transmute(x) - }) -} - -fn test_fn_ignored_pair() -> ((), ()) { - ((), ()) -} - -fn test_fn_ignored_pair_0() { - test_fn_ignored_pair().0 -} - -fn id(x: T) -> T { x } - -fn ignored_pair_named() -> (Foo, Foo) { - (Foo, Foo) -} - -fn test_fn_ignored_pair_named() -> (Foo, Foo) { - id(ignored_pair_named()) -} - -fn test_fn_nested_pair(x: &((f32, f32), u32)) -> (f32, f32) { - let y = *x; - let z = y.0; - (z.0, z.1) -} - -fn test_fn_const_arg_by_ref(mut a: [u64; 4]) -> u64 { - // Mutate the by-reference argument, which won't work with - // a non-immediate constant unless it's copied to the stack. - let a = test::black_box(&mut a); - a[0] += a[1]; - a[0] += a[2]; - a[0] += a[3]; - a[0] -} - -fn main() { - assert_eq!(test1(1, (2, 3), &[4, 5, 6]), (1, (2, 3), &[4, 5, 6][..])); - assert_eq!(test2(98), 98); - assert_eq!(test3(&Foo, 42), 42); - assert_eq!(test4(&Foo, 970), 970); - assert_eq!(test5(&Foo, 8576), 8576); - assert_eq!(test6(&Foo, 12367), 12367); - assert_eq!(test7(), 1); - assert_eq!(test8(), 2); - assert_eq!(test9(), 41 + 42 * 43); - - let r = 3; - let closure = |x: i32, y: i32| { r*(x + (y*2)) }; - assert_eq!(test_fn_const_call(&closure), 294); - assert_eq!(test_closure(&closure, 100, 1), 306); - let function_object = &closure as &Fn(i32, i32) -> i32; - assert_eq!(test_fn_object(function_object, 100, 2), 312); - assert_eq!(test_fn_impl(&function_object, 100, 3), 318); - assert_eq!(test_fn_direct_call(&closure, 100, 4), 324); - - assert_eq!(test_fn_nil_call(&(|| 42)), 42); - assert_eq!(test_fn_transmute_zst(()), [()]); - - assert_eq!(test_fn_ignored_pair_0(), ()); - assert_eq!(test_fn_ignored_pair_named(), (Foo, Foo)); - assert_eq!(test_fn_nested_pair(&((1.0, 2.0), 0)), (1.0, 2.0)); - - const ARRAY: [u64; 4] = [1, 2, 3, 4]; - assert_eq!(test_fn_const_arg_by_ref(ARRAY), 1 + 2 + 3 + 4); -} diff --git a/src/test/run-pass/mir_trans_calls_variadic.rs b/src/test/run-pass/mir_trans_calls_variadic.rs deleted file mode 100644 index 7845c9426e2..00000000000 --- a/src/test/run-pass/mir_trans_calls_variadic.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-wasm32-bare no libc to test ffi with - -#[link(name = "rust_test_helpers", kind = "static")] -extern { - fn rust_interesting_average(_: i64, ...) -> f64; -} - -fn test(a: i64, b: i64, c: i64, d: i64, e: i64, f: T, g: U) -> i64 { - unsafe { - rust_interesting_average(6, a, a as f64, - b, b as f64, - c, c as f64, - d, d as f64, - e, e as f64, - f, g) as i64 - } -} - -fn main(){ - assert_eq!(test(10, 20, 30, 40, 50, 60_i64, 60.0_f64), 70); -} diff --git a/src/test/run-pass/mir_trans_critical_edge.rs b/src/test/run-pass/mir_trans_critical_edge.rs deleted file mode 100644 index f6fe19c4309..00000000000 --- a/src/test/run-pass/mir_trans_critical_edge.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// This code produces a CFG with critical edges that, if we don't -// handle properly, will cause invalid codegen. - -#![feature(rustc_attrs)] - -enum State { - Both, - Front, - Back -} - -pub struct Foo { - state: State, - a: A, - b: B -} - -impl Foo -where A: Iterator, B: Iterator -{ - // This is the function we care about - fn next(&mut self) -> Option { - match self.state { - State::Both => match self.a.next() { - elt @ Some(..) => elt, - None => { - self.state = State::Back; - self.b.next() - } - }, - State::Front => self.a.next(), - State::Back => self.b.next(), - } - } -} - -// Make sure we actually translate a version of the function -pub fn do_stuff(mut f: Foo>, Box>>) { - let _x = f.next(); -} - -fn main() {} diff --git a/src/test/run-pass/mir_trans_spike1.rs b/src/test/run-pass/mir_trans_spike1.rs deleted file mode 100644 index 8474e841e01..00000000000 --- a/src/test/run-pass/mir_trans_spike1.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// A simple spike test for MIR version of trans. - -fn sum(x: i32, y: i32) -> i32 { - x + y -} - -fn main() { - let x = sum(22, 44); - assert_eq!(x, 66); - println!("sum()={:?}", x); -} diff --git a/src/test/run-pass/mir_trans_switch.rs b/src/test/run-pass/mir_trans_switch.rs deleted file mode 100644 index b097bf46ad3..00000000000 --- a/src/test/run-pass/mir_trans_switch.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -enum Abc { - A(u8), - B(i8), - C, - D, -} - -fn foo(x: Abc) -> i32 { - match x { - Abc::C => 3, - Abc::D => 4, - Abc::B(_) => 2, - Abc::A(_) => 1, - } -} - -fn foo2(x: Abc) -> bool { - match x { - Abc::D => true, - _ => false - } -} - -fn main() { - assert_eq!(1, foo(Abc::A(42))); - assert_eq!(2, foo(Abc::B(-100))); - assert_eq!(3, foo(Abc::C)); - assert_eq!(4, foo(Abc::D)); - - assert_eq!(false, foo2(Abc::A(1))); - assert_eq!(false, foo2(Abc::B(2))); - assert_eq!(false, foo2(Abc::C)); - assert_eq!(true, foo2(Abc::D)); -} diff --git a/src/test/run-pass/mir_trans_switchint.rs b/src/test/run-pass/mir_trans_switchint.rs deleted file mode 100644 index 537734596a5..00000000000 --- a/src/test/run-pass/mir_trans_switchint.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub fn foo(x: i8) -> i32 { - match x { - 1 => 0, - _ => 1, - } -} - -fn main() { - assert_eq!(foo(0), 1); - assert_eq!(foo(1), 0); -} diff --git a/src/test/run-pass/pattern-bound-var-in-for-each.rs b/src/test/run-pass/pattern-bound-var-in-for-each.rs index 59ead3e3e98..778f355b24b 100644 --- a/src/test/run-pass/pattern-bound-var-in-for-each.rs +++ b/src/test/run-pass/pattern-bound-var-in-for-each.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Tests that trans_path checks whether a -// pattern-bound var is an upvar (when translating +// Tests that codegen_path checks whether a +// pattern-bound var is an upvar (when codegenning // the for-each body) diff --git a/src/test/run-pass/regions-mock-codegen.rs b/src/test/run-pass/regions-mock-codegen.rs new file mode 100644 index 00000000000..60a7f70931d --- /dev/null +++ b/src/test/run-pass/regions-mock-codegen.rs @@ -0,0 +1,62 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// pretty-expanded FIXME #23616 + +#![feature(allocator_api)] + +use std::alloc::{Alloc, Global, Layout, oom}; +use std::ptr::NonNull; + +struct arena(()); + +struct Bcx<'a> { + fcx: &'a Fcx<'a> +} + +struct Fcx<'a> { + arena: &'a arena, + ccx: &'a Ccx +} + +struct Ccx { + x: isize +} + +fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> { + unsafe { + let ptr = Global.alloc(Layout::new::()) + .unwrap_or_else(|_| oom()); + &*(ptr.as_ptr() as *const _) + } +} + +fn h<'a>(bcx : &'a Bcx<'a>) -> &'a Bcx<'a> { + return alloc(bcx.fcx.arena); +} + +fn g(fcx : &Fcx) { + let bcx = Bcx { fcx: fcx }; + let bcx2 = h(&bcx); + unsafe { + Global.dealloc(NonNull::new_unchecked(bcx2 as *const _ as *mut _), Layout::new::()); + } +} + +fn f(ccx : &Ccx) { + let a = arena(()); + let fcx = Fcx { arena: &a, ccx: ccx }; + return g(&fcx); +} + +pub fn main() { + let ccx = Ccx { x: 0 }; + f(&ccx); +} diff --git a/src/test/run-pass/regions-mock-trans.rs b/src/test/run-pass/regions-mock-trans.rs deleted file mode 100644 index 60a7f70931d..00000000000 --- a/src/test/run-pass/regions-mock-trans.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// pretty-expanded FIXME #23616 - -#![feature(allocator_api)] - -use std::alloc::{Alloc, Global, Layout, oom}; -use std::ptr::NonNull; - -struct arena(()); - -struct Bcx<'a> { - fcx: &'a Fcx<'a> -} - -struct Fcx<'a> { - arena: &'a arena, - ccx: &'a Ccx -} - -struct Ccx { - x: isize -} - -fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> { - unsafe { - let ptr = Global.alloc(Layout::new::()) - .unwrap_or_else(|_| oom()); - &*(ptr.as_ptr() as *const _) - } -} - -fn h<'a>(bcx : &'a Bcx<'a>) -> &'a Bcx<'a> { - return alloc(bcx.fcx.arena); -} - -fn g(fcx : &Fcx) { - let bcx = Bcx { fcx: fcx }; - let bcx2 = h(&bcx); - unsafe { - Global.dealloc(NonNull::new_unchecked(bcx2 as *const _ as *mut _), Layout::new::()); - } -} - -fn f(ccx : &Ccx) { - let a = arena(()); - let fcx = Fcx { arena: &a, ccx: ccx }; - return g(&fcx); -} - -pub fn main() { - let ccx = Ccx { x: 0 }; - f(&ccx); -} diff --git a/src/test/run-pass/sepcomp-fns-backwards.rs b/src/test/run-pass/sepcomp-fns-backwards.rs index 1ab8bc7f88c..4fea07028b6 100644 --- a/src/test/run-pass/sepcomp-fns-backwards.rs +++ b/src/test/run-pass/sepcomp-fns-backwards.rs @@ -11,7 +11,7 @@ // ignore-bitrig // compile-flags: -C codegen-units=3 -// Test references to items that haven't been translated yet. +// Test references to items that haven't been codegened yet. // Generate some code in the first compilation unit before declaring any // modules. This ensures that the first module doesn't go into the same diff --git a/src/test/run-pass/small-enum-range-edge.rs b/src/test/run-pass/small-enum-range-edge.rs index 56abdf6e20a..d2283da8bdd 100644 --- a/src/test/run-pass/small-enum-range-edge.rs +++ b/src/test/run-pass/small-enum-range-edge.rs @@ -13,7 +13,7 @@ #![feature(core)] /*! - * Tests the range assertion wraparound case in trans::middle::adt::load_discr. + * Tests the range assertion wraparound case when reading discriminants. */ #[repr(u8)] diff --git a/src/test/run-pass/trans-object-shim.rs b/src/test/run-pass/trans-object-shim.rs deleted file mode 100644 index 5fbfef05e10..00000000000 --- a/src/test/run-pass/trans-object-shim.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn main() { - assert_eq!((ToString::to_string as fn(&(ToString+'static)) -> String)(&"foo"), - String::from("foo")); -} diff --git a/src/test/run-pass/trans-tag-static-padding.rs b/src/test/run-pass/trans-tag-static-padding.rs deleted file mode 100644 index ba01d51dc6a..00000000000 --- a/src/test/run-pass/trans-tag-static-padding.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -// Issue #13186 - -// For simplicity of explanations assuming code is compiled for x86_64 -// Linux ABI. - -// Size of TestOption is 16, and alignment of TestOption is 8. -// Size of u8 is 1, and alignment of u8 is 1. -// So size of Request is 24, and alignment of Request must be 8: -// the maximum alignment of its fields. -// Last 7 bytes of Request struct are not occupied by any fields. - - - -enum TestOption { - TestNone, - TestSome(T), -} - -pub struct Request { - foo: TestOption, - bar: u8, -} - -fn default_instance() -> &'static Request { - static instance: Request = Request { - // LLVM does not allow to specify alignment of expressions, thus - // alignment of `foo` in constant is 1, not 8. - foo: TestOption::TestNone, - bar: 17, - // Space after last field is not occupied by any data, but it is - // reserved to make struct aligned properly. If compiler does - // not insert padding after last field when emitting constant, - // size of struct may be not equal to size of struct, and - // compiler crashes in internal assertion check. - }; - &instance -} - -fn non_default_instance() -> &'static Request { - static instance: Request = Request { - foo: TestOption::TestSome(0x1020304050607080), - bar: 19, - }; - &instance -} - -pub fn main() { - match default_instance() { - &Request { foo: TestOption::TestNone, bar: 17 } => {}, - _ => panic!(), - }; - match non_default_instance() { - &Request { foo: TestOption::TestSome(0x1020304050607080), bar: 19 } => {}, - _ => panic!(), - }; -} diff --git a/src/test/run-pass/union/union-const-codegen.rs b/src/test/run-pass/union/union-const-codegen.rs new file mode 100644 index 00000000000..77270364bb5 --- /dev/null +++ b/src/test/run-pass/union/union-const-codegen.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +union U { + a: u64, + b: u64, +} + +const C: U = U { b: 10 }; + +fn main() { + unsafe { + let a = C.a; + let b = C.b; + assert_eq!(a, 10); + assert_eq!(b, 10); + } +} diff --git a/src/test/run-pass/union/union-const-trans.rs b/src/test/run-pass/union/union-const-trans.rs deleted file mode 100644 index 77270364bb5..00000000000 --- a/src/test/run-pass/union/union-const-trans.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -union U { - a: u64, - b: u64, -} - -const C: U = U { b: 10 }; - -fn main() { - unsafe { - let a = C.a; - let b = C.b; - assert_eq!(a, 10); - assert_eq!(b, 10); - } -} diff --git a/src/test/run-pass/zero-sized-tuple-struct.rs b/src/test/run-pass/zero-sized-tuple-struct.rs index aaffdc4ec7c..9625d6a88ac 100644 --- a/src/test/run-pass/zero-sized-tuple-struct.rs +++ b/src/test/run-pass/zero-sized-tuple-struct.rs @@ -10,7 +10,7 @@ #![allow(unused_assignments)] -// Make sure that the constructor args are translated for zero-sized tuple structs +// Make sure that the constructor args are codegened for zero-sized tuple structs struct Foo(()); diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 06ec9e893f0..f66f5c5b70e 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -224,7 +224,7 @@ pub struct TestProps { // The test must be compiled and run successfully. Only used in UI tests for now. pub run_pass: bool, // Skip any codegen step and running the executable. Only for run-pass. - pub skip_trans: bool, + pub skip_codegen: bool, // Do not pass `-Z ui-testing` to UI tests pub disable_ui_testing_normalization: bool, // customized normalization rules @@ -258,7 +258,7 @@ impl TestProps { compile_pass: false, check_test_line_numbers_match: false, run_pass: false, - skip_trans: false, + skip_codegen: false, disable_ui_testing_normalization: false, normalize_stdout: vec![], normalize_stderr: vec![], @@ -371,8 +371,8 @@ impl TestProps { self.compile_pass = config.parse_compile_pass(ln) || self.run_pass; } - if !self.skip_trans { - self.skip_trans = config.parse_skip_trans(ln); + if !self.skip_codegen { + self.skip_codegen = config.parse_skip_codegen(ln); } if !self.disable_ui_testing_normalization { @@ -532,8 +532,8 @@ impl Config { self.parse_name_directive(line, "run-pass") } - fn parse_skip_trans(&self, line: &str) -> bool { - self.parse_name_directive(line, "skip-trans") + fn parse_skip_codegen(&self, line: &str) -> bool { + self.parse_name_directive(line, "skip-codegen") } fn parse_env(&self, line: &str, name: &str) -> Option<(String, String)> { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 59d94e1fa51..780c8122734 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -357,7 +357,7 @@ impl<'test> TestCx<'test> { "run-pass tests with expected warnings should be moved to ui/" ); - if !self.props.skip_trans { + if !self.props.skip_codegen { let proc_res = self.exec_compiled_test(); if !proc_res.status.success() { self.fatal_proc_rec("test run failed!", &proc_res); @@ -555,7 +555,7 @@ impl<'test> TestCx<'test> { rustc .arg("-") - .arg("-Zno-trans") + .arg("-Zno-codegen") .arg("--out-dir") .arg(&out_dir) .arg(&format!("--target={}", target)) @@ -1703,7 +1703,7 @@ impl<'test> TestCx<'test> { } } - if self.props.skip_trans { + if self.props.skip_codegen { assert!(!self.props.compile_flags.iter().any(|s| s.starts_with("--emit"))); rustc.args(&["--emit", "metadata"]); } @@ -2181,19 +2181,19 @@ impl<'test> TestCx<'test> { self.check_no_compiler_crash(&proc_res); - const PREFIX: &'static str = "TRANS_ITEM "; + const PREFIX: &'static str = "MONO_ITEM "; const CGU_MARKER: &'static str = "@@"; - let actual: Vec = proc_res + let actual: Vec = proc_res .stdout .lines() .filter(|line| line.starts_with(PREFIX)) - .map(str_to_trans_item) + .map(str_to_mono_item) .collect(); - let expected: Vec = errors::load_errors(&self.testpaths.file, None) + let expected: Vec = errors::load_errors(&self.testpaths.file, None) .iter() - .map(|e| str_to_trans_item(&e.msg[..])) + .map(|e| str_to_mono_item(&e.msg[..])) .collect(); let mut missing = Vec::new(); @@ -2271,14 +2271,14 @@ impl<'test> TestCx<'test> { } #[derive(Clone, Eq, PartialEq)] - struct TransItem { + struct MonoItem { name: String, codegen_units: HashSet, string: String, } - // [TRANS_ITEM] name [@@ (cgu)+] - fn str_to_trans_item(s: &str) -> TransItem { + // [MONO_ITEM] name [@@ (cgu)+] + fn str_to_mono_item(s: &str) -> MonoItem { let s = if s.starts_with(PREFIX) { (&s[PREFIX.len()..]).trim() } else { @@ -2307,7 +2307,7 @@ impl<'test> TestCx<'test> { HashSet::new() }; - TransItem { + MonoItem { name: name.to_owned(), codegen_units: cgus, string: full_string, diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index c34cf1bd5ec..5739ec5f325 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -52,7 +52,7 @@ static EXCEPTIONS: &'static [&'static str] = &[ /// Which crates to check against the whitelist? static WHITELIST_CRATES: &'static [CrateVersion] = &[ CrateVersion("rustc", "0.0.0"), - CrateVersion("rustc_trans", "0.0.0"), + CrateVersion("rustc_codegen_llvm", "0.0.0"), ]; /// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible. -- cgit 1.4.1-3-g733a5 From 9e3432447a9c6386443acdf731d488c159be3f66 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Thu, 10 May 2018 12:02:19 -0600 Subject: Switch to 1.26 bootstrap compiler --- src/bootstrap/channel.rs | 2 +- src/liballoc/Cargo.toml | 2 + src/liballoc/alloc.rs | 47 +- src/liballoc/lib.rs | 10 - src/liballoc/slice.rs | 13 +- src/liballoc/str.rs | 7 +- src/liballoc/vec.rs | 3 - src/liballoc_jemalloc/lib.rs | 7 - src/liballoc_system/lib.rs | 27 - src/libarena/lib.rs | 1 - src/libcore/Cargo.toml | 2 + src/libcore/clone.rs | 1 - src/libcore/internal_macros.rs | 14 - src/libcore/lib.rs | 19 +- src/libcore/marker.rs | 1 - src/libcore/num/f32.rs | 4 +- src/libcore/num/f64.rs | 4 +- src/libcore/num/mod.rs | 2 - src/libcore/ops/range.rs | 10 - src/libcore/prelude/v1.rs | 10 - src/libcore/slice/mod.rs | 987 ++++++++----------------------- src/libcore/str/mod.rs | 590 ++++-------------- src/libcore/tests/lib.rs | 1 - src/libcore/tests/num/uint_macros.rs | 1 - src/librustc/lib.rs | 1 - src/librustc_mir/borrow_check/nll/mod.rs | 4 +- src/librustc_mir/lib.rs | 13 +- src/librustc_mir/util/pretty.rs | 8 +- src/librustc_typeck/lib.rs | 2 - src/librustdoc/lib.rs | 2 - src/libstd/alloc.rs | 61 -- src/libstd/f32.rs | 12 +- src/libstd/f64.rs | 12 +- src/libstd/lib.rs | 9 +- src/libsyntax_ext/asm.rs | 21 +- src/libsyntax_ext/lib.rs | 3 +- src/rtstartup/rsbegin.rs | 31 +- src/stage0.txt | 2 +- 38 files changed, 434 insertions(+), 1512 deletions(-) (limited to 'src/libcore') diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 3453933a965..a2495f68c1f 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -24,7 +24,7 @@ use Build; use config::Config; // The version number -pub const CFG_RELEASE_NUM: &str = "1.27.0"; +pub const CFG_RELEASE_NUM: &str = "1.28.0"; pub struct GitInfo { inner: Option, diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index 6383bd1e941..ada21e04b30 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -2,6 +2,8 @@ authors = ["The Rust Project Developers"] name = "alloc" version = "0.0.0" +autotests = false +autobenches = false [lib] name = "alloc" diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index f59c9f7fd61..b4b82e6ecff 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -22,28 +22,6 @@ use core::usize; #[doc(inline)] pub use core::alloc::*; -#[cfg(stage0)] -extern "Rust" { - #[allocator] - #[rustc_allocator_nounwind] - fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8; - #[cold] - #[rustc_allocator_nounwind] - fn __rust_oom(err: *const u8) -> !; - #[rustc_allocator_nounwind] - fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); - #[rustc_allocator_nounwind] - fn __rust_realloc(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - err: *mut u8) -> *mut u8; - #[rustc_allocator_nounwind] - fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8; -} - -#[cfg(not(stage0))] extern "Rust" { #[allocator] #[rustc_allocator_nounwind] @@ -74,10 +52,7 @@ pub const Heap: Global = Global; unsafe impl GlobalAlloc for Global { #[inline] unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { - #[cfg(not(stage0))] let ptr = __rust_alloc(layout.size(), layout.align()); - #[cfg(stage0)] - let ptr = __rust_alloc(layout.size(), layout.align(), &mut 0); ptr as *mut Opaque } @@ -88,20 +63,13 @@ unsafe impl GlobalAlloc for Global { #[inline] unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { - #[cfg(not(stage0))] let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), new_size); - #[cfg(stage0)] - let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), - new_size, layout.align(), &mut 0); ptr as *mut Opaque } #[inline] unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { - #[cfg(not(stage0))] let ptr = __rust_alloc_zeroed(layout.size(), layout.align()); - #[cfg(stage0)] - let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), &mut 0); ptr as *mut Opaque } } @@ -152,14 +120,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { } } -#[cfg(stage0)] -#[lang = "box_free"] -#[inline] -unsafe fn old_box_free(ptr: *mut T) { - box_free(Unique::new_unchecked(ptr)) -} - -#[cfg_attr(not(any(test, stage0)), lang = "box_free")] +#[cfg_attr(not(test), lang = "box_free")] #[inline] pub(crate) unsafe fn box_free(ptr: Unique) { let ptr = ptr.as_ptr(); @@ -172,12 +133,6 @@ pub(crate) unsafe fn box_free(ptr: Unique) { } } -#[cfg(stage0)] -pub fn oom() -> ! { - unsafe { ::core::intrinsics::abort() } -} - -#[cfg(not(stage0))] pub fn oom() -> ! { extern { #[lang = "oom"] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index f7dd9d4f010..91de3ad0c39 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -75,7 +75,6 @@ #![deny(missing_debug_implementations)] #![cfg_attr(test, allow(deprecated))] // rand -#![cfg_attr(all(not(test), stage0), feature(float_internals))] #![cfg_attr(not(test), feature(exact_size_is_empty))] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(rand, test))] @@ -90,13 +89,10 @@ #![feature(collections_range)] #![feature(const_fn)] #![feature(core_intrinsics)] -#![cfg_attr(stage0, feature(core_slice_ext))] -#![cfg_attr(stage0, feature(core_str_ext))] #![feature(custom_attribute)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] #![feature(fmt_internals)] -#![cfg_attr(stage0, feature(fn_must_use))] #![feature(from_ref)] #![feature(fundamental)] #![feature(lang_items)] @@ -122,7 +118,6 @@ #![feature(exact_chunks)] #![feature(pointer_methods)] #![feature(inclusive_range_methods)] -#![cfg_attr(stage0, feature(generic_param_attrs))] #![feature(rustc_const_unstable)] #![feature(const_vec_new)] @@ -157,15 +152,10 @@ pub mod alloc; #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] /// Use the `alloc` module instead. -#[cfg(not(stage0))] pub mod heap { pub use alloc::*; } -#[unstable(feature = "allocator_api", issue = "32838")] -#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -#[cfg(stage0)] -pub mod heap; // Primitive types using the heaps above diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 6caf12aa7eb..4427ac004f9 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -101,7 +101,6 @@ use core::cmp::Ordering::{self, Less}; use core::mem::size_of; use core::mem; use core::ptr; -#[cfg(stage0)] use core::slice::SliceExt; use core::{u8, u16, u32}; use borrow::{Borrow, BorrowMut, ToOwned}; @@ -171,13 +170,9 @@ mod hack { } } -#[cfg_attr(stage0, lang = "slice")] -#[cfg_attr(not(stage0), lang = "slice_alloc")] +#[lang = "slice_alloc"] #[cfg(not(test))] impl [T] { - #[cfg(stage0)] - slice_core_methods!(); - /// Sorts the slice. /// /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case. @@ -467,8 +462,7 @@ impl [T] { } } -#[cfg_attr(stage0, lang = "slice_u8")] -#[cfg_attr(not(stage0), lang = "slice_u8_alloc")] +#[lang = "slice_u8_alloc"] #[cfg(not(test))] impl [u8] { /// Returns a vector containing a copy of this slice where each byte @@ -504,9 +498,6 @@ impl [u8] { me.make_ascii_lowercase(); me } - - #[cfg(stage0)] - slice_u8_core_methods!(); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 42efdea74b1..c10c0a69433 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -40,7 +40,6 @@ use core::fmt; use core::str as core_str; -#[cfg(stage0)] use core::str::StrExt; use core::str::pattern::Pattern; use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; @@ -158,13 +157,9 @@ impl ToOwned for str { } /// Methods for string slices. -#[cfg_attr(stage0, lang = "str")] -#[cfg_attr(not(stage0), lang = "str_alloc")] +#[lang = "str_alloc"] #[cfg(not(test))] impl str { - #[cfg(stage0)] - str_core_methods!(); - /// Converts a `Box` into a `Box<[u8]>` without copying or allocating. /// /// # Examples diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index d30f8cd0fca..bf89b377b7e 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -73,9 +73,6 @@ use core::intrinsics::{arith_offset, assume}; use core::iter::{FromIterator, FusedIterator, TrustedLen}; use core::marker::PhantomData; use core::mem; -#[cfg(not(test))] -#[cfg(stage0)] -use core::num::Float; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{Index, IndexMut, RangeBounds}; use core::ops; diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 4b8755877de..ce856eccd83 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -97,13 +97,6 @@ mod contents { ptr } - #[cfg(stage0)] - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_oom() -> ! { - ::core::intrinsics::abort(); - } - #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rde_dealloc(ptr: *mut u8, diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 7376ac0f15d..9490b54e675 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -73,33 +73,6 @@ unsafe impl Alloc for System { } } -#[cfg(stage0)] -#[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl<'a> Alloc for &'a System { - #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::alloc(*self, layout)).ok_or(AllocErr) - } - - #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::alloc_zeroed(*self, layout)).ok_or(AllocErr) - } - - #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { - GlobalAlloc::dealloc(*self, ptr.as_ptr(), layout) - } - - #[inline] - unsafe fn realloc(&mut self, - ptr: NonNull, - layout: Layout, - new_size: usize) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::realloc(*self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) - } -} - #[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))] mod realloc_fallback { use core::alloc::{GlobalAlloc, Opaque, Layout}; diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index c79e0e14e3d..f7143a4f981 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -26,7 +26,6 @@ #![feature(alloc)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] -#![cfg_attr(stage0, feature(generic_param_attrs))] #![cfg_attr(test, feature(test))] #![allow(deprecated)] diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index 24529f7a9d8..321ed892ea9 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -2,6 +2,8 @@ authors = ["The Rust Project Developers"] name = "core" version = "0.0.0" +autotests = false +autobenches = false [lib] name = "core" diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index f79f7351698..3b15ba2b4ab 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -153,7 +153,6 @@ pub struct AssertParamIsCopy { _field: ::marker::PhantomData { - $(#[$attr])* pub $($Item)* - } -} - -#[cfg(not(stage0))] -macro_rules! public_in_stage0 { - ( { $(#[$attr:meta])* } $($Item: tt)*) => { - $(#[$attr])* pub(crate) $($Item)* - } -} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 06fbfcecba8..77b5488084d 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -112,18 +112,13 @@ #![feature(unwind_attributes)] #![feature(doc_alias)] #![feature(inclusive_range_methods)] - -#![cfg_attr(not(stage0), feature(mmx_target_feature))] -#![cfg_attr(not(stage0), feature(tbm_target_feature))] -#![cfg_attr(not(stage0), feature(sse4a_target_feature))] -#![cfg_attr(not(stage0), feature(arm_target_feature))] -#![cfg_attr(not(stage0), feature(powerpc_target_feature))] -#![cfg_attr(not(stage0), feature(mips_target_feature))] -#![cfg_attr(not(stage0), feature(aarch64_target_feature))] - -#![cfg_attr(stage0, feature(target_feature))] -#![cfg_attr(stage0, feature(cfg_target_feature))] -#![cfg_attr(stage0, feature(fn_must_use))] +#![feature(mmx_target_feature)] +#![feature(tbm_target_feature)] +#![feature(sse4a_target_feature)] +#![feature(arm_target_feature)] +#![feature(powerpc_target_feature)] +#![feature(mips_target_feature)] +#![feature(aarch64_target_feature)] #[prelude_import] #[allow(unused)] diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index db5f50a99ca..6c8ee0eda11 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -611,7 +611,6 @@ pub unsafe auto trait Unpin {} /// /// Implementations that cannot be described in Rust /// are implemented in `SelectionContext::copy_clone_conditions()` in librustc. -#[cfg(not(stage0))] mod copy_impls { use super::Copy; diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 4a7dc13f0f2..718dd42a615 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -19,7 +19,7 @@ use mem; use num::Float; -#[cfg(not(stage0))] use num::FpCategory; +use num::FpCategory; use num::FpCategory as Fp; /// The radix or base of the internal representation of `f32`. @@ -277,7 +277,6 @@ impl Float for f32 { // FIXME: remove (inline) this macro and the Float trait // when updating to a bootstrap compiler that has the new lang items. -#[cfg_attr(stage0, macro_export)] #[unstable(feature = "core_float", issue = "32110")] macro_rules! f32_core_methods { () => { /// Returns `true` if this value is `NaN` and false otherwise. @@ -553,7 +552,6 @@ macro_rules! f32_core_methods { () => { #[lang = "f32"] #[cfg(not(test))] -#[cfg(not(stage0))] impl f32 { f32_core_methods!(); } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 801de5e87bd..f128c55c78a 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -19,7 +19,7 @@ use mem; use num::Float; -#[cfg(not(stage0))] use num::FpCategory; +use num::FpCategory; use num::FpCategory as Fp; /// The radix or base of the internal representation of `f64`. @@ -276,7 +276,6 @@ impl Float for f64 { // FIXME: remove (inline) this macro and the Float trait // when updating to a bootstrap compiler that has the new lang items. -#[cfg_attr(stage0, macro_export)] #[unstable(feature = "core_float", issue = "32110")] macro_rules! f64_core_methods { () => { /// Returns `true` if this value is `NaN` and false otherwise. @@ -562,7 +561,6 @@ macro_rules! f64_core_methods { () => { #[lang = "f64"] #[cfg(not(test))] -#[cfg(not(stage0))] impl f64 { f64_core_methods!(); } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 6df8ca98ba9..58d45b107f1 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -422,7 +422,6 @@ $EndFeature, " /// assert_eq!(m, -22016); /// ``` #[unstable(feature = "reverse_bits", issue = "48763")] - #[cfg(not(stage0))] #[inline] pub fn reverse_bits(self) -> Self { (self as $UnsignedT).reverse_bits() as Self @@ -2194,7 +2193,6 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " /// assert_eq!(m, 43520); /// ``` #[unstable(feature = "reverse_bits", issue = "48763")] - #[cfg(not(stage0))] #[inline] pub fn reverse_bits(self) -> Self { unsafe { intrinsics::bitreverse(self as $ActualT) as Self } diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 697e6a3efde..1f84631ada3 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -335,18 +335,8 @@ pub struct RangeInclusive { // but it is known that LLVM is not able to optimize loops following that RFC. // Consider adding an extra `bool` field to indicate emptiness of the range. // See #45222 for performance test cases. - #[cfg(not(stage0))] pub(crate) start: Idx, - #[cfg(not(stage0))] pub(crate) end: Idx, - /// The lower bound of the range (inclusive). - #[cfg(stage0)] - #[unstable(feature = "inclusive_range_fields", issue = "49022")] - pub start: Idx, - /// The upper bound of the range (inclusive). - #[cfg(stage0)] - #[unstable(feature = "inclusive_range_fields", issue = "49022")] - pub end: Idx, } impl RangeInclusive { diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index 8212648f2d8..45f629a6442 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -54,13 +54,3 @@ pub use option::Option::{self, Some, None}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use result::Result::{self, Ok, Err}; - -// Re-exported extension traits for primitive types -#[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] -#[cfg(stage0)] -pub use slice::SliceExt; -#[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] -#[cfg(stage0)] -pub use str::StrExt; diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 93ebc23ac0b..82891b691dc 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -68,181 +68,6 @@ struct Repr { // Extension traits // -public_in_stage0! { -{ -/// Extension methods for slices. -#[unstable(feature = "core_slice_ext", - reason = "stable interface provided by `impl [T]` in later crates", - issue = "32110")] -#[allow(missing_docs)] // documented elsewhere -} -trait SliceExt { - type Item; - - #[stable(feature = "core", since = "1.6.0")] - fn split_at(&self, mid: usize) -> (&[Self::Item], &[Self::Item]); - - #[stable(feature = "core", since = "1.6.0")] - fn iter(&self) -> Iter; - - #[stable(feature = "core", since = "1.6.0")] - fn split

(&self, pred: P) -> Split - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "slice_rsplit", since = "1.27.0")] - fn rsplit

(&self, pred: P) -> RSplit - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn splitn

(&self, n: usize, pred: P) -> SplitN - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn rsplitn

(&self, n: usize, pred: P) -> RSplitN - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn windows(&self, size: usize) -> Windows; - - #[stable(feature = "core", since = "1.6.0")] - fn chunks(&self, size: usize) -> Chunks; - - #[unstable(feature = "exact_chunks", issue = "47115")] - fn exact_chunks(&self, size: usize) -> ExactChunks; - - #[stable(feature = "core", since = "1.6.0")] - fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex; - #[stable(feature = "core", since = "1.6.0")] - fn first(&self) -> Option<&Self::Item>; - - #[stable(feature = "core", since = "1.6.0")] - fn split_first(&self) -> Option<(&Self::Item, &[Self::Item])>; - - #[stable(feature = "core", since = "1.6.0")] - fn split_last(&self) -> Option<(&Self::Item, &[Self::Item])>; - - #[stable(feature = "core", since = "1.6.0")] - fn last(&self) -> Option<&Self::Item>; - - #[stable(feature = "core", since = "1.6.0")] - unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex; - #[stable(feature = "core", since = "1.6.0")] - fn as_ptr(&self) -> *const Self::Item; - - #[stable(feature = "core", since = "1.6.0")] - fn binary_search(&self, x: &Self::Item) -> Result - where Self::Item: Ord; - - #[stable(feature = "core", since = "1.6.0")] - fn binary_search_by<'a, F>(&'a self, f: F) -> Result - where F: FnMut(&'a Self::Item) -> Ordering; - - #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] - fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result - where F: FnMut(&'a Self::Item) -> B, - B: Ord; - - #[stable(feature = "core", since = "1.6.0")] - fn len(&self) -> usize; - - #[stable(feature = "core", since = "1.6.0")] - fn is_empty(&self) -> bool { self.len() == 0 } - - #[stable(feature = "core", since = "1.6.0")] - fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex; - #[stable(feature = "core", since = "1.6.0")] - fn iter_mut(&mut self) -> IterMut; - - #[stable(feature = "core", since = "1.6.0")] - fn first_mut(&mut self) -> Option<&mut Self::Item>; - - #[stable(feature = "core", since = "1.6.0")] - fn split_first_mut(&mut self) -> Option<(&mut Self::Item, &mut [Self::Item])>; - - #[stable(feature = "core", since = "1.6.0")] - fn split_last_mut(&mut self) -> Option<(&mut Self::Item, &mut [Self::Item])>; - - #[stable(feature = "core", since = "1.6.0")] - fn last_mut(&mut self) -> Option<&mut Self::Item>; - - #[stable(feature = "core", since = "1.6.0")] - fn split_mut

(&mut self, pred: P) -> SplitMut - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "slice_rsplit", since = "1.27.0")] - fn rsplit_mut

(&mut self, pred: P) -> RSplitMut - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn splitn_mut

(&mut self, n: usize, pred: P) -> SplitNMut - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn rsplitn_mut

(&mut self, n: usize, pred: P) -> RSplitNMut - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut; - - #[unstable(feature = "exact_chunks", issue = "47115")] - fn exact_chunks_mut(&mut self, size: usize) -> ExactChunksMut; - - #[stable(feature = "core", since = "1.6.0")] - fn swap(&mut self, a: usize, b: usize); - - #[stable(feature = "core", since = "1.6.0")] - fn split_at_mut(&mut self, mid: usize) -> (&mut [Self::Item], &mut [Self::Item]); - - #[stable(feature = "core", since = "1.6.0")] - fn reverse(&mut self); - - #[stable(feature = "core", since = "1.6.0")] - unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex; - #[stable(feature = "core", since = "1.6.0")] - fn as_mut_ptr(&mut self) -> *mut Self::Item; - - #[stable(feature = "core", since = "1.6.0")] - fn contains(&self, x: &Self::Item) -> bool where Self::Item: PartialEq; - - #[stable(feature = "core", since = "1.6.0")] - fn starts_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq; - - #[stable(feature = "core", since = "1.6.0")] - fn ends_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq; - - #[stable(feature = "slice_rotate", since = "1.26.0")] - fn rotate_left(&mut self, mid: usize); - - #[stable(feature = "slice_rotate", since = "1.26.0")] - fn rotate_right(&mut self, k: usize); - - #[stable(feature = "clone_from_slice", since = "1.7.0")] - fn clone_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Clone; - - #[stable(feature = "copy_from_slice", since = "1.9.0")] - fn copy_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Copy; - - #[stable(feature = "swap_with_slice", since = "1.27.0")] - fn swap_with_slice(&mut self, src: &mut [Self::Item]); - - #[stable(feature = "sort_unstable", since = "1.20.0")] - fn sort_unstable(&mut self) - where Self::Item: Ord; - - #[stable(feature = "sort_unstable", since = "1.20.0")] - fn sort_unstable_by(&mut self, compare: F) - where F: FnMut(&Self::Item, &Self::Item) -> Ordering; - - #[stable(feature = "sort_unstable", since = "1.20.0")] - fn sort_unstable_by_key(&mut self, f: F) - where F: FnMut(&Self::Item) -> B, - B: Ord; -}} - // Use macros to be generic over const/mut macro_rules! slice_offset { ($ptr:expr, $by:expr) => {{ @@ -281,488 +106,9 @@ macro_rules! make_ref_mut { }}; } -#[unstable(feature = "core_slice_ext", - reason = "stable interface provided by `impl [T]` in later crates", - issue = "32110")] -impl SliceExt for [T] { - type Item = T; - - #[inline] - fn split_at(&self, mid: usize) -> (&[T], &[T]) { - (&self[..mid], &self[mid..]) - } - - #[inline] - fn iter(&self) -> Iter { - unsafe { - let p = if mem::size_of::() == 0 { - 1 as *const _ - } else { - let p = self.as_ptr(); - assume(!p.is_null()); - p - }; - - Iter { - ptr: p, - end: slice_offset!(p, self.len() as isize), - _marker: marker::PhantomData - } - } - } - - #[inline] - fn split

(&self, pred: P) -> Split - where P: FnMut(&T) -> bool - { - Split { - v: self, - pred, - finished: false - } - } - - #[inline] - fn rsplit

(&self, pred: P) -> RSplit - where P: FnMut(&T) -> bool - { - RSplit { inner: self.split(pred) } - } - - #[inline] - fn splitn

(&self, n: usize, pred: P) -> SplitN - where P: FnMut(&T) -> bool - { - SplitN { - inner: GenericSplitN { - iter: self.split(pred), - count: n - } - } - } - - #[inline] - fn rsplitn

(&self, n: usize, pred: P) -> RSplitN - where P: FnMut(&T) -> bool - { - RSplitN { - inner: GenericSplitN { - iter: self.rsplit(pred), - count: n - } - } - } - - #[inline] - fn windows(&self, size: usize) -> Windows { - assert!(size != 0); - Windows { v: self, size: size } - } - - #[inline] - fn chunks(&self, chunk_size: usize) -> Chunks { - assert!(chunk_size != 0); - Chunks { v: self, chunk_size: chunk_size } - } - - #[inline] - fn exact_chunks(&self, chunk_size: usize) -> ExactChunks { - assert!(chunk_size != 0); - let rem = self.len() % chunk_size; - let len = self.len() - rem; - ExactChunks { v: &self[..len], chunk_size: chunk_size} - } - - #[inline] - fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex<[T]> - { - index.get(self) - } - - #[inline] - fn first(&self) -> Option<&T> { - if self.is_empty() { None } else { Some(&self[0]) } - } - - #[inline] - fn split_first(&self) -> Option<(&T, &[T])> { - if self.is_empty() { None } else { Some((&self[0], &self[1..])) } - } - - #[inline] - fn split_last(&self) -> Option<(&T, &[T])> { - let len = self.len(); - if len == 0 { None } else { Some((&self[len - 1], &self[..(len - 1)])) } - } - - #[inline] - fn last(&self) -> Option<&T> { - if self.is_empty() { None } else { Some(&self[self.len() - 1]) } - } - - #[inline] - unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex<[T]> - { - index.get_unchecked(self) - } - - #[inline] - fn as_ptr(&self) -> *const T { - self as *const [T] as *const T - } - - fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result - where F: FnMut(&'a T) -> Ordering - { - let s = self; - let mut size = s.len(); - if size == 0 { - return Err(0); - } - let mut base = 0usize; - while size > 1 { - let half = size / 2; - let mid = base + half; - // mid is always in [0, size), that means mid is >= 0 and < size. - // mid >= 0: by definition - // mid < size: mid = size / 2 + size / 4 + size / 8 ... - let cmp = f(unsafe { s.get_unchecked(mid) }); - base = if cmp == Greater { base } else { mid }; - size -= half; - } - // base is always in [0, size) because base <= mid. - let cmp = f(unsafe { s.get_unchecked(base) }); - if cmp == Equal { Ok(base) } else { Err(base + (cmp == Less) as usize) } - } - - #[inline] - fn len(&self) -> usize { - unsafe { - mem::transmute::<&[T], Repr>(self).len - } - } - - #[inline] - fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex<[T]> - { - index.get_mut(self) - } - - #[inline] - fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { - let len = self.len(); - let ptr = self.as_mut_ptr(); - - unsafe { - assert!(mid <= len); - - (from_raw_parts_mut(ptr, mid), - from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) - } - } - - #[inline] - fn iter_mut(&mut self) -> IterMut { - unsafe { - let p = if mem::size_of::() == 0 { - 1 as *mut _ - } else { - let p = self.as_mut_ptr(); - assume(!p.is_null()); - p - }; - - IterMut { - ptr: p, - end: slice_offset!(p, self.len() as isize), - _marker: marker::PhantomData - } - } - } - - #[inline] - fn last_mut(&mut self) -> Option<&mut T> { - let len = self.len(); - if len == 0 { return None; } - Some(&mut self[len - 1]) - } - - #[inline] - fn first_mut(&mut self) -> Option<&mut T> { - if self.is_empty() { None } else { Some(&mut self[0]) } - } - - #[inline] - fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { - if self.is_empty() { None } else { - let split = self.split_at_mut(1); - Some((&mut split.0[0], split.1)) - } - } - - #[inline] - fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { - let len = self.len(); - if len == 0 { None } else { - let split = self.split_at_mut(len - 1); - Some((&mut split.1[0], split.0)) - } - } - - #[inline] - fn split_mut

(&mut self, pred: P) -> SplitMut - where P: FnMut(&T) -> bool - { - SplitMut { v: self, pred: pred, finished: false } - } - - #[inline] - fn rsplit_mut

(&mut self, pred: P) -> RSplitMut - where P: FnMut(&T) -> bool - { - RSplitMut { inner: self.split_mut(pred) } - } - - #[inline] - fn splitn_mut

(&mut self, n: usize, pred: P) -> SplitNMut - where P: FnMut(&T) -> bool - { - SplitNMut { - inner: GenericSplitN { - iter: self.split_mut(pred), - count: n - } - } - } - - #[inline] - fn rsplitn_mut

(&mut self, n: usize, pred: P) -> RSplitNMut where - P: FnMut(&T) -> bool, - { - RSplitNMut { - inner: GenericSplitN { - iter: self.rsplit_mut(pred), - count: n - } - } - } - - #[inline] - fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut { - assert!(chunk_size != 0); - ChunksMut { v: self, chunk_size: chunk_size } - } - - #[inline] - fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut { - assert!(chunk_size != 0); - let rem = self.len() % chunk_size; - let len = self.len() - rem; - ExactChunksMut { v: &mut self[..len], chunk_size: chunk_size} - } - - #[inline] - fn swap(&mut self, a: usize, b: usize) { - unsafe { - // Can't take two mutable loans from one vector, so instead just cast - // them to their raw pointers to do the swap - let pa: *mut T = &mut self[a]; - let pb: *mut T = &mut self[b]; - ptr::swap(pa, pb); - } - } - - fn reverse(&mut self) { - let mut i: usize = 0; - let ln = self.len(); - - // For very small types, all the individual reads in the normal - // path perform poorly. We can do better, given efficient unaligned - // load/store, by loading a larger chunk and reversing a register. - - // Ideally LLVM would do this for us, as it knows better than we do - // whether unaligned reads are efficient (since that changes between - // different ARM versions, for example) and what the best chunk size - // would be. Unfortunately, as of LLVM 4.0 (2017-05) it only unrolls - // the loop, so we need to do this ourselves. (Hypothesis: reverse - // is troublesome because the sides can be aligned differently -- - // will be, when the length is odd -- so there's no way of emitting - // pre- and postludes to use fully-aligned SIMD in the middle.) - - let fast_unaligned = - cfg!(any(target_arch = "x86", target_arch = "x86_64")); - - if fast_unaligned && mem::size_of::() == 1 { - // Use the llvm.bswap intrinsic to reverse u8s in a usize - let chunk = mem::size_of::(); - while i + chunk - 1 < ln / 2 { - unsafe { - let pa: *mut T = self.get_unchecked_mut(i); - let pb: *mut T = self.get_unchecked_mut(ln - i - chunk); - let va = ptr::read_unaligned(pa as *mut usize); - let vb = ptr::read_unaligned(pb as *mut usize); - ptr::write_unaligned(pa as *mut usize, vb.swap_bytes()); - ptr::write_unaligned(pb as *mut usize, va.swap_bytes()); - } - i += chunk; - } - } - - if fast_unaligned && mem::size_of::() == 2 { - // Use rotate-by-16 to reverse u16s in a u32 - let chunk = mem::size_of::() / 2; - while i + chunk - 1 < ln / 2 { - unsafe { - let pa: *mut T = self.get_unchecked_mut(i); - let pb: *mut T = self.get_unchecked_mut(ln - i - chunk); - let va = ptr::read_unaligned(pa as *mut u32); - let vb = ptr::read_unaligned(pb as *mut u32); - ptr::write_unaligned(pa as *mut u32, vb.rotate_left(16)); - ptr::write_unaligned(pb as *mut u32, va.rotate_left(16)); - } - i += chunk; - } - } - - while i < ln / 2 { - // Unsafe swap to avoid the bounds check in safe swap. - unsafe { - let pa: *mut T = self.get_unchecked_mut(i); - let pb: *mut T = self.get_unchecked_mut(ln - i - 1); - ptr::swap(pa, pb); - } - i += 1; - } - } - - #[inline] - unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex<[T]> - { - index.get_unchecked_mut(self) - } - - #[inline] - fn as_mut_ptr(&mut self) -> *mut T { - self as *mut [T] as *mut T - } - - #[inline] - fn contains(&self, x: &T) -> bool where T: PartialEq { - x.slice_contains(self) - } - - #[inline] - fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq { - let n = needle.len(); - self.len() >= n && needle == &self[..n] - } - - #[inline] - fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq { - let (m, n) = (self.len(), needle.len()); - m >= n && needle == &self[m-n..] - } - - fn binary_search(&self, x: &T) -> Result - where T: Ord - { - self.binary_search_by(|p| p.cmp(x)) - } - - fn rotate_left(&mut self, mid: usize) { - assert!(mid <= self.len()); - let k = self.len() - mid; - - unsafe { - let p = self.as_mut_ptr(); - rotate::ptr_rotate(mid, p.offset(mid as isize), k); - } - } - - fn rotate_right(&mut self, k: usize) { - assert!(k <= self.len()); - let mid = self.len() - k; - - unsafe { - let p = self.as_mut_ptr(); - rotate::ptr_rotate(mid, p.offset(mid as isize), k); - } - } - - #[inline] - fn clone_from_slice(&mut self, src: &[T]) where T: Clone { - assert!(self.len() == src.len(), - "destination and source slices have different lengths"); - // NOTE: We need to explicitly slice them to the same length - // for bounds checking to be elided, and the optimizer will - // generate memcpy for simple cases (for example T = u8). - let len = self.len(); - let src = &src[..len]; - for i in 0..len { - self[i].clone_from(&src[i]); - } - } - - #[inline] - fn copy_from_slice(&mut self, src: &[T]) where T: Copy { - assert!(self.len() == src.len(), - "destination and source slices have different lengths"); - unsafe { - ptr::copy_nonoverlapping( - src.as_ptr(), self.as_mut_ptr(), self.len()); - } - } - - #[inline] - fn swap_with_slice(&mut self, src: &mut [T]) { - assert!(self.len() == src.len(), - "destination and source slices have different lengths"); - unsafe { - ptr::swap_nonoverlapping( - self.as_mut_ptr(), src.as_mut_ptr(), self.len()); - } - } - - #[inline] - fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result - where F: FnMut(&'a Self::Item) -> B, - B: Ord - { - self.binary_search_by(|k| f(k).cmp(b)) - } - - #[inline] - fn sort_unstable(&mut self) - where Self::Item: Ord - { - sort::quicksort(self, |a, b| a.lt(b)); - } - - #[inline] - fn sort_unstable_by(&mut self, mut compare: F) - where F: FnMut(&Self::Item, &Self::Item) -> Ordering - { - sort::quicksort(self, |a, b| compare(a, b) == Ordering::Less); - } - - #[inline] - fn sort_unstable_by_key(&mut self, mut f: F) - where F: FnMut(&Self::Item) -> B, - B: Ord - { - sort::quicksort(self, |a, b| f(a).lt(&f(b))); - } -} - -// FIXME: remove (inline) this macro and the SliceExt trait -// when updating to a bootstrap compiler that has the new lang items. -#[cfg_attr(stage0, macro_export)] -#[unstable(feature = "core_slice_ext", issue = "32110")] -macro_rules! slice_core_methods { () => { +#[lang = "slice"] +#[cfg(not(test))] +impl [T] { /// Returns the number of elements in the slice. /// /// # Examples @@ -774,7 +120,9 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn len(&self) -> usize { - SliceExt::len(self) + unsafe { + mem::transmute::<&[T], Repr>(self).len + } } /// Returns `true` if the slice has a length of 0. @@ -788,7 +136,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_empty(&self) -> bool { - SliceExt::is_empty(self) + self.len() == 0 } /// Returns the first element of the slice, or `None` if it is empty. @@ -805,7 +153,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn first(&self) -> Option<&T> { - SliceExt::first(self) + if self.is_empty() { None } else { Some(&self[0]) } } /// Returns a mutable pointer to the first element of the slice, or `None` if it is empty. @@ -823,7 +171,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn first_mut(&mut self) -> Option<&mut T> { - SliceExt::first_mut(self) + if self.is_empty() { None } else { Some(&mut self[0]) } } /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. @@ -841,7 +189,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "slice_splits", since = "1.5.0")] #[inline] pub fn split_first(&self) -> Option<(&T, &[T])> { - SliceExt::split_first(self) + if self.is_empty() { None } else { Some((&self[0], &self[1..])) } } /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. @@ -861,7 +209,10 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "slice_splits", since = "1.5.0")] #[inline] pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { - SliceExt::split_first_mut(self) + if self.is_empty() { None } else { + let split = self.split_at_mut(1); + Some((&mut split.0[0], split.1)) + } } /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. @@ -879,7 +230,8 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "slice_splits", since = "1.5.0")] #[inline] pub fn split_last(&self) -> Option<(&T, &[T])> { - SliceExt::split_last(self) + let len = self.len(); + if len == 0 { None } else { Some((&self[len - 1], &self[..(len - 1)])) } } /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. @@ -899,7 +251,12 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "slice_splits", since = "1.5.0")] #[inline] pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { - SliceExt::split_last_mut(self) + let len = self.len(); + if len == 0 { None } else { + let split = self.split_at_mut(len - 1); + Some((&mut split.1[0], split.0)) + } + } /// Returns the last element of the slice, or `None` if it is empty. @@ -916,7 +273,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn last(&self) -> Option<&T> { - SliceExt::last(self) + if self.is_empty() { None } else { Some(&self[self.len() - 1]) } } /// Returns a mutable pointer to the last item in the slice. @@ -934,7 +291,9 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn last_mut(&mut self) -> Option<&mut T> { - SliceExt::last_mut(self) + let len = self.len(); + if len == 0 { return None; } + Some(&mut self[len - 1]) } /// Returns a reference to an element or subslice depending on the type of @@ -959,7 +318,7 @@ macro_rules! slice_core_methods { () => { pub fn get(&self, index: I) -> Option<&I::Output> where I: SliceIndex { - SliceExt::get(self, index) + index.get(self) } /// Returns a mutable reference to an element or subslice depending on the @@ -982,7 +341,7 @@ macro_rules! slice_core_methods { () => { pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> where I: SliceIndex { - SliceExt::get_mut(self, index) + index.get_mut(self) } /// Returns a reference to an element or subslice, without doing bounds @@ -1007,7 +366,7 @@ macro_rules! slice_core_methods { () => { pub unsafe fn get_unchecked(&self, index: I) -> &I::Output where I: SliceIndex { - SliceExt::get_unchecked(self, index) + index.get_unchecked(self) } /// Returns a mutable reference to an element or subslice, without doing @@ -1034,7 +393,7 @@ macro_rules! slice_core_methods { () => { pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output where I: SliceIndex { - SliceExt::get_unchecked_mut(self, index) + index.get_unchecked_mut(self) } /// Returns a raw pointer to the slice's buffer. @@ -1060,7 +419,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn as_ptr(&self) -> *const T { - SliceExt::as_ptr(self) + self as *const [T] as *const T } /// Returns an unsafe mutable pointer to the slice's buffer. @@ -1087,7 +446,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn as_mut_ptr(&mut self) -> *mut T { - SliceExt::as_mut_ptr(self) + self as *mut [T] as *mut T } /// Swaps two elements in the slice. @@ -1111,7 +470,13 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn swap(&mut self, a: usize, b: usize) { - SliceExt::swap(self, a, b) + unsafe { + // Can't take two mutable loans from one vector, so instead just cast + // them to their raw pointers to do the swap + let pa: *mut T = &mut self[a]; + let pb: *mut T = &mut self[b]; + ptr::swap(pa, pb); + } } /// Reverses the order of elements in the slice, in place. @@ -1126,7 +491,66 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn reverse(&mut self) { - SliceExt::reverse(self) + let mut i: usize = 0; + let ln = self.len(); + + // For very small types, all the individual reads in the normal + // path perform poorly. We can do better, given efficient unaligned + // load/store, by loading a larger chunk and reversing a register. + + // Ideally LLVM would do this for us, as it knows better than we do + // whether unaligned reads are efficient (since that changes between + // different ARM versions, for example) and what the best chunk size + // would be. Unfortunately, as of LLVM 4.0 (2017-05) it only unrolls + // the loop, so we need to do this ourselves. (Hypothesis: reverse + // is troublesome because the sides can be aligned differently -- + // will be, when the length is odd -- so there's no way of emitting + // pre- and postludes to use fully-aligned SIMD in the middle.) + + let fast_unaligned = + cfg!(any(target_arch = "x86", target_arch = "x86_64")); + + if fast_unaligned && mem::size_of::() == 1 { + // Use the llvm.bswap intrinsic to reverse u8s in a usize + let chunk = mem::size_of::(); + while i + chunk - 1 < ln / 2 { + unsafe { + let pa: *mut T = self.get_unchecked_mut(i); + let pb: *mut T = self.get_unchecked_mut(ln - i - chunk); + let va = ptr::read_unaligned(pa as *mut usize); + let vb = ptr::read_unaligned(pb as *mut usize); + ptr::write_unaligned(pa as *mut usize, vb.swap_bytes()); + ptr::write_unaligned(pb as *mut usize, va.swap_bytes()); + } + i += chunk; + } + } + + if fast_unaligned && mem::size_of::() == 2 { + // Use rotate-by-16 to reverse u16s in a u32 + let chunk = mem::size_of::() / 2; + while i + chunk - 1 < ln / 2 { + unsafe { + let pa: *mut T = self.get_unchecked_mut(i); + let pb: *mut T = self.get_unchecked_mut(ln - i - chunk); + let va = ptr::read_unaligned(pa as *mut u32); + let vb = ptr::read_unaligned(pb as *mut u32); + ptr::write_unaligned(pa as *mut u32, vb.rotate_left(16)); + ptr::write_unaligned(pb as *mut u32, va.rotate_left(16)); + } + i += chunk; + } + } + + while i < ln / 2 { + // Unsafe swap to avoid the bounds check in safe swap. + unsafe { + let pa: *mut T = self.get_unchecked_mut(i); + let pb: *mut T = self.get_unchecked_mut(ln - i - 1); + ptr::swap(pa, pb); + } + i += 1; + } } /// Returns an iterator over the slice. @@ -1145,7 +569,21 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn iter(&self) -> Iter { - SliceExt::iter(self) + unsafe { + let p = if mem::size_of::() == 0 { + 1 as *const _ + } else { + let p = self.as_ptr(); + assume(!p.is_null()); + p + }; + + Iter { + ptr: p, + end: slice_offset!(p, self.len() as isize), + _marker: marker::PhantomData + } + } } /// Returns an iterator that allows modifying each value. @@ -1162,7 +600,21 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn iter_mut(&mut self) -> IterMut { - SliceExt::iter_mut(self) + unsafe { + let p = if mem::size_of::() == 0 { + 1 as *mut _ + } else { + let p = self.as_mut_ptr(); + assume(!p.is_null()); + p + }; + + IterMut { + ptr: p, + end: slice_offset!(p, self.len() as isize), + _marker: marker::PhantomData + } + } } /// Returns an iterator over all contiguous windows of length @@ -1194,7 +646,8 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn windows(&self, size: usize) -> Windows { - SliceExt::windows(self, size) + assert!(size != 0); + Windows { v: self, size: size } } /// Returns an iterator over `chunk_size` elements of the slice at a @@ -1224,7 +677,8 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn chunks(&self, chunk_size: usize) -> Chunks { - SliceExt::chunks(self, chunk_size) + assert!(chunk_size != 0); + Chunks { v: self, chunk_size: chunk_size } } /// Returns an iterator over `chunk_size` elements of the slice at a @@ -1256,7 +710,10 @@ macro_rules! slice_core_methods { () => { #[unstable(feature = "exact_chunks", issue = "47115")] #[inline] pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks { - SliceExt::exact_chunks(self, chunk_size) + assert!(chunk_size != 0); + let rem = self.len() % chunk_size; + let len = self.len() - rem; + ExactChunks { v: &self[..len], chunk_size: chunk_size} } /// Returns an iterator over `chunk_size` elements of the slice at a time. @@ -1290,7 +747,8 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut { - SliceExt::chunks_mut(self, chunk_size) + assert!(chunk_size != 0); + ChunksMut { v: self, chunk_size: chunk_size } } /// Returns an iterator over `chunk_size` elements of the slice at a time. @@ -1328,7 +786,10 @@ macro_rules! slice_core_methods { () => { #[unstable(feature = "exact_chunks", issue = "47115")] #[inline] pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut { - SliceExt::exact_chunks_mut(self, chunk_size) + assert!(chunk_size != 0); + let rem = self.len() % chunk_size; + let len = self.len() - rem; + ExactChunksMut { v: &mut self[..len], chunk_size: chunk_size} } /// Divides one slice into two at an index. @@ -1367,7 +828,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split_at(&self, mid: usize) -> (&[T], &[T]) { - SliceExt::split_at(self, mid) + (&self[..mid], &self[mid..]) } /// Divides one mutable slice into two at an index. @@ -1397,7 +858,15 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { - SliceExt::split_at_mut(self, mid) + let len = self.len(); + let ptr = self.as_mut_ptr(); + + unsafe { + assert!(mid <= len); + + (from_raw_parts_mut(ptr, mid), + from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) + } } /// Returns an iterator over subslices separated by elements that match @@ -1445,7 +914,11 @@ macro_rules! slice_core_methods { () => { pub fn split(&self, pred: F) -> Split where F: FnMut(&T) -> bool { - SliceExt::split(self, pred) + Split { + v: self, + pred, + finished: false + } } /// Returns an iterator over mutable subslices separated by elements that @@ -1466,7 +939,7 @@ macro_rules! slice_core_methods { () => { pub fn split_mut(&mut self, pred: F) -> SplitMut where F: FnMut(&T) -> bool { - SliceExt::split_mut(self, pred) + SplitMut { v: self, pred: pred, finished: false } } /// Returns an iterator over subslices separated by elements that match @@ -1501,7 +974,7 @@ macro_rules! slice_core_methods { () => { pub fn rsplit(&self, pred: F) -> RSplit where F: FnMut(&T) -> bool { - SliceExt::rsplit(self, pred) + RSplit { inner: self.split(pred) } } /// Returns an iterator over mutable subslices separated by elements that @@ -1526,7 +999,7 @@ macro_rules! slice_core_methods { () => { pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut where F: FnMut(&T) -> bool { - SliceExt::rsplit_mut(self, pred) + RSplitMut { inner: self.split_mut(pred) } } /// Returns an iterator over subslices separated by elements that match @@ -1553,7 +1026,12 @@ macro_rules! slice_core_methods { () => { pub fn splitn(&self, n: usize, pred: F) -> SplitN where F: FnMut(&T) -> bool { - SliceExt::splitn(self, n, pred) + SplitN { + inner: GenericSplitN { + iter: self.split(pred), + count: n + } + } } /// Returns an iterator over subslices separated by elements that match @@ -1578,7 +1056,12 @@ macro_rules! slice_core_methods { () => { pub fn splitn_mut(&mut self, n: usize, pred: F) -> SplitNMut where F: FnMut(&T) -> bool { - SliceExt::splitn_mut(self, n, pred) + SplitNMut { + inner: GenericSplitN { + iter: self.split_mut(pred), + count: n + } + } } /// Returns an iterator over subslices separated by elements that match @@ -1606,7 +1089,12 @@ macro_rules! slice_core_methods { () => { pub fn rsplitn(&self, n: usize, pred: F) -> RSplitN where F: FnMut(&T) -> bool { - SliceExt::rsplitn(self, n, pred) + RSplitN { + inner: GenericSplitN { + iter: self.rsplit(pred), + count: n + } + } } /// Returns an iterator over subslices separated by elements that match @@ -1632,7 +1120,12 @@ macro_rules! slice_core_methods { () => { pub fn rsplitn_mut(&mut self, n: usize, pred: F) -> RSplitNMut where F: FnMut(&T) -> bool { - SliceExt::rsplitn_mut(self, n, pred) + RSplitNMut { + inner: GenericSplitN { + iter: self.rsplit_mut(pred), + count: n + } + } } /// Returns `true` if the slice contains an element with the given value. @@ -1648,7 +1141,7 @@ macro_rules! slice_core_methods { () => { pub fn contains(&self, x: &T) -> bool where T: PartialEq { - SliceExt::contains(self, x) + x.slice_contains(self) } /// Returns `true` if `needle` is a prefix of the slice. @@ -1675,7 +1168,8 @@ macro_rules! slice_core_methods { () => { pub fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq { - SliceExt::starts_with(self, needle) + let n = needle.len(); + self.len() >= n && needle == &self[..n] } /// Returns `true` if `needle` is a suffix of the slice. @@ -1702,7 +1196,8 @@ macro_rules! slice_core_methods { () => { pub fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq { - SliceExt::ends_with(self, needle) + let (m, n) = (self.len(), needle.len()); + m >= n && needle == &self[m-n..] } /// Binary searches this sorted slice for a given element. @@ -1731,7 +1226,7 @@ macro_rules! slice_core_methods { () => { pub fn binary_search(&self, x: &T) -> Result where T: Ord { - SliceExt::binary_search(self, x) + self.binary_search_by(|p| p.cmp(x)) } /// Binary searches this sorted slice with a comparator function. @@ -1767,10 +1262,29 @@ macro_rules! slice_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result + pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result where F: FnMut(&'a T) -> Ordering { - SliceExt::binary_search_by(self, f) + let s = self; + let mut size = s.len(); + if size == 0 { + return Err(0); + } + let mut base = 0usize; + while size > 1 { + let half = size / 2; + let mid = base + half; + // mid is always in [0, size), that means mid is >= 0 and < size. + // mid >= 0: by definition + // mid < size: mid = size / 2 + size / 4 + size / 8 ... + let cmp = f(unsafe { s.get_unchecked(mid) }); + base = if cmp == Greater { base } else { mid }; + size -= half; + } + // base is always in [0, size) because base <= mid. + let cmp = f(unsafe { s.get_unchecked(base) }); + if cmp == Equal { Ok(base) } else { Err(base + (cmp == Less) as usize) } + } /// Binary searches this sorted slice with a key extraction function. @@ -1805,11 +1319,11 @@ macro_rules! slice_core_methods { () => { /// ``` #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] #[inline] - pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result + pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result where F: FnMut(&'a T) -> B, B: Ord { - SliceExt::binary_search_by_key(self, b, f) + self.binary_search_by(|k| f(k).cmp(b)) } /// Sorts the slice, but may not preserve the order of equal elements. @@ -1843,7 +1357,7 @@ macro_rules! slice_core_methods { () => { pub fn sort_unstable(&mut self) where T: Ord { - SliceExt::sort_unstable(self); + sort::quicksort(self, |a, b| a.lt(b)); } /// Sorts the slice with a comparator function, but may not preserve the order of equal @@ -1878,10 +1392,10 @@ macro_rules! slice_core_methods { () => { /// [pdqsort]: https://github.com/orlp/pdqsort #[stable(feature = "sort_unstable", since = "1.20.0")] #[inline] - pub fn sort_unstable_by(&mut self, compare: F) + pub fn sort_unstable_by(&mut self, mut compare: F) where F: FnMut(&T, &T) -> Ordering { - SliceExt::sort_unstable_by(self, compare); + sort::quicksort(self, |a, b| compare(a, b) == Ordering::Less); } /// Sorts the slice with a key extraction function, but may not preserve the order of equal @@ -1910,10 +1424,10 @@ macro_rules! slice_core_methods { () => { /// [pdqsort]: https://github.com/orlp/pdqsort #[stable(feature = "sort_unstable", since = "1.20.0")] #[inline] - pub fn sort_unstable_by_key(&mut self, f: F) + pub fn sort_unstable_by_key(&mut self, mut f: F) where F: FnMut(&T) -> K, K: Ord { - SliceExt::sort_unstable_by_key(self, f); + sort::quicksort(self, |a, b| f(a).lt(&f(b))); } /// Rotates the slice in-place such that the first `mid` elements of the @@ -1948,7 +1462,13 @@ macro_rules! slice_core_methods { () => { /// ``` #[stable(feature = "slice_rotate", since = "1.26.0")] pub fn rotate_left(&mut self, mid: usize) { - SliceExt::rotate_left(self, mid); + assert!(mid <= self.len()); + let k = self.len() - mid; + + unsafe { + let p = self.as_mut_ptr(); + rotate::ptr_rotate(mid, p.offset(mid as isize), k); + } } /// Rotates the slice in-place such that the first `self.len() - k` @@ -1983,7 +1503,13 @@ macro_rules! slice_core_methods { () => { /// ``` #[stable(feature = "slice_rotate", since = "1.26.0")] pub fn rotate_right(&mut self, k: usize) { - SliceExt::rotate_right(self, k); + assert!(k <= self.len()); + let mid = self.len() - k; + + unsafe { + let p = self.as_mut_ptr(); + rotate::ptr_rotate(mid, p.offset(mid as isize), k); + } } /// Copies the elements from `src` into `self`. @@ -2040,7 +1566,17 @@ macro_rules! slice_core_methods { () => { /// [`split_at_mut`]: #method.split_at_mut #[stable(feature = "clone_from_slice", since = "1.7.0")] pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone { - SliceExt::clone_from_slice(self, src) + assert!(self.len() == src.len(), + "destination and source slices have different lengths"); + // NOTE: We need to explicitly slice them to the same length + // for bounds checking to be elided, and the optimizer will + // generate memcpy for simple cases (for example T = u8). + let len = self.len(); + let src = &src[..len]; + for i in 0..len { + self[i].clone_from(&src[i]); + } + } /// Copies all elements from `src` into `self`, using a memcpy. @@ -2096,7 +1632,12 @@ macro_rules! slice_core_methods { () => { /// [`split_at_mut`]: #method.split_at_mut #[stable(feature = "copy_from_slice", since = "1.9.0")] pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy { - SliceExt::copy_from_slice(self, src) + assert!(self.len() == src.len(), + "destination and source slices have different lengths"); + unsafe { + ptr::copy_nonoverlapping( + src.as_ptr(), self.as_mut_ptr(), self.len()); + } } /// Swaps all elements in `self` with those in `other`. @@ -2148,22 +1689,18 @@ macro_rules! slice_core_methods { () => { /// [`split_at_mut`]: #method.split_at_mut #[stable(feature = "swap_with_slice", since = "1.27.0")] pub fn swap_with_slice(&mut self, other: &mut [T]) { - SliceExt::swap_with_slice(self, other) + assert!(self.len() == other.len(), + "destination and source slices have different lengths"); + unsafe { + ptr::swap_nonoverlapping( + self.as_mut_ptr(), other.as_mut_ptr(), self.len()); + } } -}} - -#[lang = "slice"] -#[cfg(not(test))] -#[cfg(not(stage0))] -impl [T] { - slice_core_methods!(); } -// FIXME: remove (inline) this macro -// when updating to a bootstrap compiler that has the new lang items. -#[cfg_attr(stage0, macro_export)] -#[unstable(feature = "core_slice_ext", issue = "32110")] -macro_rules! slice_u8_core_methods { () => { +#[lang = "slice_u8"] +#[cfg(not(test))] +impl [u8] { /// Checks if all bytes in this slice are within the ASCII range. #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] @@ -2217,13 +1754,7 @@ macro_rules! slice_u8_core_methods { () => { byte.make_ascii_lowercase(); } } -}} -#[lang = "slice_u8"] -#[cfg(not(test))] -#[cfg(not(stage0))] -impl [u8] { - slice_u8_core_methods!(); } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index df7b2f25a86..82bead0ab46 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2097,119 +2097,7 @@ mod traits { (..self.end+1).index_mut(slice) } } - -} - -public_in_stage0! { -{ -/// Methods for string slices -#[allow(missing_docs)] -#[doc(hidden)] -#[unstable(feature = "core_str_ext", - reason = "stable interface provided by `impl str` in later crates", - issue = "32110")] } -trait StrExt { - // NB there are no docs here are they're all located on the StrExt trait in - // liballoc, not here. - - #[stable(feature = "core", since = "1.6.0")] - fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool; - #[stable(feature = "core", since = "1.6.0")] - fn chars(&self) -> Chars; - #[stable(feature = "core", since = "1.6.0")] - fn bytes(&self) -> Bytes; - #[stable(feature = "core", since = "1.6.0")] - fn char_indices(&self) -> CharIndices; - #[stable(feature = "core", since = "1.6.0")] - fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P>; - #[stable(feature = "core", since = "1.6.0")] - fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P>; - #[stable(feature = "core", since = "1.6.0")] - fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P>; - #[stable(feature = "core", since = "1.6.0")] - fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P>; - #[stable(feature = "core", since = "1.6.0")] - fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P>; - #[stable(feature = "core", since = "1.6.0")] - fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn lines(&self) -> Lines; - #[stable(feature = "core", since = "1.6.0")] - #[rustc_deprecated(since = "1.6.0", reason = "use lines() instead now")] - #[allow(deprecated)] - fn lines_any(&self) -> LinesAny; - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - fn get>(&self, i: I) -> Option<&I::Output>; - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - fn get_mut>(&mut self, i: I) -> Option<&mut I::Output>; - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - unsafe fn get_unchecked>(&self, i: I) -> &I::Output; - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output; - #[stable(feature = "core", since = "1.6.0")] - unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str; - #[stable(feature = "core", since = "1.6.0")] - unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str; - #[stable(feature = "core", since = "1.6.0")] - fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool; - #[stable(feature = "core", since = "1.6.0")] - fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: DoubleEndedSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str; - #[stable(feature = "core", since = "1.6.0")] - fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "is_char_boundary", since = "1.9.0")] - fn is_char_boundary(&self, index: usize) -> bool; - #[stable(feature = "core", since = "1.6.0")] - fn as_bytes(&self) -> &[u8]; - #[stable(feature = "str_mut_extras", since = "1.20.0")] - unsafe fn as_bytes_mut(&mut self) -> &mut [u8]; - #[stable(feature = "core", since = "1.6.0")] - fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option; - #[stable(feature = "core", since = "1.6.0")] - fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option - where P::Searcher: ReverseSearcher<'a>; - fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option; - #[stable(feature = "core", since = "1.6.0")] - fn split_at(&self, mid: usize) -> (&str, &str); - #[stable(feature = "core", since = "1.6.0")] - fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str); - #[stable(feature = "core", since = "1.6.0")] - fn as_ptr(&self) -> *const u8; - #[stable(feature = "core", since = "1.6.0")] - fn len(&self) -> usize; - #[stable(feature = "core", since = "1.6.0")] - fn is_empty(&self) -> bool; - #[stable(feature = "core", since = "1.6.0")] - fn parse(&self) -> Result; - #[stable(feature = "split_whitespace", since = "1.1.0")] - fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>; - #[stable(feature = "rust1", since = "1.0.0")] - fn trim(&self) -> &str; - #[stable(feature = "rust1", since = "1.0.0")] - fn trim_left(&self) -> &str; - #[stable(feature = "rust1", since = "1.0.0")] - fn trim_right(&self) -> &str; -}} // truncate `&str` to length at most equal to `max` // return `true` if it were truncated, and the new str. @@ -2255,307 +2143,9 @@ fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! { index, ch, char_range, s_trunc, ellipsis); } -#[stable(feature = "core", since = "1.6.0")] -impl StrExt for str { - #[inline] - fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - pat.is_contained_in(self) - } - - #[inline] - fn chars(&self) -> Chars { - Chars{iter: self.as_bytes().iter()} - } - - #[inline] - fn bytes(&self) -> Bytes { - Bytes(self.as_bytes().iter().cloned()) - } - - #[inline] - fn char_indices(&self) -> CharIndices { - CharIndices { front_offset: 0, iter: self.chars() } - } - - #[inline] - fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { - Split(SplitInternal { - start: 0, - end: self.len(), - matcher: pat.into_searcher(self), - allow_trailing_empty: true, - finished: false, - }) - } - - #[inline] - fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - RSplit(self.split(pat).0) - } - - #[inline] - fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> { - SplitN(SplitNInternal { - iter: self.split(pat).0, - count, - }) - } - - #[inline] - fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - RSplitN(self.splitn(count, pat).0) - } - - #[inline] - fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { - SplitTerminator(SplitInternal { - allow_trailing_empty: false, - ..self.split(pat).0 - }) - } - - #[inline] - fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - RSplitTerminator(self.split_terminator(pat).0) - } - - #[inline] - fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { - Matches(MatchesInternal(pat.into_searcher(self))) - } - - #[inline] - fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - RMatches(self.matches(pat).0) - } - - #[inline] - fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { - MatchIndices(MatchIndicesInternal(pat.into_searcher(self))) - } - - #[inline] - fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - RMatchIndices(self.match_indices(pat).0) - } - #[inline] - fn lines(&self) -> Lines { - Lines(self.split_terminator('\n').map(LinesAnyMap)) - } - - #[inline] - #[allow(deprecated)] - fn lines_any(&self) -> LinesAny { - LinesAny(self.lines()) - } - - #[inline] - fn get>(&self, i: I) -> Option<&I::Output> { - i.get(self) - } - - #[inline] - fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { - i.get_mut(self) - } - - #[inline] - unsafe fn get_unchecked>(&self, i: I) -> &I::Output { - i.get_unchecked(self) - } - - #[inline] - unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { - i.get_unchecked_mut(self) - } - - #[inline] - unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { - (begin..end).get_unchecked(self) - } - - #[inline] - unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { - (begin..end).get_unchecked_mut(self) - } - - #[inline] - fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - pat.is_prefix_of(self) - } - - #[inline] - fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool - where P::Searcher: ReverseSearcher<'a> - { - pat.is_suffix_of(self) - } - - #[inline] - fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: DoubleEndedSearcher<'a> - { - let mut i = 0; - let mut j = 0; - let mut matcher = pat.into_searcher(self); - if let Some((a, b)) = matcher.next_reject() { - i = a; - j = b; // Remember earliest known match, correct it below if - // last match is different - } - if let Some((_, b)) = matcher.next_reject_back() { - j = b; - } - unsafe { - // Searcher is known to return valid indices - self.slice_unchecked(i, j) - } - } - - #[inline] - fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { - let mut i = self.len(); - let mut matcher = pat.into_searcher(self); - if let Some((a, _)) = matcher.next_reject() { - i = a; - } - unsafe { - // Searcher is known to return valid indices - self.slice_unchecked(i, self.len()) - } - } - - #[inline] - fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: ReverseSearcher<'a> - { - let mut j = 0; - let mut matcher = pat.into_searcher(self); - if let Some((_, b)) = matcher.next_reject_back() { - j = b; - } - unsafe { - // Searcher is known to return valid indices - self.slice_unchecked(0, j) - } - } - - #[inline] - fn is_char_boundary(&self, index: usize) -> bool { - // 0 and len are always ok. - // Test for 0 explicitly so that it can optimize out the check - // easily and skip reading string data for that case. - if index == 0 || index == self.len() { return true; } - match self.as_bytes().get(index) { - None => false, - // This is bit magic equivalent to: b < 128 || b >= 192 - Some(&b) => (b as i8) >= -0x40, - } - } - - #[inline] - fn as_bytes(&self) -> &[u8] { - unsafe { &*(self as *const str as *const [u8]) } - } - - #[inline] - unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { - &mut *(self as *mut str as *mut [u8]) - } - - fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { - pat.into_searcher(self).next_match().map(|(i, _)| i) - } - - fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option - where P::Searcher: ReverseSearcher<'a> - { - pat.into_searcher(self).next_match_back().map(|(i, _)| i) - } - - fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { - self.find(pat) - } - - #[inline] - fn split_at(&self, mid: usize) -> (&str, &str) { - // is_char_boundary checks that the index is in [0, .len()] - if self.is_char_boundary(mid) { - unsafe { - (self.slice_unchecked(0, mid), - self.slice_unchecked(mid, self.len())) - } - } else { - slice_error_fail(self, 0, mid) - } - } - - fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { - // is_char_boundary checks that the index is in [0, .len()] - if self.is_char_boundary(mid) { - let len = self.len(); - let ptr = self.as_ptr() as *mut u8; - unsafe { - (from_raw_parts_mut(ptr, mid), - from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) - } - } else { - slice_error_fail(self, 0, mid) - } - } - - #[inline] - fn as_ptr(&self) -> *const u8 { - self as *const str as *const u8 - } - - #[inline] - fn len(&self) -> usize { - self.as_bytes().len() - } - - #[inline] - fn is_empty(&self) -> bool { self.len() == 0 } - - #[inline] - fn parse(&self) -> Result { FromStr::from_str(self) } - - #[inline] - fn split_whitespace(&self) -> SplitWhitespace { - SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } - } - - #[inline] - fn trim(&self) -> &str { - self.trim_matches(|c: char| c.is_whitespace()) - } - - #[inline] - fn trim_left(&self) -> &str { - self.trim_left_matches(|c: char| c.is_whitespace()) - } - - #[inline] - fn trim_right(&self) -> &str { - self.trim_right_matches(|c: char| c.is_whitespace()) - } -} - -// FIXME: remove (inline) this macro and the SliceExt trait -// when updating to a bootstrap compiler that has the new lang items. -#[cfg_attr(stage0, macro_export)] -#[unstable(feature = "core_str_ext", issue = "32110")] -macro_rules! str_core_methods { () => { +#[lang = "str"] +#[cfg(not(test))] +impl str { /// Returns the length of `self`. /// /// This length is in bytes, not [`char`]s or graphemes. In other words, @@ -2577,7 +2167,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn len(&self) -> usize { - StrExt::len(self) + self.as_bytes().len() } /// Returns `true` if `self` has a length of zero bytes. @@ -2596,7 +2186,7 @@ macro_rules! str_core_methods { () => { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_empty(&self) -> bool { - StrExt::is_empty(self) + self.len() == 0 } /// Checks that `index`-th byte lies at the start and/or end of a @@ -2626,7 +2216,15 @@ macro_rules! str_core_methods { () => { #[stable(feature = "is_char_boundary", since = "1.9.0")] #[inline] pub fn is_char_boundary(&self, index: usize) -> bool { - StrExt::is_char_boundary(self, index) + // 0 and len are always ok. + // Test for 0 explicitly so that it can optimize out the check + // easily and skip reading string data for that case. + if index == 0 || index == self.len() { return true; } + match self.as_bytes().get(index) { + None => false, + // This is bit magic equivalent to: b < 128 || b >= 192 + Some(&b) => (b as i8) >= -0x40, + } } /// Converts a string slice to a byte slice. To convert the byte slice back @@ -2645,7 +2243,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline(always)] pub fn as_bytes(&self) -> &[u8] { - StrExt::as_bytes(self) + unsafe { &*(self as *const str as *const [u8]) } } /// Converts a mutable string slice to a mutable byte slice. To convert the @@ -2684,7 +2282,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_mut_extras", since = "1.20.0")] #[inline(always)] pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { - StrExt::as_bytes_mut(self) + &mut *(self as *mut str as *mut [u8]) } /// Converts a string slice to a raw pointer. @@ -2706,7 +2304,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn as_ptr(&self) -> *const u8 { - StrExt::as_ptr(self) + self as *const str as *const u8 } /// Returns a subslice of `str`. @@ -2733,7 +2331,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub fn get>(&self, i: I) -> Option<&I::Output> { - StrExt::get(self, i) + i.get(self) } /// Returns a mutable subslice of `str`. @@ -2767,7 +2365,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { - StrExt::get_mut(self, i) + i.get_mut(self) } /// Returns a unchecked subslice of `str`. @@ -2799,7 +2397,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub unsafe fn get_unchecked>(&self, i: I) -> &I::Output { - StrExt::get_unchecked(self, i) + i.get_unchecked(self) } /// Returns a mutable, unchecked subslice of `str`. @@ -2831,7 +2429,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { - StrExt::get_unchecked_mut(self, i) + i.get_unchecked_mut(self) } /// Creates a string slice from another string slice, bypassing safety @@ -2880,7 +2478,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { - StrExt::slice_unchecked(self, begin, end) + (begin..end).get_unchecked(self) } /// Creates a string slice from another string slice, bypassing safety @@ -2910,7 +2508,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_slice_mut", since = "1.5.0")] #[inline] pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { - StrExt::slice_mut_unchecked(self, begin, end) + (begin..end).get_unchecked_mut(self) } /// Divide one string slice into two at an index. @@ -2946,7 +2544,15 @@ macro_rules! str_core_methods { () => { #[inline] #[stable(feature = "str_split_at", since = "1.4.0")] pub fn split_at(&self, mid: usize) -> (&str, &str) { - StrExt::split_at(self, mid) + // is_char_boundary checks that the index is in [0, .len()] + if self.is_char_boundary(mid) { + unsafe { + (self.slice_unchecked(0, mid), + self.slice_unchecked(mid, self.len())) + } + } else { + slice_error_fail(self, 0, mid) + } } /// Divide one mutable string slice into two at an index. @@ -2983,7 +2589,17 @@ macro_rules! str_core_methods { () => { #[inline] #[stable(feature = "str_split_at", since = "1.4.0")] pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { - StrExt::split_at_mut(self, mid) + // is_char_boundary checks that the index is in [0, .len()] + if self.is_char_boundary(mid) { + let len = self.len(); + let ptr = self.as_ptr() as *mut u8; + unsafe { + (from_raw_parts_mut(ptr, mid), + from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) + } + } else { + slice_error_fail(self, 0, mid) + } } /// Returns an iterator over the [`char`]s of a string slice. @@ -3035,8 +2651,9 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn chars(&self) -> Chars { - StrExt::chars(self) + Chars{iter: self.as_bytes().iter()} } + /// Returns an iterator over the [`char`]s of a string slice, and their /// positions. /// @@ -3091,7 +2708,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn char_indices(&self) -> CharIndices { - StrExt::char_indices(self) + CharIndices { front_offset: 0, iter: self.chars() } } /// An iterator over the bytes of a string slice. @@ -3116,7 +2733,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn bytes(&self) -> Bytes { - StrExt::bytes(self) + Bytes(self.as_bytes().iter().cloned()) } /// Split a string slice by whitespace. @@ -3156,7 +2773,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "split_whitespace", since = "1.1.0")] #[inline] pub fn split_whitespace(&self) -> SplitWhitespace { - StrExt::split_whitespace(self) + SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } } /// An iterator over the lines of a string, as string slices. @@ -3198,7 +2815,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn lines(&self) -> Lines { - StrExt::lines(self) + Lines(self.split_terminator('\n').map(LinesAnyMap)) } /// An iterator over the lines of a string. @@ -3207,7 +2824,7 @@ macro_rules! str_core_methods { () => { #[inline] #[allow(deprecated)] pub fn lines_any(&self) -> LinesAny { - StrExt::lines_any(self) + LinesAny(self.lines()) } /// Returns an iterator of `u16` over the string encoded as UTF-16. @@ -3226,7 +2843,7 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "encode_utf16", since = "1.8.0")] pub fn encode_utf16(&self) -> EncodeUtf16 { - EncodeUtf16::new(self) + EncodeUtf16 { chars: self.chars(), extra: 0 } } /// Returns `true` if the given pattern matches a sub-slice of @@ -3247,7 +2864,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - StrExt::contains(self, pat) + pat.is_contained_in(self) } /// Returns `true` if the given pattern matches a prefix of this @@ -3267,7 +2884,7 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - StrExt::starts_with(self, pat) + pat.is_prefix_of(self) } /// Returns `true` if the given pattern matches a suffix of this @@ -3289,7 +2906,7 @@ macro_rules! str_core_methods { () => { pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool where P::Searcher: ReverseSearcher<'a> { - StrExt::ends_with(self, pat) + pat.is_suffix_of(self) } /// Returns the byte index of the first character of this string slice that @@ -3337,7 +2954,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { - StrExt::find(self, pat) + pat.into_searcher(self).next_match().map(|(i, _)| i) } /// Returns the byte index of the last character of this string slice that @@ -3384,7 +3001,7 @@ macro_rules! str_core_methods { () => { pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option where P::Searcher: ReverseSearcher<'a> { - StrExt::rfind(self, pat) + pat.into_searcher(self).next_match_back().map(|(i, _)| i) } /// An iterator over substrings of this string slice, separated by @@ -3496,7 +3113,13 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { - StrExt::split(self, pat) + Split(SplitInternal { + start: 0, + end: self.len(), + matcher: pat.into_searcher(self), + allow_trailing_empty: true, + finished: false, + }) } /// An iterator over substrings of the given string slice, separated by @@ -3548,7 +3171,7 @@ macro_rules! str_core_methods { () => { pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> where P::Searcher: ReverseSearcher<'a> { - StrExt::rsplit(self, pat) + RSplit(self.split(pat).0) } /// An iterator over substrings of the given string slice, separated by @@ -3593,7 +3216,10 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { - StrExt::split_terminator(self, pat) + SplitTerminator(SplitInternal { + allow_trailing_empty: false, + ..self.split(pat).0 + }) } /// An iterator over substrings of `self`, separated by characters @@ -3639,7 +3265,7 @@ macro_rules! str_core_methods { () => { pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> where P::Searcher: ReverseSearcher<'a> { - StrExt::rsplit_terminator(self, pat) + RSplitTerminator(self.split_terminator(pat).0) } /// An iterator over substrings of the given string slice, separated by a @@ -3690,7 +3316,10 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> { - StrExt::splitn(self, n, pat) + SplitN(SplitNInternal { + iter: self.split(pat).0, + count: n, + }) } /// An iterator over substrings of this string slice, separated by a @@ -3740,7 +3369,7 @@ macro_rules! str_core_methods { () => { pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P> where P::Searcher: ReverseSearcher<'a> { - StrExt::rsplitn(self, n, pat) + RSplitN(self.splitn(n, pat).0) } /// An iterator over the disjoint matches of a pattern within the given string @@ -3779,7 +3408,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_matches", since = "1.2.0")] #[inline] pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { - StrExt::matches(self, pat) + Matches(MatchesInternal(pat.into_searcher(self))) } /// An iterator over the disjoint matches of a pattern within this string slice, @@ -3818,7 +3447,7 @@ macro_rules! str_core_methods { () => { pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> where P::Searcher: ReverseSearcher<'a> { - StrExt::rmatches(self, pat) + RMatches(self.matches(pat).0) } /// An iterator over the disjoint matches of a pattern within this string @@ -3862,7 +3491,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_match_indices", since = "1.5.0")] #[inline] pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { - StrExt::match_indices(self, pat) + MatchIndices(MatchIndicesInternal(pat.into_searcher(self))) } /// An iterator over the disjoint matches of a pattern within `self`, @@ -3907,7 +3536,7 @@ macro_rules! str_core_methods { () => { pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> where P::Searcher: ReverseSearcher<'a> { - StrExt::rmatch_indices(self, pat) + RMatchIndices(self.match_indices(pat).0) } /// Returns a string slice with leading and trailing whitespace removed. @@ -3926,7 +3555,7 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim(&self) -> &str { - StrExt::trim(self) + self.trim_matches(|c: char| c.is_whitespace()) } /// Returns a string slice with leading whitespace removed. @@ -3962,7 +3591,7 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim_left(&self) -> &str { - StrExt::trim_left(self) + self.trim_left_matches(|c: char| c.is_whitespace()) } /// Returns a string slice with trailing whitespace removed. @@ -3998,7 +3627,7 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim_right(&self) -> &str { - StrExt::trim_right(self) + self.trim_right_matches(|c: char| c.is_whitespace()) } /// Returns a string slice with all prefixes and suffixes that match a @@ -4030,7 +3659,21 @@ macro_rules! str_core_methods { () => { pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str where P::Searcher: DoubleEndedSearcher<'a> { - StrExt::trim_matches(self, pat) + let mut i = 0; + let mut j = 0; + let mut matcher = pat.into_searcher(self); + if let Some((a, b)) = matcher.next_reject() { + i = a; + j = b; // Remember earliest known match, correct it below if + // last match is different + } + if let Some((_, b)) = matcher.next_reject_back() { + j = b; + } + unsafe { + // Searcher is known to return valid indices + self.slice_unchecked(i, j) + } } /// Returns a string slice with all prefixes that match a pattern @@ -4061,7 +3704,15 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { - StrExt::trim_left_matches(self, pat) + let mut i = self.len(); + let mut matcher = pat.into_searcher(self); + if let Some((a, _)) = matcher.next_reject() { + i = a; + } + unsafe { + // Searcher is known to return valid indices + self.slice_unchecked(i, self.len()) + } } /// Returns a string slice with all suffixes that match a pattern @@ -4100,7 +3751,15 @@ macro_rules! str_core_methods { () => { pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str where P::Searcher: ReverseSearcher<'a> { - StrExt::trim_right_matches(self, pat) + let mut j = 0; + let mut matcher = pat.into_searcher(self); + if let Some((_, b)) = matcher.next_reject_back() { + j = b; + } + unsafe { + // Searcher is known to return valid indices + self.slice_unchecked(0, j) + } } /// Parses this string slice into another type. @@ -4150,7 +3809,7 @@ macro_rules! str_core_methods { () => { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn parse(&self) -> Result { - StrExt::parse(self) + FromStr::from_str(self) } /// Checks if all characters in this string are within the ASCII range. @@ -4220,16 +3879,8 @@ macro_rules! str_core_methods { () => { let me = unsafe { self.as_bytes_mut() }; me.make_ascii_lowercase() } -}} - -#[lang = "str"] -#[cfg(not(test))] -#[cfg(not(stage0))] -impl str { - str_core_methods!(); } - #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<[u8]> for str { #[inline] @@ -4332,17 +3983,6 @@ pub struct EncodeUtf16<'a> { extra: u16, } -// FIXME: remove (inline) this method -// when updating to a bootstrap compiler that has the new lang items. -// For grepping purpose: #[cfg(stage0)] -impl<'a> EncodeUtf16<'a> { - #[unstable(feature = "core_str_ext", issue = "32110")] - #[doc(hidden)] - pub fn new(s: &'a str) -> Self { - EncodeUtf16 { chars: s.chars(), extra: 0 } - } -} - #[stable(feature = "collection_debug", since = "1.17.0")] impl<'a> fmt::Debug for EncodeUtf16<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 7fb4b503c01..8c481338945 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -41,7 +41,6 @@ #![feature(try_from)] #![feature(try_trait)] #![feature(exact_chunks)] -#![cfg_attr(stage0, feature(atomic_nand))] #![feature(reverse_bits)] #![feature(inclusive_range_methods)] #![feature(iterator_find_map)] diff --git a/src/libcore/tests/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs index 257f6ea20d4..ca6906f7310 100644 --- a/src/libcore/tests/num/uint_macros.rs +++ b/src/libcore/tests/num/uint_macros.rs @@ -98,7 +98,6 @@ mod tests { } #[test] - #[cfg(not(stage0))] fn test_reverse_bits() { assert_eq!(A.reverse_bits().reverse_bits(), A); assert_eq!(B.reverse_bits().reverse_bits(), B); diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index ac6ff6831ad..bbd684982fa 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -46,7 +46,6 @@ #![feature(core_intrinsics)] #![feature(drain_filter)] #![feature(entry_or_default)] -#![cfg_attr(stage0, feature(dyn_trait))] #![feature(from_ref)] #![feature(fs_read_write)] #![feature(iterator_find_map)] diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 0b1729294d8..a162ef36a60 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -240,11 +240,11 @@ fn dump_mir_results<'a, 'gcx, 'tcx>( }); // Also dump the inference graph constraints as a graphviz file. - let _: io::Result<()> = do_catch! {{ + let _: io::Result<()> = do catch { let mut file = pretty::create_dump_file(infcx.tcx, "regioncx.dot", None, "nll", &0, source)?; regioncx.dump_graphviz(&mut file)?; - }}; + }; } fn dump_annotation<'a, 'gcx, 'tcx>( diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index ecced1b8168..d9b6c406e20 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -24,7 +24,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(decl_macro)] -#![cfg_attr(stage0, feature(dyn_trait))] #![feature(fs_read_write)] #![feature(macro_vis_matcher)] #![feature(exhaustive_patterns)] @@ -34,7 +33,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(crate_visibility_modifier)] #![feature(never_type)] #![feature(specialization)] -#![cfg_attr(stage0, feature(try_trait))] +#![feature(try_trait)] extern crate arena; #[macro_use] @@ -54,16 +53,6 @@ extern crate log_settings; extern crate rustc_apfloat; extern crate byteorder; -#[cfg(stage0)] -macro_rules! do_catch { - ($t:expr) => { (|| ::std::ops::Try::from_ok($t) )() } -} - -#[cfg(not(stage0))] -macro_rules! do_catch { - ($t:expr) => { do catch { $t } } -} - mod diagnostics; mod borrow_check; diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 9d74ad0830f..9e1ce9b2851 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -137,7 +137,7 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>( ) where F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, { - let _: io::Result<()> = do_catch! {{ + let _: io::Result<()> = do catch { let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, source)?; writeln!(file, "// MIR for `{}`", node_path)?; writeln!(file, "// source = {:?}", source)?; @@ -150,14 +150,14 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>( extra_data(PassWhere::BeforeCFG, &mut file)?; write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?; extra_data(PassWhere::AfterCFG, &mut file)?; - }}; + }; if tcx.sess.opts.debugging_opts.dump_mir_graphviz { - let _: io::Result<()> = do_catch! {{ + let _: io::Result<()> = do catch { let mut file = create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, source)?; write_mir_fn_graphviz(tcx, source.def_id, mir, &mut file)?; - }}; + }; } } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 350b53a406b..ef79517d06a 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -71,8 +71,6 @@ This API is completely unstable and subject to change. #![allow(non_camel_case_types)] -#![cfg_attr(stage0, feature(dyn_trait))] - #![feature(box_patterns)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index a14a27d5d61..e4b80b13aec 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -13,8 +13,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/")] -#![cfg_attr(stage0, feature(dyn_trait))] - #![feature(ascii_ctype)] #![feature(rustc_private)] #![feature(box_patterns)] diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index a8578404467..78d3d6d5e60 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -17,7 +17,6 @@ #[doc(inline)] pub use alloc_system::System; #[doc(inline)] pub use core::alloc::*; -#[cfg(not(stage0))] #[cfg(not(test))] #[doc(hidden)] #[lang = "oom"] @@ -43,13 +42,6 @@ pub mod __default_lib_allocator { System.alloc(layout) as *mut u8 } - #[cfg(stage0)] - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_oom() -> ! { - super::oom() - } - #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, @@ -74,57 +66,4 @@ pub mod __default_lib_allocator { let layout = Layout::from_size_align_unchecked(size, align); System.alloc_zeroed(layout) as *mut u8 } - - #[cfg(stage0)] - pub mod stage0 { - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_usable_size(_layout: *const u8, - _min: *mut usize, - _max: *mut usize) { - unimplemented!() - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc_excess(_size: usize, - _align: usize, - _excess: *mut usize, - _err: *mut u8) -> *mut u8 { - unimplemented!() - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_realloc_excess(_ptr: *mut u8, - _old_size: usize, - _old_align: usize, - _new_size: usize, - _new_align: usize, - _excess: *mut usize, - _err: *mut u8) -> *mut u8 { - unimplemented!() - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_grow_in_place(_ptr: *mut u8, - _old_size: usize, - _old_align: usize, - _new_size: usize, - _new_align: usize) -> u8 { - unimplemented!() - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_shrink_in_place(_ptr: *mut u8, - _old_size: usize, - _old_align: usize, - _new_size: usize, - _new_align: usize) -> u8 { - unimplemented!() - } - - } } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 7314d32b020..ae30321f46d 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -18,15 +18,9 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#[cfg(not(test))] -#[cfg(stage0)] -use core::num::Float; #[cfg(not(test))] use intrinsics; #[cfg(not(test))] -#[cfg(stage0)] -use num::FpCategory; -#[cfg(not(test))] use sys::cmath; #[stable(feature = "rust1", since = "1.0.0")] @@ -41,12 +35,8 @@ pub use core::f32::{MIN, MIN_POSITIVE, MAX}; pub use core::f32::consts; #[cfg(not(test))] -#[cfg_attr(stage0, lang = "f32")] -#[cfg_attr(not(stage0), lang = "f32_runtime")] +#[lang = "f32_runtime"] impl f32 { - #[cfg(stage0)] - f32_core_methods!(); - /// Returns the largest integer less than or equal to a number. /// /// # Examples diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 75edba8979f..7950d434b77 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -18,15 +18,9 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#[cfg(not(test))] -#[cfg(stage0)] -use core::num::Float; #[cfg(not(test))] use intrinsics; #[cfg(not(test))] -#[cfg(stage0)] -use num::FpCategory; -#[cfg(not(test))] use sys::cmath; #[stable(feature = "rust1", since = "1.0.0")] @@ -41,12 +35,8 @@ pub use core::f64::{MIN, MIN_POSITIVE, MAX}; pub use core::f64::consts; #[cfg(not(test))] -#[cfg_attr(stage0, lang = "f64")] -#[cfg_attr(not(stage0), lang = "f64_runtime")] +#[lang = "f64_runtime"] impl f64 { - #[cfg(stage0)] - f64_core_methods!(); - /// Returns the largest integer less than or equal to a number. /// /// # Examples diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 9cdc6a21622..f7d06852f27 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -252,7 +252,6 @@ #![feature(collections_range)] #![feature(compiler_builtins_lib)] #![feature(const_fn)] -#![cfg_attr(stage0, feature(core_float))] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] @@ -260,10 +259,8 @@ #![feature(fs_read_write)] #![feature(fixed_size_array)] #![feature(float_from_str_radix)] -#![cfg_attr(stage0, feature(float_internals))] #![feature(fn_traits)] #![feature(fnbox)] -#![cfg_attr(stage0, feature(generic_param_attrs))] #![feature(hashmap_internals)] #![feature(heap_api)] #![feature(int_error_internals)] @@ -319,6 +316,7 @@ #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] #![feature(doc_alias)] +#![feature(float_internals)] #![default_lib_allocator] @@ -364,11 +362,6 @@ extern crate libc; #[allow(unused_extern_crates)] extern crate unwind; -// compiler-rt intrinsics -#[doc(masked)] -#[cfg(stage0)] -extern crate compiler_builtins; - // During testing, this crate is not actually the "real" std library, but rather // it links to the real std library, which was compiled from this same source // code. So any lang items std defines are conditionally excluded (or else they diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 369c5b1ff60..dd8f79d20ab 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -45,17 +45,6 @@ impl State { } } -macro_rules! span_err_if_not_stage0 { - ($cx:expr, $sp:expr, $code:ident, $text:tt) => { - #[cfg(not(stage0))] { - span_err!($cx, $sp, $code, $text) - } - #[cfg(stage0)] { - $cx.span_err($sp, $text) - } - } -} - const OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"]; pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, @@ -100,7 +89,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, if asm_str_style.is_some() { // If we already have a string with instructions, // ending up in Asm state again is an error. - span_err_if_not_stage0!(cx, sp, E0660, "malformed inline assembly"); + span_err!(cx, sp, E0660, "malformed inline assembly"); return DummyResult::expr(sp); } // Nested parser, stop before the first colon (see above). @@ -153,7 +142,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, Some(Symbol::intern(&format!("={}", ch.as_str()))) } _ => { - span_err_if_not_stage0!(cx, span, E0661, + span_err!(cx, span, E0661, "output operand constraint lacks '=' or '+'"); None } @@ -179,10 +168,10 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, let (constraint, _str_style) = panictry!(p.parse_str()); if constraint.as_str().starts_with("=") { - span_err_if_not_stage0!(cx, p.prev_span, E0662, + span_err!(cx, p.prev_span, E0662, "input operand constraint contains '='"); } else if constraint.as_str().starts_with("+") { - span_err_if_not_stage0!(cx, p.prev_span, E0663, + span_err!(cx, p.prev_span, E0663, "input operand constraint contains '+'"); } @@ -205,7 +194,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, if OPTIONS.iter().any(|&opt| s == opt) { cx.span_warn(p.prev_span, "expected a clobber, found an option"); } else if s.as_str().starts_with("{") || s.as_str().ends_with("}") { - span_err_if_not_stage0!(cx, p.prev_span, E0664, + span_err!(cx, p.prev_span, E0664, "clobber should not be surrounded by braces"); } diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index b6721dd28f3..e100ef29225 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -18,7 +18,7 @@ #![feature(decl_macro)] #![feature(str_escape)] -#![cfg_attr(not(stage0), feature(rustc_diagnostic_macros))] +#![feature(rustc_diagnostic_macros)] extern crate fmt_macros; #[macro_use] @@ -29,7 +29,6 @@ extern crate rustc_data_structures; extern crate rustc_errors as errors; extern crate rustc_target; -#[cfg(not(stage0))] mod diagnostics; mod assert; diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs index 7d5581bb774..8ff401164c1 100644 --- a/src/rtstartup/rsbegin.rs +++ b/src/rtstartup/rsbegin.rs @@ -23,7 +23,7 @@ // of other runtime components (registered via yet another special image section). #![feature(no_core, lang_items, optin_builtin_traits)] -#![crate_type="rlib"] +#![crate_type = "rlib"] #![no_core] #![allow(non_camel_case_types)] @@ -43,7 +43,7 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { drop_in_place(to_drop); } -#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] +#[cfg(all(target_os = "windows", target_arch = "x86", target_env = "gnu"))] pub mod eh_frames { #[no_mangle] #[link_section = ".eh_frame"] @@ -54,6 +54,21 @@ pub mod eh_frames { // This is defined as `struct object` in $GCC/libgcc/unwind-dw2-fde.h. static mut OBJ: [isize; 6] = [0; 6]; + macro_rules! impl_copy { + ($($t:ty)*) => { + $( + impl ::Copy for $t {} + )* + } + } + + impl_copy! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 + f32 f64 + bool char + } + // Unwind info registration/deregistration routines. // See the docs of `unwind` module in libstd. extern "C" { @@ -63,14 +78,18 @@ pub mod eh_frames { unsafe fn init() { // register unwind info on module startup - rust_eh_register_frames(&__EH_FRAME_BEGIN__ as *const u8, - &mut OBJ as *mut _ as *mut u8); + rust_eh_register_frames( + &__EH_FRAME_BEGIN__ as *const u8, + &mut OBJ as *mut _ as *mut u8, + ); } unsafe fn uninit() { // unregister on shutdown - rust_eh_unregister_frames(&__EH_FRAME_BEGIN__ as *const u8, - &mut OBJ as *mut _ as *mut u8); + rust_eh_unregister_frames( + &__EH_FRAME_BEGIN__ as *const u8, + &mut OBJ as *mut _ as *mut u8, + ); } // MSVC-specific init/uninit routine registration diff --git a/src/stage0.txt b/src/stage0.txt index a5ad2b315a1..435cfd2f6db 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.x.0` for Cargo where they were released on `date`. -date: 2018-04-24 +date: 2018-05-10 rustc: beta cargo: beta -- cgit 1.4.1-3-g733a5 From eac94d105394a34f54beddfb77f1d4e7b18769e7 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Thu, 17 May 2018 13:19:41 -0400 Subject: Revert #49767 There was [some confusion](https://github.com/rust-lang/rust/pull/49767#issuecomment-389250815) and I accidentally merged a PR that wasn't ready. --- src/libcore/intrinsics.rs | 161 ++++---------------- src/libcore/ptr.rs | 370 +++++++++------------------------------------- 2 files changed, 101 insertions(+), 430 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 7d3e7af1a18..fb0d2d9c882 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -962,122 +962,59 @@ extern "rust-intrinsic" { /// value is not necessarily valid to be used to actually access memory. pub fn arith_offset(dst: *const T, offset: isize) -> *const T; - /// Copies `count * size_of::()` bytes from `src` to `dst`. The source - /// and destination must *not* overlap. + /// Copies `count * size_of` bytes from `src` to `dst`. The source + /// and destination may *not* overlap. /// - /// For regions of memory which might overlap, use [`copy`] instead. - /// - /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`]. - /// - /// [`copy`]: ./fn.copy.html - /// [`memcpy`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memcpy + /// `copy_nonoverlapping` is semantically equivalent to C's `memcpy`. /// /// # Safety /// - /// Behavior is undefined if any of the following conditions are violated: - /// - /// * The region of memory which begins at `src` and has a length of - /// `count * size_of::()` bytes must be *both* valid and initialized. - /// - /// * The region of memory which begins at `dst` and has a length of - /// `count * size_of::()` bytes must be valid (but may or may not be - /// initialized). - /// - /// * The two regions of memory must *not* overlap. - /// - /// * `src` must be properly aligned. - /// - /// * `dst` must be properly aligned. - /// - /// Additionally, if `T` is not [`Copy`], only the region at `src` *or* the - /// region at `dst` can be used or dropped after calling - /// `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise copies of - /// `T`, regardless of whether `T: Copy`, which can result in undefined - /// behavior if both copies are used. - /// - /// [`Copy`]: ../marker/trait.Copy.html + /// Beyond requiring that the program must be allowed to access both regions + /// of memory, it is Undefined Behavior for source and destination to + /// overlap. Care must also be taken with the ownership of `src` and + /// `dst`. This method semantically moves the values of `src` into `dst`. + /// However it does not drop the contents of `dst`, or prevent the contents + /// of `src` from being dropped or used. /// /// # Examples /// - /// Manually implement [`Vec::append`]: + /// A safe swap function: /// /// ``` + /// use std::mem; /// use std::ptr; /// - /// /// Moves all the elements of `src` into `dst`, leaving `src` empty. - /// fn append(dst: &mut Vec, src: &mut Vec) { - /// let src_len = src.len(); - /// let dst_len = dst.len(); - /// - /// // Ensure that `dst` has enough capacity to hold all of `src`. - /// dst.reserve(src_len); - /// + /// # #[allow(dead_code)] + /// fn swap(x: &mut T, y: &mut T) { /// unsafe { - /// // The call to offset is always safe because `Vec` will never - /// // allocate more than `isize::MAX` bytes. - /// let dst = dst.as_mut_ptr().offset(dst_len as isize); - /// let src = src.as_ptr(); - /// - /// // The two regions cannot overlap becuase mutable references do - /// // not alias, and two different vectors cannot own the same - /// // memory. - /// ptr::copy_nonoverlapping(src, dst, src_len); - /// } + /// // Give ourselves some scratch space to work with + /// let mut t: T = mem::uninitialized(); /// - /// unsafe { - /// // Truncate `src` without dropping its contents. - /// src.set_len(0); + /// // Perform the swap, `&mut` pointers never alias + /// ptr::copy_nonoverlapping(x, &mut t, 1); + /// ptr::copy_nonoverlapping(y, x, 1); + /// ptr::copy_nonoverlapping(&t, y, 1); /// - /// // Notify `dst` that it now holds the contents of `src`. - /// dst.set_len(dst_len + src_len); + /// // y and t now point to the same thing, but we need to completely forget `t` + /// // because it's no longer relevant. + /// mem::forget(t); /// } /// } - /// - /// let mut a = vec!['r']; - /// let mut b = vec!['u', 's', 't']; - /// - /// append(&mut a, &mut b); - /// - /// assert_eq!(a, &['r', 'u', 's', 't']); - /// assert!(b.is_empty()); /// ``` - /// - /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append #[stable(feature = "rust1", since = "1.0.0")] pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); - /// Copies `count * size_of::()` bytes from `src` to `dst`. The source + /// Copies `count * size_of` bytes from `src` to `dst`. The source /// and destination may overlap. /// - /// If the source and destination will *never* overlap, - /// [`copy_nonoverlapping`] can be used instead. - /// - /// `copy` is semantically equivalent to C's [`memmove`]. - /// - /// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html - /// [`memmove`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memmove + /// `copy` is semantically equivalent to C's `memmove`. /// /// # Safety /// - /// Behavior is undefined if any of the following conditions are violated: - /// - /// * The region of memory which begins at `src` and has a length of - /// `count * size_of::()` bytes must be *both* valid and initialized. - /// - /// * The region of memory which begins at `dst` and has a length of - /// `count * size_of::()` bytes must be valid (but may or may not be - /// initialized). - /// - /// * `src` must be properly aligned. - /// - /// * `dst` must be properly aligned. - /// - /// Additionally, if `T` is not [`Copy`], only the region at `src` *or* the - /// region at `dst` can be used or dropped after calling `copy`. `copy` - /// creates bitwise copies of `T`, regardless of whether `T: Copy`, which - /// can result in undefined behavior if both copies are used. - /// - /// [`Copy`]: ../marker/trait.Copy.html + /// Care must be taken with the ownership of `src` and `dst`. + /// This method semantically moves the values of `src` into `dst`. + /// However it does not drop the contents of `dst`, or prevent the contents of `src` + /// from being dropped or used. /// /// # Examples /// @@ -1094,34 +1031,15 @@ extern "rust-intrinsic" { /// dst /// } /// ``` + /// #[stable(feature = "rust1", since = "1.0.0")] pub fn copy(src: *const T, dst: *mut T, count: usize); - /// Sets `count * size_of::()` bytes of memory starting at `dst` to - /// `val`. - /// - /// `write_bytes` is semantically equivalent to C's [`memset`]. - /// - /// [`memset`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memset - /// - /// # Safety - /// - /// Behavior is undefined if any of the following conditions are violated: - /// - /// * The region of memory which begins at `dst` and has a length of - /// `count` bytes must be valid. - /// - /// * `dst` must be properly aligned. - /// - /// Additionally, the caller must ensure that writing `count` bytes to the - /// given region of memory results in a valid value of `T`. Creating an - /// invalid value of `T` can result in undefined behavior. An example is - /// provided below. + /// Invokes memset on the specified pointer, setting `count * size_of::()` + /// bytes of memory starting at `dst` to `val`. /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::ptr; /// @@ -1132,23 +1050,6 @@ extern "rust-intrinsic" { /// } /// assert_eq!(vec, [b'a', b'a', 0, 0]); /// ``` - /// - /// Creating an invalid value: - /// - /// ```no_run - /// use std::{mem, ptr}; - /// - /// let mut v = Box::new(0i32); - /// - /// unsafe { - /// // Leaks the previously held value by overwriting the `Box` with - /// // a null pointer. - /// ptr::write_bytes(&mut v, 0, mem::size_of::>()); - /// } - /// - /// // At this point, using or dropping `v` results in undefined behavior. - /// // v = Box::new(0i32); // ERROR - /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn write_bytes(dst: *mut T, val: u8, count: usize); diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 63bcc024020..5f778482f42 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -10,7 +10,7 @@ // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory -//! Manually manage memory through raw pointers. +//! Raw, unsafe pointers, `*const T`, and `*mut T`. //! //! *[See also the pointer primitive types](../../std/primitive.pointer.html).* @@ -38,62 +38,21 @@ pub use intrinsics::write_bytes; /// Executes the destructor (if any) of the pointed-to value. /// -/// This is semantically equivalent to calling [`ptr::read`] and discarding -/// the result, but has the following advantages: +/// This has two use cases: /// /// * It is *required* to use `drop_in_place` to drop unsized types like /// trait objects, because they can't be read out onto the stack and /// dropped normally. /// -/// * It is friendlier to the optimizer to do this over [`ptr::read`] when +/// * It is friendlier to the optimizer to do this over `ptr::read` when /// dropping manually allocated memory (e.g. when writing Box/Rc/Vec), /// as the compiler doesn't need to prove that it's sound to elide the /// copy. /// -/// [`ptr::read`]: ../ptr/fn.read.html -/// /// # Safety /// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `to_drop` must point to valid memory. -/// -/// * `to_drop` must be properly aligned. -/// -/// Additionally, if `T` is not [`Copy`], using the pointed-to value after -/// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop = -/// foo` counts as a use because it will cause the the value to be dropped -/// again. [`write`] can be used to overwrite data without causing it to be -/// dropped. -/// -/// [`Copy`]: ../marker/trait.Copy.html -/// [`write`]: ../ptr/fn.write.html -/// -/// # Examples -/// -/// Manually remove the last item from a vector: -/// -/// ``` -/// use std::ptr; -/// use std::rc::Rc; -/// -/// let last = Rc::new(1); -/// let weak = Rc::downgrade(&last); -/// -/// let mut v = vec![Rc::new(0), last]; -/// -/// unsafe { -/// // Without a call `drop_in_place`, the last item would never be dropped, -/// // and the memory it manages would be leaked. -/// ptr::drop_in_place(&mut v[1]); -/// v.set_len(1); -/// } -/// -/// assert_eq!(v, &[0.into()]); -/// -/// // Ensure that the last item was dropped. -/// assert!(weak.upgrade().is_none()); -/// ``` +/// This has all the same safety problems as `ptr::read` with respect to +/// invalid pointers, types, and double drops. #[stable(feature = "drop_in_place", since = "1.8.0")] #[lang = "drop_in_place"] #[allow(unconditional_recursion)] @@ -134,25 +93,17 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// Swaps the values at two mutable locations of the same type, without /// deinitializing either. /// -/// But for the following two exceptions, this function is semantically -/// equivalent to [`mem::swap`]: -/// -/// * It operates on raw pointers instead of references. When references are -/// available, [`mem::swap`] should be preferred. -/// -/// * The two pointed-to values may overlap. If the values do overlap, then the -/// overlapping region of memory from `x` will be used. This is demonstrated -/// in the examples below. -/// -/// [`mem::swap`]: ../mem/fn.swap.html +/// The values pointed at by `x` and `y` may overlap, unlike `mem::swap` which +/// is otherwise equivalent. If the values do overlap, then the overlapping +/// region of memory from `x` will be used. This is demonstrated in the +/// examples section below. /// /// # Safety /// -/// Behavior is undefined if any of the following conditions are violated: +/// This function copies the memory through the raw pointers passed to it +/// as arguments. /// -/// * `x` and `y` must point to valid, initialized memory. -/// -/// * `x` and `y` must be properly aligned. +/// Ensure that these pointers are valid before calling `swap`. /// /// # Examples /// @@ -288,39 +239,13 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { } } -/// Replaces the value at `dest` with `src`, returning the old value, without -/// dropping either. -/// -/// This function is semantically equivalent to [`mem::replace`] except that it -/// operates on raw pointers instead of references. When references are -/// available, [`mem::replace`] should be preferred. -/// -/// [`mem::replace`]: ../mem/fn.replace.html +/// Replaces the value at `dest` with `src`, returning the old +/// value, without dropping either. /// /// # Safety /// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `dest` must point to valid, initialized memory. -/// -/// * `dest` must be properly aligned. -/// -/// # Examples -/// -/// ``` -/// use std::ptr; -/// -/// let mut rust = vec!['b', 'u', 's', 't']; -/// -/// // `mem::replace` would have the same effect without requiring the unsafe -/// // block. -/// let b = unsafe { -/// ptr::replace(&mut rust[0], 'r') -/// }; -/// -/// assert_eq!(b, 'b'); -/// assert_eq!(rust, &['r', 'u', 's', 't']); -/// ``` +/// This is only unsafe because it accepts a raw pointer. +/// Otherwise, this operation is identical to `mem::replace`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn replace(dest: *mut T, mut src: T) -> T { @@ -333,23 +258,14 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// /// # Safety /// -/// Behavior is undefined if any of the following conditions are violated: +/// Beyond accepting a raw pointer, this is unsafe because it semantically +/// moves the value out of `src` without preventing further usage of `src`. +/// If `T` is not `Copy`, then care must be taken to ensure that the value at +/// `src` is not used before the data is overwritten again (e.g. with `write`, +/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use +/// because it will attempt to drop the value previously at `*src`. /// -/// * `src` must point to valid, initialized memory. -/// -/// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the -/// case. -/// -/// Additionally, if `T` is not [`Copy`], only the returned value *or* the -/// pointed-to value can be used or dropped after calling `read`. `read` creates -/// a bitwise copy of `T`, regardless of whether `T: Copy`, which can result -/// in undefined behavior if both copies are used. Note that `*src = foo` counts -/// as a use because it will attempt to drop the value previously at `*src`. -/// [`write`] can be used to overwrite data without causing it to be dropped. -/// -/// [`Copy`]: ../marker/trait.Copy.html -/// [`read_unaligned`]: ./fn.read_unaligned.html -/// [`write`]: ./fn.write.html +/// The pointer must be aligned; use `read_unaligned` if that is not the case. /// /// # Examples /// @@ -363,44 +279,6 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// assert_eq!(std::ptr::read(y), 12); /// } /// ``` -/// -/// Manually implement [`mem::swap`]: -/// -/// ``` -/// use std::ptr; -/// -/// fn swap(a: &mut T, b: &mut T) { -/// unsafe { -/// // Create a bitwise copy of the value at `a` in `tmp`. -/// let tmp = ptr::read(a); -/// -/// // Exiting at this point (either by explicitly returning or by -/// // calling a function which panics) would cause the value in `tmp` to -/// // be dropped while the same value is still referenced by `a`. This -/// // could trigger undefined behavior if `T` is not `Copy`. -/// -/// // Create a bitwise copy of the value at `b` in `a`. -/// // This is safe because mutable references cannot alias. -/// ptr::copy_nonoverlapping(b, a, 1); -/// -/// // As above, exiting here could trigger undefined behavior because -/// // the same value is referenced by `a` and `b`. -/// -/// // Move `tmp` into `b`. -/// ptr::write(b, tmp); -/// } -/// } -/// -/// let mut foo = "foo".to_owned(); -/// let mut bar = "bar".to_owned(); -/// -/// swap(&mut foo, &mut bar); -/// -/// assert_eq!(foo, "bar"); -/// assert_eq!(bar, "foo"); -/// ``` -/// -/// [`mem::swap`]: ../mem/fn.swap.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn read(src: *const T) -> T { @@ -412,62 +290,28 @@ pub unsafe fn read(src: *const T) -> T { /// Reads the value from `src` without moving it. This leaves the /// memory in `src` unchanged. /// -/// Unlike [`read`], `read_unaligned` works with unaligned pointers. -/// -/// [`read`]: ./fn.read.html +/// Unlike `read`, the pointer may be unaligned. /// /// # Safety /// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `src` must point to valid, initialized memory. -/// -/// Additionally, if `T` is not [`Copy`], only the returned value *or* the -/// pointed-to value can be used or dropped after calling `read_unaligned`. -/// `read_unaligned` creates a bitwise copy of `T`, regardless of whether `T: -/// Copy`, and this can result in undefined behavior if both copies are used. -/// Note that `*src = foo` counts as a use because it will attempt to drop the -/// value previously at `*src`. [`write_unaligned`] can be used to overwrite -/// data without causing it to be dropped. -/// -/// [`Copy`]: ../marker/trait.Copy.html -/// [`write_unaligned`]: ./fn.write_unaligned.html +/// Beyond accepting a raw pointer, this is unsafe because it semantically +/// moves the value out of `src` without preventing further usage of `src`. +/// If `T` is not `Copy`, then care must be taken to ensure that the value at +/// `src` is not used before the data is overwritten again (e.g. with `write`, +/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use +/// because it will attempt to drop the value previously at `*src`. /// /// # Examples /// -/// Access members of a packed struct by reference: +/// Basic usage: /// /// ``` -/// use std::ptr; +/// let x = 12; +/// let y = &x as *const i32; /// -/// #[repr(packed, C)] -/// #[derive(Default)] -/// struct Packed { -/// _padding: u8, -/// unaligned: u32, +/// unsafe { +/// assert_eq!(std::ptr::read_unaligned(y), 12); /// } -/// -/// let x = Packed { -/// _padding: 0x00, -/// unaligned: 0x01020304, -/// }; -/// -/// let v = unsafe { -/// // Take a reference to a 32-bit integer which is not aligned. -/// let unaligned = &x.unaligned; -/// -/// // Dereferencing normally will emit an unaligned load instruction, -/// // causing undefined behavior. -/// // let v = *unaligned; // ERROR -/// -/// // Instead, use `read_unaligned` to read improperly aligned values. -/// let v = ptr::read_unaligned(unaligned); -/// -/// v -/// }; -/// -/// // Accessing unaligned values directly is safe. -/// assert!(x.unaligned == v); /// ``` #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] @@ -482,7 +326,11 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// Overwrites a memory location with the given value without reading or /// dropping the old value. /// -/// `write` does not drop the contents of `dst`. This is safe, but it could leak +/// # Safety +/// +/// This operation is marked unsafe because it accepts a raw pointer. +/// +/// It does not drop the contents of `dst`. This is safe, but it could leak /// allocations or resources, so care must be taken not to overwrite an object /// that should be dropped. /// @@ -490,20 +338,9 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// location pointed to by `dst`. /// /// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been [`read`] from. -/// -/// [`read`]: ./fn.read.html -/// -/// # Safety +/// memory that has previously been `read` from. /// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `dst` must point to valid memory. -/// -/// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the -/// case. -/// -/// [`write_unaligned`]: ./fn.write_unaligned.html +/// The pointer must be aligned; use `write_unaligned` if that is not the case. /// /// # Examples /// @@ -519,30 +356,6 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// assert_eq!(std::ptr::read(y), 12); /// } /// ``` -/// -/// Manually implement [`mem::swap`]: -/// -/// ``` -/// use std::ptr; -/// -/// fn swap(a: &mut T, b: &mut T) { -/// unsafe { -/// let tmp = ptr::read(a); -/// ptr::copy_nonoverlapping(b, a, 1); -/// ptr::write(b, tmp); -/// } -/// } -/// -/// let mut foo = "foo".to_owned(); -/// let mut bar = "bar".to_owned(); -/// -/// swap(&mut foo, &mut bar); -/// -/// assert_eq!(foo, "bar"); -/// assert_eq!(bar, "foo"); -/// ``` -/// -/// [`mem::swap`]: ../mem/fn.swap.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn write(dst: *mut T, src: T) { @@ -552,58 +365,36 @@ pub unsafe fn write(dst: *mut T, src: T) { /// Overwrites a memory location with the given value without reading or /// dropping the old value. /// -/// Unlike [`write`], the pointer may be unaligned. +/// Unlike `write`, the pointer may be unaligned. +/// +/// # Safety /// -/// `write_unaligned` does not drop the contents of `dst`. This is safe, but it -/// could leak allocations or resources, so care must be taken not to overwrite -/// an object that should be dropped. +/// This operation is marked unsafe because it accepts a raw pointer. +/// +/// It does not drop the contents of `dst`. This is safe, but it could leak +/// allocations or resources, so care must be taken not to overwrite an object +/// that should be dropped. /// /// Additionally, it does not drop `src`. Semantically, `src` is moved into the /// location pointed to by `dst`. /// /// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been read with [`read_unaligned`]. -/// -/// [`write`]: ./fn.write.html -/// [`read_unaligned`]: ./fn.read_unaligned.html -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `dst` must point to valid memory. +/// memory that has previously been `read` from. /// /// # Examples /// -/// Access fields in a packed struct: +/// Basic usage: /// /// ``` -/// use std::{mem, ptr}; -/// -/// #[repr(packed, C)] -/// #[derive(Default)] -/// struct Packed { -/// _padding: u8, -/// unaligned: u32, -/// } -/// -/// let v = 0x01020304; -/// let mut x: Packed = unsafe { mem::zeroed() }; +/// let mut x = 0; +/// let y = &mut x as *mut i32; +/// let z = 12; /// /// unsafe { -/// // Take a reference to a 32-bit integer which is not aligned. -/// let unaligned = &mut x.unaligned; -/// -/// // Dereferencing normally will emit an unaligned store instruction, -/// // causing undefined behavior. -/// // *unaligned = v; // ERROR -/// -/// // Instead, use `write_unaligned` to write improperly aligned values. -/// ptr::write_unaligned(unaligned, v); +/// std::ptr::write_unaligned(y, z); +/// assert_eq!(std::ptr::read_unaligned(y), 12); /// } -/// -/// // Accessing unaligned values directly is safe. -/// assert!(x.unaligned == v); +/// ``` #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] pub unsafe fn write_unaligned(dst: *mut T, src: T) { @@ -620,11 +411,6 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// to not be elided or reordered by the compiler across other volatile /// operations. /// -/// Memory read with `read_volatile` should almost always be written to using -/// [`write_volatile`]. -/// -/// [`write_volatile`]: ./fn.write_volatile.html -/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model, @@ -641,19 +427,12 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// # Safety /// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `src` must point to valid, initialized memory. -/// -/// * `src` must be properly aligned. -/// -/// Like [`read`], `read_volatile` creates a bitwise copy of the pointed-to -/// object, regardless of whether `T` is [`Copy`]. Using both values can cause -/// undefined behavior. However, storing non-[`Copy`] data in I/O memory is -/// almost certainly incorrect. -/// -/// [`Copy`]: ../marker/trait.Copy.html -/// [`read`]: ./fn.read.html +/// Beyond accepting a raw pointer, this is unsafe because it semantically +/// moves the value out of `src` without preventing further usage of `src`. +/// If `T` is not `Copy`, then care must be taken to ensure that the value at +/// `src` is not used before the data is overwritten again (e.g. with `write`, +/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use +/// because it will attempt to drop the value previously at `*src`. /// /// # Examples /// @@ -680,18 +459,6 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// to not be elided or reordered by the compiler across other volatile /// operations. /// -/// Memory written with `write_volatile` should almost always be read from using -/// [`read_volatile`]. -/// -/// `write_volatile` does not drop the contents of `dst`. This is safe, but it -/// could leak allocations or resources, so care must be taken not to overwrite -/// an object that should be dropped. -/// -/// Additionally, it does not drop `src`. Semantically, `src` is moved into the -/// location pointed to by `dst`. -/// -/// [`read_volatile`]: ./fn.read_volatile.html -/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model, @@ -708,11 +475,14 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// # Safety /// -/// Behavior is undefined if any of the following conditions are violated: +/// This operation is marked unsafe because it accepts a raw pointer. /// -/// * `dst` must point to valid memory. +/// It does not drop the contents of `dst`. This is safe, but it could leak +/// allocations or resources, so care must be taken not to overwrite an object +/// that should be dropped. /// -/// * `dst` must be properly aligned. +/// This is appropriate for initializing uninitialized memory, or overwriting +/// memory that has previously been `read` from. /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From d45378216b31eab9ee7c7c461ae20bfb29bd20b3 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 18 Apr 2018 18:38:12 +0300 Subject: Change align_offset to support different strides MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is necessary if we want to implement `[T]::align_to` and is more useful in general. This implementation effort has begun during the All Hands and represents a month of my futile efforts to do any sort of maths. Luckily, I found the very very nice Chris McDonald (cjm) on IRC who figured out the core formulas for me! All the thanks for existence of this PR go to them! Anyway… Those formulas were mangled by yours truly into the arcane forms you see here to squeeze out the best assembly possible on most of the modern architectures (x86 and ARM were evaluated in practice). I mean, just look at it: *one actual* modulo operation and everything else is just the cheap single cycle ops! Admitedly, the naive solution might be faster in some common scenarios, but this code absolutely butchers the naive solution on the worst case scenario. Alas, the result of this arcane magic also means that the code pretty heavily relies on the preconditions holding true and breaking those preconditions will unleash the UB-est of all UBs! So don’t. --- src/libcore/intrinsics.rs | 30 ++-- src/libcore/ptr.rs | 259 +++++++++++++++++++++++++++------ src/libcore/slice/mod.rs | 22 +++ src/librustc/middle/lang_items.rs | 3 + src/librustc_codegen_llvm/intrinsic.rs | 32 ++-- src/librustc_typeck/check/intrinsic.rs | 3 +- src/test/run-pass/align-offset-sign.rs | 82 ++++++++++- 7 files changed, 363 insertions(+), 68 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 5ec6cb6c710..510a5bb3df7 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1463,15 +1463,26 @@ extern "rust-intrinsic" { /// source as well as std's catch implementation. pub fn try(f: fn(*mut u8), data: *mut u8, local_ptr: *mut u8) -> i32; - /// Computes the byte offset that needs to be applied to `ptr` in order to - /// make it aligned to `align`. - /// If it is not possible to align `ptr`, the implementation returns + #[cfg(stage0)] + /// docs my friends, its friday! + pub fn align_offset(ptr: *const (), align: usize) -> usize; + + /// Computes the offset that needs to be applied to the pointer in order to make it aligned to + /// `align`. + /// + /// If it is not possible to align the pointer, the implementation returns /// `usize::max_value()`. /// - /// There are no guarantees whatsover that offsetting the pointer will not - /// overflow or go beyond the allocation that `ptr` points into. - /// It is up to the caller to ensure that the returned offset is correct - /// in all terms other than alignment. + /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be + /// used with the `offset` or `offset_to` methods. + /// + /// There are no guarantees whatsover that offsetting the pointer will not overflow or go + /// beyond the allocation that the pointer points into. It is up to the caller to ensure that + /// the returned offset is correct in all terms other than alignment. + /// + /// # Unsafety + /// + /// `align` must be a power-of-two. /// /// # Examples /// @@ -1485,7 +1496,7 @@ extern "rust-intrinsic" { /// # unsafe { /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; /// let ptr = &x[n] as *const u8; - /// let offset = align_offset(ptr as *const (), align_of::()); + /// let offset = align_offset(ptr, align_of::()); /// if offset < x.len() - n - 1 { /// let u16_ptr = ptr.offset(offset as isize) as *const u16; /// assert_ne!(*u16_ptr, 500); @@ -1495,7 +1506,8 @@ extern "rust-intrinsic" { /// } /// # } } /// ``` - pub fn align_offset(ptr: *const (), align: usize) -> usize; + #[cfg(not(stage0))] + pub fn align_offset(ptr: *const T, align: usize) -> usize; /// Emits a `!nontemporal` store according to LLVM (see their docs). /// Probably will never become stable. diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 63bcc024020..a762a8a6f92 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -1433,15 +1433,22 @@ impl *const T { copy_nonoverlapping(self, dest, count) } - /// Computes the byte offset that needs to be applied in order to - /// make the pointer aligned to `align`. + /// Computes the offset that needs to be applied to the pointer in order to make it aligned to + /// `align`. + /// /// If it is not possible to align the pointer, the implementation returns /// `usize::max_value()`. /// - /// There are no guarantees whatsover that offsetting the pointer will not - /// overflow or go beyond the allocation that the pointer points into. - /// It is up to the caller to ensure that the returned offset is correct - /// in all terms other than alignment. + /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be + /// used with the `offset` or `offset_to` methods. + /// + /// There are no guarantees whatsover that offsetting the pointer will not overflow or go + /// beyond the allocation that the pointer points into. It is up to the caller to ensure that + /// the returned offset is correct in all terms other than alignment. + /// + /// # Panics + /// + /// The function panics if `align` is not a power-of-two. /// /// # Examples /// @@ -1465,13 +1472,30 @@ impl *const T { /// # } } /// ``` #[unstable(feature = "align_offset", issue = "44488")] - pub fn align_offset(self, align: usize) -> usize { + #[cfg(not(stage0))] + pub fn align_offset(self, align: usize) -> usize where T: Sized { + if !align.is_power_of_two() { + panic!("align_offset: align is not a power-of-two"); + } unsafe { - intrinsics::align_offset(self as *const _, align) + intrinsics::align_offset(self, align) + } + } + + /// definitely docs. + #[unstable(feature = "align_offset", issue = "44488")] + #[cfg(stage0)] + pub fn align_offset(self, align: usize) -> usize where T: Sized { + if !align.is_power_of_two() { + panic!("align_offset: align is not a power-of-two"); + } + unsafe { + intrinsics::align_offset(self as *const (), align) } } } + #[lang = "mut_ptr"] impl *mut T { /// Returns `true` if the pointer is null. @@ -1804,44 +1828,6 @@ impl *mut T { (self as *const T).wrapping_offset_from(origin) } - /// Computes the byte offset that needs to be applied in order to - /// make the pointer aligned to `align`. - /// If it is not possible to align the pointer, the implementation returns - /// `usize::max_value()`. - /// - /// There are no guarantees whatsover that offsetting the pointer will not - /// overflow or go beyond the allocation that the pointer points into. - /// It is up to the caller to ensure that the returned offset is correct - /// in all terms other than alignment. - /// - /// # Examples - /// - /// Accessing adjacent `u8` as `u16` - /// - /// ``` - /// # #![feature(align_offset)] - /// # fn foo(n: usize) { - /// # use std::mem::align_of; - /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = &x[n] as *const u8; - /// let offset = ptr.align_offset(align_of::()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.offset(offset as isize) as *const u16; - /// assert_ne!(*u16_ptr, 500); - /// } else { - /// // while the pointer can be aligned via `offset`, it would point - /// // outside the allocation - /// } - /// # } } - /// ``` - #[unstable(feature = "align_offset", issue = "44488")] - pub fn align_offset(self, align: usize) -> usize { - unsafe { - intrinsics::align_offset(self as *const _, align) - } - } - /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). /// /// `count` is in units of T; e.g. a `count` of 3 represents a pointer @@ -2511,8 +2497,189 @@ impl *mut T { { swap(self, with) } + + /// Computes the offset that needs to be applied to the pointer in order to make it aligned to + /// `align`. + /// + /// If it is not possible to align the pointer, the implementation returns + /// `usize::max_value()`. + /// + /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be + /// used with the `offset` or `offset_to` methods. + /// + /// There are no guarantees whatsover that offsetting the pointer will not overflow or go + /// beyond the allocation that the pointer points into. It is up to the caller to ensure that + /// the returned offset is correct in all terms other than alignment. + /// + /// # Panics + /// + /// The function panics if `align` is not a power-of-two. + /// + /// # Examples + /// + /// Accessing adjacent `u8` as `u16` + /// + /// ``` + /// # #![feature(align_offset)] + /// # fn foo(n: usize) { + /// # use std::mem::align_of; + /// # unsafe { + /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; + /// let ptr = &x[n] as *const u8; + /// let offset = ptr.align_offset(align_of::()); + /// if offset < x.len() - n - 1 { + /// let u16_ptr = ptr.offset(offset as isize) as *const u16; + /// assert_ne!(*u16_ptr, 500); + /// } else { + /// // while the pointer can be aligned via `offset`, it would point + /// // outside the allocation + /// } + /// # } } + /// ``` + #[unstable(feature = "align_offset", issue = "44488")] + #[cfg(not(stage0))] + pub fn align_offset(self, align: usize) -> usize where T: Sized { + if !align.is_power_of_two() { + panic!("align_offset: align is not a power-of-two"); + } + unsafe { + intrinsics::align_offset(self, align) + } + } + + /// definitely docs. + #[unstable(feature = "align_offset", issue = "44488")] + #[cfg(stage0)] + pub fn align_offset(self, align: usize) -> usize where T: Sized { + if !align.is_power_of_two() { + panic!("align_offset: align is not a power-of-two"); + } + unsafe { + intrinsics::align_offset(self as *const (), align) + } + } } +/// Align pointer `p`. +/// +/// Calculate offset (in terms of elements of `stride` stride) that has to be applied +/// to pointer `p` so that pointer `p` would get aligned to `a`. +/// +/// This is an implementation of the `align_offset` intrinsic for the case where `stride > 1`. +/// +/// Note: This implementation has been carefully tailored to not panic. It is UB for this to panic. +/// The only real change that can be made here is change of `INV_TABLE_MOD_16` and associated +/// constants. +/// +/// If we ever decide to make it possible to call the intrinsic with `a` that is not a +/// power-of-two, it will probably be more prudent to just change to a naive implementation rather +/// than trying to adapt this to accomodate that change. +/// +/// Any questions go to @nagisa. +#[lang="align_offset"] +#[cfg(not(stage0))] +unsafe fn align_offset(p: *const (), a: usize, stride: usize) -> usize { + /// Calculate multiplicative modular inverse of `x` modulo `m`. + /// + /// This implementation is tailored for align_offset and has following preconditions: + /// + /// * `m` is a power-of-two; + /// * `x < m`; (if `x ≥ m`, pass in `x % m` instead) + /// + /// Implementation of this function shall not panic. Ever. + fn mod_inv(x: usize, m: usize) -> usize { + /// Multiplicative modular inverse table modulo 2⁴ = 16. + /// + /// Note, that this table does not contain values where inverse does not exist (i.e. for + /// `0⁻¹ mod 16`, `2⁻¹ mod 16`, etc.) + static INV_TABLE_MOD_16: [usize; 8] = [1, 11, 13, 7, 9, 3, 5, 15]; + /// Modulo for which the `INV_TABLE_MOD_16` is intended. + const INV_TABLE_MOD: usize = 16; + /// INV_TABLE_MOD² + const INV_TABLE_MOD_SQUARED: usize = INV_TABLE_MOD * INV_TABLE_MOD; + + let table_inverse = INV_TABLE_MOD_16[(x & (INV_TABLE_MOD - 1)) >> 1]; + if m <= INV_TABLE_MOD { + return table_inverse & (m - 1); + } else { + // We iterate "up" using the following formula: + // + // $$ xy ≡ 1 (mod 2ⁿ) → xy (2 - xy) ≡ 1 (mod 2²ⁿ) $$ + // + // until 2²ⁿ ≥ m. Then we can reduce to our desired `m` by taking the result `mod m`. + let mut inverse = table_inverse; + let mut going_mod = INV_TABLE_MOD_SQUARED; + loop { + // y = y * (2 - xy) mod n + // + // Note, that we use wrapping operations here intentionally – the original formula + // uses e.g. subtraction `mod n`. It is entirely fine to do them `mod + // usize::max_value()` instead, because we take the result `mod n` at the end + // anyway. + inverse = inverse.wrapping_mul( + 2usize.wrapping_sub(x.wrapping_mul(inverse)) + ) & (going_mod - 1); + if going_mod > m { + return inverse & (m - 1); + } + going_mod = going_mod.wrapping_mul(going_mod); + } + } + } + + let a_minus_one = a.wrapping_sub(1); + let pmoda = p as usize & a_minus_one; + let smoda = stride & a_minus_one; + // a is power-of-two so cannot be 0. stride = 0 is handled by the intrinsic. + let gcdpow = intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a)); + let gcd = 1usize << gcdpow; + + if pmoda == 0 { + // Already aligned. Yay! + return 0; + } + + if gcd == 1 { + // This branch solves for the variable $o$ in following linear congruence equation: + // + // ⎰ p + o ≡ 0 (mod a) # $p + o$ must be aligned to specified alignment $a$ + // ⎱ o ≡ 0 (mod s) # offset $o$ must be a multiple of stride $s$ + // + // where + // + // * a, s are co-prime + // + // This gives us the formula below: + // + // o = (a - (p mod a)) * (s⁻¹ mod a) * s + // + // The first term is “the relative alignment of p to a”, the second term is “how does + // incrementing p by one s change the relative alignment of p”, the third term is + // translating change in units of s to a byte count. + // + // Furthermore, the result produced by this solution is not “minimal”, so it is necessary + // to take the result $o mod lcm(s, a)$. Since $s$ and $a$ are co-prime (i.e. $gcd(s, a) = + // 1$) and $lcm(s, a) = s * a / gcd(s, a)$, we can replace $lcm(s, a)$ with just a $s * a$. + // + // (Author note: we decided later on to express the offset in "elements" rather than bytes, + // which drops the multiplication by `s` on both sides of the modulo.) + return intrinsics::unchecked_rem(a.wrapping_sub(pmoda).wrapping_mul(mod_inv(smoda, a)), a); + } + + if p as usize & (gcd - 1) == 0 { + // This can be aligned, but `a` and `stride` are not co-prime, so a somewhat adapted + // formula is used. + let j = a.wrapping_sub(pmoda) >> gcdpow; + let k = smoda >> gcdpow; + return intrinsics::unchecked_rem(j.wrapping_mul(mod_inv(k, a)), a >> gcdpow); + } + + // Cannot be aligned at all. + return usize::max_value(); +} + + + // Equality for pointers #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for *const T { diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 82891b691dc..6b3c1fcddc2 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1696,6 +1696,28 @@ impl [T] { self.as_mut_ptr(), other.as_mut_ptr(), self.len()); } } + + // #[unstable(feature = "slice_align_to", issue = "44488")] + // pub fn align_to(&self) -> (&[T], &[U], &[T]) { + // // First, find at what point do we split between the first and 2nd slice. + // let x = self.as_ptr(); + // let offset = x.align_offset(::mem::align_of::()); + // if offset > x * ::mem::size_of::() { + // return (self, [], []); + // } + + // } + + // #[unstable(feature = "slice_align_to", issue = "44488")] + // pub fn align_to_mut(&mut self) -> (&mut [T], &mut [U], &mut [T]) { + // } +}} + +#[lang = "slice"] +#[cfg(not(test))] +#[cfg(not(stage0))] +impl [T] { + slice_core_methods!(); } #[lang = "slice_u8"] diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 95e92e21b09..d70f994e87b 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -348,6 +348,9 @@ language_item_table! { I128ShroFnLangItem, "i128_shro", i128_shro_fn; U128ShroFnLangItem, "u128_shro", u128_shro_fn; + // Align offset for stride != 1, must not panic. + AlignOffsetLangItem, "align_offset", align_offset_fn; + TerminationTraitLangItem, "termination", termination; } diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index ba04cc7fad5..93351651db9 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -25,6 +25,7 @@ use type_of::LayoutLlvmExt; use rustc::ty::{self, Ty}; use rustc::ty::layout::{HasDataLayout, LayoutOf}; use rustc::hir; +use rustc::middle::lang_items::AlignOffsetLangItem; use syntax::ast; use syntax::symbol::Symbol; use builder::Builder; @@ -390,16 +391,29 @@ pub fn codegen_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, } "align_offset" => { - // `ptr as usize` - let ptr_val = bx.ptrtoint(args[0].immediate(), bx.cx.isize_ty); - // `ptr_val % align` - let align = args[1].immediate(); - let offset = bx.urem(ptr_val, align); + let (ptr, align) = (args[0].immediate(), args[1].immediate()); + let stride_of_t = bx.cx.layout_of(substs.type_at(0)).size_and_align().0.bytes(); + let stride = C_usize(bx.cx, stride_of_t); let zero = C_null(bx.cx.isize_ty); - // `offset == 0` - let is_zero = bx.icmp(llvm::IntPredicate::IntEQ, offset, zero); - // `if offset == 0 { 0 } else { align - offset }` - bx.select(is_zero, zero, bx.sub(align, offset)) + let max = C_int(cx.isize_ty, -1); // -1isize (wherein I cheat horribly to make !0usize) + + if stride_of_t <= 1 { + // offset = ptr as usize % align => offset = ptr as usize & (align - 1) + let modmask = bx.sub(align, C_usize(bx.cx, 1)); + let offset = bx.and(bx.ptrtoint(ptr, bx.cx.isize_ty), modmask); + let is_zero = bx.icmp(llvm::IntPredicate::IntEQ, offset, zero); + // if offset == 0 { 0 } else { if stride_of_t == 1 { align - offset } else { !0 } } + bx.select(is_zero, zero, if stride_of_t == 1 { + bx.sub(align, offset) + } else { + max + }) + } else { + let did = ::common::langcall(bx.tcx(), Some(span), "", AlignOffsetLangItem); + let instance = ty::Instance::mono(bx.tcx(), did); + let llfn = ::callee::get_fn(bx.cx, instance); + bx.call(llfn, &[ptr, align, stride], None) + } } name if name.starts_with("simd_") => { match generic_simd_intrinsic(bx, name, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index feb26e76162..db6062db1fb 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -315,8 +315,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } "align_offset" => { - let ptr_ty = tcx.mk_imm_ptr(tcx.mk_nil()); - (0, vec![ptr_ty, tcx.types.usize], tcx.types.usize) + (1, vec![tcx.mk_imm_ptr(param(0)), tcx.types.usize], tcx.types.usize) }, "nontemporal_store" => { diff --git a/src/test/run-pass/align-offset-sign.rs b/src/test/run-pass/align-offset-sign.rs index aaa0419d061..f7d427cb7b2 100644 --- a/src/test/run-pass/align-offset-sign.rs +++ b/src/test/run-pass/align-offset-sign.rs @@ -10,7 +10,85 @@ #![feature(align_offset)] +#[derive(Clone, Copy)] +#[repr(packed)] +struct A3(u16, u8); +struct A4(u32); +#[repr(packed)] +struct A5(u32, u8); +#[repr(packed)] +struct A6(u32, u16); +#[repr(packed)] +struct A7(u32, u16, u8); +#[repr(packed)] +struct A8(u32, u32); +#[repr(packed)] +struct A9(u32, u32, u8); +#[repr(packed)] +struct A10(u32, u32, u16); + +unsafe fn test_weird_stride(ptr: *const T, align: usize) -> bool { + let numptr = ptr as usize; + let mut expected = usize::max_value(); + // Naive but definitely correct way to find the *first* aligned element of stride::. + for el in (0..align) { + if (numptr + el * ::std::mem::size_of::()) % align == 0 { + expected = el; + break; + } + } + let got = ptr.align_offset(align); + if got != expected { + eprintln!("aligning {:p} (with stride of {}) to {}, expected {}, got {}", ptr, ::std::mem::size_of::(), align, expected, got); + return true; + } + return false; +} + fn main() { - let x = 1 as *const u8; - assert_eq!(x.align_offset(8), 7); + unsafe { + // For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at + // all, because no amount of elements will align the pointer. + let mut p = 1; + while p < 1024 { + assert_eq!((p as *const ()).align_offset(p), 0); + if (p != 1) { + assert_eq!(((p + 1) as *const ()).align_offset(p), !0); + } + p = (p + 1).next_power_of_two(); + } + + // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to + // number of bytes. + let mut align = 1; + while align < 1024 { + for ptr in 1..2*align { + let expected = ptr % align; + let offset = if expected == 0 { 0 } else { align - expected }; + assert_eq!((ptr as *const u8).align_offset(align), offset, + "ptr = {}, align = {}, size = 1", ptr, align); + align = (align + 1).next_power_of_two(); + } + } + + + // For pointers of stride != 1, we verify the algorithm against the naivest possible + // implementation + let mut align = 1; + let mut x = false; + while align < 1024 { + for ptr in 1usize..4*align { + x |= test_weird_stride::(ptr as *const A3, align); + x |= test_weird_stride::(ptr as *const A4, align); + x |= test_weird_stride::(ptr as *const A5, align); + x |= test_weird_stride::(ptr as *const A6, align); + x |= test_weird_stride::(ptr as *const A7, align); + x |= test_weird_stride::(ptr as *const A8, align); + x |= test_weird_stride::(ptr as *const A9, align); + x |= test_weird_stride::(ptr as *const A10, align); + } + align = (align + 1).next_power_of_two(); + } + assert!(!x); + } } -- cgit 1.4.1-3-g733a5 From edad2eff0c0587cd0b9d4b46f11579ef43388be8 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 14 May 2018 23:25:22 +0100 Subject: Stabilise inclusive_range_methods --- src/liballoc/tests/lib.rs | 1 - src/libcore/ops/range.rs | 13 +++---------- src/libcore/tests/lib.rs | 1 - src/librustc/lib.rs | 1 - src/librustc_codegen_llvm/lib.rs | 1 - src/librustc_mir/lib.rs | 1 - src/librustc_target/lib.rs | 1 - 7 files changed, 3 insertions(+), 16 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 1c8ff316e55..081c473768f 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -25,7 +25,6 @@ #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(exact_chunks)] -#![feature(inclusive_range_methods)] extern crate alloc_system; extern crate core; diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 1f84631ada3..70da5fcda00 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -318,8 +318,6 @@ impl> RangeTo { /// # Examples /// /// ``` -/// #![feature(inclusive_range_methods)] -/// /// assert_eq!((3..=5), std::ops::RangeInclusive::new(3, 5)); /// assert_eq!(3 + 4 + 5, (3..=5).sum()); /// @@ -345,12 +343,11 @@ impl RangeInclusive { /// # Examples /// /// ``` - /// #![feature(inclusive_range_methods)] /// use std::ops::RangeInclusive; /// /// assert_eq!(3..=5, RangeInclusive::new(3, 5)); /// ``` - #[unstable(feature = "inclusive_range_methods", issue = "49022")] + #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] pub const fn new(start: Idx, end: Idx) -> Self { Self { start, end } @@ -369,11 +366,9 @@ impl RangeInclusive { /// # Examples /// /// ``` - /// #![feature(inclusive_range_methods)] - /// /// assert_eq!((3..=5).start(), &3); /// ``` - #[unstable(feature = "inclusive_range_methods", issue = "49022")] + #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] pub fn start(&self) -> &Idx { &self.start @@ -392,11 +387,9 @@ impl RangeInclusive { /// # Examples /// /// ``` - /// #![feature(inclusive_range_methods)] - /// /// assert_eq!((3..=5).end(), &5); /// ``` - #[unstable(feature = "inclusive_range_methods", issue = "49022")] + #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] pub fn end(&self) -> &Idx { &self.end diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 8c481338945..cd6b5c6a4ad 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -42,7 +42,6 @@ #![feature(try_trait)] #![feature(exact_chunks)] #![feature(reverse_bits)] -#![feature(inclusive_range_methods)] #![feature(iterator_find_map)] #![feature(slice_internals)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index bbd684982fa..1d53a305193 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -68,7 +68,6 @@ #![feature(trusted_len)] #![feature(catch_expr)] #![feature(test)] -#![feature(inclusive_range_methods)] #![recursion_limit="512"] diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index bd053da4bd3..0b0bab96dfd 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -29,7 +29,6 @@ #![feature(rustc_diagnostic_macros)] #![feature(slice_sort_by_cached_key)] #![feature(optin_builtin_traits)] -#![feature(inclusive_range_methods)] use rustc::dep_graph::WorkProduct; use syntax_pos::symbol::Symbol; diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index d9b6c406e20..3bf9453fb51 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -29,7 +29,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(exhaustive_patterns)] #![feature(range_contains)] #![feature(rustc_diagnostic_macros)] -#![feature(inclusive_range_methods)] #![feature(crate_visibility_modifier)] #![feature(never_type)] #![feature(specialization)] diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs index 45f2ee13bbd..8f491157439 100644 --- a/src/librustc_target/lib.rs +++ b/src/librustc_target/lib.rs @@ -29,7 +29,6 @@ #![feature(const_fn)] #![feature(fs_read_write)] #![feature(inclusive_range)] -#![feature(inclusive_range_methods)] #![feature(slice_patterns)] #[macro_use] -- cgit 1.4.1-3-g733a5 From 1b3ecbcebb38e06495819324f2a67f1d0eb24a23 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 14 May 2018 23:31:20 +0100 Subject: Stabilise into_inner --- src/libcore/ops/range.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 70da5fcda00..6f2a08999bc 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -400,11 +400,9 @@ impl RangeInclusive { /// # Examples /// /// ``` - /// #![feature(inclusive_range_methods)] - /// /// assert_eq!((3..=5).into_inner(), (3, 5)); /// ``` - #[unstable(feature = "inclusive_range_methods", issue = "49022")] + #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] pub fn into_inner(self) -> (Idx, Idx) { (self.start, self.end) -- cgit 1.4.1-3-g733a5 From ff0f00d3182cd604d2d40ea0fe75a4bca407c6b9 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 16 May 2018 21:19:17 +0100 Subject: Add doc comments mentioning unspecified behaviour upon exhaustion --- src/libcore/ops/range.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 6f2a08999bc..7c6e2447bdb 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -360,6 +360,9 @@ impl RangeInclusive { /// whether the inclusive range is empty, use the [`is_empty()`] method /// instead of comparing `start() > end()`. /// + /// Note: the value returned by this method is unspecified after the range + /// has been iterated to exhaustion. + /// /// [`end()`]: #method.end /// [`is_empty()`]: #method.is_empty /// @@ -381,6 +384,9 @@ impl RangeInclusive { /// whether the inclusive range is empty, use the [`is_empty()`] method /// instead of comparing `start() > end()`. /// + /// Note: the value returned by this method is unspecified after the range + /// has been iterated to exhaustion. + /// /// [`start()`]: #method.start /// [`is_empty()`]: #method.is_empty /// @@ -395,7 +401,10 @@ impl RangeInclusive { &self.end } - /// Destructures the RangeInclusive into (lower bound, upper (inclusive) bound). + /// Destructures the `RangeInclusive` into (lower bound, upper (inclusive) bound). + /// + /// Note: the value returned by this method is unspecified after the range + /// has been iterated to exhaustion. /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 680031b0164a94aaeee17a1d8c3027e6e8865a4c Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 29 Apr 2018 17:09:56 +0300 Subject: Implement [T]::align_to --- src/libcore/slice/mod.rs | 182 +++++++++++++++++++++++++++++---- src/libcore/tests/lib.rs | 2 + src/libcore/tests/ptr.rs | 89 ++++++++++++++++ src/libcore/tests/slice.rs | 34 ++++++ src/test/run-pass/align-offset-sign.rs | 94 ----------------- 5 files changed, 287 insertions(+), 114 deletions(-) delete mode 100644 src/test/run-pass/align-offset-sign.rs (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 6b3c1fcddc2..ffa4a66346c 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1697,27 +1697,169 @@ impl [T] { } } - // #[unstable(feature = "slice_align_to", issue = "44488")] - // pub fn align_to(&self) -> (&[T], &[U], &[T]) { - // // First, find at what point do we split between the first and 2nd slice. - // let x = self.as_ptr(); - // let offset = x.align_offset(::mem::align_of::()); - // if offset > x * ::mem::size_of::() { - // return (self, [], []); - // } - - // } - - // #[unstable(feature = "slice_align_to", issue = "44488")] - // pub fn align_to_mut(&mut self) -> (&mut [T], &mut [U], &mut [T]) { - // } -}} + /// Function to calculate lenghts of the middle and trailing slice for `align_to{,_mut}`. + fn align_to_offsets(&self) -> (usize, usize) { + // What we gonna do about `rest` is figure out what multiple of `U`s we can put in a + // lowest number of `T`s. And how many `T`s we need for each such "multiple". + // + // Consider for example T=u8 U=u16. Then we can put 1 U in 2 Ts. Simple. Now, consider + // for example a case where size_of:: = 16, size_of:: = 24. We can put 2 Us in + // place of every 3 Ts in the `rest` slice. A bit more complicated. + // + // Formula to calculate this is: + // + // Us = lcm(size_of::, size_of::) / size_of:: + // Ts = lcm(size_of::, size_of::) / size_of:: + // + // Expanded and simplified: + // + // Us = size_of:: / gcd(size_of::, size_of::) + // Ts = size_of:: / gcd(size_of::, size_of::) + // + // Luckily since all this is constant-evaluated... performance here matters not! + #[inline] + fn gcd(a: usize, b: usize) -> usize { + // iterative stein’s algorithm + // We should still make this `const fn` (and revert to recursive algorithm if we do) + // because relying on llvm to consteval all this is… well, it makes me + let (ctz_a, mut ctz_b) = unsafe { + if a == 0 { return b; } + if b == 0 { return a; } + (::intrinsics::cttz_nonzero(a), ::intrinsics::cttz_nonzero(b)) + }; + let k = ctz_a.min(ctz_b); + let mut a = a >> ctz_a; + let mut b = b; + loop { + // remove all factors of 2 from b + b >>= ctz_b; + if a > b { + ::mem::swap(&mut a, &mut b); + } + b = b - a; + unsafe { + if b == 0 { + break; + } + ctz_b = ::intrinsics::cttz_nonzero(b); + } + } + return a << k; + } + let gcd: usize = gcd(::mem::size_of::(), ::mem::size_of::()); + let ts: usize = ::mem::size_of::() / gcd; + let us: usize = ::mem::size_of::() / gcd; -#[lang = "slice"] -#[cfg(not(test))] -#[cfg(not(stage0))] -impl [T] { - slice_core_methods!(); + // Armed with this knowledge, we can find how many `U`s we can fit! + let us_len = self.len() / ts * us; + // And how many `T`s will be in the trailing slice! + let ts_len = self.len() % ts; + return (us_len, ts_len); + } + + /// Transmute the slice to a slice of another type, ensuring aligment of the types is + /// maintained. + /// + /// This method splits the slice into three distinct slices: prefix, correctly aligned middle + /// slice of a new type, and the suffix slice. The middle slice will have the greatest length + /// possible for a given type and input slice. + /// + /// This method has no purpose when either input element `T` or output element `U` are + /// zero-sized and will return the original slice without splitting anything. + /// + /// # Unsafety + /// + /// This method is essentially a `transmute` with respect to the elements in the returned + /// middle slice, so all the usual caveats pertaining to `transmute::` also apply here. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(slice_align_to)] + /// unsafe { + /// let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; + /// let (prefix, shorts, suffix) = bytes.align_to::(); + /// // less_efficient_algorithm_for_bytes(prefix); + /// // more_efficient_algorithm_for_aligned_shorts(shorts); + /// // less_efficient_algorithm_for_bytes(suffix); + /// } + /// ``` + #[unstable(feature = "slice_align_to", issue = "44488")] + #[cfg(not(stage0))] + pub unsafe fn align_to(&self) -> (&[T], &[U], &[T]) { + // Note that most of this function will be constant-evaluated, + if ::mem::size_of::() == 0 || ::mem::size_of::() == 0 { + // handle ZSTs specially, which is – don't handle them at all. + return (self, &[], &[]); + } + let ptr = self.as_ptr(); + let offset = ::intrinsics::align_offset(ptr, ::mem::align_of::()); + if offset > self.len() { + return (self, &[], &[]); + } else { + let (left, rest) = self.split_at(offset); + let (us_len, ts_len) = rest.align_to_offsets::(); + return (left, + from_raw_parts(rest.as_ptr() as *const U, us_len), + from_raw_parts(rest.as_ptr().offset((rest.len() - ts_len) as isize), ts_len)) + } + } + + /// Transmute the slice to a slice of another type, ensuring aligment of the types is + /// maintained. + /// + /// This method splits the slice into three distinct slices: prefix, correctly aligned middle + /// slice of a new type, and the suffix slice. The middle slice will have the greatest length + /// possible for a given type and input slice. + /// + /// This method has no purpose when either input element `T` or output element `U` are + /// zero-sized and will return the original slice without splitting anything. + /// + /// # Unsafety + /// + /// This method is essentially a `transmute` with respect to the elements in the returned + /// middle slice, so all the usual caveats pertaining to `transmute::` also apply here. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(slice_align_to)] + /// unsafe { + /// let mut bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; + /// let (prefix, shorts, suffix) = bytes.align_to_mut::(); + /// // less_efficient_algorithm_for_bytes(prefix); + /// // more_efficient_algorithm_for_aligned_shorts(shorts); + /// // less_efficient_algorithm_for_bytes(suffix); + /// } + /// ``` + #[unstable(feature = "slice_align_to", issue = "44488")] + #[cfg(not(stage0))] + pub unsafe fn align_to_mut(&mut self) -> (&mut [T], &mut [U], &mut [T]) { + // Note that most of this function will be constant-evaluated, + if ::mem::size_of::() == 0 || ::mem::size_of::() == 0 { + // handle ZSTs specially, which is – don't handle them at all. + return (self, &mut [], &mut []); + } + + // First, find at what point do we split between the first and 2nd slice. Easy with + // ptr.align_offset. + let ptr = self.as_ptr(); + let offset = ::intrinsics::align_offset(ptr, ::mem::align_of::()); + if offset > self.len() { + return (self, &mut [], &mut []); + } else { + let (left, rest) = self.split_at_mut(offset); + let (us_len, ts_len) = rest.align_to_offsets::(); + let mut_ptr = rest.as_mut_ptr(); + return (left, + from_raw_parts_mut(mut_ptr as *mut U, us_len), + from_raw_parts_mut(mut_ptr.offset((rest.len() - ts_len) as isize), ts_len)) + } + } } #[lang = "slice_u8"] diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 8c481338945..dbd26b2c718 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -41,6 +41,8 @@ #![feature(try_from)] #![feature(try_trait)] #![feature(exact_chunks)] +#![feature(slice_align_to)] +#![feature(align_offset)] #![feature(reverse_bits)] #![feature(inclusive_range_methods)] #![feature(iterator_find_map)] diff --git a/src/libcore/tests/ptr.rs b/src/libcore/tests/ptr.rs index 00f87336f3c..9384cb32798 100644 --- a/src/libcore/tests/ptr.rs +++ b/src/libcore/tests/ptr.rs @@ -296,3 +296,92 @@ fn write_unaligned_drop() { } DROPS.with(|d| assert_eq!(*d.borrow(), [0])); } + +#[test] +fn align_offset_zst() { + // For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at + // all, because no amount of elements will align the pointer. + let mut p = 1; + while p < 1024 { + assert_eq!((p as *const ()).align_offset(p), 0); + if p != 1 { + assert_eq!(((p + 1) as *const ()).align_offset(p), !0); + } + p = (p + 1).next_power_of_two(); + } +} + +#[test] +fn align_offset_stride1() { + // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to + // number of bytes. + let mut align = 1; + while align < 1024 { + for ptr in 1..2*align { + let expected = ptr % align; + let offset = if expected == 0 { 0 } else { align - expected }; + assert_eq!((ptr as *const u8).align_offset(align), offset, + "ptr = {}, align = {}, size = 1", ptr, align); + align = (align + 1).next_power_of_two(); + } + } +} + +#[test] +fn align_offset_weird_strides() { + #[repr(packed)] + struct A3(u16, u8); + struct A4(u32); + #[repr(packed)] + struct A5(u32, u8); + #[repr(packed)] + struct A6(u32, u16); + #[repr(packed)] + struct A7(u32, u16, u8); + #[repr(packed)] + struct A8(u32, u32); + #[repr(packed)] + struct A9(u32, u32, u8); + #[repr(packed)] + struct A10(u32, u32, u16); + + unsafe fn test_weird_stride(ptr: *const T, align: usize) -> bool { + let numptr = ptr as usize; + let mut expected = usize::max_value(); + // Naive but definitely correct way to find the *first* aligned element of stride::. + for el in 0..align { + if (numptr + el * ::std::mem::size_of::()) % align == 0 { + expected = el; + break; + } + } + let got = ptr.align_offset(align); + if got != expected { + eprintln!("aligning {:p} (with stride of {}) to {}, expected {}, got {}", ptr, + ::std::mem::size_of::(), align, expected, got); + return true; + } + return false; + } + + // For pointers of stride != 1, we verify the algorithm against the naivest possible + // implementation + let mut align = 1; + let mut x = false; + while align < 1024 { + for ptr in 1usize..4*align { + unsafe { + x |= test_weird_stride::(ptr as *const A3, align); + x |= test_weird_stride::(ptr as *const A4, align); + x |= test_weird_stride::(ptr as *const A5, align); + x |= test_weird_stride::(ptr as *const A6, align); + x |= test_weird_stride::(ptr as *const A7, align); + x |= test_weird_stride::(ptr as *const A8, align); + x |= test_weird_stride::(ptr as *const A9, align); + x |= test_weird_stride::(ptr as *const A10, align); + } + } + align = (align + 1).next_power_of_two(); + } + assert!(!x); +} diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 19b5c86c474..8acb531b989 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -812,3 +812,37 @@ pub mod memchr { } } } + +#[test] +fn test_align_to_simple() { + let bytes = [1u8, 2, 3, 4, 5, 6, 7]; + let (prefix, aligned, suffix) = unsafe { bytes.align_to::() }; + assert_eq!(aligned.len(), 3); + assert!(prefix == [1] || suffix == [7]); + let expect1 = [1 << 8 | 2, 3 << 8 | 4, 5 << 8 | 6]; + let expect2 = [1 | 2 << 8, 3 | 4 << 8, 5 | 6 << 8]; + let expect3 = [2 | 3 << 8, 4 | 5 << 8, 6 | 7 << 8]; + let expect4 = [2 | 3 << 8, 4 | 5 << 8, 6 | 7 << 8]; + assert!(aligned == expect1 || aligned == expect2 || aligned == expect3 || aligned == expect4, + "aligned={:?} expected={:?} || {:?} || {:?} || {:?}", + aligned, expect1, expect2, expect3, expect4); +} + +#[test] +fn test_align_to_zst() { + let bytes = [1, 2, 3, 4, 5, 6, 7]; + let (prefix, aligned, suffix) = unsafe { bytes.align_to::<()>() }; + assert_eq!(aligned.len(), 0); + assert!(prefix == [1, 2, 3, 4, 5, 6, 7] || suffix == [1, 2, 3, 4, 5, 6, 7]); +} + +#[test] +fn test_align_to_non_trivial() { + #[repr(align(8))] struct U64(u64, u64); + #[repr(align(8))] struct U64U64U32(u64, u64, u32); + let data = [U64(1, 2), U64(3, 4), U64(5, 6), U64(7, 8), U64(9, 10), U64(11, 12), U64(13, 14), + U64(15, 16)]; + let (prefix, aligned, suffix) = unsafe { data.align_to::() }; + assert_eq!(aligned.len(), 4); + assert_eq!(prefix.len() + suffix.len(), 2); +} diff --git a/src/test/run-pass/align-offset-sign.rs b/src/test/run-pass/align-offset-sign.rs deleted file mode 100644 index f7d427cb7b2..00000000000 --- a/src/test/run-pass/align-offset-sign.rs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(align_offset)] - -#[derive(Clone, Copy)] -#[repr(packed)] -struct A3(u16, u8); -struct A4(u32); -#[repr(packed)] -struct A5(u32, u8); -#[repr(packed)] -struct A6(u32, u16); -#[repr(packed)] -struct A7(u32, u16, u8); -#[repr(packed)] -struct A8(u32, u32); -#[repr(packed)] -struct A9(u32, u32, u8); -#[repr(packed)] -struct A10(u32, u32, u16); - -unsafe fn test_weird_stride(ptr: *const T, align: usize) -> bool { - let numptr = ptr as usize; - let mut expected = usize::max_value(); - // Naive but definitely correct way to find the *first* aligned element of stride::. - for el in (0..align) { - if (numptr + el * ::std::mem::size_of::()) % align == 0 { - expected = el; - break; - } - } - let got = ptr.align_offset(align); - if got != expected { - eprintln!("aligning {:p} (with stride of {}) to {}, expected {}, got {}", ptr, ::std::mem::size_of::(), align, expected, got); - return true; - } - return false; -} - -fn main() { - unsafe { - // For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at - // all, because no amount of elements will align the pointer. - let mut p = 1; - while p < 1024 { - assert_eq!((p as *const ()).align_offset(p), 0); - if (p != 1) { - assert_eq!(((p + 1) as *const ()).align_offset(p), !0); - } - p = (p + 1).next_power_of_two(); - } - - // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to - // number of bytes. - let mut align = 1; - while align < 1024 { - for ptr in 1..2*align { - let expected = ptr % align; - let offset = if expected == 0 { 0 } else { align - expected }; - assert_eq!((ptr as *const u8).align_offset(align), offset, - "ptr = {}, align = {}, size = 1", ptr, align); - align = (align + 1).next_power_of_two(); - } - } - - - // For pointers of stride != 1, we verify the algorithm against the naivest possible - // implementation - let mut align = 1; - let mut x = false; - while align < 1024 { - for ptr in 1usize..4*align { - x |= test_weird_stride::(ptr as *const A3, align); - x |= test_weird_stride::(ptr as *const A4, align); - x |= test_weird_stride::(ptr as *const A5, align); - x |= test_weird_stride::(ptr as *const A6, align); - x |= test_weird_stride::(ptr as *const A7, align); - x |= test_weird_stride::(ptr as *const A8, align); - x |= test_weird_stride::(ptr as *const A9, align); - x |= test_weird_stride::(ptr as *const A10, align); - } - align = (align + 1).next_power_of_two(); - } - assert!(!x); - } -} -- cgit 1.4.1-3-g733a5 From 6d5bf8b23f4e59fdc67f635a10f450dfab2f076b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 4 May 2018 00:49:22 +0300 Subject: Remove the intrinsic for align_offset Keep only the language item. This removes some indirection and makes codegen worse for debug builds, but simplifies code significantly, which is a good tradeoff to make, in my opinion. Besides, the codegen can be improved even further with some constant evaluation improvements that we expect to happen in the future. --- src/libcore/intrinsics.rs | 42 ---------------------------------- src/libcore/ptr.rs | 31 +++++++++++++++++-------- src/libcore/slice/mod.rs | 7 ++++-- src/librustc_codegen_llvm/intrinsic.rs | 26 --------------------- src/librustc_typeck/check/intrinsic.rs | 4 ---- 5 files changed, 26 insertions(+), 84 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 510a5bb3df7..1420e00b47f 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1467,48 +1467,6 @@ extern "rust-intrinsic" { /// docs my friends, its friday! pub fn align_offset(ptr: *const (), align: usize) -> usize; - /// Computes the offset that needs to be applied to the pointer in order to make it aligned to - /// `align`. - /// - /// If it is not possible to align the pointer, the implementation returns - /// `usize::max_value()`. - /// - /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be - /// used with the `offset` or `offset_to` methods. - /// - /// There are no guarantees whatsover that offsetting the pointer will not overflow or go - /// beyond the allocation that the pointer points into. It is up to the caller to ensure that - /// the returned offset is correct in all terms other than alignment. - /// - /// # Unsafety - /// - /// `align` must be a power-of-two. - /// - /// # Examples - /// - /// Accessing adjacent `u8` as `u16` - /// - /// ``` - /// # #![feature(core_intrinsics)] - /// # fn foo(n: usize) { - /// # use std::intrinsics::align_offset; - /// # use std::mem::align_of; - /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = &x[n] as *const u8; - /// let offset = align_offset(ptr, align_of::()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.offset(offset as isize) as *const u16; - /// assert_ne!(*u16_ptr, 500); - /// } else { - /// // while the pointer can be aligned via `offset`, it would point - /// // outside the allocation - /// } - /// # } } - /// ``` - #[cfg(not(stage0))] - pub fn align_offset(ptr: *const T, align: usize) -> usize; - /// Emits a `!nontemporal` store according to LLVM (see their docs). /// Probably will never become stable. pub fn nontemporal_store(ptr: *mut T, val: T); diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index a762a8a6f92..e2286d23e33 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -1478,7 +1478,7 @@ impl *const T { panic!("align_offset: align is not a power-of-two"); } unsafe { - intrinsics::align_offset(self, align) + align_offset(self, align) } } @@ -2543,7 +2543,7 @@ impl *mut T { panic!("align_offset: align is not a power-of-two"); } unsafe { - intrinsics::align_offset(self, align) + align_offset(self, align) } } @@ -2565,8 +2565,6 @@ impl *mut T { /// Calculate offset (in terms of elements of `stride` stride) that has to be applied /// to pointer `p` so that pointer `p` would get aligned to `a`. /// -/// This is an implementation of the `align_offset` intrinsic for the case where `stride > 1`. -/// /// Note: This implementation has been carefully tailored to not panic. It is UB for this to panic. /// The only real change that can be made here is change of `INV_TABLE_MOD_16` and associated /// constants. @@ -2578,7 +2576,7 @@ impl *mut T { /// Any questions go to @nagisa. #[lang="align_offset"] #[cfg(not(stage0))] -unsafe fn align_offset(p: *const (), a: usize, stride: usize) -> usize { +pub(crate) unsafe fn align_offset(p: *const T, a: usize) -> usize { /// Calculate multiplicative modular inverse of `x` modulo `m`. /// /// This implementation is tailored for align_offset and has following preconditions: @@ -2587,12 +2585,13 @@ unsafe fn align_offset(p: *const (), a: usize, stride: usize) -> usize { /// * `x < m`; (if `x ≥ m`, pass in `x % m` instead) /// /// Implementation of this function shall not panic. Ever. + #[inline] fn mod_inv(x: usize, m: usize) -> usize { /// Multiplicative modular inverse table modulo 2⁴ = 16. /// /// Note, that this table does not contain values where inverse does not exist (i.e. for /// `0⁻¹ mod 16`, `2⁻¹ mod 16`, etc.) - static INV_TABLE_MOD_16: [usize; 8] = [1, 11, 13, 7, 9, 3, 5, 15]; + const INV_TABLE_MOD_16: [usize; 8] = [1, 11, 13, 7, 9, 3, 5, 15]; /// Modulo for which the `INV_TABLE_MOD_16` is intended. const INV_TABLE_MOD: usize = 16; /// INV_TABLE_MOD² @@ -2627,18 +2626,30 @@ unsafe fn align_offset(p: *const (), a: usize, stride: usize) -> usize { } } + let stride = ::mem::size_of::(); let a_minus_one = a.wrapping_sub(1); let pmoda = p as usize & a_minus_one; - let smoda = stride & a_minus_one; - // a is power-of-two so cannot be 0. stride = 0 is handled by the intrinsic. - let gcdpow = intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a)); - let gcd = 1usize << gcdpow; if pmoda == 0 { // Already aligned. Yay! return 0; } + if stride <= 1 { + return if stride == 0 { + // If the pointer is not aligned, and the element is zero-sized, then no amount of + // elements will ever align the pointer. + !0 + } else { + a.wrapping_sub(pmoda) + }; + } + + let smoda = stride & a_minus_one; + // a is power-of-two so cannot be 0. stride = 0 is handled above. + let gcdpow = intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a)); + let gcd = 1usize << gcdpow; + if gcd == 1 { // This branch solves for the variable $o$ in following linear congruence equation: // diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index ffa4a66346c..fdc9aa473e8 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1794,8 +1794,11 @@ impl [T] { // handle ZSTs specially, which is – don't handle them at all. return (self, &[], &[]); } + + // First, find at what point do we split between the first and 2nd slice. Easy with + // ptr.align_offset. let ptr = self.as_ptr(); - let offset = ::intrinsics::align_offset(ptr, ::mem::align_of::()); + let offset = ::ptr::align_offset(ptr, ::mem::align_of::()); if offset > self.len() { return (self, &[], &[]); } else { @@ -1848,7 +1851,7 @@ impl [T] { // First, find at what point do we split between the first and 2nd slice. Easy with // ptr.align_offset. let ptr = self.as_ptr(); - let offset = ::intrinsics::align_offset(ptr, ::mem::align_of::()); + let offset = ::ptr::align_offset(ptr, ::mem::align_of::()); if offset > self.len() { return (self, &mut [], &mut []); } else { diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 93351651db9..cffe7f79e97 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -25,7 +25,6 @@ use type_of::LayoutLlvmExt; use rustc::ty::{self, Ty}; use rustc::ty::layout::{HasDataLayout, LayoutOf}; use rustc::hir; -use rustc::middle::lang_items::AlignOffsetLangItem; use syntax::ast; use syntax::symbol::Symbol; use builder::Builder; @@ -390,31 +389,6 @@ pub fn codegen_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, args[0].deref(bx.cx).codegen_get_discr(bx, ret_ty) } - "align_offset" => { - let (ptr, align) = (args[0].immediate(), args[1].immediate()); - let stride_of_t = bx.cx.layout_of(substs.type_at(0)).size_and_align().0.bytes(); - let stride = C_usize(bx.cx, stride_of_t); - let zero = C_null(bx.cx.isize_ty); - let max = C_int(cx.isize_ty, -1); // -1isize (wherein I cheat horribly to make !0usize) - - if stride_of_t <= 1 { - // offset = ptr as usize % align => offset = ptr as usize & (align - 1) - let modmask = bx.sub(align, C_usize(bx.cx, 1)); - let offset = bx.and(bx.ptrtoint(ptr, bx.cx.isize_ty), modmask); - let is_zero = bx.icmp(llvm::IntPredicate::IntEQ, offset, zero); - // if offset == 0 { 0 } else { if stride_of_t == 1 { align - offset } else { !0 } } - bx.select(is_zero, zero, if stride_of_t == 1 { - bx.sub(align, offset) - } else { - max - }) - } else { - let did = ::common::langcall(bx.tcx(), Some(span), "", AlignOffsetLangItem); - let instance = ty::Instance::mono(bx.tcx(), did); - let llfn = ::callee::get_fn(bx.cx, instance); - bx.call(llfn, &[ptr, align, stride], None) - } - } name if name.starts_with("simd_") => { match generic_simd_intrinsic(bx, name, callee_ty, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index db6062db1fb..af1f1044edf 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -314,10 +314,6 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32) } - "align_offset" => { - (1, vec![tcx.mk_imm_ptr(param(0)), tcx.types.usize], tcx.types.usize) - }, - "nontemporal_store" => { (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil()) } -- cgit 1.4.1-3-g733a5 From 59bb0fe66ea6d80c5e1466b9609887e4cf7cde47 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 17 May 2018 18:02:47 +0300 Subject: Fix align_offset_stride1 & align_to_simple tests --- src/libcore/tests/ptr.rs | 2 +- src/libcore/tests/slice.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/ptr.rs b/src/libcore/tests/ptr.rs index 9384cb32798..31bc1d67768 100644 --- a/src/libcore/tests/ptr.rs +++ b/src/libcore/tests/ptr.rs @@ -322,8 +322,8 @@ fn align_offset_stride1() { let offset = if expected == 0 { 0 } else { align - expected }; assert_eq!((ptr as *const u8).align_offset(align), offset, "ptr = {}, align = {}, size = 1", ptr, align); - align = (align + 1).next_power_of_two(); } + align = (align + 1).next_power_of_two(); } } diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 8acb531b989..fcd79222e16 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -821,7 +821,7 @@ fn test_align_to_simple() { assert!(prefix == [1] || suffix == [7]); let expect1 = [1 << 8 | 2, 3 << 8 | 4, 5 << 8 | 6]; let expect2 = [1 | 2 << 8, 3 | 4 << 8, 5 | 6 << 8]; - let expect3 = [2 | 3 << 8, 4 | 5 << 8, 6 | 7 << 8]; + let expect3 = [2 << 8 | 3, 4 << 8 | 5, 6 << 8 | 7]; let expect4 = [2 | 3 << 8, 4 | 5 << 8, 6 | 7 << 8]; assert!(aligned == expect1 || aligned == expect2 || aligned == expect3 || aligned == expect4, "aligned={:?} expected={:?} || {:?} || {:?} || {:?}", -- cgit 1.4.1-3-g733a5 From 8b024888349f2c28b74c6697a33572dbd0d077b0 Mon Sep 17 00:00:00 2001 From: Dan Robertson Date: Sat, 19 May 2018 01:13:31 +0000 Subject: Fix warning when building stage0 libcore When building stage0 a warning will be triggered when compiling libcore due to align_to_offsets not being used. --- src/libcore/slice/mod.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index fdc9aa473e8..3b19a401859 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1698,6 +1698,7 @@ impl [T] { } /// Function to calculate lenghts of the middle and trailing slice for `align_to{,_mut}`. + #[cfg(not(stage0))] fn align_to_offsets(&self) -> (usize, usize) { // What we gonna do about `rest` is figure out what multiple of `U`s we can put in a // lowest number of `T`s. And how many `T`s we need for each such "multiple". -- cgit 1.4.1-3-g733a5 From 99f5136f9e2df5d60b371e9e19d2f6efe0d2e59e Mon Sep 17 00:00:00 2001 From: Jonathan Behrens Date: Sat, 19 May 2018 15:18:07 -0400 Subject: Add as_micros and as_millis methods --- src/libcore/time.rs | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/time.rs b/src/libcore/time.rs index f49917f848a..f43d2db51e7 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -263,18 +263,52 @@ impl Duration { #[inline] pub fn subsec_nanos(&self) -> u32 { self.nanos } + /// Returns the total number of milliseconds contained by this `Duration`. + /// + /// # Examples + /// + /// ``` + /// # #![feature(duration_as_u128)] + /// use std::time::Duration; + /// + /// let duration = Duration::new(5, 730023852); + /// assert_eq!(duration.as_millis(), 5730); + /// ``` + #[unstable(feature = "duration_as_u128", issue = "50202")] + #[inline] + pub fn as_millis(&self) -> u128 { + self.secs as u128 * MILLIS_PER_SEC as u128 + self.nanos as u128 / NANOS_PER_MILLI as u128 + } + + /// Returns the total number of microseconds contained by this `Duration`. + /// + /// # Examples + /// + /// ``` + /// # #![feature(duration_as_u128)] + /// use std::time::Duration; + /// + /// let duration = Duration::new(5, 730023852); + /// assert_eq!(duration.as_micros(), 5730023); + /// ``` + #[unstable(feature = "duration_as_u128", issue = "50202")] + #[inline] + pub fn as_micros(&self) -> u128 { + self.secs as u128 * MICROS_PER_SEC as u128 + self.nanos as u128 / NANOS_PER_MICRO as u128 + } + /// Returns the total number of nanoseconds contained by this `Duration`. /// /// # Examples /// /// ``` - /// # #![feature(duration_nanos)] + /// # #![feature(duration_as_u128)] /// use std::time::Duration; /// /// let duration = Duration::new(5, 730023852); /// assert_eq!(duration.as_nanos(), 5730023852); /// ``` - #[unstable(feature = "duration_nanos", issue = "50202")] + #[unstable(feature = "duration_as_u128", issue = "50202")] #[inline] pub fn as_nanos(&self) -> u128 { self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos as u128 -- cgit 1.4.1-3-g733a5 From 52249e357d38c1133cca16e6e17d1c1b452ba52e Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Sat, 19 May 2018 13:58:16 -0400 Subject: UnsafeCell doc typos and minor flow improvements --- src/libcore/cell.rs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 1ff187ed3f1..9a46c6106db 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1231,25 +1231,26 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// /// If you have a reference `&SomeStruct`, then normally in Rust all fields of `SomeStruct` are /// immutable. The compiler makes optimizations based on the knowledge that `&T` is not mutably -/// aliased or mutated, and that `&mut T` is unique. `UnsafeCel` is the only core language +/// aliased or mutated, and that `&mut T` is unique. `UnsafeCell` is the only core language /// feature to work around this restriction. All other types that allow internal mutability, such as -/// `Cell` and `RefCell` use `UnsafeCell` to wrap their internal data. +/// `Cell` and `RefCell`, use `UnsafeCell` to wrap their internal data. /// /// The `UnsafeCell` API itself is technically very simple: it gives you a raw pointer `*mut T` to /// its contents. It is up to _you_ as the abstraction designer to use that raw pointer correctly. /// /// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious: /// -/// - If you create a safe reference with lifetime `'a` (either a `&T` or `&mut T` reference) that -/// is accessible by safe code (for example, because you returned it), then you must not access -/// the data in any way that contradicts that reference for the remainder of `'a`. For example, that -/// means that if you take the `*mut T` from an `UnsafeCell` and case it to an `&T`, then until -/// that reference's lifetime expires, the data in `T` must remain immutable (modulo any -/// `UnsafeCell` data found within `T`, of course). Similarly, if you create an `&mut T` reference -/// that is released to safe code, then you must not access the data within the `UnsafeCell` until -/// that reference expires. +/// - If you create a safe reference with lifetime `'a` (either a `&T` or `&mut T` +/// reference) that is accessible by safe code (for example, because you returned it), +/// then you must not access the data in any way that contradicts that reference for the +/// remainder of `'a`. For example, this means that if you take the `*mut T` from an +/// `UnsafeCell` and cast it to an `&T`, then the data in `T` must remain immutable +/// (modulo any `UnsafeCell` data found within `T`, of course) until that reference's +/// lifetime expires. Similarly, if you create a `&mut T` reference that is released to +/// safe code, then you must not access the data within the `UnsafeCell` until that +/// reference expires. /// -/// - At all times, you must avoid data races, meaning that if multiple threads have access to +/// - At all times, you must avoid data races. If multiple threads have access to /// the same `UnsafeCell`, then any writes must have a proper happens-before relation to all other /// accesses (or use atomics). /// @@ -1259,10 +1260,10 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// 1. A `&T` reference can be released to safe code and there it can co-exit with other `&T` /// references, but not with a `&mut T` /// -/// 2. A `&mut T` reference may be released to safe code, provided neither other `&mut T` nor `&T` +/// 2. A `&mut T` reference may be released to safe code provided neither other `&mut T` nor `&T` /// co-exist with it. A `&mut T` must always be unique. /// -/// Note that while mutating or mutably aliasing the contents of an `& UnsafeCell` is +/// Note that while mutating or mutably aliasing the contents of an `&UnsafeCell` is /// okay (provided you enforce the invariants some other way), it is still undefined behavior /// to have multiple `&mut UnsafeCell` aliases. /// -- cgit 1.4.1-3-g733a5 From e2f0cc084f8253e7dab29c661ff1fc208766e44f Mon Sep 17 00:00:00 2001 From: Daniel Mueller Date: Sat, 19 May 2018 20:40:11 -0700 Subject: Fix typo in cell.rs --- src/libcore/cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 1ff187ed3f1..2eb50b8d5b9 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1256,7 +1256,7 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// To assist with proper design, the following scenarios are explicitly declared legal /// for single-threaded code: /// -/// 1. A `&T` reference can be released to safe code and there it can co-exit with other `&T` +/// 1. A `&T` reference can be released to safe code and there it can co-exist with other `&T` /// references, but not with a `&mut T` /// /// 2. A `&mut T` reference may be released to safe code, provided neither other `&mut T` nor `&T` -- cgit 1.4.1-3-g733a5 From 26d62f55a40db77c6bca85ad56a44aee898096a5 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 21 May 2018 17:59:20 +0200 Subject: Stabilize feature from_ref --- src/liballoc/slice.rs | 4 ++-- src/libcore/slice/mod.rs | 6 +++--- src/librustc/mir/mod.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 4427ac004f9..161493f3892 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -119,8 +119,8 @@ pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut}; pub use core::slice::{RSplit, RSplitMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{from_raw_parts, from_raw_parts_mut}; -#[unstable(feature = "from_ref", issue = "45703")] -pub use core::slice::{from_ref, from_ref_mut}; +#[stable(feature = "from_ref", since = "1.28.0")] +pub use core::slice::{from_ref, from_mut}; #[unstable(feature = "slice_get_slice", issue = "35729")] pub use core::slice::SliceIndex; #[unstable(feature = "exact_chunks", issue = "47115")] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 3b19a401859..6278da85e9b 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -3874,7 +3874,7 @@ pub unsafe fn from_raw_parts_mut<'a, T>(p: *mut T, len: usize) -> &'a mut [T] { } /// Converts a reference to T into a slice of length 1 (without copying). -#[unstable(feature = "from_ref", issue = "45703")] +#[stable(feature = "from_ref", since = "1.28.0")] pub fn from_ref(s: &T) -> &[T] { unsafe { from_raw_parts(s, 1) @@ -3882,8 +3882,8 @@ pub fn from_ref(s: &T) -> &[T] { } /// Converts a reference to T into a slice of length 1 (without copying). -#[unstable(feature = "from_ref", issue = "45703")] -pub fn from_ref_mut(s: &mut T) -> &mut [T] { +#[stable(feature = "from_ref", since = "1.28.0")] +pub fn from_mut(s: &mut T) -> &mut [T] { unsafe { from_raw_parts_mut(s, 1) } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index f42f876510d..246377b7b57 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -948,7 +948,7 @@ impl<'tcx> TerminatorKind<'tcx> { Drop { target: ref mut t, unwind: Some(ref mut u), .. } | Assert { target: ref mut t, cleanup: Some(ref mut u), .. } | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => { - Some(t).into_iter().chain(slice::from_ref_mut(u)) + Some(t).into_iter().chain(slice::from_mut(u)) } SwitchInt { ref mut targets, .. } => { None.into_iter().chain(&mut targets[..]) -- cgit 1.4.1-3-g733a5 From d6fc3e176eb0a015e9911a60fc1a5e0b6103416a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 18 May 2018 15:16:57 +0200 Subject: Make `[T]::len` and `str::len` const fn --- src/libcore/lib.rs | 3 +++ src/libcore/slice/mod.rs | 32 +++++++++++++++++++++----------- src/libcore/str/mod.rs | 20 +++++++++++++++----- src/test/ui/const-eval/strlen.rs | 26 ++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/const-eval/strlen.rs (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 77b5488084d..d37629ced11 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -119,6 +119,9 @@ #![feature(powerpc_target_feature)] #![feature(mips_target_feature)] #![feature(aarch64_target_feature)] +#![feature(const_slice_len)] +#![feature(const_str_as_bytes)] +#![feature(const_str_len)] #[prelude_import] #[allow(unused)] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 3b19a401859..b453edcb4e1 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -59,9 +59,16 @@ mod rotate; mod sort; #[repr(C)] -struct Repr { - pub data: *const T, - pub len: usize, +union Repr<'a, T: 'a> { + rust: &'a [T], + rust_mut: &'a mut [T], + raw: FatPtr, +} + +#[repr(C)] +struct FatPtr { + data: *const T, + len: usize, } // @@ -119,9 +126,10 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn len(&self) -> usize { + #[rustc_const_unstable(feature = "const_slice_len")] + pub const fn len(&self) -> usize { unsafe { - mem::transmute::<&[T], Repr>(self).len + Repr { rust: self }.raw.len } } @@ -135,7 +143,8 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_empty(&self) -> bool { + #[rustc_const_unstable(feature = "const_slice_len")] + pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -418,7 +427,8 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn as_ptr(&self) -> *const T { + #[rustc_const_unstable(feature = "const_slice_as_ptr")] + pub const fn as_ptr(&self) -> *const T { self as *const [T] as *const T } @@ -3856,8 +3866,8 @@ unsafe impl<'a, T> TrustedRandomAccess for ExactChunksMut<'a, T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn from_raw_parts<'a, T>(p: *const T, len: usize) -> &'a [T] { - mem::transmute(Repr { data: p, len: len }) +pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { + Repr { raw: FatPtr { data, len } }.rust } /// Performs the same functionality as `from_raw_parts`, except that a mutable @@ -3869,8 +3879,8 @@ pub unsafe fn from_raw_parts<'a, T>(p: *const T, len: usize) -> &'a [T] { /// `from_raw_parts`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn from_raw_parts_mut<'a, T>(p: *mut T, len: usize) -> &'a mut [T] { - mem::transmute(Repr { data: p, len: len }) +pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { + Repr { raw: FatPtr { data, len} }.rust_mut } /// Converts a reference to T into a slice of length 1 (without copying). diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 82bead0ab46..70aaf10f421 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2166,7 +2166,8 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn len(&self) -> usize { + #[rustc_const_unstable(feature = "const_str_len")] + pub const fn len(&self) -> usize { self.as_bytes().len() } @@ -2185,7 +2186,8 @@ impl str { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { + #[rustc_const_unstable(feature = "const_str_len")] + pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -2242,8 +2244,15 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline(always)] - pub fn as_bytes(&self) -> &[u8] { - unsafe { &*(self as *const str as *const [u8]) } + #[rustc_const_unstable(feature="const_str_as_bytes")] + pub const fn as_bytes(&self) -> &[u8] { + unsafe { + union Slices<'a> { + str: &'a str, + slice: &'a [u8], + } + Slices { str: self }.slice + } } /// Converts a mutable string slice to a mutable byte slice. To convert the @@ -2303,7 +2312,8 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn as_ptr(&self) -> *const u8 { + #[rustc_const_unstable(feature = "const_str_as_ptr")] + pub const fn as_ptr(&self) -> *const u8 { self as *const str as *const u8 } diff --git a/src/test/ui/const-eval/strlen.rs b/src/test/ui/const-eval/strlen.rs new file mode 100644 index 00000000000..bdadf5dd5e1 --- /dev/null +++ b/src/test/ui/const-eval/strlen.rs @@ -0,0 +1,26 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +#![feature(const_str_len, const_str_as_bytes)] + +#![crate_type = "lib"] + +const S: &str = "foo"; +pub const B: &[u8] = S.as_bytes(); + +pub fn foo() -> [u8; S.len()] { + let mut buf = [0; S.len()]; + for (i, &c) in S.as_bytes().iter().enumerate() { + buf[i] = c; + } + buf +} -- cgit 1.4.1-3-g733a5 From f53022f88d1820a1a8b2991f661e4373329d317f Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 12 Apr 2018 11:57:49 +0100 Subject: Update unicode/tables.rs with Mn --- src/libcore/unicode/tables.rs | 120 +++++++++++++++++++++++++++++++++++++++++ src/libcore/unicode/unicode.py | 2 +- 2 files changed, 121 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs index 3fbbc011bc4..1d553fe5538 100644 --- a/src/libcore/unicode/tables.rs +++ b/src/libcore/unicode/tables.rs @@ -38,6 +38,126 @@ pub mod general_category { Cc_table.lookup(c) } + pub const Mn_table: &super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0xffffffffffffffff, 0x0000ffffffffffff, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x00000000000000f8, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0xbffffffffffe0000, 0x00000000000000b6, + 0x0000000007ff0000, 0x00010000fffff800, 0x0000000000000000, 0x00003d9f9fc00000, + 0xffff000000020000, 0x00000000000007ff, 0x0001ffc000000000, 0x000ff80000000000 + ], + r2: [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 15, 16, 11, 17, 18, 7, 2, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 31, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 33, 34, 35, 36, 2, 37, 2, 38, 2, 2, 2, 39, 40, 41, 2, 42, + 43, 44, 45, 46, 2, 2, 47, 2, 2, 2, 48, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 49, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 50, 2, 51, 2, 52, 2, 2, 2, 2, 2, 2, 2, 2, 53, + 2, 54, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 55, 56, 57, 2, 2, 2, 2, 58, 2, 2, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 2, 2, 2, 68, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, 2, 2, 2, 2, 2, 2, 2 + ], + r3: &[ + 0x00003eeffbc00000, 0x000000000e000000, 0x0000000000000000, 0xfffffffbfff00000, + 0x1400000000000007, 0x0000000c00fe21fe, 0x1000000000000002, 0x0000000c0000201e, + 0x1000000000000006, 0x0023000000023986, 0xfc00000c000021be, 0x9000000000000002, + 0x0000000c0040201e, 0x0000000000000004, 0x0000000000002001, 0xc000000000000001, + 0x0000000c00603dc1, 0x0000000c00003040, 0x1800000000000003, 0x00000000005c0400, + 0x07f2000000000000, 0x0000000000007f80, 0x1bf2000000000000, 0x0000000000003f00, + 0x02a0000003000000, 0x7ffe000000000000, 0x1ffffffffeffe0df, 0x0000000000000040, + 0x66fde00000000000, 0x001e0001c3000000, 0x0000000020002064, 0x00000000e0000000, + 0x001c0000001c0000, 0x000c0000000c0000, 0x3fb0000000000000, 0x00000000200ffe40, + 0x0000000000003800, 0x0000020000000060, 0x0e04018700000000, 0x0000000009800000, + 0x9ff81fe57f400000, 0x3fff000000000000, 0x17d000000000000f, 0x000ff80000000004, + 0x00003b3c00000003, 0x0003a34000000000, 0x00cff00000000000, 0x031021fdfff70000, + 0xfbffffffffffffff, 0x0001ffe21fff0000, 0x0003800000000000, 0x8000000000000000, + 0xffffffff00000000, 0x00003c0000000000, 0x0000000006000000, 0x3ff0800000000000, + 0x00000000c0000000, 0x0003000000000000, 0x0000006000000844, 0x0003ffff00000030, + 0x00003fc000000000, 0x000000000003ff80, 0x13c8000000000007, 0x0000002000000000, + 0x00667e0000000000, 0x1000000000001008, 0xc19d000000000000, 0x0040300000000002, + 0x0000212000000000, 0x0000000040000000, 0x0000ffff0000ffff + ], + r4: [ + 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 4, 2, 5, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + ], + r5: &[ + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 7, 8, 0, 9, 10, 11, 12, 13, 0, 0, 14, 15, 16, 0, 0, 17, 18, 19, 20, + 0, 0, 21, 22, 23, 24, 25, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 0, 0, 0, + 0, 0, 30, 0, 31, 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 43, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 46, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 47, + 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ], + r6: &[ + 0x0000000000000000, 0x2000000000000000, 0x0000000100000000, 0x07c0000000000000, + 0x870000000000f06e, 0x0000006000000000, 0xff00000000000002, 0x800000000000007f, + 0x0678000000000003, 0x001fef8000000007, 0x0008000000000000, 0x7fc0000000000003, + 0x0000000000001c00, 0x40d3800000000000, 0x000007f880000000, 0x1000000000000003, + 0x001f1fc000000001, 0xff00000000000000, 0x000000000000005c, 0x85f8000000000000, + 0x000000000000000d, 0xb03c000000000000, 0x0000000030000001, 0xa7f8000000000000, + 0x0000000000000001, 0x00bf280000000000, 0x00000fbce0000000, 0x79f800000000067e, + 0x000000000e7e0080, 0x00000000037ffc00, 0xbf7f000000000000, 0x006dfcfffffc0000, + 0xb47e000000000000, 0x00000000000000bf, 0x001f000000000000, 0x007f000000000000, + 0x0000000000078000, 0x0000000060000000, 0xf800038000000000, 0x00003c0000000fe7, + 0x000000000000001c, 0xf87fffffffffffff, 0x00201fffffffffff, 0x0000fffef8000010, + 0x000007dbf9ffff7f, 0x00000000007f0000, 0x00000000000007f0, 0xffffffffffffffff, + 0x0000ffffffffffff + ], + }; + + pub fn Mn(c: char) -> bool { + Mn_table.lookup(c) + } + pub const N_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x03ff000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py index 75ec01944bf..260251b96dc 100755 --- a/src/libcore/unicode/unicode.py +++ b/src/libcore/unicode/unicode.py @@ -21,7 +21,7 @@ # - UnicodeData.txt # # Since this should not require frequent updates, we just store this -# out-of-line and check the unicode.rs file into git. +# out-of-line and check the unicode.py file into git. import fileinput, re, os, sys, operator, math -- cgit 1.4.1-3-g733a5 From a0b5d3813e5793caed9a6cf973851d40b75bf7b9 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 12 Apr 2018 12:09:47 +0100 Subject: Download unicode data files in directory of unicode.py --- src/libcore/unicode/unicode.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py index 260251b96dc..2527c1c103e 100755 --- a/src/libcore/unicode/unicode.py +++ b/src/libcore/unicode/unicode.py @@ -25,6 +25,9 @@ import fileinput, re, os, sys, operator, math +# The directory in which this file resides. +fdir = os.path.dirname(os.path.realpath(__file__)) + "/" + preamble = '''// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. @@ -61,11 +64,12 @@ expanded_categories = { surrogate_codepoints = (0xd800, 0xdfff) def fetch(f): - if not os.path.exists(os.path.basename(f)): + path = fdir + os.path.basename(f) + if not os.path.exists(path): os.system("curl -O http://www.unicode.org/Public/UNIDATA/%s" % f) - if not os.path.exists(os.path.basename(f)): + if not os.path.exists(path): sys.stderr.write("cannot load %s" % f) exit(1) @@ -84,7 +88,7 @@ def load_unicode_data(f): udict = {} range_start = -1 - for line in fileinput.input(f): + for line in fileinput.input(fdir + f): data = line.split(';') if len(data) != 15: continue @@ -156,7 +160,7 @@ def load_unicode_data(f): def load_special_casing(f, to_upper, to_lower, to_title): fetch(f) - for line in fileinput.input(f): + for line in fileinput.input(fdir + f): data = line.split('#')[0].split(';') if len(data) == 5: code, lower, title, upper, _comment = data @@ -243,7 +247,7 @@ def load_properties(f, interestingprops): re1 = re.compile("^ *([0-9A-F]+) *; *(\w+)") re2 = re.compile("^ *([0-9A-F]+)\.\.([0-9A-F]+) *; *(\w+)") - for line in fileinput.input(os.path.basename(f)): + for line in fileinput.input(fdir + os.path.basename(f)): prop = None d_lo = 0 d_hi = 0 @@ -456,7 +460,7 @@ def emit_norm_module(f, canon, compat, combine, norm_props): canon_comp_keys = sorted(canon_comp.keys()) if __name__ == "__main__": - r = "tables.rs" + r = fdir + "tables.rs" if os.path.exists(r): os.remove(r) with open(r, "w") as rf: @@ -465,7 +469,7 @@ if __name__ == "__main__": # download and parse all the data fetch("ReadMe.txt") - with open("ReadMe.txt") as readme: + with open(fdir + "ReadMe.txt") as readme: pattern = "for Version (\d+)\.(\d+)\.(\d+) of the Unicode" unicode_version = re.search(pattern, readme.read()).groups() rf.write(""" -- cgit 1.4.1-3-g733a5 From b72faf5795681352b5fba83dce91ee24c22e71c8 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 12 Apr 2018 12:24:08 +0100 Subject: Keep tables.rs copyright notice up to date --- src/libcore/unicode/tables.rs | 2 +- src/libcore/unicode/unicode.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs index 1d553fe5538..1fdd92cd47d 100644 --- a/src/libcore/unicode/tables.rs +++ b/src/libcore/unicode/tables.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py index 2527c1c103e..d24b4eb4ce4 100755 --- a/src/libcore/unicode/unicode.py +++ b/src/libcore/unicode/unicode.py @@ -23,12 +23,12 @@ # Since this should not require frequent updates, we just store this # out-of-line and check the unicode.py file into git. -import fileinput, re, os, sys, operator, math +import fileinput, re, os, sys, operator, math, datetime # The directory in which this file resides. fdir = os.path.dirname(os.path.realpath(__file__)) + "/" -preamble = '''// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +preamble = '''// Copyright 2012-{year} The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -43,8 +43,8 @@ preamble = '''// Copyright 2012-2016 The Rust Project Developers. See the COPYRI #![allow(missing_docs, non_upper_case_globals, non_snake_case)] use unicode::version::UnicodeVersion; -use unicode::bool_trie::{BoolTrie, SmallBoolTrie}; -''' +use unicode::bool_trie::{{BoolTrie, SmallBoolTrie}}; +'''.format(year = datetime.datetime.now().year) # Mapping taken from Table 12 from: # http://www.unicode.org/reports/tr44/#General_Category_Values -- cgit 1.4.1-3-g733a5 From 4694d20170e1a67f8a801c1f6dda11473d6fef77 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 12 Apr 2018 11:39:18 +0100 Subject: Escape combining characters in escape_debug --- src/libcore/char/methods.rs | 26 ++++++++++++++++++++++++-- src/libcore/fmt/mod.rs | 10 ++++++++-- src/libcore/unicode/unicode.py | 2 +- 3 files changed, 33 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 374adafef64..c170e0c1ba1 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -229,8 +229,8 @@ impl char { '\r' => EscapeDefaultState::Backslash('r'), '\n' => EscapeDefaultState::Backslash('n'), '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), - c if is_printable(c) => EscapeDefaultState::Char(c), - c => EscapeDefaultState::Unicode(c.escape_unicode()), + _ if is_printable(self) => EscapeDefaultState::Char(self), + _ => EscapeDefaultState::Unicode(self.escape_unicode()), }; EscapeDebug(EscapeDefault { state: init_state }) } @@ -692,6 +692,28 @@ impl char { general_category::Cc(self) } + /// Returns true if this `char` is a nonspacing mark code point, and false otherwise. + /// + /// 'Nonspacing mark code point' is defined in terms of the Unicode General + /// Category `Mn`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // U+0301, COMBINING ACUTE ACCENT + /// assert!('\u{301}'.is_nonspacing_mark()); + /// assert!(!'e'.is_nonspacing_mark()); + /// ``` + #[unstable(feature = "rustc_private", + reason = "mainly needed for compiler internals", + issue = "27812")] + #[inline] + pub fn is_nonspacing_mark(self) -> bool { + general_category::Mn(self) + } + /// Returns true if this `char` is numeric, and false otherwise. /// /// 'Numeric'-ness is defined in terms of the Unicode General Categories diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 5820fe58932..1cfde513102 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1844,8 +1844,14 @@ impl Display for str { impl Debug for char { fn fmt(&self, f: &mut Formatter) -> Result { f.write_char('\'')?; - for c in self.escape_debug() { - f.write_char(c)? + if self.is_nonspacing_mark() { + for c in self.escape_unicode() { + f.write_char(c)? + } + } else { + for c in self.escape_debug() { + f.write_char(c)? + } } f.write_char('\'') } diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py index d24b4eb4ce4..5b3c181ea9b 100755 --- a/src/libcore/unicode/unicode.py +++ b/src/libcore/unicode/unicode.py @@ -496,7 +496,7 @@ pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { ["Full_Composition_Exclusion"]) # category tables - for (name, cat, pfuns) in ("general_category", gencats, ["N", "Cc"]), \ + for (name, cat, pfuns) in ("general_category", gencats, ["N", "Cc", "Mn"]), \ ("derived_property", derived, want_derived), \ ("property", props, ["White_Space", "Pattern_White_Space"]): emit_property_module(rf, name, cat, pfuns) -- cgit 1.4.1-3-g733a5 From 699a2b5c7ee900c1ff99b70f9b6402ded78d3b3b Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 12 Apr 2018 22:19:02 +0100 Subject: Add test for Debug formatting of char --- src/libcore/tests/char.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/tests/char.rs b/src/libcore/tests/char.rs index ab90763abf8..76f28d493ab 100644 --- a/src/libcore/tests/char.rs +++ b/src/libcore/tests/char.rs @@ -186,6 +186,14 @@ fn test_escape_debug() { assert_eq!(string('\u{100000}'), "\\u{100000}"); // private use 2 } +#[test] +fn test_debug() { + assert_eq!(format!("{:?}", 'a'), "'a'"); // ASCII character + assert_eq!(format!("{:?}", 'é'), "'é'"); // printable character + assert_eq!(format!("{:?}", '\u{301}'), "'\\u{301}'"); // combining character + assert_eq!(format!("{:?}", '\u{e000}'), "'\\u{e000}'"); // private use 1 +} + #[test] fn test_escape_default() { fn string(c: char) -> String { -- cgit 1.4.1-3-g733a5 From 68c4fb8f2f556aca74394e07cbfb457d216e75b9 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 14 Apr 2018 00:21:25 +0100 Subject: Remove example in test for is_nonspacing_mark because it's currently private --- src/libcore/char/methods.rs | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index c170e0c1ba1..bffbba1a723 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -696,16 +696,6 @@ impl char { /// /// 'Nonspacing mark code point' is defined in terms of the Unicode General /// Category `Mn`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // U+0301, COMBINING ACUTE ACCENT - /// assert!('\u{301}'.is_nonspacing_mark()); - /// assert!(!'e'.is_nonspacing_mark()); - /// ``` #[unstable(feature = "rustc_private", reason = "mainly needed for compiler internals", issue = "27812")] -- cgit 1.4.1-3-g733a5 From d3c257b0aed1f6c0d541659539f27aca5c5bc25a Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 16 May 2018 23:08:19 +0100 Subject: Use the correct output directory for downloading Unicode files --- src/libcore/unicode/unicode.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py index 5b3c181ea9b..ce22c6f226a 100755 --- a/src/libcore/unicode/unicode.py +++ b/src/libcore/unicode/unicode.py @@ -66,8 +66,7 @@ surrogate_codepoints = (0xd800, 0xdfff) def fetch(f): path = fdir + os.path.basename(f) if not os.path.exists(path): - os.system("curl -O http://www.unicode.org/Public/UNIDATA/%s" - % f) + os.system("curl -o {0}{1} http://www.unicode.org/Public/UNIDATA/{1}".format(fdir, f)) if not os.path.exists(path): sys.stderr.write("cannot load %s" % f) -- cgit 1.4.1-3-g733a5 From d7aa35eb1bdc61db0842ab81f6c96f24897e61ad Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 16 May 2018 23:19:58 +0100 Subject: Use Grapheme_Extend instead of Mn --- src/libcore/char/methods.rs | 16 +-- src/libcore/unicode/tables.rs | 290 ++++++++++++++++++----------------------- src/libcore/unicode/unicode.py | 5 +- 3 files changed, 137 insertions(+), 174 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index bffbba1a723..bf7772492e5 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -229,6 +229,9 @@ impl char { '\r' => EscapeDefaultState::Backslash('r'), '\n' => EscapeDefaultState::Backslash('n'), '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), + _ if self.is_grapheme_extended() => { + EscapeDefaultState::Unicode(self.escape_unicode()) + } _ if is_printable(self) => EscapeDefaultState::Char(self), _ => EscapeDefaultState::Unicode(self.escape_unicode()), }; @@ -692,16 +695,13 @@ impl char { general_category::Cc(self) } - /// Returns true if this `char` is a nonspacing mark code point, and false otherwise. + /// Returns true if this `char` is an extended grapheme character, and false otherwise. /// - /// 'Nonspacing mark code point' is defined in terms of the Unicode General - /// Category `Mn`. - #[unstable(feature = "rustc_private", - reason = "mainly needed for compiler internals", - issue = "27812")] + /// 'Extended grapheme character' is defined in terms of the Unicode Shaping and Rendering + /// Category `Grapheme_Extend`. #[inline] - pub fn is_nonspacing_mark(self) -> bool { - general_category::Mn(self) + pub(crate) fn is_grapheme_extended(self) -> bool { + derived_property::Grapheme_Extend(self) } /// Returns true if this `char` is numeric, and false otherwise. diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs index 1fdd92cd47d..7f9c52e3aa5 100644 --- a/src/libcore/unicode/tables.rs +++ b/src/libcore/unicode/tables.rs @@ -38,126 +38,6 @@ pub mod general_category { Cc_table.lookup(c) } - pub const Mn_table: &super::BoolTrie = &super::BoolTrie { - r1: [ - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0xffffffffffffffff, 0x0000ffffffffffff, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x00000000000000f8, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0xbffffffffffe0000, 0x00000000000000b6, - 0x0000000007ff0000, 0x00010000fffff800, 0x0000000000000000, 0x00003d9f9fc00000, - 0xffff000000020000, 0x00000000000007ff, 0x0001ffc000000000, 0x000ff80000000000 - ], - r2: [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 15, 16, 11, 17, 18, 7, 2, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 31, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 33, 34, 35, 36, 2, 37, 2, 38, 2, 2, 2, 39, 40, 41, 2, 42, - 43, 44, 45, 46, 2, 2, 47, 2, 2, 2, 48, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 49, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 50, 2, 51, 2, 52, 2, 2, 2, 2, 2, 2, 2, 2, 53, - 2, 54, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 55, 56, 57, 2, 2, 2, 2, 58, 2, 2, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 2, 2, 2, 68, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, 2, 2, 2, 2, 2, 2, 2 - ], - r3: &[ - 0x00003eeffbc00000, 0x000000000e000000, 0x0000000000000000, 0xfffffffbfff00000, - 0x1400000000000007, 0x0000000c00fe21fe, 0x1000000000000002, 0x0000000c0000201e, - 0x1000000000000006, 0x0023000000023986, 0xfc00000c000021be, 0x9000000000000002, - 0x0000000c0040201e, 0x0000000000000004, 0x0000000000002001, 0xc000000000000001, - 0x0000000c00603dc1, 0x0000000c00003040, 0x1800000000000003, 0x00000000005c0400, - 0x07f2000000000000, 0x0000000000007f80, 0x1bf2000000000000, 0x0000000000003f00, - 0x02a0000003000000, 0x7ffe000000000000, 0x1ffffffffeffe0df, 0x0000000000000040, - 0x66fde00000000000, 0x001e0001c3000000, 0x0000000020002064, 0x00000000e0000000, - 0x001c0000001c0000, 0x000c0000000c0000, 0x3fb0000000000000, 0x00000000200ffe40, - 0x0000000000003800, 0x0000020000000060, 0x0e04018700000000, 0x0000000009800000, - 0x9ff81fe57f400000, 0x3fff000000000000, 0x17d000000000000f, 0x000ff80000000004, - 0x00003b3c00000003, 0x0003a34000000000, 0x00cff00000000000, 0x031021fdfff70000, - 0xfbffffffffffffff, 0x0001ffe21fff0000, 0x0003800000000000, 0x8000000000000000, - 0xffffffff00000000, 0x00003c0000000000, 0x0000000006000000, 0x3ff0800000000000, - 0x00000000c0000000, 0x0003000000000000, 0x0000006000000844, 0x0003ffff00000030, - 0x00003fc000000000, 0x000000000003ff80, 0x13c8000000000007, 0x0000002000000000, - 0x00667e0000000000, 0x1000000000001008, 0xc19d000000000000, 0x0040300000000002, - 0x0000212000000000, 0x0000000040000000, 0x0000ffff0000ffff - ], - r4: [ - 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 4, 2, 5, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 - ], - r5: &[ - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 6, 7, 8, 0, 9, 10, 11, 12, 13, 0, 0, 14, 15, 16, 0, 0, 17, 18, 19, 20, - 0, 0, 21, 22, 23, 24, 25, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 0, 0, 0, - 0, 0, 30, 0, 31, 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 43, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 46, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 47, - 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ], - r6: &[ - 0x0000000000000000, 0x2000000000000000, 0x0000000100000000, 0x07c0000000000000, - 0x870000000000f06e, 0x0000006000000000, 0xff00000000000002, 0x800000000000007f, - 0x0678000000000003, 0x001fef8000000007, 0x0008000000000000, 0x7fc0000000000003, - 0x0000000000001c00, 0x40d3800000000000, 0x000007f880000000, 0x1000000000000003, - 0x001f1fc000000001, 0xff00000000000000, 0x000000000000005c, 0x85f8000000000000, - 0x000000000000000d, 0xb03c000000000000, 0x0000000030000001, 0xa7f8000000000000, - 0x0000000000000001, 0x00bf280000000000, 0x00000fbce0000000, 0x79f800000000067e, - 0x000000000e7e0080, 0x00000000037ffc00, 0xbf7f000000000000, 0x006dfcfffffc0000, - 0xb47e000000000000, 0x00000000000000bf, 0x001f000000000000, 0x007f000000000000, - 0x0000000000078000, 0x0000000060000000, 0xf800038000000000, 0x00003c0000000fe7, - 0x000000000000001c, 0xf87fffffffffffff, 0x00201fffffffffff, 0x0000fffef8000010, - 0x000007dbf9ffff7f, 0x00000000007f0000, 0x00000000000007f0, 0xffffffffffffffff, - 0x0000ffffffffffff - ], - }; - - pub fn Mn(c: char) -> bool { - Mn_table.lookup(c) - } - pub const N_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x03ff000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, @@ -213,7 +93,7 @@ pub mod general_category { 0x03ff000003ff0000 ], r4: [ - 0, 1, 2, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 5, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 1, 2, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -235,17 +115,12 @@ pub mod general_category { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0 ], r6: &[ 0x0000000000000000, 0x001fffffffffffff, 0x0000000000000402, 0x00000000003e0000, 0x000003ff00000000, 0x0000ffc000000000, 0x03ff000000000000, 0xffc0000000000000, - 0x0000000003ff0000, 0x00000000000003ff, 0xffffffffffffffff, 0x00007fffffffffff, - 0xffffffffffffc000 + 0x0000000003ff0000, 0x00000000000003ff, 0xffffffffffffffff, 0x00007fffffffffff ], }; @@ -669,6 +544,127 @@ pub mod derived_property { Cased_table.lookup(c) } + pub const Grapheme_Extend_table: &super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0xffffffffffffffff, 0x0000ffffffffffff, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x00000000000003f8, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0xbffffffffffe0000, 0x00000000000000b6, + 0x0000000007ff0000, 0x00010000fffff800, 0x0000000000000000, 0x00003d9f9fc00000, + 0xffff000000020000, 0x00000000000007ff, 0x0001ffc000000000, 0x000ff80000000000 + ], + r2: [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 7, 2, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 34, 35, 36, 37, 2, 38, 2, 39, 2, 2, 2, 40, 41, 42, 2, 43, + 44, 45, 46, 47, 2, 2, 48, 2, 2, 2, 49, 2, 2, 2, 2, 2, 2, 2, 2, 50, 2, 2, 51, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 52, 2, 53, 2, 54, 2, 2, 2, 2, 2, 2, 2, 2, 55, + 2, 56, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 57, 58, 59, 2, 2, 2, 2, 60, 2, 2, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 2, 2, 2, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 71, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 72, 2, 2, 2, 2, 2, 58, 2 + ], + r3: &[ + 0x00003eeffbc00000, 0x000000000e000000, 0x0000000000000000, 0xfffffffbfff00000, + 0x1400000000000007, 0x0000000c00fe21fe, 0x5000000000000002, 0x0000000c0080201e, + 0x1000000000000006, 0x0023000000023986, 0xfc00000c000021be, 0xd000000000000002, + 0x0000000c00c0201e, 0x4000000000000004, 0x0000000000802001, 0xc000000000000001, + 0x0000000c00603dc1, 0x9000000000000002, 0x0000000c00603044, 0x5800000000000003, + 0x00000000805c8400, 0x07f2000000000000, 0x0000000000007f80, 0x1bf2000000000000, + 0x0000000000003f00, 0x02a0000003000000, 0x7ffe000000000000, 0x1ffffffffeffe0df, + 0x0000000000000040, 0x66fde00000000000, 0x001e0001c3000000, 0x0000000020002064, + 0x00000000e0000000, 0x001c0000001c0000, 0x000c0000000c0000, 0x3fb0000000000000, + 0x00000000200ffe40, 0x0000000000003800, 0x0000020000000060, 0x0e04018700000000, + 0x0000000009800000, 0x9ff81fe57f400000, 0x7fff000000000000, 0x17d000000000000f, + 0x000ff80000000004, 0x00003b3c00000003, 0x0003a34000000000, 0x00cff00000000000, + 0x031021fdfff70000, 0xfbffffffffffffff, 0x0000000000001000, 0x0001ffffffff0000, + 0x0003800000000000, 0x8000000000000000, 0xffffffff00000000, 0x0000fc0000000000, + 0x0000000006000000, 0x3ff7800000000000, 0x00000000c0000000, 0x0003000000000000, + 0x0000006000000844, 0x0003ffff00000030, 0x00003fc000000000, 0x000000000003ff80, + 0x13c8000000000007, 0x0000002000000000, 0x00667e0000000000, 0x1000000000001008, + 0xc19d000000000000, 0x0040300000000002, 0x0000212000000000, 0x0000000040000000, + 0x0000ffff0000ffff + ], + r4: [ + 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 4, 2, 5, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + ], + r5: &[ + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 7, 8, 0, 9, 10, 11, 12, 13, 0, 0, 14, 15, 16, 0, 0, 17, 18, 19, 20, + 0, 0, 21, 22, 23, 24, 25, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 0, 0, 0, + 0, 0, 30, 0, 31, 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 43, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 46, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 48, 0, 0, 48, 48, + 48, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ], + r6: &[ + 0x0000000000000000, 0x2000000000000000, 0x0000000100000000, 0x07c0000000000000, + 0x870000000000f06e, 0x0000006000000000, 0xff00000000000002, 0x800000000000007f, + 0x0678000000000003, 0x001fef8000000007, 0x0008000000000000, 0x7fc0000000000003, + 0x0000000000001c00, 0x40d3800000000000, 0x000007f880000000, 0x5000000000000003, + 0x001f1fc000800001, 0xff00000000000000, 0x000000000000005c, 0xa5f9000000000000, + 0x000000000000000d, 0xb03c800000000000, 0x0000000030000001, 0xa7f8000000000000, + 0x0000000000000001, 0x00bf280000000000, 0x00000fbce0000000, 0x79f800000000067e, + 0x000000000e7e0080, 0x00000000037ffc00, 0xbf7f000000000000, 0x006dfcfffffc0000, + 0xb47e000000000000, 0x00000000000000bf, 0x001f000000000000, 0x007f000000000000, + 0x0000000000078000, 0x0000000060000000, 0xf807c3a000000000, 0x00003c0000000fe7, + 0x000000000000001c, 0xf87fffffffffffff, 0x00201fffffffffff, 0x0000fffef8000010, + 0x000007dbf9ffff7f, 0x00000000007f0000, 0x00000000000007f0, 0xffffffff00000000, + 0xffffffffffffffff, 0x0000ffffffffffff + ], + }; + + pub fn Grapheme_Extend(c: char) -> bool { + Grapheme_Extend_table.lookup(c) + } + pub const Lowercase_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x0000000000000000, 0x07fffffe00000000, 0x0420040000000000, 0xff7fffff80000000, @@ -1841,24 +1837,7 @@ pub mod conversions { ('\u{118b8}', ['\u{118d8}', '\0', '\0']), ('\u{118b9}', ['\u{118d9}', '\0', '\0']), ('\u{118ba}', ['\u{118da}', '\0', '\0']), ('\u{118bb}', ['\u{118db}', '\0', '\0']), ('\u{118bc}', ['\u{118dc}', '\0', '\0']), ('\u{118bd}', ['\u{118dd}', '\0', '\0']), - ('\u{118be}', ['\u{118de}', '\0', '\0']), ('\u{118bf}', ['\u{118df}', '\0', '\0']), - ('\u{1e900}', ['\u{1e922}', '\0', '\0']), ('\u{1e901}', ['\u{1e923}', '\0', '\0']), - ('\u{1e902}', ['\u{1e924}', '\0', '\0']), ('\u{1e903}', ['\u{1e925}', '\0', '\0']), - ('\u{1e904}', ['\u{1e926}', '\0', '\0']), ('\u{1e905}', ['\u{1e927}', '\0', '\0']), - ('\u{1e906}', ['\u{1e928}', '\0', '\0']), ('\u{1e907}', ['\u{1e929}', '\0', '\0']), - ('\u{1e908}', ['\u{1e92a}', '\0', '\0']), ('\u{1e909}', ['\u{1e92b}', '\0', '\0']), - ('\u{1e90a}', ['\u{1e92c}', '\0', '\0']), ('\u{1e90b}', ['\u{1e92d}', '\0', '\0']), - ('\u{1e90c}', ['\u{1e92e}', '\0', '\0']), ('\u{1e90d}', ['\u{1e92f}', '\0', '\0']), - ('\u{1e90e}', ['\u{1e930}', '\0', '\0']), ('\u{1e90f}', ['\u{1e931}', '\0', '\0']), - ('\u{1e910}', ['\u{1e932}', '\0', '\0']), ('\u{1e911}', ['\u{1e933}', '\0', '\0']), - ('\u{1e912}', ['\u{1e934}', '\0', '\0']), ('\u{1e913}', ['\u{1e935}', '\0', '\0']), - ('\u{1e914}', ['\u{1e936}', '\0', '\0']), ('\u{1e915}', ['\u{1e937}', '\0', '\0']), - ('\u{1e916}', ['\u{1e938}', '\0', '\0']), ('\u{1e917}', ['\u{1e939}', '\0', '\0']), - ('\u{1e918}', ['\u{1e93a}', '\0', '\0']), ('\u{1e919}', ['\u{1e93b}', '\0', '\0']), - ('\u{1e91a}', ['\u{1e93c}', '\0', '\0']), ('\u{1e91b}', ['\u{1e93d}', '\0', '\0']), - ('\u{1e91c}', ['\u{1e93e}', '\0', '\0']), ('\u{1e91d}', ['\u{1e93f}', '\0', '\0']), - ('\u{1e91e}', ['\u{1e940}', '\0', '\0']), ('\u{1e91f}', ['\u{1e941}', '\0', '\0']), - ('\u{1e920}', ['\u{1e942}', '\0', '\0']), ('\u{1e921}', ['\u{1e943}', '\0', '\0']) + ('\u{118be}', ['\u{118de}', '\0', '\0']), ('\u{118bf}', ['\u{118df}', '\0', '\0']) ]; const to_uppercase_table: &[(char, [char; 3])] = &[ @@ -2472,24 +2451,7 @@ pub mod conversions { ('\u{118d8}', ['\u{118b8}', '\0', '\0']), ('\u{118d9}', ['\u{118b9}', '\0', '\0']), ('\u{118da}', ['\u{118ba}', '\0', '\0']), ('\u{118db}', ['\u{118bb}', '\0', '\0']), ('\u{118dc}', ['\u{118bc}', '\0', '\0']), ('\u{118dd}', ['\u{118bd}', '\0', '\0']), - ('\u{118de}', ['\u{118be}', '\0', '\0']), ('\u{118df}', ['\u{118bf}', '\0', '\0']), - ('\u{1e922}', ['\u{1e900}', '\0', '\0']), ('\u{1e923}', ['\u{1e901}', '\0', '\0']), - ('\u{1e924}', ['\u{1e902}', '\0', '\0']), ('\u{1e925}', ['\u{1e903}', '\0', '\0']), - ('\u{1e926}', ['\u{1e904}', '\0', '\0']), ('\u{1e927}', ['\u{1e905}', '\0', '\0']), - ('\u{1e928}', ['\u{1e906}', '\0', '\0']), ('\u{1e929}', ['\u{1e907}', '\0', '\0']), - ('\u{1e92a}', ['\u{1e908}', '\0', '\0']), ('\u{1e92b}', ['\u{1e909}', '\0', '\0']), - ('\u{1e92c}', ['\u{1e90a}', '\0', '\0']), ('\u{1e92d}', ['\u{1e90b}', '\0', '\0']), - ('\u{1e92e}', ['\u{1e90c}', '\0', '\0']), ('\u{1e92f}', ['\u{1e90d}', '\0', '\0']), - ('\u{1e930}', ['\u{1e90e}', '\0', '\0']), ('\u{1e931}', ['\u{1e90f}', '\0', '\0']), - ('\u{1e932}', ['\u{1e910}', '\0', '\0']), ('\u{1e933}', ['\u{1e911}', '\0', '\0']), - ('\u{1e934}', ['\u{1e912}', '\0', '\0']), ('\u{1e935}', ['\u{1e913}', '\0', '\0']), - ('\u{1e936}', ['\u{1e914}', '\0', '\0']), ('\u{1e937}', ['\u{1e915}', '\0', '\0']), - ('\u{1e938}', ['\u{1e916}', '\0', '\0']), ('\u{1e939}', ['\u{1e917}', '\0', '\0']), - ('\u{1e93a}', ['\u{1e918}', '\0', '\0']), ('\u{1e93b}', ['\u{1e919}', '\0', '\0']), - ('\u{1e93c}', ['\u{1e91a}', '\0', '\0']), ('\u{1e93d}', ['\u{1e91b}', '\0', '\0']), - ('\u{1e93e}', ['\u{1e91c}', '\0', '\0']), ('\u{1e93f}', ['\u{1e91d}', '\0', '\0']), - ('\u{1e940}', ['\u{1e91e}', '\0', '\0']), ('\u{1e941}', ['\u{1e91f}', '\0', '\0']), - ('\u{1e942}', ['\u{1e920}', '\0', '\0']), ('\u{1e943}', ['\u{1e921}', '\0', '\0']) + ('\u{118de}', ['\u{118be}', '\0', '\0']), ('\u{118df}', ['\u{118bf}', '\0', '\0']) ]; } diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py index ce22c6f226a..1da5878c4c6 100755 --- a/src/libcore/unicode/unicode.py +++ b/src/libcore/unicode/unicode.py @@ -486,7 +486,7 @@ pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { to_upper, to_lower, to_title) = load_unicode_data("UnicodeData.txt") load_special_casing("SpecialCasing.txt", to_upper, to_lower, to_title) want_derived = ["XID_Start", "XID_Continue", "Alphabetic", "Lowercase", "Uppercase", - "Cased", "Case_Ignorable"] + "Cased", "Case_Ignorable", "Grapheme_Extend"] derived = load_properties("DerivedCoreProperties.txt", want_derived) scripts = load_properties("Scripts.txt", []) props = load_properties("PropList.txt", @@ -495,7 +495,7 @@ pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { ["Full_Composition_Exclusion"]) # category tables - for (name, cat, pfuns) in ("general_category", gencats, ["N", "Cc", "Mn"]), \ + for (name, cat, pfuns) in ("general_category", gencats, ["N", "Cc"]), \ ("derived_property", derived, want_derived), \ ("property", props, ["White_Space", "Pattern_White_Space"]): emit_property_module(rf, name, cat, pfuns) @@ -503,3 +503,4 @@ pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { # normalizations and conversions module emit_norm_module(rf, canon_decomp, compat_decomp, combines, norm_props) emit_conversions_module(rf, to_upper, to_lower, to_title) + print("Regenerated tables.rs.") -- cgit 1.4.1-3-g733a5 From 8c89e7f3d58ff110aa4de64aef8ef29f78ebf456 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 16 May 2018 23:20:22 +0100 Subject: Make {char, str}::escape_debug and impl Debug for {char, str} consistent --- src/liballoc/tests/str.rs | 1 + src/libcore/fmt/mod.rs | 10 ++-------- src/libcore/tests/char.rs | 9 +-------- 3 files changed, 4 insertions(+), 16 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index 1a47e5433ea..2f38c8b3ae2 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -999,6 +999,7 @@ fn test_escape_debug() { assert_eq!("\u{10000}\u{10ffff}".escape_debug(), "\u{10000}\\u{10ffff}"); assert_eq!("ab\u{200b}".escape_debug(), "ab\\u{200b}"); assert_eq!("\u{10d4ea}\r".escape_debug(), "\\u{10d4ea}\\r"); + assert_eq!("\u{301}a\u{301}bé\u{e000}".escape_debug(), "\\u{301}a\\u{301}bé\\u{e000}"); } #[test] diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 1cfde513102..5820fe58932 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1844,14 +1844,8 @@ impl Display for str { impl Debug for char { fn fmt(&self, f: &mut Formatter) -> Result { f.write_char('\'')?; - if self.is_nonspacing_mark() { - for c in self.escape_unicode() { - f.write_char(c)? - } - } else { - for c in self.escape_debug() { - f.write_char(c)? - } + for c in self.escape_debug() { + f.write_char(c)? } f.write_char('\'') } diff --git a/src/libcore/tests/char.rs b/src/libcore/tests/char.rs index 76f28d493ab..d19e3b52769 100644 --- a/src/libcore/tests/char.rs +++ b/src/libcore/tests/char.rs @@ -181,19 +181,12 @@ fn test_escape_debug() { assert_eq!(string('\u{ff}'), "\u{ff}"); assert_eq!(string('\u{11b}'), "\u{11b}"); assert_eq!(string('\u{1d4b6}'), "\u{1d4b6}"); + assert_eq!(string('\u{301}'), "'\\u{301}'"); // combining character assert_eq!(string('\u{200b}'),"\\u{200b}"); // zero width space assert_eq!(string('\u{e000}'), "\\u{e000}"); // private use 1 assert_eq!(string('\u{100000}'), "\\u{100000}"); // private use 2 } -#[test] -fn test_debug() { - assert_eq!(format!("{:?}", 'a'), "'a'"); // ASCII character - assert_eq!(format!("{:?}", 'é'), "'é'"); // printable character - assert_eq!(format!("{:?}", '\u{301}'), "'\\u{301}'"); // combining character - assert_eq!(format!("{:?}", '\u{e000}'), "'\\u{e000}'"); // private use 1 -} - #[test] fn test_escape_default() { fn string(c: char) -> String { -- cgit 1.4.1-3-g733a5 From c51f00280205d476651ff9f9a46cff6645b411a2 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 17 May 2018 10:45:34 +0100 Subject: Only escape extended grapheme characters in the first position --- src/liballoc/str.rs | 5 ++++- src/liballoc/tests/str.rs | 2 +- src/libcore/char/methods.rs | 34 ++++++++++++++++++++++------------ src/libcore/tests/char.rs | 2 +- 4 files changed, 28 insertions(+), 15 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index c10c0a69433..8af14d3c698 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -372,12 +372,15 @@ impl str { /// Escapes each char in `s` with [`char::escape_debug`]. /// + /// Note: only extended grapheme codepoints that begin the string will be + /// escaped. + /// /// [`char::escape_debug`]: primitive.char.html#method.escape_debug #[unstable(feature = "str_escape", reason = "return type may change to be an iterator", issue = "27791")] pub fn escape_debug(&self) -> String { - self.chars().flat_map(|c| c.escape_debug()).collect() + self.chars().enumerate().flat_map(|(i, c)| c.escape_debug_ext(i == 0)).collect() } /// Escapes each char in `s` with [`char::escape_default`]. diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index 2f38c8b3ae2..84c97abcbc2 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -999,7 +999,7 @@ fn test_escape_debug() { assert_eq!("\u{10000}\u{10ffff}".escape_debug(), "\u{10000}\\u{10ffff}"); assert_eq!("ab\u{200b}".escape_debug(), "ab\\u{200b}"); assert_eq!("\u{10d4ea}\r".escape_debug(), "\\u{10d4ea}\\r"); - assert_eq!("\u{301}a\u{301}bé\u{e000}".escape_debug(), "\\u{301}a\\u{301}bé\\u{e000}"); + assert_eq!("\u{301}a\u{301}bé\u{e000}".escape_debug(), "\\u{301}a\u{301}bé\\u{e000}"); } #[test] diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index bf7772492e5..f6b201fe06d 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -187,6 +187,27 @@ impl char { } } + /// An extended version of `escape_debug` that optionally permits escaping + /// Extended Grapheme codepoints. This allows us to format characters like + /// nonspacing marks better when they're at the start of a string. + #[doc(hidden)] + #[unstable(feature = "str_internals", issue = "0")] + #[inline] + pub fn escape_debug_ext(self, escape_grapheme_extended: bool) -> EscapeDebug { + let init_state = match self { + '\t' => EscapeDefaultState::Backslash('t'), + '\r' => EscapeDefaultState::Backslash('r'), + '\n' => EscapeDefaultState::Backslash('n'), + '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), + _ if escape_grapheme_extended && self.is_grapheme_extended() => { + EscapeDefaultState::Unicode(self.escape_unicode()) + } + _ if is_printable(self) => EscapeDefaultState::Char(self), + _ => EscapeDefaultState::Unicode(self.escape_unicode()), + }; + EscapeDebug(EscapeDefault { state: init_state }) + } + /// Returns an iterator that yields the literal escape code of a character /// as `char`s. /// @@ -224,18 +245,7 @@ impl char { #[stable(feature = "char_escape_debug", since = "1.20.0")] #[inline] pub fn escape_debug(self) -> EscapeDebug { - let init_state = match self { - '\t' => EscapeDefaultState::Backslash('t'), - '\r' => EscapeDefaultState::Backslash('r'), - '\n' => EscapeDefaultState::Backslash('n'), - '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), - _ if self.is_grapheme_extended() => { - EscapeDefaultState::Unicode(self.escape_unicode()) - } - _ if is_printable(self) => EscapeDefaultState::Char(self), - _ => EscapeDefaultState::Unicode(self.escape_unicode()), - }; - EscapeDebug(EscapeDefault { state: init_state }) + self.escape_debug_ext(true) } /// Returns an iterator that yields the literal escape code of a character diff --git a/src/libcore/tests/char.rs b/src/libcore/tests/char.rs index d19e3b52769..d2a9ed75be6 100644 --- a/src/libcore/tests/char.rs +++ b/src/libcore/tests/char.rs @@ -181,7 +181,7 @@ fn test_escape_debug() { assert_eq!(string('\u{ff}'), "\u{ff}"); assert_eq!(string('\u{11b}'), "\u{11b}"); assert_eq!(string('\u{1d4b6}'), "\u{1d4b6}"); - assert_eq!(string('\u{301}'), "'\\u{301}'"); // combining character + assert_eq!(string('\u{301}'), "\\u{301}"); // combining character assert_eq!(string('\u{200b}'),"\\u{200b}"); // zero width space assert_eq!(string('\u{e000}'), "\\u{e000}"); // private use 1 assert_eq!(string('\u{100000}'), "\\u{100000}"); // private use 2 -- cgit 1.4.1-3-g733a5 From 2fa22effb6e1dd3b3e2e587ec5fcabefe2eb3443 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 21 May 2018 18:57:49 +0100 Subject: Avoid counting characters and add explanatory comment to test --- src/liballoc/str.rs | 8 +++++++- src/liballoc/tests/str.rs | 6 ++++++ src/libcore/unicode/unicode.py | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 8af14d3c698..823e56b64e3 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -380,7 +380,13 @@ impl str { reason = "return type may change to be an iterator", issue = "27791")] pub fn escape_debug(&self) -> String { - self.chars().enumerate().flat_map(|(i, c)| c.escape_debug_ext(i == 0)).collect() + let mut string = String::with_capacity(self.len()); + let mut chars = self.chars(); + if let Some(first) = chars.next() { + string.extend(first.escape_debug_ext(true)) + } + string.extend(chars.flat_map(|c| c.escape_debug_ext(false))); + string } /// Escapes each char in `s` with [`char::escape_default`]. diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index 84c97abcbc2..d11bf5dc3e9 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -989,6 +989,12 @@ fn test_escape_unicode() { #[test] fn test_escape_debug() { + // Note that there are subtleties with the number of backslashes + // on the left- and right-hand sides. In particular, Unicode code points + // are usually escaped with two backslashes on the right-hand side, as + // they are escaped. However, when the character is unescaped (e.g. for + // printable characters), only a single backslash appears (as the character + // itself appears in the debug string). assert_eq!("abc".escape_debug(), "abc"); assert_eq!("a c".escape_debug(), "a c"); assert_eq!("éèê".escape_debug(), "éèê"); diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py index 1da5878c4c6..07f873b13c0 100755 --- a/src/libcore/unicode/unicode.py +++ b/src/libcore/unicode/unicode.py @@ -21,7 +21,7 @@ # - UnicodeData.txt # # Since this should not require frequent updates, we just store this -# out-of-line and check the unicode.py file into git. +# out-of-line and check the tables.rs file into git. import fileinput, re, os, sys, operator, math, datetime -- cgit 1.4.1-3-g733a5 From b6539372e9d4dddb1c9f8c894f23bd4c3e8d9489 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 21 May 2018 19:12:36 +0100 Subject: Fix tables.rs --- src/libcore/unicode/tables.rs | 49 +++++++++++++++++++++++++++++++++++++----- src/libcore/unicode/unicode.py | 2 +- 2 files changed, 45 insertions(+), 6 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs index 7f9c52e3aa5..e3d27474b9a 100644 --- a/src/libcore/unicode/tables.rs +++ b/src/libcore/unicode/tables.rs @@ -93,7 +93,7 @@ pub mod general_category { 0x03ff000003ff0000 ], r4: [ - 0, 1, 2, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 1, 2, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 5, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -115,12 +115,17 @@ pub mod general_category { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], r6: &[ 0x0000000000000000, 0x001fffffffffffff, 0x0000000000000402, 0x00000000003e0000, 0x000003ff00000000, 0x0000ffc000000000, 0x03ff000000000000, 0xffc0000000000000, - 0x0000000003ff0000, 0x00000000000003ff, 0xffffffffffffffff, 0x00007fffffffffff + 0x0000000003ff0000, 0x00000000000003ff, 0xffffffffffffffff, 0x00007fffffffffff, + 0xffffffffffffc000 ], }; @@ -1837,7 +1842,24 @@ pub mod conversions { ('\u{118b8}', ['\u{118d8}', '\0', '\0']), ('\u{118b9}', ['\u{118d9}', '\0', '\0']), ('\u{118ba}', ['\u{118da}', '\0', '\0']), ('\u{118bb}', ['\u{118db}', '\0', '\0']), ('\u{118bc}', ['\u{118dc}', '\0', '\0']), ('\u{118bd}', ['\u{118dd}', '\0', '\0']), - ('\u{118be}', ['\u{118de}', '\0', '\0']), ('\u{118bf}', ['\u{118df}', '\0', '\0']) + ('\u{118be}', ['\u{118de}', '\0', '\0']), ('\u{118bf}', ['\u{118df}', '\0', '\0']), + ('\u{1e900}', ['\u{1e922}', '\0', '\0']), ('\u{1e901}', ['\u{1e923}', '\0', '\0']), + ('\u{1e902}', ['\u{1e924}', '\0', '\0']), ('\u{1e903}', ['\u{1e925}', '\0', '\0']), + ('\u{1e904}', ['\u{1e926}', '\0', '\0']), ('\u{1e905}', ['\u{1e927}', '\0', '\0']), + ('\u{1e906}', ['\u{1e928}', '\0', '\0']), ('\u{1e907}', ['\u{1e929}', '\0', '\0']), + ('\u{1e908}', ['\u{1e92a}', '\0', '\0']), ('\u{1e909}', ['\u{1e92b}', '\0', '\0']), + ('\u{1e90a}', ['\u{1e92c}', '\0', '\0']), ('\u{1e90b}', ['\u{1e92d}', '\0', '\0']), + ('\u{1e90c}', ['\u{1e92e}', '\0', '\0']), ('\u{1e90d}', ['\u{1e92f}', '\0', '\0']), + ('\u{1e90e}', ['\u{1e930}', '\0', '\0']), ('\u{1e90f}', ['\u{1e931}', '\0', '\0']), + ('\u{1e910}', ['\u{1e932}', '\0', '\0']), ('\u{1e911}', ['\u{1e933}', '\0', '\0']), + ('\u{1e912}', ['\u{1e934}', '\0', '\0']), ('\u{1e913}', ['\u{1e935}', '\0', '\0']), + ('\u{1e914}', ['\u{1e936}', '\0', '\0']), ('\u{1e915}', ['\u{1e937}', '\0', '\0']), + ('\u{1e916}', ['\u{1e938}', '\0', '\0']), ('\u{1e917}', ['\u{1e939}', '\0', '\0']), + ('\u{1e918}', ['\u{1e93a}', '\0', '\0']), ('\u{1e919}', ['\u{1e93b}', '\0', '\0']), + ('\u{1e91a}', ['\u{1e93c}', '\0', '\0']), ('\u{1e91b}', ['\u{1e93d}', '\0', '\0']), + ('\u{1e91c}', ['\u{1e93e}', '\0', '\0']), ('\u{1e91d}', ['\u{1e93f}', '\0', '\0']), + ('\u{1e91e}', ['\u{1e940}', '\0', '\0']), ('\u{1e91f}', ['\u{1e941}', '\0', '\0']), + ('\u{1e920}', ['\u{1e942}', '\0', '\0']), ('\u{1e921}', ['\u{1e943}', '\0', '\0']) ]; const to_uppercase_table: &[(char, [char; 3])] = &[ @@ -2451,7 +2473,24 @@ pub mod conversions { ('\u{118d8}', ['\u{118b8}', '\0', '\0']), ('\u{118d9}', ['\u{118b9}', '\0', '\0']), ('\u{118da}', ['\u{118ba}', '\0', '\0']), ('\u{118db}', ['\u{118bb}', '\0', '\0']), ('\u{118dc}', ['\u{118bc}', '\0', '\0']), ('\u{118dd}', ['\u{118bd}', '\0', '\0']), - ('\u{118de}', ['\u{118be}', '\0', '\0']), ('\u{118df}', ['\u{118bf}', '\0', '\0']) + ('\u{118de}', ['\u{118be}', '\0', '\0']), ('\u{118df}', ['\u{118bf}', '\0', '\0']), + ('\u{1e922}', ['\u{1e900}', '\0', '\0']), ('\u{1e923}', ['\u{1e901}', '\0', '\0']), + ('\u{1e924}', ['\u{1e902}', '\0', '\0']), ('\u{1e925}', ['\u{1e903}', '\0', '\0']), + ('\u{1e926}', ['\u{1e904}', '\0', '\0']), ('\u{1e927}', ['\u{1e905}', '\0', '\0']), + ('\u{1e928}', ['\u{1e906}', '\0', '\0']), ('\u{1e929}', ['\u{1e907}', '\0', '\0']), + ('\u{1e92a}', ['\u{1e908}', '\0', '\0']), ('\u{1e92b}', ['\u{1e909}', '\0', '\0']), + ('\u{1e92c}', ['\u{1e90a}', '\0', '\0']), ('\u{1e92d}', ['\u{1e90b}', '\0', '\0']), + ('\u{1e92e}', ['\u{1e90c}', '\0', '\0']), ('\u{1e92f}', ['\u{1e90d}', '\0', '\0']), + ('\u{1e930}', ['\u{1e90e}', '\0', '\0']), ('\u{1e931}', ['\u{1e90f}', '\0', '\0']), + ('\u{1e932}', ['\u{1e910}', '\0', '\0']), ('\u{1e933}', ['\u{1e911}', '\0', '\0']), + ('\u{1e934}', ['\u{1e912}', '\0', '\0']), ('\u{1e935}', ['\u{1e913}', '\0', '\0']), + ('\u{1e936}', ['\u{1e914}', '\0', '\0']), ('\u{1e937}', ['\u{1e915}', '\0', '\0']), + ('\u{1e938}', ['\u{1e916}', '\0', '\0']), ('\u{1e939}', ['\u{1e917}', '\0', '\0']), + ('\u{1e93a}', ['\u{1e918}', '\0', '\0']), ('\u{1e93b}', ['\u{1e919}', '\0', '\0']), + ('\u{1e93c}', ['\u{1e91a}', '\0', '\0']), ('\u{1e93d}', ['\u{1e91b}', '\0', '\0']), + ('\u{1e93e}', ['\u{1e91c}', '\0', '\0']), ('\u{1e93f}', ['\u{1e91d}', '\0', '\0']), + ('\u{1e940}', ['\u{1e91e}', '\0', '\0']), ('\u{1e941}', ['\u{1e91f}', '\0', '\0']), + ('\u{1e942}', ['\u{1e920}', '\0', '\0']), ('\u{1e943}', ['\u{1e921}', '\0', '\0']) ]; } diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py index 07f873b13c0..be0970b5444 100755 --- a/src/libcore/unicode/unicode.py +++ b/src/libcore/unicode/unicode.py @@ -66,7 +66,7 @@ surrogate_codepoints = (0xd800, 0xdfff) def fetch(f): path = fdir + os.path.basename(f) if not os.path.exists(path): - os.system("curl -o {0}{1} http://www.unicode.org/Public/UNIDATA/{1}".format(fdir, f)) + os.system("curl -o {0}{1} ftp://ftp.unicode.org/Public/UNIDATA/{1}".format(fdir, f)) if not os.path.exists(path): sys.stderr.write("cannot load %s" % f) -- cgit 1.4.1-3-g733a5 From b825477154e32e8538e00e1e230dadf93bc7e6df Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 21 May 2018 10:45:11 +0200 Subject: Remove the unstable Float trait Following up to #49896 and #50629. Fixes #32110. E0689 is weird. --- src/libcore/num/dec2flt/rawfp.rs | 33 ++- src/libcore/num/f32.rs | 222 +++++++------------- src/libcore/num/f64.rs | 228 +++++++-------------- src/libcore/num/mod.rs | 55 ----- src/libcore/tests/num/mod.rs | 77 ++++--- src/librustc_typeck/diagnostics.rs | 12 +- .../ui/macros/macro-backtrace-invalid-internals.rs | 4 +- .../macro-backtrace-invalid-internals.stderr | 16 +- .../method-on-ambiguous-numeric-type.rs | 8 +- .../method-on-ambiguous-numeric-type.stderr | 14 +- 10 files changed, 232 insertions(+), 437 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index 77180233a23..456d0e956d4 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -33,7 +33,7 @@ use ops::{Add, Mul, Div, Neg}; use fmt::{Debug, LowerExp}; use num::diy_float::Fp; use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan}; -use num::Float; +use num::FpCategory; use num::dec2flt::num::{self, Big}; use num::dec2flt::table; @@ -54,24 +54,29 @@ impl Unpacked { /// See the parent module's doc comment for why this is necessary. /// /// Should **never ever** be implemented for other types or be used outside the dec2flt module. -/// Inherits from `Float` because there is some overlap, but all the reused methods are trivial. pub trait RawFloat - : Float - + Copy + : Copy + Debug + LowerExp + Mul + Div + Neg -where - Self: Float::RawBits> { const INFINITY: Self; const NAN: Self; const ZERO: Self; - /// Same as `Float::Bits` with extra traits. - type RawBits: Add + From + TryFrom; + /// Type used by `to_bits` and `from_bits`. + type Bits: Add + From + TryFrom; + + /// Raw transmutation to integer. + fn to_bits(self) -> Self::Bits; + + /// Raw transmutation from integer. + fn from_bits(v: Self::Bits) -> Self; + + /// Returns the category that this number falls into. + fn classify(self) -> FpCategory; /// Returns the mantissa, exponent and sign as integers. fn integer_decode(self) -> (u64, i16, i8); @@ -153,7 +158,7 @@ macro_rules! other_constants { } impl RawFloat for f32 { - type RawBits = u32; + type Bits = u32; const SIG_BITS: u8 = 24; const EXP_BITS: u8 = 8; @@ -192,11 +197,15 @@ impl RawFloat for f32 { fn short_fast_pow10(e: usize) -> Self { table::F32_SHORT_POWERS[e] } + + fn classify(self) -> FpCategory { self.classify() } + fn to_bits(self) -> Self::Bits { self.to_bits() } + fn from_bits(v: Self::Bits) -> Self { Self::from_bits(v) } } impl RawFloat for f64 { - type RawBits = u64; + type Bits = u64; const SIG_BITS: u8 = 53; const EXP_BITS: u8 = 11; @@ -235,6 +244,10 @@ impl RawFloat for f64 { fn short_fast_pow10(e: usize) -> Self { table::F64_SHORT_POWERS[e] } + + fn classify(self) -> FpCategory { self.classify() } + fn to_bits(self) -> Self::Bits { self.to_bits() } + fn from_bits(v: Self::Bits) -> Self { Self::from_bits(v) } } /// Convert an Fp to the closest machine float type. diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 718dd42a615..e5dbc65cd99 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -18,9 +18,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use mem; -use num::Float; use num::FpCategory; -use num::FpCategory as Fp; /// The radix or base of the internal representation of `f32`. #[stable(feature = "rust1", since = "1.0.0")] @@ -149,136 +147,9 @@ pub mod consts { pub const LN_10: f32 = 2.30258509299404568401799145468436421_f32; } -#[unstable(feature = "core_float", - reason = "stable interface is via `impl f{32,64}` in later crates", - issue = "32110")] -impl Float for f32 { - type Bits = u32; - - /// Returns `true` if the number is NaN. - #[inline] - fn is_nan(self) -> bool { - self != self - } - - /// Returns `true` if the number is infinite. - #[inline] - fn is_infinite(self) -> bool { - self == INFINITY || self == NEG_INFINITY - } - - /// Returns `true` if the number is neither infinite or NaN. - #[inline] - fn is_finite(self) -> bool { - !(self.is_nan() || self.is_infinite()) - } - - /// Returns `true` if the number is neither zero, infinite, subnormal or NaN. - #[inline] - fn is_normal(self) -> bool { - self.classify() == Fp::Normal - } - - /// Returns the floating point category of the number. If only one property - /// is going to be tested, it is generally faster to use the specific - /// predicate instead. - fn classify(self) -> Fp { - const EXP_MASK: u32 = 0x7f800000; - const MAN_MASK: u32 = 0x007fffff; - - let bits = self.to_bits(); - match (bits & MAN_MASK, bits & EXP_MASK) { - (0, 0) => Fp::Zero, - (_, 0) => Fp::Subnormal, - (0, EXP_MASK) => Fp::Infinite, - (_, EXP_MASK) => Fp::Nan, - _ => Fp::Normal, - } - } - - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with - /// positive sign bit and positive infinity. - #[inline] - fn is_sign_positive(self) -> bool { - !self.is_sign_negative() - } - - /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with - /// negative sign bit and negative infinity. - #[inline] - fn is_sign_negative(self) -> bool { - // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus - // applies to zeros and NaNs as well. - self.to_bits() & 0x8000_0000 != 0 - } - - /// Returns the reciprocal (multiplicative inverse) of the number. - #[inline] - fn recip(self) -> f32 { - 1.0 / self - } - - /// Converts to degrees, assuming the number is in radians. - #[inline] - fn to_degrees(self) -> f32 { - // Use a constant for better precision. - const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32; - self * PIS_IN_180 - } - - /// Converts to radians, assuming the number is in degrees. - #[inline] - fn to_radians(self) -> f32 { - let value: f32 = consts::PI; - self * (value / 180.0f32) - } - - /// Returns the maximum of the two numbers. - #[inline] - fn max(self, other: f32) -> f32 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if self.is_nan() || self < other { other } else { self }) * 1.0 - } - - /// Returns the minimum of the two numbers. - #[inline] - fn min(self, other: f32) -> f32 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if other.is_nan() || self < other { self } else { other }) * 1.0 - } - - /// Raw transmutation to `u32`. - #[inline] - fn to_bits(self) -> u32 { - unsafe { mem::transmute(self) } - } - - /// Raw transmutation from `u32`. - #[inline] - fn from_bits(v: u32) -> Self { - // It turns out the safety issues with sNaN were overblown! Hooray! - unsafe { mem::transmute(v) } - } -} - -// FIXME: remove (inline) this macro and the Float trait -// when updating to a bootstrap compiler that has the new lang items. -#[unstable(feature = "core_float", issue = "32110")] -macro_rules! f32_core_methods { () => { +#[lang = "f32"] +#[cfg(not(test))] +impl f32 { /// Returns `true` if this value is `NaN` and false otherwise. /// /// ``` @@ -292,7 +163,9 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_nan(self) -> bool { Float::is_nan(self) } + pub fn is_nan(self) -> bool { + self != self + } /// Returns `true` if this value is positive infinity or negative infinity and /// false otherwise. @@ -313,7 +186,9 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_infinite(self) -> bool { Float::is_infinite(self) } + pub fn is_infinite(self) -> bool { + self == INFINITY || self == NEG_INFINITY + } /// Returns `true` if this number is neither infinite nor `NaN`. /// @@ -333,7 +208,9 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_finite(self) -> bool { Float::is_finite(self) } + pub fn is_finite(self) -> bool { + !(self.is_nan() || self.is_infinite()) + } /// Returns `true` if the number is neither zero, infinite, /// [subnormal][subnormal], or `NaN`. @@ -358,7 +235,9 @@ macro_rules! f32_core_methods { () => { /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_normal(self) -> bool { Float::is_normal(self) } + pub fn is_normal(self) -> bool { + self.classify() == FpCategory::Normal + } /// Returns the floating point category of the number. If only one property /// is going to be tested, it is generally faster to use the specific @@ -375,8 +254,19 @@ macro_rules! f32_core_methods { () => { /// assert_eq!(inf.classify(), FpCategory::Infinite); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn classify(self) -> FpCategory { Float::classify(self) } + pub fn classify(self) -> FpCategory { + const EXP_MASK: u32 = 0x7f800000; + const MAN_MASK: u32 = 0x007fffff; + + let bits = self.to_bits(); + match (bits & MAN_MASK, bits & EXP_MASK) { + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + (0, EXP_MASK) => FpCategory::Infinite, + (_, EXP_MASK) => FpCategory::Nan, + _ => FpCategory::Normal, + } + } /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with /// positive sign bit and positive infinity. @@ -390,7 +280,9 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_sign_positive(self) -> bool { Float::is_sign_positive(self) } + pub fn is_sign_positive(self) -> bool { + !self.is_sign_negative() + } /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with /// negative sign bit and negative infinity. @@ -404,7 +296,11 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_sign_negative(self) -> bool { Float::is_sign_negative(self) } + pub fn is_sign_negative(self) -> bool { + // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus + // applies to zeros and NaNs as well. + self.to_bits() & 0x8000_0000 != 0 + } /// Takes the reciprocal (inverse) of a number, `1/x`. /// @@ -418,7 +314,9 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn recip(self) -> f32 { Float::recip(self) } + pub fn recip(self) -> f32 { + 1.0 / self + } /// Converts radians to degrees. /// @@ -433,7 +331,11 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] #[inline] - pub fn to_degrees(self) -> f32 { Float::to_degrees(self) } + pub fn to_degrees(self) -> f32 { + // Use a constant for better precision. + const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32; + self * PIS_IN_180 + } /// Converts degrees to radians. /// @@ -448,7 +350,10 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] #[inline] - pub fn to_radians(self) -> f32 { Float::to_radians(self) } + pub fn to_radians(self) -> f32 { + let value: f32 = consts::PI; + self * (value / 180.0f32) + } /// Returns the maximum of the two numbers. /// @@ -463,7 +368,15 @@ macro_rules! f32_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn max(self, other: f32) -> f32 { - Float::max(self, other) + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if self.is_nan() || self < other { other } else { self }) * 1.0 } /// Returns the minimum of the two numbers. @@ -479,7 +392,15 @@ macro_rules! f32_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn min(self, other: f32) -> f32 { - Float::min(self, other) + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if other.is_nan() || self < other { self } else { other }) * 1.0 } /// Raw transmutation to `u32`. @@ -502,7 +423,7 @@ macro_rules! f32_core_methods { () => { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn to_bits(self) -> u32 { - Float::to_bits(self) + unsafe { mem::transmute(self) } } /// Raw transmutation from `u32`. @@ -546,12 +467,7 @@ macro_rules! f32_core_methods { () => { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn from_bits(v: u32) -> Self { - Float::from_bits(v) + // It turns out the safety issues with sNaN were overblown! Hooray! + unsafe { mem::transmute(v) } } -}} - -#[lang = "f32"] -#[cfg(not(test))] -impl f32 { - f32_core_methods!(); } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index f128c55c78a..eb769c4ad5a 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -18,9 +18,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use mem; -use num::Float; use num::FpCategory; -use num::FpCategory as Fp; /// The radix or base of the internal representation of `f64`. #[stable(feature = "rust1", since = "1.0.0")] @@ -149,135 +147,9 @@ pub mod consts { pub const LN_10: f64 = 2.30258509299404568401799145468436421_f64; } -#[unstable(feature = "core_float", - reason = "stable interface is via `impl f{32,64}` in later crates", - issue = "32110")] -impl Float for f64 { - type Bits = u64; - - /// Returns `true` if the number is NaN. - #[inline] - fn is_nan(self) -> bool { - self != self - } - - /// Returns `true` if the number is infinite. - #[inline] - fn is_infinite(self) -> bool { - self == INFINITY || self == NEG_INFINITY - } - - /// Returns `true` if the number is neither infinite or NaN. - #[inline] - fn is_finite(self) -> bool { - !(self.is_nan() || self.is_infinite()) - } - - /// Returns `true` if the number is neither zero, infinite, subnormal or NaN. - #[inline] - fn is_normal(self) -> bool { - self.classify() == Fp::Normal - } - - /// Returns the floating point category of the number. If only one property - /// is going to be tested, it is generally faster to use the specific - /// predicate instead. - fn classify(self) -> Fp { - const EXP_MASK: u64 = 0x7ff0000000000000; - const MAN_MASK: u64 = 0x000fffffffffffff; - - let bits = self.to_bits(); - match (bits & MAN_MASK, bits & EXP_MASK) { - (0, 0) => Fp::Zero, - (_, 0) => Fp::Subnormal, - (0, EXP_MASK) => Fp::Infinite, - (_, EXP_MASK) => Fp::Nan, - _ => Fp::Normal, - } - } - - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with - /// positive sign bit and positive infinity. - #[inline] - fn is_sign_positive(self) -> bool { - !self.is_sign_negative() - } - - /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with - /// negative sign bit and negative infinity. - #[inline] - fn is_sign_negative(self) -> bool { - self.to_bits() & 0x8000_0000_0000_0000 != 0 - } - - /// Returns the reciprocal (multiplicative inverse) of the number. - #[inline] - fn recip(self) -> f64 { - 1.0 / self - } - - /// Converts to degrees, assuming the number is in radians. - #[inline] - fn to_degrees(self) -> f64 { - // The division here is correctly rounded with respect to the true - // value of 180/π. (This differs from f32, where a constant must be - // used to ensure a correctly rounded result.) - self * (180.0f64 / consts::PI) - } - - /// Converts to radians, assuming the number is in degrees. - #[inline] - fn to_radians(self) -> f64 { - let value: f64 = consts::PI; - self * (value / 180.0) - } - - /// Returns the maximum of the two numbers. - #[inline] - fn max(self, other: f64) -> f64 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if self.is_nan() || self < other { other } else { self }) * 1.0 - } - - /// Returns the minimum of the two numbers. - #[inline] - fn min(self, other: f64) -> f64 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if other.is_nan() || self < other { self } else { other }) * 1.0 - } - - /// Raw transmutation to `u64`. - #[inline] - fn to_bits(self) -> u64 { - unsafe { mem::transmute(self) } - } - - /// Raw transmutation from `u64`. - #[inline] - fn from_bits(v: u64) -> Self { - // It turns out the safety issues with sNaN were overblown! Hooray! - unsafe { mem::transmute(v) } - } -} - -// FIXME: remove (inline) this macro and the Float trait -// when updating to a bootstrap compiler that has the new lang items. -#[unstable(feature = "core_float", issue = "32110")] -macro_rules! f64_core_methods { () => { +#[lang = "f64"] +#[cfg(not(test))] +impl f64 { /// Returns `true` if this value is `NaN` and false otherwise. /// /// ``` @@ -291,7 +163,9 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_nan(self) -> bool { Float::is_nan(self) } + pub fn is_nan(self) -> bool { + self != self + } /// Returns `true` if this value is positive infinity or negative infinity and /// false otherwise. @@ -312,7 +186,9 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_infinite(self) -> bool { Float::is_infinite(self) } + pub fn is_infinite(self) -> bool { + self == INFINITY || self == NEG_INFINITY + } /// Returns `true` if this number is neither infinite nor `NaN`. /// @@ -332,7 +208,9 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_finite(self) -> bool { Float::is_finite(self) } + pub fn is_finite(self) -> bool { + !(self.is_nan() || self.is_infinite()) + } /// Returns `true` if the number is neither zero, infinite, /// [subnormal][subnormal], or `NaN`. @@ -357,7 +235,9 @@ macro_rules! f64_core_methods { () => { /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_normal(self) -> bool { Float::is_normal(self) } + pub fn is_normal(self) -> bool { + self.classify() == FpCategory::Normal + } /// Returns the floating point category of the number. If only one property /// is going to be tested, it is generally faster to use the specific @@ -374,8 +254,19 @@ macro_rules! f64_core_methods { () => { /// assert_eq!(inf.classify(), FpCategory::Infinite); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn classify(self) -> FpCategory { Float::classify(self) } + pub fn classify(self) -> FpCategory { + const EXP_MASK: u64 = 0x7ff0000000000000; + const MAN_MASK: u64 = 0x000fffffffffffff; + + let bits = self.to_bits(); + match (bits & MAN_MASK, bits & EXP_MASK) { + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + (0, EXP_MASK) => FpCategory::Infinite, + (_, EXP_MASK) => FpCategory::Nan, + _ => FpCategory::Normal, + } + } /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with /// positive sign bit and positive infinity. @@ -389,13 +280,17 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_sign_positive(self) -> bool { Float::is_sign_positive(self) } + pub fn is_sign_positive(self) -> bool { + !self.is_sign_negative() + } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")] #[inline] #[doc(hidden)] - pub fn is_positive(self) -> bool { Float::is_sign_positive(self) } + pub fn is_positive(self) -> bool { + self.is_sign_positive() + } /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with /// negative sign bit and negative infinity. @@ -409,13 +304,17 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_sign_negative(self) -> bool { Float::is_sign_negative(self) } + pub fn is_sign_negative(self) -> bool { + self.to_bits() & 0x8000_0000_0000_0000 != 0 + } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")] #[inline] #[doc(hidden)] - pub fn is_negative(self) -> bool { Float::is_sign_negative(self) } + pub fn is_negative(self) -> bool { + self.is_sign_negative() + } /// Takes the reciprocal (inverse) of a number, `1/x`. /// @@ -427,7 +326,9 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn recip(self) -> f64 { Float::recip(self) } + pub fn recip(self) -> f64 { + 1.0 / self + } /// Converts radians to degrees. /// @@ -442,7 +343,12 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn to_degrees(self) -> f64 { Float::to_degrees(self) } + pub fn to_degrees(self) -> f64 { + // The division here is correctly rounded with respect to the true + // value of 180/π. (This differs from f32, where a constant must be + // used to ensure a correctly rounded result.) + self * (180.0f64 / consts::PI) + } /// Converts degrees to radians. /// @@ -457,7 +363,10 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn to_radians(self) -> f64 { Float::to_radians(self) } + pub fn to_radians(self) -> f64 { + let value: f64 = consts::PI; + self * (value / 180.0) + } /// Returns the maximum of the two numbers. /// @@ -472,7 +381,15 @@ macro_rules! f64_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn max(self, other: f64) -> f64 { - Float::max(self, other) + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if self.is_nan() || self < other { other } else { self }) * 1.0 } /// Returns the minimum of the two numbers. @@ -488,7 +405,15 @@ macro_rules! f64_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn min(self, other: f64) -> f64 { - Float::min(self, other) + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if other.is_nan() || self < other { self } else { other }) * 1.0 } /// Raw transmutation to `u64`. @@ -511,7 +436,7 @@ macro_rules! f64_core_methods { () => { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn to_bits(self) -> u64 { - Float::to_bits(self) + unsafe { mem::transmute(self) } } /// Raw transmutation from `u64`. @@ -555,12 +480,7 @@ macro_rules! f64_core_methods { () => { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn from_bits(v: u64) -> Self { - Float::from_bits(v) + // It turns out the safety issues with sNaN were overblown! Hooray! + unsafe { mem::transmute(v) } } -}} - -#[lang = "f64"] -#[cfg(not(test))] -impl f64 { - f64_core_methods!(); } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 58d45b107f1..232ecb8fbae 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4080,61 +4080,6 @@ pub enum FpCategory { Normal, } -// Technically private and only exposed for coretests: -#[doc(hidden)] -#[unstable(feature = "float_internals", - reason = "internal routines only exposed for testing", - issue = "0")] -pub trait Float: Sized { - /// Type used by `to_bits` and `from_bits`. - type Bits; - - /// Returns `true` if this value is NaN and false otherwise. - fn is_nan(self) -> bool; - - /// Returns `true` if this value is positive infinity or negative infinity and - /// false otherwise. - fn is_infinite(self) -> bool; - - /// Returns `true` if this number is neither infinite nor NaN. - fn is_finite(self) -> bool; - - /// Returns `true` if this number is neither zero, infinite, denormal, or NaN. - fn is_normal(self) -> bool; - - /// Returns the category that this number falls into. - fn classify(self) -> FpCategory; - - /// Returns `true` if `self` is positive, including `+0.0` and - /// `Float::infinity()`. - fn is_sign_positive(self) -> bool; - - /// Returns `true` if `self` is negative, including `-0.0` and - /// `Float::neg_infinity()`. - fn is_sign_negative(self) -> bool; - - /// Take the reciprocal (inverse) of a number, `1/x`. - fn recip(self) -> Self; - - /// Convert radians to degrees. - fn to_degrees(self) -> Self; - - /// Convert degrees to radians. - fn to_radians(self) -> Self; - - /// Returns the maximum of the two numbers. - fn max(self, other: Self) -> Self; - - /// Returns the minimum of the two numbers. - fn min(self, other: Self) -> Self; - - /// Raw transmutation to integer. - fn to_bits(self) -> Self::Bits; - - /// Raw transmutation from integer. - fn from_bits(v: Self::Bits) -> Self; -} - macro_rules! from_str_radix_int_impl { ($($t:ty)*) => {$( #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index c7edb55b378..f3439890fce 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -508,51 +508,50 @@ assume_usize_width! { macro_rules! test_float { ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr) => { mod $modname { - use core::num::Float; // FIXME(nagisa): these tests should test for sign of -0.0 #[test] fn min() { - assert_eq!(0.0.min(0.0), 0.0); - assert_eq!((-0.0).min(-0.0), -0.0); - assert_eq!(9.0.min(9.0), 9.0); - assert_eq!((-9.0).min(0.0), -9.0); - assert_eq!(0.0.min(9.0), 0.0); - assert_eq!((-0.0).min(-9.0), -9.0); - assert_eq!($inf.min(9.0), 9.0); - assert_eq!(9.0.min($inf), 9.0); - assert_eq!($inf.min(-9.0), -9.0); - assert_eq!((-9.0).min($inf), -9.0); - assert_eq!($neginf.min(9.0), $neginf); - assert_eq!(9.0.min($neginf), $neginf); - assert_eq!($neginf.min(-9.0), $neginf); - assert_eq!((-9.0).min($neginf), $neginf); - assert_eq!($nan.min(9.0), 9.0); - assert_eq!($nan.min(-9.0), -9.0); - assert_eq!(9.0.min($nan), 9.0); - assert_eq!((-9.0).min($nan), -9.0); - assert!($nan.min($nan).is_nan()); + assert_eq!((0.0 as $fty).min(0.0), 0.0); + assert_eq!((-0.0 as $fty).min(-0.0), -0.0); + assert_eq!((9.0 as $fty).min(9.0), 9.0); + assert_eq!((-9.0 as $fty).min(0.0), -9.0); + assert_eq!((0.0 as $fty).min(9.0), 0.0); + assert_eq!((-0.0 as $fty).min(-9.0), -9.0); + assert_eq!(($inf as $fty).min(9.0), 9.0); + assert_eq!((9.0 as $fty).min($inf), 9.0); + assert_eq!(($inf as $fty).min(-9.0), -9.0); + assert_eq!((-9.0 as $fty).min($inf), -9.0); + assert_eq!(($neginf as $fty).min(9.0), $neginf); + assert_eq!((9.0 as $fty).min($neginf), $neginf); + assert_eq!(($neginf as $fty).min(-9.0), $neginf); + assert_eq!((-9.0 as $fty).min($neginf), $neginf); + assert_eq!(($nan as $fty).min(9.0), 9.0); + assert_eq!(($nan as $fty).min(-9.0), -9.0); + assert_eq!((9.0 as $fty).min($nan), 9.0); + assert_eq!((-9.0 as $fty).min($nan), -9.0); + assert!(($nan as $fty).min($nan).is_nan()); } #[test] fn max() { - assert_eq!(0.0.max(0.0), 0.0); - assert_eq!((-0.0).max(-0.0), -0.0); - assert_eq!(9.0.max(9.0), 9.0); - assert_eq!((-9.0).max(0.0), 0.0); - assert_eq!(0.0.max(9.0), 9.0); - assert_eq!((-0.0).max(-9.0), -0.0); - assert_eq!($inf.max(9.0), $inf); - assert_eq!(9.0.max($inf), $inf); - assert_eq!($inf.max(-9.0), $inf); - assert_eq!((-9.0).max($inf), $inf); - assert_eq!($neginf.max(9.0), 9.0); - assert_eq!(9.0.max($neginf), 9.0); - assert_eq!($neginf.max(-9.0), -9.0); - assert_eq!((-9.0).max($neginf), -9.0); - assert_eq!($nan.max(9.0), 9.0); - assert_eq!($nan.max(-9.0), -9.0); - assert_eq!(9.0.max($nan), 9.0); - assert_eq!((-9.0).max($nan), -9.0); - assert!($nan.max($nan).is_nan()); + assert_eq!((0.0 as $fty).max(0.0), 0.0); + assert_eq!((-0.0 as $fty).max(-0.0), -0.0); + assert_eq!((9.0 as $fty).max(9.0), 9.0); + assert_eq!((-9.0 as $fty).max(0.0), 0.0); + assert_eq!((0.0 as $fty).max(9.0), 9.0); + assert_eq!((-0.0 as $fty).max(-9.0), -0.0); + assert_eq!(($inf as $fty).max(9.0), $inf); + assert_eq!((9.0 as $fty).max($inf), $inf); + assert_eq!(($inf as $fty).max(-9.0), $inf); + assert_eq!((-9.0 as $fty).max($inf), $inf); + assert_eq!(($neginf as $fty).max(9.0), 9.0); + assert_eq!((9.0 as $fty).max($neginf), 9.0); + assert_eq!(($neginf as $fty).max(-9.0), -9.0); + assert_eq!((-9.0 as $fty).max($neginf), -9.0); + assert_eq!(($nan as $fty).max(9.0), 9.0); + assert_eq!(($nan as $fty).max(-9.0), -9.0); + assert_eq!((9.0 as $fty).max($nan), 9.0); + assert_eq!((-9.0 as $fty).max($nan), -9.0); + assert!(($nan as $fty).max($nan).is_nan()); } } } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 7a572bbbffd..e6a66cd613e 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4552,23 +4552,25 @@ but the type of the numeric value or binding could not be identified. The error happens on numeric literals: ```compile_fail,E0689 -2.0.recip(); +2.0.neg(); ``` and on numeric bindings without an identified concrete type: ```compile_fail,E0689 let x = 2.0; -x.recip(); // same error as above +x.neg(); // same error as above ``` Because of this, you must give the numeric literal or binding a type: ``` -let _ = 2.0_f32.recip(); +use std::ops::Neg; + +let _ = 2.0_f32.neg(); let x: f32 = 2.0; -let _ = x.recip(); -let _ = (2.0 as f32).recip(); +let _ = x.neg(); +let _ = (2.0 as f32).neg(); ``` "##, diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.rs b/src/test/ui/macros/macro-backtrace-invalid-internals.rs index 090ff817eb0..0bc2dd5a601 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.rs +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.rs @@ -48,13 +48,13 @@ macro_rules! fake_anon_field_expr { macro_rules! real_method_stmt { () => { - 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` + 2.0.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` } } macro_rules! real_method_expr { () => { - 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` + 2.0.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` } } diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr index 284960d2f6e..ec8eee65739 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr @@ -25,17 +25,17 @@ LL | (1).0 //~ ERROR doesn't have fields LL | fake_anon_field_stmt!(); | ------------------------ in this macro invocation -error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` +error[E0689]: can't call method `neg` on ambiguous numeric type `{float}` --> $DIR/macro-backtrace-invalid-internals.rs:51:15 | -LL | 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` - | ^^^^^ +LL | 2.0.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` + | ^^^ ... LL | real_method_stmt!(); | -------------------- in this macro invocation help: you must specify a concrete type for this numeric value, like `f32` | -LL | 2.0_f32.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` +LL | 2.0_f32.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` | ^^^^^^^ error[E0599]: no method named `fake` found for type `{integer}` in the current scope @@ -65,17 +65,17 @@ LL | (1).0 //~ ERROR doesn't have fields LL | let _ = fake_anon_field_expr!(); | ----------------------- in this macro invocation -error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` +error[E0689]: can't call method `neg` on ambiguous numeric type `{float}` --> $DIR/macro-backtrace-invalid-internals.rs:57:15 | -LL | 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` - | ^^^^^ +LL | 2.0.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` + | ^^^ ... LL | let _ = real_method_expr!(); | ------------------- in this macro invocation help: you must specify a concrete type for this numeric value, like `f32` | -LL | 2.0_f32.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` +LL | 2.0_f32.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` | ^^^^^^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs index 2e452f9671f..9bf74c3875f 100644 --- a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs +++ b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs @@ -9,10 +9,10 @@ // except according to those terms. fn main() { - let x = 2.0.recip(); - //~^ ERROR can't call method `recip` on ambiguous numeric type `{float}` + let x = 2.0.neg(); + //~^ ERROR can't call method `neg` on ambiguous numeric type `{float}` let y = 2.0; - let x = y.recip(); - //~^ ERROR can't call method `recip` on ambiguous numeric type `{float}` + let x = y.neg(); + //~^ ERROR can't call method `neg` on ambiguous numeric type `{float}` println!("{:?}", x); } diff --git a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr index 477b4c3821d..68c8be7dff8 100644 --- a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr +++ b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr @@ -1,18 +1,18 @@ -error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` +error[E0689]: can't call method `neg` on ambiguous numeric type `{float}` --> $DIR/method-on-ambiguous-numeric-type.rs:12:17 | -LL | let x = 2.0.recip(); - | ^^^^^ +LL | let x = 2.0.neg(); + | ^^^ help: you must specify a concrete type for this numeric value, like `f32` | -LL | let x = 2.0_f32.recip(); +LL | let x = 2.0_f32.neg(); | ^^^^^^^ -error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` +error[E0689]: can't call method `neg` on ambiguous numeric type `{float}` --> $DIR/method-on-ambiguous-numeric-type.rs:15:15 | -LL | let x = y.recip(); - | ^^^^^ +LL | let x = y.neg(); + | ^^^ help: you must specify a type for this binding, like `f32` | LL | let y: f32 = 2.0; -- cgit 1.4.1-3-g733a5 From a44abfdc29ee66ec1d51c2389405cbac479f35a7 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 22 May 2018 17:09:49 -0700 Subject: Make `Unpin` safe to implement --- src/liballoc/boxed.rs | 2 +- src/libcore/marker.rs | 2 +- src/libcore/mem.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index a1567344235..a83ce7f379f 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -850,4 +850,4 @@ impl fmt::Pointer for PinBox { impl, U: ?Sized> CoerceUnsized> for PinBox {} #[unstable(feature = "pin", issue = "49150")] -unsafe impl Unpin for PinBox {} +impl Unpin for PinBox {} diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 6c8ee0eda11..d4a87b13f04 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -605,7 +605,7 @@ unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} /// /// [`PinMut`]: ../mem/struct.PinMut.html #[unstable(feature = "pin", issue = "49150")] -pub unsafe auto trait Unpin {} +pub auto trait Unpin {} /// Implementations of `Copy` for primitive types. /// diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 20445def634..116e56f4ae9 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1207,4 +1207,4 @@ impl<'a, T: ?Sized> fmt::Pointer for PinMut<'a, T> { impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for PinMut<'a, T> {} #[unstable(feature = "pin", issue = "49150")] -unsafe impl<'a, T: ?Sized> Unpin for PinMut<'a, T> {} +impl<'a, T: ?Sized> Unpin for PinMut<'a, T> {} -- cgit 1.4.1-3-g733a5 From 640f6f07494ece4ebe7e4d9680fff9a83ab4b0d2 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 22 May 2018 17:10:14 -0700 Subject: Add Pinned type for opting out of Unpin on stable --- src/libcore/marker.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index d4a87b13f04..77db165bcbd 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -607,6 +607,16 @@ unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} #[unstable(feature = "pin", issue = "49150")] pub auto trait Unpin {} +/// A type which does not implement `Unpin`. +/// +/// If a type contains a `Pinned`, it will not implement `Unpin` by default. +#[unstable(feature = "pin", issue = "49150")] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct Pinned; + +#[unstable(feature = "pin", issue = "49150")] +impl !Unpin for Pinned {} + /// Implementations of `Copy` for primitive types. /// /// Implementations that cannot be described in Rust -- cgit 1.4.1-3-g733a5 From b7ccb248480918ae589756b585f4cdcae82a26b7 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 22 May 2018 16:59:53 -0700 Subject: Add PinMut::set --- src/libcore/mem.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 116e56f4ae9..059c099d66b 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1164,6 +1164,14 @@ impl<'a, T: ?Sized> PinMut<'a, T> { { PinMut { inner: f(this.inner) } } + + /// Assign a new value to the memory behind the pinned reference. + #[unstable(feature = "pin", issue = "49150")] + pub fn set(this: PinMut<'a, T>, value: T) + where T: Sized, + { + *this.inner = value; + } } #[unstable(feature = "pin", issue = "49150")] -- cgit 1.4.1-3-g733a5 From 15d2f965d83672dc8e7edc972ab256e587878332 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 22 May 2018 17:07:51 -0700 Subject: Add Option::as_pin_mut --- src/libcore/lib.rs | 1 + src/libcore/option.rs | 10 ++++++++++ 2 files changed, 11 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index d37629ced11..2121bc44380 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -74,6 +74,7 @@ #![deny(missing_debug_implementations)] #![feature(allow_internal_unstable)] +#![feature(arbitrary_self_types)] #![feature(asm)] #![feature(associated_type_defaults)] #![feature(attr_literals)] diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 28f37f72d6f..1e615042a6d 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -147,6 +147,7 @@ use iter::{FromIterator, FusedIterator, TrustedLen}; use {mem, ops}; +use mem::PinMut; // Note that this is not a lang item per se, but it has a hidden dependency on // `Iterator`, which is one. The compiler assumes that the `next` method of @@ -269,6 +270,15 @@ impl Option { } } + /// Converts from `Option` to `Option>` + #[inline] + #[unstable(feature = "pin", issue = "49150")] + pub fn as_pin_mut<'a>(self: PinMut<'a, Self>) -> Option> { + unsafe { + PinMut::get_mut(self).as_mut().map(|x| PinMut::new_unchecked(x)) + } + } + ///////////////////////////////////////////////////////////////////////// // Getting to contained values ///////////////////////////////////////////////////////////////////////// -- cgit 1.4.1-3-g733a5 From 1977c62339acceabe711d8ca6bf9404475c7f75d Mon Sep 17 00:00:00 2001 From: Joe ST Date: Wed, 23 May 2018 15:01:11 +0100 Subject: move type def out of unsafe block from https://github.com/rust-lang/rust/pull/50863#discussion_r190213000 move the union definition outside of the unsafe block --- src/libcore/str/mod.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 70aaf10f421..13d808ede5f 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2246,13 +2246,11 @@ impl str { #[inline(always)] #[rustc_const_unstable(feature="const_str_as_bytes")] pub const fn as_bytes(&self) -> &[u8] { - unsafe { - union Slices<'a> { - str: &'a str, - slice: &'a [u8], - } - Slices { str: self }.slice + union Slices<'a> { + str: &'a str, + slice: &'a [u8], } + unsafe { Slices { str: self }.slice } } /// Converts a mutable string slice to a mutable byte slice. To convert the -- cgit 1.4.1-3-g733a5 From 1440f300d848610b0cb798a735e2c75a94998aa9 Mon Sep 17 00:00:00 2001 From: Cory Sherman Date: Thu, 24 May 2018 04:39:35 -0700 Subject: stabilize RangeBounds collections_range #30877 rename RangeBounds::start() -> start_bound() rename RangeBounds::end() -> end_bound() --- src/liballoc/btree/map.rs | 6 +- src/liballoc/string.rs | 8 +- src/liballoc/vec.rs | 4 +- src/liballoc/vec_deque.rs | 4 +- src/libcore/ops/range.rs | 138 +++++++++++------------------ src/librustc_data_structures/array_vec.rs | 4 +- src/librustc_data_structures/sorted_map.rs | 4 +- 7 files changed, 68 insertions(+), 100 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index bb2c68a27ba..28c42144b2a 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -1834,7 +1834,7 @@ fn range_search>( Handle, marker::Edge>) where Q: Ord, K: Borrow { - match (range.start(), range.end()) { + match (range.start_bound(), range.end_bound()) { (Excluded(s), Excluded(e)) if s==e => panic!("range start and end are equal and excluded in BTreeMap"), (Included(s), Included(e)) | @@ -1852,7 +1852,7 @@ fn range_search>( let mut diverged = false; loop { - let min_edge = match (min_found, range.start()) { + let min_edge = match (min_found, range.start_bound()) { (false, Included(key)) => match search::search_linear(&min_node, key) { (i, true) => { min_found = true; i }, (i, false) => i, @@ -1866,7 +1866,7 @@ fn range_search>( (true, Excluded(_)) => 0, }; - let max_edge = match (max_found, range.end()) { + let max_edge = match (max_found, range.end_bound()) { (false, Included(key)) => match search::search_linear(&max_node, key) { (i, true) => { max_found = true; i+1 }, (i, false) => i, diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 449e3152d8f..a988b6a26d9 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1493,12 +1493,12 @@ impl String { // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. let len = self.len(); - let start = match range.start() { + let start = match range.start_bound() { Included(&n) => n, Excluded(&n) => n + 1, Unbounded => 0, }; - let end = match range.end() { + let end = match range.end_bound() { Included(&n) => n + 1, Excluded(&n) => n, Unbounded => len, @@ -1551,12 +1551,12 @@ impl String { // Replace_range does not have the memory safety issues of a vector Splice. // of the vector version. The data is just plain bytes. - match range.start() { + match range.start_bound() { Included(&n) => assert!(self.is_char_boundary(n)), Excluded(&n) => assert!(self.is_char_boundary(n + 1)), Unbounded => {}, }; - match range.end() { + match range.end_bound() { Included(&n) => assert!(self.is_char_boundary(n + 1)), Excluded(&n) => assert!(self.is_char_boundary(n)), Unbounded => {}, diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index c48c64a8bef..b5739e1a825 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1166,12 +1166,12 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let start = match range.start() { + let start = match range.start_bound() { Included(&n) => n, Excluded(&n) => n + 1, Unbounded => 0, }; - let end = match range.end() { + let end = match range.end_bound() { Included(&n) => n + 1, Excluded(&n) => n, Unbounded => len, diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index ff82b3a469c..e917a65c9c5 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -980,12 +980,12 @@ impl VecDeque { // and the head/tail values will be restored correctly. // let len = self.len(); - let start = match range.start() { + let start = match range.start_bound() { Included(&n) => n, Excluded(&n) => n + 1, Unbounded => 0, }; - let end = match range.end() { + let end = match range.end_bound() { Included(&n) => n + 1, Excluded(&n) => n, Unbounded => len, diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 7c6e2447bdb..01e279589da 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -588,14 +588,12 @@ impl> RangeToInclusive { /// `Bound`s are range endpoints: /// /// ``` -/// #![feature(collections_range)] -/// /// use std::ops::Bound::*; /// use std::ops::RangeBounds; /// -/// assert_eq!((..100).start(), Unbounded); -/// assert_eq!((1..12).start(), Included(&1)); -/// assert_eq!((1..12).end(), Excluded(&12)); +/// assert_eq!((..100).start_bound(), Unbounded); +/// assert_eq!((1..12).start_bound(), Included(&1)); +/// assert_eq!((1..12).end_bound(), Excluded(&12)); /// ``` /// /// Using a tuple of `Bound`s as an argument to [`BTreeMap::range`]. @@ -632,9 +630,7 @@ pub enum Bound { Unbounded, } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] /// `RangeBounds` is implemented by Rust's built-in range types, produced /// by range syntax like `..`, `a..`, `..b` or `c..d`. pub trait RangeBounds { @@ -645,17 +641,16 @@ pub trait RangeBounds { /// # Examples /// /// ``` - /// #![feature(collections_range)] - /// /// # fn main() { /// use std::ops::Bound::*; /// use std::ops::RangeBounds; /// - /// assert_eq!((..10).start(), Unbounded); - /// assert_eq!((3..10).start(), Included(&3)); + /// assert_eq!((..10).start_bound(), Unbounded); + /// assert_eq!((3..10).start_bound(), Included(&3)); /// # } /// ``` - fn start(&self) -> Bound<&T>; + #[stable(feature = "collections_range", since = "1.28.0")] + fn start_bound(&self) -> Bound<&T>; /// End index bound. /// @@ -664,17 +659,16 @@ pub trait RangeBounds { /// # Examples /// /// ``` - /// #![feature(collections_range)] - /// /// # fn main() { /// use std::ops::Bound::*; /// use std::ops::RangeBounds; /// - /// assert_eq!((3..).end(), Unbounded); - /// assert_eq!((3..10).end(), Excluded(&10)); + /// assert_eq!((3..).end_bound(), Unbounded); + /// assert_eq!((3..10).end_bound(), Excluded(&10)); /// # } /// ``` - fn end(&self) -> Bound<&T>; + #[stable(feature = "collections_range", since = "1.28.0")] + fn end_bound(&self) -> Bound<&T>; /// Returns `true` if `item` is contained in the range. @@ -699,13 +693,13 @@ pub trait RangeBounds { T: PartialOrd, U: ?Sized + PartialOrd, { - (match self.start() { + (match self.start_bound() { Included(ref start) => *start <= item, Excluded(ref start) => *start < item, Unbounded => true, }) && - (match self.end() { + (match self.end_bound() { Included(ref end) => item <= *end, Excluded(ref end) => item < *end, Unbounded => true, @@ -715,83 +709,69 @@ pub trait RangeBounds { use self::Bound::{Excluded, Included, Unbounded}; -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for RangeFull { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Unbounded } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Unbounded } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for RangeFrom { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(&self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Unbounded } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for RangeTo { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Unbounded } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Excluded(&self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for Range { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(&self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Excluded(&self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for RangeInclusive { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(&self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Included(&self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for RangeToInclusive { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Unbounded } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Included(&self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for (Bound, Bound) { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { match *self { (Included(ref start), _) => Included(start), (Excluded(ref start), _) => Excluded(start), @@ -799,7 +779,7 @@ impl RangeBounds for (Bound, Bound) { } } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { match *self { (_, Included(ref end)) => Included(end), (_, Excluded(ref end)) => Excluded(end), @@ -808,75 +788,63 @@ impl RangeBounds for (Bound, Bound) { } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T: ?Sized + 'a> RangeBounds for (Bound<&'a T>, Bound<&'a T>) { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { self.0 } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { self.1 } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T> RangeBounds for RangeFrom<&'a T> { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Unbounded } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T> RangeBounds for RangeTo<&'a T> { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Unbounded } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Excluded(self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T> RangeBounds for Range<&'a T> { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Excluded(self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T> RangeBounds for RangeInclusive<&'a T> { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Included(self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T> RangeBounds for RangeToInclusive<&'a T> { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Unbounded } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Included(self.end) } } diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 7b33ee40d8c..56bb9613242 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -119,12 +119,12 @@ impl ArrayVec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let start = match range.start() { + let start = match range.start_bound() { Included(&n) => n, Excluded(&n) => n + 1, Unbounded => 0, }; - let end = match range.end() { + let end = match range.end_bound() { Included(&n) => n + 1, Excluded(&n) => n, Unbounded => len, diff --git a/src/librustc_data_structures/sorted_map.rs b/src/librustc_data_structures/sorted_map.rs index e14bd33c82c..f7e7d6405fc 100644 --- a/src/librustc_data_structures/sorted_map.rs +++ b/src/librustc_data_structures/sorted_map.rs @@ -214,7 +214,7 @@ impl SortedMap { fn range_slice_indices(&self, range: R) -> (usize, usize) where R: RangeBounds { - let start = match range.start() { + let start = match range.start_bound() { Bound::Included(ref k) => { match self.lookup_index_for(k) { Ok(index) | Err(index) => index @@ -229,7 +229,7 @@ impl SortedMap { Bound::Unbounded => 0, }; - let end = match range.end() { + let end = match range.end_bound() { Bound::Included(ref k) => { match self.lookup_index_for(k) { Ok(index) => index + 1, -- cgit 1.4.1-3-g733a5 From 6ff940963715b6d7f2e3f243441c81f2a3ebdd89 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 24 May 2018 22:26:58 +0200 Subject: Add more missing examples for Formatter --- src/libcore/fmt/mod.rs | 81 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 5820fe58932..1dc0faa156d 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1202,6 +1202,23 @@ impl<'a> Formatter<'a> { /// is longer than this length /// /// Notably this function ignores the `flag` parameters. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo; + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// formatter.pad("Foo") + /// } + /// } + /// + /// assert_eq!(&format!("{:<4}", Foo), "Foo "); + /// assert_eq!(&format!("{:0>4}", Foo), "0Foo"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn pad(&mut self, s: &str) -> Result { // Make sure there's a fast path up front @@ -1368,7 +1385,7 @@ impl<'a> Formatter<'a> { self.buf.write_str(data) } - /// Writes some formatted information into this instance + /// Writes some formatted information into this instance. #[stable(feature = "rust1", since = "1.0.0")] pub fn write_fmt(&mut self, fmt: Arguments) -> Result { write(self.buf, fmt) @@ -1381,11 +1398,69 @@ impl<'a> Formatter<'a> { or `sign_aware_zero_pad` methods instead")] pub fn flags(&self) -> u32 { self.flags } - /// Character used as 'fill' whenever there is alignment + /// Character used as 'fill' whenever there is alignment. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo; + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// let c = formatter.fill(); + /// if let Some(width) = formatter.width() { + /// for _ in 0..width { + /// write!(formatter, "{}", c)?; + /// } + /// Ok(()) + /// } else { + /// write!(formatter, "{}", c) + /// } + /// } + /// } + /// + /// // We set alignment to the left with ">". + /// assert_eq!(&format!("{:G>3}", Foo), "GGG"); + /// assert_eq!(&format!("{:t>6}", Foo), "tttttt"); + /// ``` #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn fill(&self) -> char { self.fill } - /// Flag indicating what form of alignment was requested + /// Flag indicating what form of alignment was requested. + /// + /// # Examples + /// + /// ``` + /// #![feature(fmt_flags_align)] + /// + /// extern crate core; + /// + /// use std::fmt; + /// use core::fmt::Alignment; + /// + /// struct Foo; + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// let s = match formatter.align() { + /// Alignment::Left => "left", + /// Alignment::Right => "right", + /// Alignment::Center => "center", + /// Alignment::Unknown => "into the void", + /// }; + /// write!(formatter, "{}", s) + /// } + /// } + /// + /// fn main() { + /// assert_eq!(&format!("{:<}", Foo), "left"); + /// assert_eq!(&format!("{:>}", Foo), "right"); + /// assert_eq!(&format!("{:^}", Foo), "center"); + /// assert_eq!(&format!("{}", Foo), "into the void"); + /// } + /// ``` #[unstable(feature = "fmt_flags_align", reason = "method was just created", issue = "27726")] pub fn align(&self) -> Alignment { -- cgit 1.4.1-3-g733a5 From 37cbd11a9f864f6747ed9b4a3aab4c59ca2bae81 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 25 May 2018 11:47:48 -0700 Subject: Update nomicon link in transmute docs The list of "invalid primitive values" has moved to a different URL within the Rustonomicon. --- src/libcore/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 2e3f5cb65c9..95f13daf841 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -717,7 +717,7 @@ extern "rust-intrinsic" { /// Reinterprets the bits of a value of one type as another type. /// /// Both types must have the same size. Neither the original, nor the result, - /// may be an [invalid value](../../nomicon/meet-safe-and-unsafe.html). + /// may be an [invalid value](../../nomicon/what-unsafe-does.html). /// /// `transmute` is semantically equivalent to a bitwise move of one type /// into another. It copies the bits from the source value into the -- cgit 1.4.1-3-g733a5 From bbd790ced37d2249f793d02c6864d449914bf468 Mon Sep 17 00:00:00 2001 From: uuttff8 Date: Sun, 27 May 2018 11:53:43 +0300 Subject: lib.rs don't beautiful --- src/libcore/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 2121bc44380..32cf31231c3 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -147,14 +147,14 @@ mod uint_macros; #[path = "num/i16.rs"] pub mod i16; #[path = "num/i32.rs"] pub mod i32; #[path = "num/i64.rs"] pub mod i64; -#[path = "num/i128.rs"] pub mod i128; +#[path = "num/i128.rs"] pub mod i128; #[path = "num/usize.rs"] pub mod usize; #[path = "num/u8.rs"] pub mod u8; #[path = "num/u16.rs"] pub mod u16; #[path = "num/u32.rs"] pub mod u32; #[path = "num/u64.rs"] pub mod u64; -#[path = "num/u128.rs"] pub mod u128; +#[path = "num/u128.rs"] pub mod u128; #[path = "num/f32.rs"] pub mod f32; #[path = "num/f64.rs"] pub mod f64; -- cgit 1.4.1-3-g733a5 From fb447f118d3cf9d896ae4ff60ebf0befc238f0db Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 26 May 2018 10:41:48 +0200 Subject: Stabilize Formatter alignment --- src/libcore/fmt/mod.rs | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 1dc0faa156d..0515eeed30b 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -25,18 +25,19 @@ mod float; mod num; mod builders; -#[unstable(feature = "fmt_flags_align", issue = "27726")] +#[stable(feature = "fmt_flags_align", since = "1.28.0")] /// Possible alignments returned by `Formatter::align` #[derive(Debug)] pub enum Alignment { + #[stable(feature = "fmt_flags_align", since = "1.28.0")] /// Indication that contents should be left-aligned. Left, + #[stable(feature = "fmt_flags_align", since = "1.28.0")] /// Indication that contents should be right-aligned. Right, + #[stable(feature = "fmt_flags_align", since = "1.28.0")] /// Indication that contents should be center-aligned. Center, - /// No alignment was requested. - Unknown, } #[stable(feature = "debug_builders", since = "1.2.0")] @@ -1433,8 +1434,6 @@ impl<'a> Formatter<'a> { /// # Examples /// /// ``` - /// #![feature(fmt_flags_align)] - /// /// extern crate core; /// /// use std::fmt; @@ -1444,11 +1443,14 @@ impl<'a> Formatter<'a> { /// /// impl fmt::Display for Foo { /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - /// let s = match formatter.align() { - /// Alignment::Left => "left", - /// Alignment::Right => "right", - /// Alignment::Center => "center", - /// Alignment::Unknown => "into the void", + /// let s = if let Some(s) = formatter.align() { + /// match s { + /// Alignment::Left => "left", + /// Alignment::Right => "right", + /// Alignment::Center => "center", + /// } + /// } else { + /// "into the void" /// }; /// write!(formatter, "{}", s) /// } @@ -1461,14 +1463,13 @@ impl<'a> Formatter<'a> { /// assert_eq!(&format!("{}", Foo), "into the void"); /// } /// ``` - #[unstable(feature = "fmt_flags_align", reason = "method was just created", - issue = "27726")] - pub fn align(&self) -> Alignment { + #[stable(feature = "fmt_flags_align", since = "1.28.0")] + pub fn align(&self) -> Option { match self.align { - rt::v1::Alignment::Left => Alignment::Left, - rt::v1::Alignment::Right => Alignment::Right, - rt::v1::Alignment::Center => Alignment::Center, - rt::v1::Alignment::Unknown => Alignment::Unknown, + rt::v1::Alignment::Left => Some(Alignment::Left), + rt::v1::Alignment::Right => Some(Alignment::Right), + rt::v1::Alignment::Center => Some(Alignment::Center), + rt::v1::Alignment::Unknown => None, } } -- cgit 1.4.1-3-g733a5 From 12878a78a7528dbe5888fe70fd5a0861c820c86a Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 20 May 2018 12:39:13 -0400 Subject: Provide more context for what the {f32,f64}::EPSILON values represent. --- src/libcore/num/f32.rs | 6 +++++- src/libcore/num/f64.rs | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 718dd42a615..65332d4b97a 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -33,7 +33,11 @@ pub const MANTISSA_DIGITS: u32 = 24; #[stable(feature = "rust1", since = "1.0.0")] pub const DIGITS: u32 = 6; -/// Difference between `1.0` and the next largest representable number. +/// [Machine epsilon] value for `f32`. +/// +/// This is the difference between `1.0` and the next largest representable number. +/// +/// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon #[stable(feature = "rust1", since = "1.0.0")] pub const EPSILON: f32 = 1.19209290e-07_f32; diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index f128c55c78a..c9a643e7b33 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -33,7 +33,11 @@ pub const MANTISSA_DIGITS: u32 = 53; #[stable(feature = "rust1", since = "1.0.0")] pub const DIGITS: u32 = 15; -/// Difference between `1.0` and the next largest representable number. +/// [Machine epsilon] value for `f64`. +/// +/// This is the difference between `1.0` and the next largest representable number. +/// +/// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon #[stable(feature = "rust1", since = "1.0.0")] pub const EPSILON: f64 = 2.2204460492503131e-16_f64; -- cgit 1.4.1-3-g733a5 From 3ee9d899695edf3a00870f6243c27c21d9084a8f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 May 2018 18:27:26 +0200 Subject: extend from_raw_parts docs for slices and strs to mention alignment requirement --- src/libcore/slice/mod.rs | 11 ++++++----- src/libcore/str/mod.rs | 10 ++++------ 2 files changed, 10 insertions(+), 11 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index ab986e4c86d..d52cc8cbe3f 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -3839,10 +3839,9 @@ unsafe impl<'a, T> TrustedRandomAccess for ExactChunksMut<'a, T> { /// valid for `len` elements, nor whether the lifetime inferred is a suitable /// lifetime for the returned slice. /// -/// `p` must be non-null, even for zero-length slices, because non-zero bits -/// are required to distinguish between a zero-length slice within `Some()` -/// from `None`. `p` can be a bogus non-dereferencable pointer, such as `0x1`, -/// for zero-length slices, though. +/// `p` must be non-null and aligned, even for zero-length slices, as is +/// required for all references. However, for zero-length slices, `p` can be +/// a bogus non-dereferencable pointer such as [`NonNull::dangling()`]. /// /// # Caveat /// @@ -3864,6 +3863,8 @@ unsafe impl<'a, T> TrustedRandomAccess for ExactChunksMut<'a, T> { /// let slice = slice::from_raw_parts(ptr, amt); /// } /// ``` +/// +/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { @@ -3875,7 +3876,7 @@ pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { /// /// This function is unsafe for the same reasons as `from_raw_parts`, as well /// as not being able to provide a non-aliasing guarantee of the returned -/// mutable slice. `p` must be non-null even for zero-length slices as with +/// mutable slice. `p` must be non-null and aligned even for zero-length slices as with /// `from_raw_parts`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 13d808ede5f..ea0a0b74db6 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -388,10 +388,9 @@ pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { /// /// The data must be valid UTF-8 /// -/// `p` must be non-null, even for zero-length strs, because non-zero bits -/// are required to distinguish between a zero-length str within `Some()` -/// from `None`. `p` can be a bogus non-dereferencable pointer, such as `0x1`, -/// for zero-length strs, though. +/// `p` must be non-null and aligned, even for zero-length strs, as is +/// required for all references. However, for zero-length strs, `p` can be +/// a bogus non-dereferencable pointer such as [`NonNull::dangling()`]. /// /// # Caveat /// @@ -400,9 +399,8 @@ pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { /// source lifetime is safe in the context, such as by providing a helper /// function taking the lifetime of a host value for the str, or by explicit /// annotation. -/// Performs the same functionality as `from_raw_parts`, except that a mutable -/// str is returned. /// +/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str { from_utf8_unchecked_mut(slice::from_raw_parts_mut(p, len)) } -- cgit 1.4.1-3-g733a5 From b30aaf244e73f638007220445be53180c8f2db87 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 May 2018 22:04:50 +0200 Subject: get rid of str::from_raw_parts_mut str::from_raw_parts has been removed long ago because it can be obtained via str::from_utf8_unchecked and slice::from_raw_parts. The same goes for str::from_raw_parts_mut. --- src/libcore/str/mod.rs | 36 +++++------------------------------- 1 file changed, 5 insertions(+), 31 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index ea0a0b74db6..3169893fcde 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -376,35 +376,6 @@ pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { Ok(unsafe { from_utf8_unchecked_mut(v) }) } -/// Forms a str from a pointer and a length. -/// -/// The `len` argument is the number of bytes in the string. -/// -/// # Safety -/// -/// This function is unsafe as there is no guarantee that the given pointer is -/// valid for `len` bytes, nor whether the lifetime inferred is a suitable -/// lifetime for the returned str. -/// -/// The data must be valid UTF-8 -/// -/// `p` must be non-null and aligned, even for zero-length strs, as is -/// required for all references. However, for zero-length strs, `p` can be -/// a bogus non-dereferencable pointer such as [`NonNull::dangling()`]. -/// -/// # Caveat -/// -/// The lifetime for the returned str is inferred from its usage. To -/// prevent accidental misuse, it's suggested to tie the lifetime to whichever -/// source lifetime is safe in the context, such as by providing a helper -/// function taking the lifetime of a host value for the str, or by explicit -/// annotation. -/// -/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling -unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str { - from_utf8_unchecked_mut(slice::from_raw_parts_mut(p, len)) -} - /// Converts a slice of bytes to a string slice without checking /// that the string contains valid UTF-8. /// @@ -2600,8 +2571,11 @@ impl str { let len = self.len(); let ptr = self.as_ptr() as *mut u8; unsafe { - (from_raw_parts_mut(ptr, mid), - from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) + (from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, mid)), + from_utf8_unchecked_mut(slice::from_raw_parts_mut( + ptr.offset(mid as isize), + len - mid + ))) } } else { slice_error_fail(self, 0, mid) -- cgit 1.4.1-3-g733a5 From fc895665c9a6ba9bc0be7844cb7162797b557a34 Mon Sep 17 00:00:00 2001 From: Jonathan Behrens Date: Mon, 28 May 2018 19:01:50 -0400 Subject: Avoid 128-bit arithmetic where possible --- src/libcore/time.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/time.rs b/src/libcore/time.rs index f43d2db51e7..72b03cd0965 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -277,7 +277,7 @@ impl Duration { #[unstable(feature = "duration_as_u128", issue = "50202")] #[inline] pub fn as_millis(&self) -> u128 { - self.secs as u128 * MILLIS_PER_SEC as u128 + self.nanos as u128 / NANOS_PER_MILLI as u128 + self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos / NANOS_PER_MILLI) as u128 } /// Returns the total number of microseconds contained by this `Duration`. @@ -294,7 +294,7 @@ impl Duration { #[unstable(feature = "duration_as_u128", issue = "50202")] #[inline] pub fn as_micros(&self) -> u128 { - self.secs as u128 * MICROS_PER_SEC as u128 + self.nanos as u128 / NANOS_PER_MICRO as u128 + self.secs as u128 * MICROS_PER_SEC as u128 + (self.nanos / NANOS_PER_MICRO) as u128 } /// Returns the total number of nanoseconds contained by this `Duration`. -- cgit 1.4.1-3-g733a5 From 18cf47bc7de897168d19806e13467d6c8168a581 Mon Sep 17 00:00:00 2001 From: Nick Babcock Date: Mon, 28 May 2018 18:50:16 -0500 Subject: Document additional use case for iter::inspect --- src/libcore/iter/iterator.rs | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index d22c5376211..f5b23a3793b 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1169,8 +1169,9 @@ pub trait Iterator { /// happening at various parts in the pipeline. To do that, insert /// a call to `inspect()`. /// - /// It's much more common for `inspect()` to be used as a debugging tool - /// than to exist in your final code, but never say never. + /// It's more common for `inspect()` to be used as a debugging tool than to + /// exist in your final code, but applications may find it useful in certain + /// situations when errors need to be logged before being discarded. /// /// # Examples /// @@ -1210,6 +1211,32 @@ pub trait Iterator { /// about to filter: 3 /// 6 /// ``` + /// + /// Logging errors before discarding them: + /// + /// ``` + /// let lines = ["1", "2", "a"]; + /// + /// let sum: i32 = lines + /// .iter() + /// .map(|line| line.parse::()) + /// .inspect(|num| { + /// if let Err(ref e) = *num { + /// println!("Parsing error: {}", e); + /// } + /// }) + /// .filter_map(Result::ok) + /// .sum(); + /// + /// println!("Sum: {}", sum); + /// ``` + /// + /// This will print: + /// + /// ```text + /// Parsing error: invalid digit found in string + /// Sum: 3 + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn inspect(self, f: F) -> Inspect where -- cgit 1.4.1-3-g733a5 From 6c3ebcd223af3ebd4d45cd4a648b8b25ef6d3ba3 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 30 May 2018 21:00:37 +0200 Subject: make Layout's align a NonZeroUsize --- src/libcore/alloc.rs | 74 +++++++++++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 36 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 674c4fb57c7..064c7514112 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -20,6 +20,7 @@ use fmt; use mem; use usize; use ptr::{self, NonNull}; +use num::NonZeroUsize; extern { /// An opaque, unsized type. Used for pointers to allocated memory. @@ -66,7 +67,7 @@ fn size_align() -> (usize, usize) { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Layout { // size of the requested block of memory, measured in bytes. - size: usize, + size_: usize, // alignment of the requested block of memory, measured in bytes. // we ensure that this is always a power-of-two, because API's @@ -75,17 +76,12 @@ pub struct Layout { // // (However, we do not analogously require `align >= sizeof(void*)`, // even though that is *also* a requirement of `posix_memalign`.) - align: usize, + align_: NonZeroUsize, } - -// FIXME: audit default implementations for overflow errors, -// (potentially switching to overflowing_add and -// overflowing_mul as necessary). - impl Layout { /// Constructs a `Layout` from a given `size` and `align`, - /// or returns `None` if either of the following conditions + /// or returns `LayoutErr` if either of the following conditions /// are not met: /// /// * `align` must be a power of two, @@ -126,23 +122,23 @@ impl Layout { /// /// # Safety /// - /// This function is unsafe as it does not verify that `align` is - /// a power-of-two nor `size` aligned to `align` fits within the - /// address space (i.e. the `Layout::from_size_align` preconditions). + /// This function is unsafe as it does not verify the preconditions from + /// [`Layout::from_size_align`](#method.from_size_align). #[inline] pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { - Layout { size: size, align: align } + Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) } } /// The minimum size in bytes for a memory block of this layout. #[inline] - pub fn size(&self) -> usize { self.size } + pub fn size(&self) -> usize { self.size_ } /// The minimum byte alignment for a memory block of this layout. #[inline] - pub fn align(&self) -> usize { self.align } + pub fn align(&self) -> usize { self.align_.get() } /// Constructs a `Layout` suitable for holding a value of type `T`. + #[inline] pub fn new() -> Self { let (size, align) = size_align::(); // Note that the align is guaranteed by rustc to be a power of two and @@ -158,6 +154,7 @@ impl Layout { /// Produces layout describing a record that could be used to /// allocate backing structure for `T` (which could be a trait /// or other unsized type like a slice). + #[inline] pub fn for_value(t: &T) -> Self { let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); // See rationale in `new` for why this us using an unsafe variant below @@ -181,18 +178,19 @@ impl Layout { /// /// # Panics /// - /// Panics if the combination of `self.size` and the given `align` - /// violates the conditions listed in `from_size_align`. + /// Panics if the combination of `self.size()` and the given `align` + /// violates the conditions listed in + /// [`Layout::from_size_align`](#method.from_size_align). #[inline] pub fn align_to(&self, align: usize) -> Self { - Layout::from_size_align(self.size, cmp::max(self.align, align)).unwrap() + Layout::from_size_align(self.size(), cmp::max(self.align(), align)).unwrap() } /// Returns the amount of padding we must insert after `self` /// to ensure that the following address will satisfy `align` /// (measured in bytes). /// - /// E.g. if `self.size` is 9, then `self.padding_needed_for(4)` + /// E.g. if `self.size()` is 9, then `self.padding_needed_for(4)` /// returns 3, because that is the minimum number of bytes of /// padding required to get a 4-aligned address (assuming that the /// corresponding memory block starts at a 4-aligned address). @@ -203,9 +201,12 @@ impl Layout { /// Note that the utility of the returned value requires `align` /// to be less than or equal to the alignment of the starting /// address for the whole allocated block of memory. One way to - /// satisfy this constraint is to ensure `align <= self.align`. + /// satisfy this constraint is to ensure `align <= self.align()`. #[inline] pub fn padding_needed_for(&self, align: usize) -> usize { + // **FIXME**: This function is only called with proper power-of-two + // alignments. Maybe we should turn this into a real assert!. + debug_assert!(align.is_power_of_two()); let len = self.size(); // Rounded up value is: @@ -227,7 +228,8 @@ impl Layout { // size and padding overflow in the above manner should cause // the allocator to yield an error anyway.) - let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); + let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) + & !align.wrapping_sub(1); return len_rounded_up.wrapping_sub(len); } @@ -238,14 +240,14 @@ impl Layout { /// layout of the array and `offs` is the distance between the start /// of each element in the array. /// - /// On arithmetic overflow, returns `None`. + /// On arithmetic overflow, returns `LayoutErr`. #[inline] pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> { - let padded_size = self.size.checked_add(self.padding_needed_for(self.align)) + let padded_size = self.size().checked_add(self.padding_needed_for(self.align())) .ok_or(LayoutErr { private: () })?; let alloc_size = padded_size.checked_mul(n) .ok_or(LayoutErr { private: () })?; - Ok((Layout::from_size_align(alloc_size, self.align)?, padded_size)) + Ok((Layout::from_size_align(alloc_size, self.align())?, padded_size)) } /// Creates a layout describing the record for `self` followed by @@ -258,16 +260,16 @@ impl Layout { /// start of the `next` embedded within the concatenated record /// (assuming that the record itself starts at offset 0). /// - /// On arithmetic overflow, returns `None`. + /// On arithmetic overflow, returns `LayoutErr`. pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> { - let new_align = cmp::max(self.align, next.align); - let realigned = Layout::from_size_align(self.size, new_align)?; + let new_align = cmp::max(self.align(), next.align()); + let realigned = Layout::from_size_align(self.size(), new_align)?; - let pad = realigned.padding_needed_for(next.align); + let pad = realigned.padding_needed_for(next.align()); - let offset = self.size.checked_add(pad) + let offset = self.size().checked_add(pad) .ok_or(LayoutErr { private: () })?; - let new_size = offset.checked_add(next.size) + let new_size = offset.checked_add(next.size()) .ok_or(LayoutErr { private: () })?; let layout = Layout::from_size_align(new_size, new_align)?; @@ -285,10 +287,10 @@ impl Layout { /// guaranteed that all elements in the array will be properly /// aligned. /// - /// On arithmetic overflow, returns `None`. + /// On arithmetic overflow, returns `LayoutErr`. pub fn repeat_packed(&self, n: usize) -> Result { let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?; - Layout::from_size_align(size, self.align) + Layout::from_size_align(size, self.align()) } /// Creates a layout describing the record for `self` followed by @@ -305,17 +307,17 @@ impl Layout { /// signature out of convenience in matching the signature of /// `extend`.) /// - /// On arithmetic overflow, returns `None`. + /// On arithmetic overflow, returns `LayoutErr`. pub fn extend_packed(&self, next: Self) -> Result<(Self, usize), LayoutErr> { let new_size = self.size().checked_add(next.size()) .ok_or(LayoutErr { private: () })?; - let layout = Layout::from_size_align(new_size, self.align)?; + let layout = Layout::from_size_align(new_size, self.align())?; Ok((layout, self.size())) } /// Creates a layout describing the record for a `[T; n]`. /// - /// On arithmetic overflow, returns `None`. + /// On arithmetic overflow, returns `LayoutErr`. pub fn array(n: usize) -> Result { Layout::new::() .repeat(n) @@ -834,7 +836,7 @@ pub unsafe trait Alloc { layout: Layout, new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. - debug_assert!(new_size >= layout.size); + debug_assert!(new_size >= layout.size()); let (_l, u) = self.usable_size(&layout); // _l <= layout.size() [guaranteed by usable_size()] // layout.size() <= new_layout.size() [required by this method] @@ -889,7 +891,7 @@ pub unsafe trait Alloc { layout: Layout, new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. - debug_assert!(new_size <= layout.size); + debug_assert!(new_size <= layout.size()); let (l, _u) = self.usable_size(&layout); // layout.size() <= _u [guaranteed by usable_size()] // new_layout.size() <= layout.size() [required by this method] -- cgit 1.4.1-3-g733a5 From d6b8c67ee6d7c657741909a847ab8dde178000cb Mon Sep 17 00:00:00 2001 From: uuttff8 Date: Wed, 30 May 2018 22:24:24 +0300 Subject: mod.rs isn't beautiful --- src/libcore/char/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index 4f6c302247d..59bcf1383f4 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -60,10 +60,10 @@ use fmt::{self, Write}; use iter::FusedIterator; // UTF-8 ranges and tags for encoding characters -const TAG_CONT: u8 = 0b1000_0000; -const TAG_TWO_B: u8 = 0b1100_0000; -const TAG_THREE_B: u8 = 0b1110_0000; -const TAG_FOUR_B: u8 = 0b1111_0000; +const TAG_CONT: u8 = 0b1000_0000; +const TAG_TWO_B: u8 = 0b1100_0000; +const TAG_THREE_B: u8 = 0b1110_0000; +const TAG_FOUR_B: u8 = 0b1111_0000; const MAX_ONE_B: u32 = 0x80; const MAX_TWO_B: u32 = 0x800; const MAX_THREE_B: u32 = 0x10000; -- cgit 1.4.1-3-g733a5 From 1c883d67615267d42aad3b3a38729bd8ee42a8c8 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 28 May 2018 09:18:04 -0400 Subject: Add doc link from discriminant struct to function. --- src/libcore/mem.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 059c099d66b..c033b670798 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -835,7 +835,9 @@ pub unsafe fn transmute_copy(src: &T) -> U { /// Opaque type representing the discriminant of an enum. /// -/// See the `discriminant` function in this module for more information. +/// See the [`discriminant`] function in this module for more information. +/// +/// [`discriminant`]: fn.discriminant.html #[stable(feature = "discriminant_value", since = "1.21.0")] pub struct Discriminant(u64, PhantomData T>); -- cgit 1.4.1-3-g733a5 From 72433e179d203431c85164555e651c7d65bd93c7 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Wed, 16 May 2018 23:09:58 -0700 Subject: Add implementations for Any + Send + Sync Implement `is`, `downcast_ref`, `downcast_mut` and `Debug` for `Any + Send + Sync`. --- src/libcore/any.rs | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/any.rs b/src/libcore/any.rs index a6ba53087ac..d608fed443d 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -136,6 +136,13 @@ impl fmt::Debug for Any + Send { } } +#[stable(feature = "any_send_sync_methods", since = "1.28.0")] +impl fmt::Debug for Any + Send + Sync { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Any") + } +} + impl Any { /// Returns `true` if the boxed type is the same as `T`. /// @@ -325,6 +332,89 @@ impl Any+Send { } } +impl Any+Send+Sync { + /// Forwards to the method defined on the type `Any`. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// + /// fn is_string(s: &(Any + Send + Sync)) { + /// if s.is::() { + /// println!("It's a string!"); + /// } else { + /// println!("Not a string..."); + /// } + /// } + /// + /// fn main() { + /// is_string(&0); + /// is_string(&"cookie monster".to_string()); + /// } + /// ``` + #[stable(feature = "any_send_sync_methods", since = "1.28.0")] + #[inline] + pub fn is(&self) -> bool { + Any::is::(self) + } + + /// Forwards to the method defined on the type `Any`. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// + /// fn print_if_string(s: &(Any + Send)) { + /// if let Some(string) = s.downcast_ref::() { + /// println!("It's a string({}): '{}'", string.len(), string); + /// } else { + /// println!("Not a string..."); + /// } + /// } + /// + /// fn main() { + /// print_if_string(&0); + /// print_if_string(&"cookie monster".to_string()); + /// } + /// ``` + #[stable(feature = "any_send_sync_methods", since = "1.28.0")] + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + Any::downcast_ref::(self) + } + + /// Forwards to the method defined on the type `Any`. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// + /// fn modify_if_u32(s: &mut (Any+ Send)) { + /// if let Some(num) = s.downcast_mut::() { + /// *num = 42; + /// } + /// } + /// + /// fn main() { + /// let mut x = 10u32; + /// let mut s = "starlord".to_string(); + /// + /// modify_if_u32(&mut x); + /// modify_if_u32(&mut s); + /// + /// assert_eq!(x, 42); + /// assert_eq!(&s, "starlord"); + /// } + /// ``` + #[stable(feature = "any_send_sync_methods", since = "1.28.0")] + #[inline] + pub fn downcast_mut(&mut self) -> Option<&mut T> { + Any::downcast_mut::(self) + } +} /////////////////////////////////////////////////////////////////////////////// // TypeID and its methods -- cgit 1.4.1-3-g733a5 From 87c3d7bee52fb99f922c77fa267729b7898bc9a6 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 18 May 2018 08:18:44 -0700 Subject: Fix up Any doc examples Make the Any+Send+Sync examples use the right trait bounds, and fix a small whitespace issue. --- src/libcore/any.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/any.rs b/src/libcore/any.rs index d608fed443d..4437c36c15a 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -308,7 +308,7 @@ impl Any+Send { /// ``` /// use std::any::Any; /// - /// fn modify_if_u32(s: &mut (Any+ Send)) { + /// fn modify_if_u32(s: &mut (Any + Send)) { /// if let Some(num) = s.downcast_mut::() { /// *num = 42; /// } @@ -366,7 +366,7 @@ impl Any+Send+Sync { /// ``` /// use std::any::Any; /// - /// fn print_if_string(s: &(Any + Send)) { + /// fn print_if_string(s: &(Any + Send + Sync)) { /// if let Some(string) = s.downcast_ref::() { /// println!("It's a string({}): '{}'", string.len(), string); /// } else { @@ -392,7 +392,7 @@ impl Any+Send+Sync { /// ``` /// use std::any::Any; /// - /// fn modify_if_u32(s: &mut (Any+ Send)) { + /// fn modify_if_u32(s: &mut (Any + Send + Sync)) { /// if let Some(num) = s.downcast_mut::() { /// *num = 42; /// } -- cgit 1.4.1-3-g733a5 From 32dcaab58578e8c0cb6f76e8a1842e5a2b79a3fb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 1 Jun 2018 01:29:22 +0200 Subject: Add missing whitespace in num example --- src/libcore/num/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 013d0334d41..2418b5e8c75 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2313,7 +2313,7 @@ Basic usage: ``` ", $Feature, "assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(1), ", "Some(", stringify!($SelfT), "::max_value() - 1)); -assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3),None);", $EndFeature, " +assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] -- cgit 1.4.1-3-g733a5 From 8e90a2d02f4d90409dcd65a8e54b76f1edcba42c Mon Sep 17 00:00:00 2001 From: CrLF0710 Date: Tue, 29 May 2018 15:58:50 +0800 Subject: Replace `if` with `if and only if` in the definition dox of `Sync` The old text was: "The precise definition is: a type T is Sync if &T is Send." Since we've also got ``` impl<'a, T> Send for &'a T where T: Sync + ?Sized, ``` I purpose we can change the `if` to `if and only if` to make it more precise. --- src/libcore/marker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 77db165bcbd..3d3f63ecf37 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -294,7 +294,7 @@ pub trait Copy : Clone { /// This trait is automatically implemented when the compiler determines /// it's appropriate. /// -/// The precise definition is: a type `T` is `Sync` if `&T` is +/// The precise definition is: a type `T` is `Sync` if and only if `&T` is /// [`Send`][send]. In other words, if there is no possibility of /// [undefined behavior][ub] (including data races) when passing /// `&T` references between threads. -- cgit 1.4.1-3-g733a5 From 9d770e9959ed5fedad31bfc04f946f5e268cfc37 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Mon, 28 May 2018 20:19:39 -0600 Subject: Stabilize SliceIndex trait. Fixes #35729 According to recommendations in https://github.com/rust-lang/rust/issues/35729#issuecomment-377784884 --- src/liballoc/lib.rs | 1 - src/liballoc/slice.rs | 2 +- src/libcore/slice/mod.rs | 32 ++++++++++++++++++++++++++++++-- 3 files changed, 31 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 91de3ad0c39..a56420d52d0 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -104,7 +104,6 @@ #![feature(ptr_internals)] #![feature(ptr_offset_from)] #![feature(rustc_attrs)] -#![feature(slice_get_slice)] #![feature(specialization)] #![feature(staged_api)] #![feature(str_internals)] diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 161493f3892..8686ecd7bcf 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -121,7 +121,7 @@ pub use core::slice::{RSplit, RSplitMut}; pub use core::slice::{from_raw_parts, from_raw_parts_mut}; #[stable(feature = "from_ref", since = "1.28.0")] pub use core::slice::{from_ref, from_mut}; -#[unstable(feature = "slice_get_slice", issue = "35729")] +#[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; #[unstable(feature = "exact_chunks", issue = "47115")] pub use core::slice::{ExactChunks, ExactChunksMut}; diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index d52cc8cbe3f..43236c33104 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1977,35 +1977,63 @@ fn slice_index_overflow_fail() -> ! { panic!("attempted to index slice up to maximum usize"); } +mod private_slice_index { + use super::ops; + #[stable(feature = "slice_get_slice", since = "1.28.0")] + pub trait Sealed {} + + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for usize {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::Range {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeTo {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeFrom {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeFull {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeInclusive {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeToInclusive {} +} + /// A helper trait used for indexing operations. -#[unstable(feature = "slice_get_slice", issue = "35729")] +#[stable(feature = "slice_get_slice", since = "1.28.0")] #[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] -pub trait SliceIndex { +pub trait SliceIndex: private_slice_index::Sealed { /// The output type returned by methods. + #[stable(feature = "slice_get_slice", since = "1.28.0")] type Output: ?Sized; /// Returns a shared reference to the output at this location, if in /// bounds. + #[unstable(feature = "slice_index_methods", issue = "0")] fn get(self, slice: &T) -> Option<&Self::Output>; /// Returns a mutable reference to the output at this location, if in /// bounds. + #[unstable(feature = "slice_index_methods", issue = "0")] fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>; /// Returns a shared reference to the output at this location, without /// performing any bounds checking. + #[unstable(feature = "slice_index_methods", issue = "0")] unsafe fn get_unchecked(self, slice: &T) -> &Self::Output; /// Returns a mutable reference to the output at this location, without /// performing any bounds checking. + #[unstable(feature = "slice_index_methods", issue = "0")] unsafe fn get_unchecked_mut(self, slice: &mut T) -> &mut Self::Output; /// Returns a shared reference to the output at this location, panicking /// if out of bounds. + #[unstable(feature = "slice_index_methods", issue = "0")] fn index(self, slice: &T) -> &Self::Output; /// Returns a mutable reference to the output at this location, panicking /// if out of bounds. + #[unstable(feature = "slice_index_methods", issue = "0")] fn index_mut(self, slice: &mut T) -> &mut Self::Output; } -- cgit 1.4.1-3-g733a5 From c6bebf4554692c07ff96c8395f8aeddb09443708 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 29 May 2018 13:09:09 +0200 Subject: Simplify HashMap layout calculation by using Layout --- src/libcore/alloc.rs | 8 +++ src/libstd/collections/hash/table.rs | 120 ++++------------------------------- 2 files changed, 21 insertions(+), 107 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 674c4fb57c7..6172a98bca6 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -392,6 +392,14 @@ impl From for CollectionAllocErr { } } +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +impl From for CollectionAllocErr { + #[inline] + fn from(_: LayoutErr) -> Self { + CollectionAllocErr::CapacityOverflow + } +} + /// A memory allocator that can be registered to be the one backing `std::alloc::Global` /// though the `#[global_allocator]` attributes. pub unsafe trait GlobalAlloc { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index eed2debcaa2..c62a409ac02 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -8,11 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::{Global, Alloc, Layout, CollectionAllocErr, oom}; -use cmp; +use alloc::{Global, Alloc, Layout, LayoutErr, CollectionAllocErr, oom}; use hash::{BuildHasher, Hash, Hasher}; use marker; -use mem::{align_of, size_of, needs_drop}; +use mem::{size_of, needs_drop}; use mem; use ops::{Deref, DerefMut}; use ptr::{self, Unique, NonNull}; @@ -651,64 +650,12 @@ impl GapThenFull } } - -/// Rounds up to a multiple of a power of two. Returns the closest multiple -/// of `target_alignment` that is higher or equal to `unrounded`. -/// -/// # Panics -/// -/// Panics if `target_alignment` is not a power of two. -#[inline] -fn round_up_to_next(unrounded: usize, target_alignment: usize) -> usize { - assert!(target_alignment.is_power_of_two()); - (unrounded + target_alignment - 1) & !(target_alignment - 1) -} - -#[test] -fn test_rounding() { - assert_eq!(round_up_to_next(0, 4), 0); - assert_eq!(round_up_to_next(1, 4), 4); - assert_eq!(round_up_to_next(2, 4), 4); - assert_eq!(round_up_to_next(3, 4), 4); - assert_eq!(round_up_to_next(4, 4), 4); - assert_eq!(round_up_to_next(5, 4), 8); -} - -// Returns a tuple of (pairs_offset, end_of_pairs_offset), -// from the start of a mallocated array. -#[inline] -fn calculate_offsets(hashes_size: usize, - pairs_size: usize, - pairs_align: usize) - -> (usize, usize, bool) { - let pairs_offset = round_up_to_next(hashes_size, pairs_align); - let (end_of_pairs, oflo) = pairs_offset.overflowing_add(pairs_size); - - (pairs_offset, end_of_pairs, oflo) -} - -// Returns a tuple of (minimum required malloc alignment, -// array_size), from the start of a mallocated array. -fn calculate_allocation(hash_size: usize, - hash_align: usize, - pairs_size: usize, - pairs_align: usize) - -> (usize, usize, bool) { - let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align); - - let align = cmp::max(hash_align, pairs_align); - - (align, end_of_pairs, oflo) -} - -#[test] -fn test_offset_calculation() { - assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 144, false)); - assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 5, false)); - assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 20, false)); - assert_eq!(calculate_offsets(128, 15, 4), (128, 143, false)); - assert_eq!(calculate_offsets(3, 2, 4), (4, 6, false)); - assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false)); +// Returns a Layout which describes the allocation required for a hash table, +// and the offset of the array of (key, value) pairs in the allocation. +fn calculate_layout(capacity: usize) -> Result<(Layout, usize), LayoutErr> { + let hashes = Layout::array::(capacity)?; + let pairs = Layout::array::<(K, V)>(capacity)?; + hashes.extend(pairs) } pub(crate) enum Fallibility { @@ -735,37 +682,11 @@ impl RawTable { }); } - // No need for `checked_mul` before a more restrictive check performed - // later in this method. - let hashes_size = capacity.wrapping_mul(size_of::()); - let pairs_size = capacity.wrapping_mul(size_of::<(K, V)>()); - // Allocating hashmaps is a little tricky. We need to allocate two // arrays, but since we know their sizes and alignments up front, // we just allocate a single array, and then have the subarrays // point into it. - // - // This is great in theory, but in practice getting the alignment - // right is a little subtle. Therefore, calculating offsets has been - // factored out into a different function. - let (alignment, size, oflo) = calculate_allocation(hashes_size, - align_of::(), - pairs_size, - align_of::<(K, V)>()); - if oflo { - return Err(CollectionAllocErr::CapacityOverflow); - } - - // One check for overflow that covers calculation and rounding of size. - let size_of_bucket = size_of::().checked_add(size_of::<(K, V)>()) - .ok_or(CollectionAllocErr::CapacityOverflow)?; - let capacity_mul_size_of_bucket = capacity.checked_mul(size_of_bucket); - if capacity_mul_size_of_bucket.is_none() || size < capacity_mul_size_of_bucket.unwrap() { - return Err(CollectionAllocErr::CapacityOverflow); - } - - let layout = Layout::from_size_align(size, alignment) - .map_err(|_| CollectionAllocErr::CapacityOverflow)?; + let (layout, _) = calculate_layout::(capacity)?; let buffer = Global.alloc(layout).map_err(|e| match fallibility { Infallible => oom(layout), Fallible => e, @@ -790,18 +711,12 @@ impl RawTable { } fn raw_bucket_at(&self, index: usize) -> RawBucket { - let hashes_size = self.capacity() * size_of::(); - let pairs_size = self.capacity() * size_of::<(K, V)>(); - - let (pairs_offset, _, oflo) = - calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>()); - debug_assert!(!oflo, "capacity overflow"); - + let (_, pairs_offset) = calculate_layout::(self.capacity()).unwrap(); let buffer = self.hashes.ptr() as *mut u8; unsafe { RawBucket { hash_start: buffer as *mut HashUint, - pair_start: buffer.offset(pairs_offset as isize) as *const (K, V), + pair_start: buffer.add(pairs_offset) as *const (K, V), idx: index, _marker: marker::PhantomData, } @@ -1194,18 +1109,9 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { } } - let hashes_size = self.capacity() * size_of::(); - let pairs_size = self.capacity() * size_of::<(K, V)>(); - let (align, size, oflo) = calculate_allocation(hashes_size, - align_of::(), - pairs_size, - align_of::<(K, V)>()); - - debug_assert!(!oflo, "should be impossible"); - + let (layout, _) = calculate_layout::(self.capacity()).unwrap(); unsafe { - Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), - Layout::from_size_align(size, align).unwrap()); + Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), layout); // Remember how everything was allocated out of one buffer // during initialization? We only need one call to free here. } -- cgit 1.4.1-3-g733a5 From 8c3bdcc35a96d42cb089405530a0016b1113358f Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Tue, 8 May 2018 21:38:22 -0400 Subject: Add From for int types --- src/libcore/num/mod.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 013d0334d41..06447dcdce9 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4454,6 +4454,20 @@ macro_rules! impl_from { } } +// Bool -> Any +impl_from! { bool, u8, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from! { bool, u16, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from! { bool, u32, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from! { bool, u64, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from! { bool, u128, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from! { bool, usize, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from! { bool, i8, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from! { bool, i16, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from! { bool, i32, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from! { bool, i64, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from! { bool, i128, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from! { bool, isize, #[stable(feature = "from_bool", since = "1.28.0")] } + // Unsigned -> Unsigned impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -- cgit 1.4.1-3-g733a5 From 7fe56e81b74e90b78d268e1749ee0de3e2ff54cd Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Sun, 20 May 2018 14:52:08 -0400 Subject: Fix ambiguity in Result test --- src/libcore/tests/result.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs index ce41bde8342..d9927ce4487 100644 --- a/src/libcore/tests/result.rs +++ b/src/libcore/tests/result.rs @@ -220,13 +220,15 @@ fn test_try() { assert_eq!(try_result_none(), None); fn try_result_ok() -> Result { - let val = Ok(1)?; + let result: Result = Ok(1); + let val = result?; Ok(val) } assert_eq!(try_result_ok(), Ok(1)); fn try_result_err() -> Result { - let val = Err(1)?; + let result: Result = Err(1); + let val = result?; Ok(val) } assert_eq!(try_result_err(), Err(1)); -- cgit 1.4.1-3-g733a5 From b1797d57ffb42a063a8ecc8cc5f9d2b625708c72 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Sun, 20 May 2018 14:56:46 -0400 Subject: Add @ithinuel's tests from #50597 --- src/libcore/tests/num/mod.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index f3439890fce..b5e6a019a22 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -134,6 +134,15 @@ fn test_infallible_try_from_int_error() { } macro_rules! test_impl_from { + ($fn_name:ident, bool, $target: ty) => { + #[test] + fn $fn_name() { + let one: $target = 1; + let zero: $target = 0; + assert_eq!(one, <$target>::from(true)); + assert_eq!(zero, <$target>::from(false)); + } + }; ($fn_name: ident, $Small: ty, $Large: ty) => { #[test] fn $fn_name() { @@ -173,6 +182,18 @@ test_impl_from! { test_u16i32, u16, i32 } test_impl_from! { test_u16i64, u16, i64 } test_impl_from! { test_u32i64, u32, i64 } +// Bool -> Integer +test_impl_from! { test_boolu8, bool, u8 } +test_impl_from! { test_boolu16, bool, u16 } +test_impl_from! { test_boolu32, bool, u32 } +test_impl_from! { test_boolu64, bool, u64 } +test_impl_from! { test_boolu128, bool, u128 } +test_impl_from! { test_booli8, bool, i8 } +test_impl_from! { test_booli16, bool, i16 } +test_impl_from! { test_booli32, bool, i32 } +test_impl_from! { test_booli64, bool, i64 } +test_impl_from! { test_booli128, bool, i128 } + // Signed -> Float test_impl_from! { test_i8f32, i8, f32 } test_impl_from! { test_i8f64, i8, f64 } -- cgit 1.4.1-3-g733a5 From 61b5bd25b528853f1b3064bbba3328a3360e8101 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 28 May 2018 08:36:14 -0400 Subject: Reword {ptr,mem}::replace docs. Fixes https://github.com/rust-lang/rust/issues/50657. --- src/libcore/mem.rs | 5 +++-- src/libcore/ptr.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 059c099d66b..e4e3b1c2a3a 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -635,8 +635,9 @@ pub fn swap(x: &mut T, y: &mut T) { } } -/// Replaces the value at a mutable location with a new one, returning the old value, without -/// deinitializing either one. +/// Moves `src` into the referenced `dest`, returning the previous `dest` value. +/// +/// Neither value is dropped. /// /// # Examples /// diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 6c0709caa08..39315d8f0c8 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -239,8 +239,9 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { } } -/// Replaces the value at `dest` with `src`, returning the old -/// value, without dropping either. +/// Moves `src` into the pointed `dest`, returning the previous `dest` value. +/// +/// Neither value is dropped. /// /// # Safety /// -- cgit 1.4.1-3-g733a5 From 1b9ab8939efc1a38a7a5398a069517466fd88d38 Mon Sep 17 00:00:00 2001 From: Linus Färnstrand Date: Tue, 29 May 2018 11:42:13 +0200 Subject: Make most integer operations const fns --- src/libcore/lib.rs | 1 + src/libcore/num/mod.rs | 154 ++++++++++++++++++++++++++++++++++++------------- 2 files changed, 115 insertions(+), 40 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 32cf31231c3..71a727f4c01 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -81,6 +81,7 @@ #![feature(cfg_target_has_atomic)] #![feature(concat_idents)] #![feature(const_fn)] +#![feature(const_int_ops)] #![feature(core_float)] #![feature(custom_attribute)] #![feature(doc_cfg)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index ea652ad811e..60fdd4a3642 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -267,8 +267,9 @@ $EndFeature, " ``` "), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } + pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } } doc_comment! { @@ -282,8 +283,9 @@ Basic usage: ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 1);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn count_zeros(self) -> u32 { + pub const fn count_zeros(self) -> u32 { (!self).count_ones() } } @@ -302,8 +304,9 @@ assert_eq!(n.leading_zeros(), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn leading_zeros(self) -> u32 { + pub const fn leading_zeros(self) -> u32 { (self as $UnsignedT).leading_zeros() } } @@ -322,8 +325,9 @@ assert_eq!(n.trailing_zeros(), 2);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn trailing_zeros(self) -> u32 { + pub const fn trailing_zeros(self) -> u32 { (self as $UnsignedT).trailing_zeros() } } @@ -396,8 +400,9 @@ $EndFeature, " /// assert_eq!(m, 21760); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn swap_bytes(self) -> Self { + pub const fn swap_bytes(self) -> Self { (self as $UnsignedT).swap_bytes() as Self } @@ -447,9 +452,17 @@ if cfg!(target_endian = \"big\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn from_be(x: Self) -> Self { - if cfg!(target_endian = "big") { x } else { x.swap_bytes() } + pub const fn from_be(x: Self) -> Self { + #[cfg(target_endian = "big")] + { + x + } + #[cfg(not(target_endian = "big"))] + { + x.swap_bytes() + } } } @@ -473,9 +486,17 @@ if cfg!(target_endian = \"little\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn from_le(x: Self) -> Self { - if cfg!(target_endian = "little") { x } else { x.swap_bytes() } + pub const fn from_le(x: Self) -> Self { + #[cfg(target_endian = "little")] + { + x + } + #[cfg(not(target_endian = "little"))] + { + x.swap_bytes() + } } } @@ -499,9 +520,17 @@ if cfg!(target_endian = \"big\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn to_be(self) -> Self { // or not to be? - if cfg!(target_endian = "big") { self } else { self.swap_bytes() } + pub const fn to_be(self) -> Self { // or not to be? + #[cfg(target_endian = "big")] + { + self + } + #[cfg(not(target_endian = "big"))] + { + self.swap_bytes() + } } } @@ -525,9 +554,17 @@ if cfg!(target_endian = \"little\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn to_le(self) -> Self { - if cfg!(target_endian = "little") { self } else { self.swap_bytes() } + pub const fn to_le(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + self.swap_bytes() + } } } @@ -1943,6 +1980,19 @@ impl isize { int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "" } } +// Emits the correct `cttz` call, depending on the size of the type. +macro_rules! uint_cttz_call { + // As of LLVM 3.6 the codegen for the zero-safe cttz8 intrinsic + // emits two conditional moves on x86_64. By promoting the value to + // u16 and setting bit 8, we get better code without any conditional + // operations. + // FIXME: There's a LLVM patch (http://reviews.llvm.org/D9284) + // pending, remove this workaround once LLVM generates better code + // for cttz8. + ($value:expr, 8) => { intrinsics::cttz($value as u16 | 0x100) }; + ($value:expr, $_BITS:expr) => { intrinsics::cttz($value) } +} + // `Int` + `UnsignedInt` implemented for unsigned integers macro_rules! uint_impl { ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr) => { @@ -2020,8 +2070,9 @@ Basic usage: assert_eq!(n.count_ones(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn count_ones(self) -> u32 { + pub const fn count_ones(self) -> u32 { unsafe { intrinsics::ctpop(self as $ActualT) as u32 } } } @@ -2037,8 +2088,9 @@ Basic usage: ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn count_zeros(self) -> u32 { + pub const fn count_zeros(self) -> u32 { (!self).count_ones() } } @@ -2056,8 +2108,9 @@ Basic usage: assert_eq!(n.leading_zeros(), 2);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn leading_zeros(self) -> u32 { + pub const fn leading_zeros(self) -> u32 { unsafe { intrinsics::ctlz(self as $ActualT) as u32 } } } @@ -2076,22 +2129,10 @@ Basic usage: assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn trailing_zeros(self) -> u32 { - // As of LLVM 3.6 the codegen for the zero-safe cttz8 intrinsic - // emits two conditional moves on x86_64. By promoting the value to - // u16 and setting bit 8, we get better code without any conditional - // operations. - // FIXME: There's a LLVM patch (http://reviews.llvm.org/D9284) - // pending, remove this workaround once LLVM generates better code - // for cttz8. - unsafe { - if $BITS == 8 { - intrinsics::cttz(self as u16 | 0x100) as u32 - } else { - intrinsics::cttz(self) as u32 - } - } + pub const fn trailing_zeros(self) -> u32 { + unsafe { uint_cttz_call!(self, $BITS) as u32 } } } @@ -2167,8 +2208,9 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " /// assert_eq!(m, 21760); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn swap_bytes(self) -> Self { + pub const fn swap_bytes(self) -> Self { unsafe { intrinsics::bswap(self as $ActualT) as Self } } @@ -2218,9 +2260,17 @@ if cfg!(target_endian = \"big\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn from_be(x: Self) -> Self { - if cfg!(target_endian = "big") { x } else { x.swap_bytes() } + pub const fn from_be(x: Self) -> Self { + #[cfg(target_endian = "big")] + { + x + } + #[cfg(not(target_endian = "big"))] + { + x.swap_bytes() + } } } @@ -2244,9 +2294,17 @@ if cfg!(target_endian = \"little\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn from_le(x: Self) -> Self { - if cfg!(target_endian = "little") { x } else { x.swap_bytes() } + pub const fn from_le(x: Self) -> Self { + #[cfg(target_endian = "little")] + { + x + } + #[cfg(not(target_endian = "little"))] + { + x.swap_bytes() + } } } @@ -2270,9 +2328,17 @@ if cfg!(target_endian = \"big\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn to_be(self) -> Self { // or not to be? - if cfg!(target_endian = "big") { self } else { self.swap_bytes() } + pub const fn to_be(self) -> Self { // or not to be? + #[cfg(target_endian = "big")] + { + self + } + #[cfg(not(target_endian = "big"))] + { + self.swap_bytes() + } } } @@ -2296,9 +2362,17 @@ if cfg!(target_endian = \"little\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn to_le(self) -> Self { - if cfg!(target_endian = "little") { self } else { self.swap_bytes() } + pub const fn to_le(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + self.swap_bytes() + } } } -- cgit 1.4.1-3-g733a5 From 8a27c19c92b293051bd5fa8c3bd18082d8d7dd51 Mon Sep 17 00:00:00 2001 From: Linus Färnstrand Date: Sat, 2 Jun 2018 11:24:32 +0200 Subject: Make integer methods non-const in stage0 --- src/libcore/num/mod.rs | 192 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 60fdd4a3642..26dd08b10b9 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -267,11 +267,20 @@ $EndFeature, " ``` "), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } } + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } + } + doc_comment! { concat!("Returns the number of zeros in the binary representation of `self`. @@ -283,6 +292,7 @@ Basic usage: ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 1);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn count_zeros(self) -> u32 { @@ -290,6 +300,16 @@ Basic usage: } } + doc_comment! { + concat!("Dummy docs. See !stage0 documentatio"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn count_zeros(self) -> u32 { + (!self).count_ones() + } + } + doc_comment! { concat!("Returns the number of leading zeros in the binary representation of `self`. @@ -304,6 +324,7 @@ assert_eq!(n.leading_zeros(), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn leading_zeros(self) -> u32 { @@ -311,6 +332,16 @@ $EndFeature, " } } + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn leading_zeros(self) -> u32 { + (self as $UnsignedT).leading_zeros() + } + } + doc_comment! { concat!("Returns the number of trailing zeros in the binary representation of `self`. @@ -325,6 +356,7 @@ assert_eq!(n.trailing_zeros(), 2);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn trailing_zeros(self) -> u32 { @@ -332,6 +364,16 @@ $EndFeature, " } } + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn trailing_zeros(self) -> u32 { + (self as $UnsignedT).trailing_zeros() + } + } + /// Shifts the bits to the left by a specified amount, `n`, /// wrapping the truncated bits to the end of the resulting integer. /// @@ -400,12 +442,21 @@ $EndFeature, " /// assert_eq!(m, 21760); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn swap_bytes(self) -> Self { (self as $UnsignedT).swap_bytes() as Self } + /// Dummy docs. See !stage0 documentation. + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn swap_bytes(self) -> Self { + (self as $UnsignedT).swap_bytes() as Self + } + /// Reverses the bit pattern of the integer. /// /// # Examples @@ -452,6 +503,7 @@ if cfg!(target_endian = \"big\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn from_be(x: Self) -> Self { @@ -466,6 +518,16 @@ $EndFeature, " } } + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn from_be(x: Self) -> Self { + if cfg!(target_endian = "big") { x } else { x.swap_bytes() } + } + } + doc_comment! { concat!("Converts an integer from little endian to the target's endianness. @@ -486,6 +548,7 @@ if cfg!(target_endian = \"little\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn from_le(x: Self) -> Self { @@ -500,6 +563,16 @@ $EndFeature, " } } + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn from_le(x: Self) -> Self { + if cfg!(target_endian = "little") { x } else { x.swap_bytes() } + } + } + doc_comment! { concat!("Converts `self` to big endian from the target's endianness. @@ -520,6 +593,7 @@ if cfg!(target_endian = \"big\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn to_be(self) -> Self { // or not to be? @@ -534,6 +608,16 @@ $EndFeature, " } } + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn to_be(self) -> Self { // or not to be? + if cfg!(target_endian = "big") { self } else { self.swap_bytes() } + } + } + doc_comment! { concat!("Converts `self` to little endian from the target's endianness. @@ -554,6 +638,7 @@ if cfg!(target_endian = \"little\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn to_le(self) -> Self { @@ -568,6 +653,16 @@ $EndFeature, " } } + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn to_le(self) -> Self { + if cfg!(target_endian = "little") { self } else { self.swap_bytes() } + } + } + doc_comment! { concat!("Checked integer addition. Computes `self + rhs`, returning `None` if overflow occurred. @@ -2070,6 +2165,7 @@ Basic usage: assert_eq!(n.count_ones(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn count_ones(self) -> u32 { @@ -2077,6 +2173,16 @@ assert_eq!(n.count_ones(), 3);", $EndFeature, " } } + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn count_ones(self) -> u32 { + unsafe { intrinsics::ctpop(self as $ActualT) as u32 } + } + } + doc_comment! { concat!("Returns the number of zeros in the binary representation of `self`. @@ -2088,6 +2194,7 @@ Basic usage: ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn count_zeros(self) -> u32 { @@ -2095,6 +2202,16 @@ Basic usage: } } + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn count_zeros(self) -> u32 { + (!self).count_ones() + } + } + doc_comment! { concat!("Returns the number of leading zeros in the binary representation of `self`. @@ -2108,6 +2225,7 @@ Basic usage: assert_eq!(n.leading_zeros(), 2);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn leading_zeros(self) -> u32 { @@ -2115,6 +2233,16 @@ assert_eq!(n.leading_zeros(), 2);", $EndFeature, " } } + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn leading_zeros(self) -> u32 { + unsafe { intrinsics::ctlz(self as $ActualT) as u32 } + } + } + doc_comment! { concat!("Returns the number of trailing zeros in the binary representation of `self`. @@ -2129,6 +2257,7 @@ Basic usage: assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn trailing_zeros(self) -> u32 { @@ -2136,6 +2265,16 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " } } + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn trailing_zeros(self) -> u32 { + unsafe { uint_cttz_call!(self, $BITS) as u32 } + } + } + /// Shifts the bits to the left by a specified amount, `n`, /// wrapping the truncated bits to the end of the resulting integer. /// @@ -2208,12 +2347,21 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " /// assert_eq!(m, 21760); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn swap_bytes(self) -> Self { unsafe { intrinsics::bswap(self as $ActualT) as Self } } + /// Dummy docs. See !stage0 documentation. + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn swap_bytes(self) -> Self { + unsafe { intrinsics::bswap(self as $ActualT) as Self } + } + /// Reverses the bit pattern of the integer. /// /// # Examples @@ -2260,6 +2408,7 @@ if cfg!(target_endian = \"big\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn from_be(x: Self) -> Self { @@ -2274,6 +2423,16 @@ if cfg!(target_endian = \"big\") { } } + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn from_be(x: Self) -> Self { + if cfg!(target_endian = "big") { x } else { x.swap_bytes() } + } + } + doc_comment! { concat!("Converts an integer from little endian to the target's endianness. @@ -2294,6 +2453,7 @@ if cfg!(target_endian = \"little\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn from_le(x: Self) -> Self { @@ -2308,6 +2468,16 @@ if cfg!(target_endian = \"little\") { } } + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn from_le(x: Self) -> Self { + if cfg!(target_endian = "little") { x } else { x.swap_bytes() } + } + } + doc_comment! { concat!("Converts `self` to big endian from the target's endianness. @@ -2328,6 +2498,7 @@ if cfg!(target_endian = \"big\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn to_be(self) -> Self { // or not to be? @@ -2342,6 +2513,16 @@ if cfg!(target_endian = \"big\") { } } + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn to_be(self) -> Self { // or not to be? + if cfg!(target_endian = "big") { self } else { self.swap_bytes() } + } + } + doc_comment! { concat!("Converts `self` to little endian from the target's endianness. @@ -2362,6 +2543,7 @@ if cfg!(target_endian = \"little\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn to_le(self) -> Self { @@ -2376,6 +2558,16 @@ if cfg!(target_endian = \"little\") { } } + doc_comment! { + concat!("Dummy docs. See !stage0 documentation"), + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] + #[inline] + pub fn to_le(self) -> Self { + if cfg!(target_endian = "little") { self } else { self.swap_bytes() } + } + } + doc_comment! { concat!("Checked integer addition. Computes `self + rhs`, returning `None` if overflow occurred. -- cgit 1.4.1-3-g733a5 From 6ff67ee0d7b4f9f962809a82d9078f353e200818 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Sat, 2 Jun 2018 16:03:33 +0200 Subject: remove debug_assert in padding_needed_for --- src/libcore/alloc.rs | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 064c7514112..cddd142045a 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -204,9 +204,6 @@ impl Layout { /// satisfy this constraint is to ensure `align <= self.align()`. #[inline] pub fn padding_needed_for(&self, align: usize) -> usize { - // **FIXME**: This function is only called with proper power-of-two - // alignments. Maybe we should turn this into a real assert!. - debug_assert!(align.is_power_of_two()); let len = self.size(); // Rounded up value is: -- cgit 1.4.1-3-g733a5 From 2d7cd70b1ac0dc1ce3a2602b51301dedae6a25a6 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Sat, 2 Jun 2018 16:11:57 +0200 Subject: add missing inline's and optimizations --- src/libcore/alloc.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index cddd142045a..4a817ebc43b 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -244,7 +244,12 @@ impl Layout { .ok_or(LayoutErr { private: () })?; let alloc_size = padded_size.checked_mul(n) .ok_or(LayoutErr { private: () })?; - Ok((Layout::from_size_align(alloc_size, self.align())?, padded_size)) + + unsafe { + // self.align is already known to be valid and alloc_size has been + // padded already. + Ok((Layout::from_size_align_unchecked(alloc_size, self.align()), padded_size)) + } } /// Creates a layout describing the record for `self` followed by @@ -258,11 +263,10 @@ impl Layout { /// (assuming that the record itself starts at offset 0). /// /// On arithmetic overflow, returns `LayoutErr`. + #[inline] pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> { let new_align = cmp::max(self.align(), next.align()); - let realigned = Layout::from_size_align(self.size(), new_align)?; - - let pad = realigned.padding_needed_for(next.align()); + let pad = self.padding_needed_for(next.align()); let offset = self.size().checked_add(pad) .ok_or(LayoutErr { private: () })?; @@ -285,6 +289,7 @@ impl Layout { /// aligned. /// /// On arithmetic overflow, returns `LayoutErr`. + #[inline] pub fn repeat_packed(&self, n: usize) -> Result { let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?; Layout::from_size_align(size, self.align()) @@ -305,6 +310,7 @@ impl Layout { /// `extend`.) /// /// On arithmetic overflow, returns `LayoutErr`. + #[inline] pub fn extend_packed(&self, next: Self) -> Result<(Self, usize), LayoutErr> { let new_size = self.size().checked_add(next.size()) .ok_or(LayoutErr { private: () })?; @@ -315,6 +321,7 @@ impl Layout { /// Creates a layout describing the record for a `[T; n]`. /// /// On arithmetic overflow, returns `LayoutErr`. + #[inline] pub fn array(n: usize) -> Result { Layout::new::() .repeat(n) -- cgit 1.4.1-3-g733a5 From 0ff8d40fa1c6be4428a65f6539ffe98c83245eab Mon Sep 17 00:00:00 2001 From: kennytm Date: Sun, 3 Jun 2018 00:29:50 +0800 Subject: impl Default for &mut str --- src/liballoc/tests/str.rs | 1 + src/libcore/str/mod.rs | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'src/libcore') diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index 03d295d16e6..75306ac82df 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -1326,6 +1326,7 @@ fn test_str_default() { t::<&str>(); t::(); + t::<&mut str>(); } #[test] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 3169893fcde..5e1a9c25a21 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -3875,6 +3875,12 @@ impl<'a> Default for &'a str { fn default() -> &'a str { "" } } +#[stable(feature = "default_mut_str", since = "1.28.0")] +impl<'a> Default for &'a mut str { + /// Creates an empty mutable str + fn default() -> &'a mut str { unsafe { from_utf8_unchecked_mut(&mut []) } } +} + /// An iterator over the non-whitespace substrings of a string, /// separated by any amount of whitespace. /// -- cgit 1.4.1-3-g733a5 From 87941b079ab29a3831c659bf467d7fb87d347c36 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Tue, 29 May 2018 23:30:16 -0600 Subject: Stabilize iterator_repeat_with Fixes #48169 --- src/libcore/iter/mod.rs | 2 +- src/libcore/iter/sources.rs | 26 +++++++------------------- src/libcore/lib.rs | 1 - src/libcore/tests/iter.rs | 12 ------------ src/libcore/tests/lib.rs | 1 - 5 files changed, 8 insertions(+), 34 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 1e8476d3880..f313f0d9147 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -333,7 +333,7 @@ pub use self::range::Step; #[stable(feature = "rust1", since = "1.0.0")] pub use self::sources::{Repeat, repeat}; -#[unstable(feature = "iterator_repeat_with", issue = "48169")] +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] pub use self::sources::{RepeatWith, repeat_with}; #[stable(feature = "iter_empty", since = "1.2.0")] pub use self::sources::{Empty, empty}; diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 0fc1a3aa8ac..d500cc99fa1 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -113,12 +113,12 @@ pub fn repeat(elt: T) -> Repeat { /// /// [`repeat_with`]: fn.repeat_with.html #[derive(Copy, Clone, Debug)] -#[unstable(feature = "iterator_repeat_with", issue = "48169")] +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] pub struct RepeatWith { repeater: F } -#[unstable(feature = "iterator_repeat_with", issue = "48169")] +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] impl A> Iterator for RepeatWith { type Item = A; @@ -129,13 +129,7 @@ impl A> Iterator for RepeatWith { fn size_hint(&self) -> (usize, Option) { (usize::MAX, None) } } -#[unstable(feature = "iterator_repeat_with", issue = "48169")] -impl A> DoubleEndedIterator for RepeatWith { - #[inline] - fn next_back(&mut self) -> Option { self.next() } -} - -#[unstable(feature = "iterator_repeat_with", issue = "48169")] +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] impl A> FusedIterator for RepeatWith {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -158,19 +152,15 @@ unsafe impl A> TrustedLen for RepeatWith {} /// /// [`repeat`]: fn.repeat.html /// -/// An iterator produced by `repeat_with()` is a `DoubleEndedIterator`. -/// It is important to note that reversing `repeat_with(f)` will produce -/// the exact same sequence as the non-reversed iterator. In other words, -/// `repeat_with(f).rev().collect::>()` is equivalent to -/// `repeat_with(f).collect::>()`. +/// An iterator produced by `repeat_with()` is not a `DoubleEndedIterator`. +/// If you need `repeat_with()` to return a `DoubleEndedIterator`, +/// please open a GitHub issue explaining your use case. /// /// # Examples /// /// Basic usage: /// /// ``` -/// #![feature(iterator_repeat_with)] -/// /// use std::iter; /// /// // let's assume we have some value of a type that is not `Clone` @@ -191,8 +181,6 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Using mutation and going finite: /// /// ```rust -/// #![feature(iterator_repeat_with)] -/// /// use std::iter; /// /// // From the zeroth to the third power of two: @@ -209,7 +197,7 @@ unsafe impl A> TrustedLen for RepeatWith {} /// assert_eq!(None, pow2.next()); /// ``` #[inline] -#[unstable(feature = "iterator_repeat_with", issue = "48169")] +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] pub fn repeat_with A>(repeater: F) -> RepeatWith { RepeatWith { repeater } } diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 32cf31231c3..ce86f469695 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -89,7 +89,6 @@ #![feature(fundamental)] #![feature(intrinsics)] #![feature(iterator_flatten)] -#![feature(iterator_repeat_with)] #![feature(lang_items)] #![feature(link_llvm_intrinsics)] #![feature(never_type)] diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 2abac0cf1d5..9b8d7031f8e 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1722,18 +1722,6 @@ fn test_repeat_with() { assert_eq!(repeat_with(|| NotClone(42)).size_hint(), (usize::MAX, None)); } -#[test] -fn test_repeat_with_rev() { - let mut curr = 1; - let mut pow2 = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) - .rev().take(4); - assert_eq!(pow2.next(), Some(1)); - assert_eq!(pow2.next(), Some(2)); - assert_eq!(pow2.next(), Some(4)); - assert_eq!(pow2.next(), Some(8)); - assert_eq!(pow2.next(), None); -} - #[test] fn test_repeat_with_take() { let mut it = repeat_with(|| 42).take(3); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 13189d532ab..b17c240f0eb 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -25,7 +25,6 @@ #![feature(hashmap_internals)] #![feature(iterator_step_by)] #![feature(iterator_flatten)] -#![feature(iterator_repeat_with)] #![feature(pattern)] #![feature(range_is_empty)] #![feature(raw)] -- cgit 1.4.1-3-g733a5 From 72e17b81fa88894e3fe04f221166f5a48e753e94 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Sat, 2 Jun 2018 20:42:42 -0600 Subject: Stabilize Iterator::step_by Fixes #27741 --- src/liballoc/tests/lib.rs | 1 - src/libcore/iter/iterator.rs | 5 +---- src/libcore/iter/mod.rs | 12 +++--------- src/libcore/tests/lib.rs | 1 - src/test/run-pass/range_inclusive.rs | 2 -- src/test/run-pass/sync-send-iterators-in-libcore.rs | 1 - 6 files changed, 4 insertions(+), 18 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 081c473768f..dbac2c0bb18 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -15,7 +15,6 @@ #![feature(const_fn)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] -#![feature(iterator_step_by)] #![feature(pattern)] #![feature(rand)] #![feature(slice_sort_by_cached_key)] diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index f5b23a3793b..1972b009905 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -283,7 +283,6 @@ pub trait Iterator { /// Basic usage: /// /// ``` - /// #![feature(iterator_step_by)] /// let a = [0, 1, 2, 3, 4, 5]; /// let mut iter = a.into_iter().step_by(2); /// @@ -293,9 +292,7 @@ pub trait Iterator { /// assert_eq!(iter.next(), None); /// ``` #[inline] - #[unstable(feature = "iterator_step_by", - reason = "unstable replacement of Range::step_by", - issue = "27741")] + #[stable(feature = "iterator_step_by", since = "1.28.0")] fn step_by(self, step: usize) -> StepBy where Self: Sized { assert!(step != 0); StepBy{iter: self, step: step - 1, first_take: true} diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 1e8476d3880..3458527c322 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -673,9 +673,7 @@ impl FusedIterator for Cycle where I: Clone + Iterator {} /// [`step_by`]: trait.Iterator.html#method.step_by /// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[unstable(feature = "iterator_step_by", - reason = "unstable replacement of Range::step_by", - issue = "27741")] +#[stable(feature = "iterator_step_by", since = "1.28.0")] #[derive(Clone, Debug)] pub struct StepBy { iter: I, @@ -683,9 +681,7 @@ pub struct StepBy { first_take: bool, } -#[unstable(feature = "iterator_step_by", - reason = "unstable replacement of Range::step_by", - issue = "27741")] +#[stable(feature = "iterator_step_by", since = "1.28.0")] impl Iterator for StepBy where I: Iterator { type Item = I::Item; @@ -757,9 +753,7 @@ impl Iterator for StepBy where I: Iterator { } // StepBy can only make the iterator shorter, so the len will still fit. -#[unstable(feature = "iterator_step_by", - reason = "unstable replacement of Range::step_by", - issue = "27741")] +#[stable(feature = "iterator_step_by", since = "1.28.0")] impl ExactSizeIterator for StepBy where I: ExactSizeIterator {} /// An iterator that strings two iterators together. diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 13189d532ab..7c62d0d758d 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -23,7 +23,6 @@ #![feature(flt2dec)] #![feature(fmt_internals)] #![feature(hashmap_internals)] -#![feature(iterator_step_by)] #![feature(iterator_flatten)] #![feature(iterator_repeat_with)] #![feature(pattern)] diff --git a/src/test/run-pass/range_inclusive.rs b/src/test/run-pass/range_inclusive.rs index 5d46bfab887..b08d16e5088 100644 --- a/src/test/run-pass/range_inclusive.rs +++ b/src/test/run-pass/range_inclusive.rs @@ -10,8 +10,6 @@ // Test inclusive range syntax. -#![feature(iterator_step_by)] - use std::ops::{RangeInclusive, RangeToInclusive}; fn foo() -> isize { 42 } diff --git a/src/test/run-pass/sync-send-iterators-in-libcore.rs b/src/test/run-pass/sync-send-iterators-in-libcore.rs index c11a0d391a4..bb190543ecd 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcore.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcore.rs @@ -14,7 +14,6 @@ #![feature(iter_empty)] #![feature(iter_once)] #![feature(iter_unfold)] -#![feature(iterator_step_by)] #![feature(str_escape)] use std::iter::{empty, once, repeat}; -- cgit 1.4.1-3-g733a5 From e44ad61a2d8e3bac1d2cbf2467a7202250b8a77e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 30 Apr 2018 10:55:24 +0200 Subject: implement #[panic_implementation] --- src/libcore/macros.rs | 22 +++++ src/libcore/panic.rs | 6 +- src/libcore/panicking.rs | 40 +++++++++ src/librustc/middle/dead.rs | 2 +- src/librustc/middle/lang_items.rs | 5 +- src/librustc/middle/weak_lang_items.rs | 2 +- src/librustc_typeck/check/mod.rs | 44 +++++++++- src/libstd/lib.rs | 2 + src/libstd/panicking.rs | 97 +++++++++++++++++++++- src/libsyntax/feature_gate.rs | 9 ++ src/test/compile-fail/duplicate_entry_error.rs | 8 +- .../feature-gate-panic-implementation.rs | 21 +++++ src/test/compile-fail/no_owned_box_lang_item.rs | 2 +- .../panic-implementation-bad-signature-1.rs | 24 ++++++ .../panic-implementation-bad-signature-2.rs | 25 ++++++ .../panic-implementation-bad-signature-3.rs | 22 +++++ .../compile-fail/panic-implementation-duplicate.rs | 28 +++++++ .../panic-implementation-requires-panic-info.rs | 26 ++++++ .../auxiliary/panic-runtime-lang-items.rs | 6 +- src/test/compile-fail/weak-lang-item.rs | 2 +- src/test/ui/error-codes/E0152.rs | 2 +- src/test/ui/error-codes/E0152.stderr | 2 +- 22 files changed, 379 insertions(+), 18 deletions(-) create mode 100644 src/test/compile-fail/feature-gate-panic-implementation.rs create mode 100644 src/test/compile-fail/panic-implementation-bad-signature-1.rs create mode 100644 src/test/compile-fail/panic-implementation-bad-signature-2.rs create mode 100644 src/test/compile-fail/panic-implementation-bad-signature-3.rs create mode 100644 src/test/compile-fail/panic-implementation-duplicate.rs create mode 100644 src/test/compile-fail/panic-implementation-requires-panic-info.rs (limited to 'src/libcore') diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index c830c22ee5f..f98626d939d 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -9,6 +9,7 @@ // except according to those terms. /// Entry point of thread panic, for details, see std::macros +#[cfg(stage0)] #[macro_export] #[allow_internal_unstable] #[stable(feature = "core", since = "1.6.0")] @@ -28,6 +29,27 @@ macro_rules! panic { }); } +/// Entry point of thread panic, for details, see std::macros +#[cfg(not(stage0))] +#[macro_export] +#[allow_internal_unstable] +#[stable(feature = "core", since = "1.6.0")] +macro_rules! panic { + () => ( + panic!("explicit panic") + ); + ($msg:expr) => ({ + $crate::panicking::panic_payload($msg, &(file!(), line!(), __rust_unstable_column!())) + }); + ($msg:expr,) => ( + panic!($msg) + ); + ($fmt:expr, $($arg:tt)+) => ({ + $crate::panicking::panic_fmt(format_args!($fmt, $($arg)*), + &(file!(), line!(), __rust_unstable_column!())) + }); +} + /// Asserts that two expressions are equal to each other (using [`PartialEq`]). /// /// On panic, this macro will print the values of the expressions with their diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 27ec4aaac75..37ae05309af 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -35,6 +35,7 @@ use fmt; /// /// panic!("Normal panic"); /// ``` +#[cfg_attr(not(stage0), lang = "panic_info")] #[stable(feature = "panic_hooks", since = "1.10.0")] #[derive(Debug)] pub struct PanicInfo<'a> { @@ -53,7 +54,8 @@ impl<'a> PanicInfo<'a> { pub fn internal_constructor(message: Option<&'a fmt::Arguments<'a>>, location: Location<'a>) -> Self { - PanicInfo { payload: &(), location, message } + struct NoPayload; + PanicInfo { payload: &NoPayload, location, message } } #[doc(hidden)] @@ -121,7 +123,7 @@ impl<'a> PanicInfo<'a> { #[stable(feature = "panic_hooks", since = "1.10.0")] pub fn location(&self) -> Option<&Location> { // NOTE: If this is changed to sometimes return None, - // deal with that case in std::panicking::default_hook. + // deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt. Some(&self.location) } } diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 6b3dc75af46..1470a01e0e6 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -36,7 +36,33 @@ and related macros", issue = "0")] +#[cfg(not(stage0))] +use any::Any; use fmt; +#[cfg(not(stage0))] +use panic::{Location, PanicInfo}; + +#[cfg(not(stage0))] +#[allow(improper_ctypes)] // PanicInfo contains a trait object which is not FFI safe +extern "C" { + #[lang = "panic_impl"] + fn panic_impl(pi: &PanicInfo) -> !; +} + +#[cfg(not(stage0))] +#[cold] #[inline(never)] +pub fn panic_payload(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! +where + M: Any + Send, +{ + let (file, line, col) = *file_line_col; + let mut pi = PanicInfo::internal_constructor( + None, + Location::internal_constructor(file, line, col), + ); + pi.set_payload(&msg); + unsafe { panic_impl(&pi) } +} #[cold] #[inline(never)] // this is the slow path, always #[lang = "panic"] @@ -59,6 +85,7 @@ fn panic_bounds_check(file_line_col: &(&'static str, u32, u32), len, index), file_line_col) } +#[cfg(stage0)] #[cold] #[inline(never)] pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { #[allow(improper_ctypes)] @@ -70,3 +97,16 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) let (file, line, col) = *file_line_col; unsafe { panic_impl(fmt, file, line, col) } } + +#[cfg(not(stage0))] +#[cold] #[inline(never)] +pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { + struct NoPayload; + + let (file, line, col) = *file_line_col; + let pi = PanicInfo::internal_constructor( + Some(&fmt), + Location::internal_constructor(file, line, col), + ); + unsafe { panic_impl(&pi) } +} diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index e3b20789714..7ebc0d4a4de 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -284,7 +284,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt, id: ast::NodeId, attrs: &[ast::Attribute]) -> bool { - if attr::contains_name(attrs, "lang") { + if attr::contains_name(attrs, "lang") || attr::contains_name(attrs, "panic_implementation") { return true; } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index d70f994e87b..fe676919a7d 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -185,6 +185,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { if let Some(value) = attribute.value_str() { return Some((value, attribute.span)); } + } else if attribute.check_name("panic_implementation") { + return Some((Symbol::intern("panic_impl"), attribute.span)) } } @@ -299,7 +301,8 @@ language_item_table! { // lang item, but do not have it defined. PanicFnLangItem, "panic", panic_fn; PanicBoundsCheckFnLangItem, "panic_bounds_check", panic_bounds_check_fn; - PanicFmtLangItem, "panic_fmt", panic_fmt; + PanicInfoLangItem, "panic_info", panic_info; + PanicImplLangItem, "panic_impl", panic_impl; ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn; BoxFreeFnLangItem, "box_free", box_free_fn; diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 42e4d3861ba..3c2ea047218 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -148,7 +148,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { ) } weak_lang_items! { - panic_fmt, PanicFmtLangItem, rust_begin_unwind; + panic_impl, PanicImplLangItem, rust_begin_unwind; eh_personality, EhPersonalityLangItem, rust_eh_personality; eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume; oom, OomLangItem, rust_oom; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 90b974fb972..5c33eb5f0af 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -96,7 +96,7 @@ use rustc::middle::region; use rustc::mir::interpret::{GlobalId}; use rustc::ty::subst::{UnpackedKind, Subst, Substs}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; -use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate}; +use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind}; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::fold::TypeFoldable; use rustc::ty::maps::Providers; @@ -1129,6 +1129,48 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, } } + // Check that a function marked as `#[panic_implementation]` has signature `fn(&PanicInfo) -> !` + if let Some(panic_impl_did) = fcx.tcx.lang_items().panic_impl() { + if panic_impl_did == fn_hir_id.owner_def_id() { + if let Some(panic_info_did) = fcx.tcx.lang_items().panic_info() { + if ret_ty.sty != ty::TyNever { + fcx.tcx.sess.span_err( + decl.output.span(), + "return type should be `!`", + ); + } + + let inputs = fn_sig.inputs(); + let span = fcx.tcx.hir.span(fn_id); + if inputs.len() == 1 { + let arg_is_panic_info = match inputs[0].sty { + ty::TyRef(region, ty::TypeAndMut { ty, mutbl }) => match ty.sty { + ty::TyAdt(ref adt, _) => { + adt.did == panic_info_did && + mutbl == hir::Mutability::MutImmutable && + *region != RegionKind::ReStatic + }, + _ => false, + }, + _ => false, + }; + + if !arg_is_panic_info { + fcx.tcx.sess.span_err( + decl.inputs[0].span, + "argument should be `&PanicInfo`", + ); + } + } else { + fcx.tcx.sess.span_err(span, "function should have one argument"); + } + } else { + fcx.tcx.sess.err("language item required, but not found: `panic_info`"); + } + } + + } + (fcx, gen_ty) } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f7d06852f27..c576245edb7 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -317,6 +317,8 @@ #![cfg_attr(windows, feature(used))] #![feature(doc_alias)] #![feature(float_internals)] +#![feature(panic_info_message)] +#![cfg_attr(not(stage0), feature(panic_implementation))] #![default_lib_allocator] diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 403056240bf..6bb098310de 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -186,7 +186,7 @@ fn default_hook(info: &PanicInfo) { let location = info.location().unwrap(); // The current implementation always returns Some - let msg = match info.payload().downcast_ref::<&'static str>() { + let msg = match info.payload().downcast_ref::<&str>() { Some(s) => *s, None => match info.payload().downcast_ref::() { Some(s) => &s[..], @@ -319,6 +319,7 @@ pub fn panicking() -> bool { /// Entry point of panic from the libcore crate. #[cfg(not(test))] +#[cfg(stage0)] #[lang = "panic_fmt"] #[unwind(allowed)] pub extern fn rust_begin_panic(msg: fmt::Arguments, @@ -328,12 +329,22 @@ pub extern fn rust_begin_panic(msg: fmt::Arguments, begin_panic_fmt(&msg, &(file, line, col)) } +/// Entry point of panic from the libcore crate. +#[cfg(not(test))] +#[cfg(not(stage0))] +#[panic_implementation] +#[unwind(allowed)] +pub fn rust_begin_panic(info: &PanicInfo) -> ! { + continue_panic_fmt(&info) +} + /// The entry point for panicking with a formatted message. /// /// This is designed to reduce the amount of code required at the call /// site as much as possible (so that `panic!()` has as low an impact /// on (e.g.) the inlining of other functions as possible), by moving /// the actual formatting into this shared place. +#[cfg(stage0)] #[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "0")] @@ -381,12 +392,92 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, } } +/// The entry point for panicking with a formatted message. +/// +/// This is designed to reduce the amount of code required at the call +/// site as much as possible (so that `panic!()` has as low an impact +/// on (e.g.) the inlining of other functions as possible), by moving +/// the actual formatting into this shared place. +#[cfg(not(stage0))] +#[unstable(feature = "libstd_sys_internals", + reason = "used by the panic! macro", + issue = "0")] +#[inline(never)] #[cold] +pub fn begin_panic_fmt(msg: &fmt::Arguments, + file_line_col: &(&'static str, u32, u32)) -> ! { + let (file, line, col) = *file_line_col; + let info = PanicInfo::internal_constructor( + Some(msg), + Location::internal_constructor(file, line, col), + ); + continue_panic_fmt(&info) +} + +#[cfg(not(stage0))] +fn continue_panic_fmt(info: &PanicInfo) -> ! { + use fmt::Write; + + // We do two allocations here, unfortunately. But (a) they're + // required with the current scheme, and (b) we don't handle + // panic + OOM properly anyway (see comment in begin_panic + // below). + + let loc = info.location().unwrap(); // The current implementation always returns Some + let file_line_col = (loc.file(), loc.line(), loc.column()); + rust_panic_with_hook( + &mut PanicPayload::new(info.payload(), info.message()), + info.message(), + &file_line_col); + + struct PanicPayload<'a> { + payload: &'a (Any + Send), + msg: Option<&'a fmt::Arguments<'a>>, + string: Option, + } + + impl<'a> PanicPayload<'a> { + fn new(payload: &'a (Any + Send), msg: Option<&'a fmt::Arguments<'a>>) -> PanicPayload<'a> { + PanicPayload { payload, msg, string: None } + } + + + fn fill(&mut self) -> Option<&mut String> { + if let Some(msg) = self.msg.take() { + Some(self.string.get_or_insert_with(|| { + let mut s = String::new(); + drop(s.write_fmt(*msg)); + s + })) + } else { + None + } + } + } + + unsafe impl<'a> BoxMeUp for PanicPayload<'a> { + fn box_me_up(&mut self) -> *mut (Any + Send) { + if let Some(string) = self.fill() { + let contents = mem::replace(string, String::new()); + Box::into_raw(Box::new(contents)) + } else { + // We can't go from &(Any+Send) to Box so the payload is lost here + struct NoPayload; + Box::into_raw(Box::new(NoPayload)) + } + } + + fn get(&mut self) -> &(Any + Send) { + self.payload + } + } +} + /// This is the entry point of panicking for panic!() and assert!(). #[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "0")] #[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible -pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! { +pub fn begin_panic(msg: M, file_line_col: &(&str, u32, u32)) -> ! { // Note that this should be the only allocation performed in this code path. // Currently this means that panic!() on OOM will invoke this code path, // but then again we're not really ready for panic on OOM anyway. If @@ -431,7 +522,7 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 /// abort or unwind. fn rust_panic_with_hook(payload: &mut BoxMeUp, message: Option<&fmt::Arguments>, - file_line_col: &(&'static str, u32, u32)) -> ! { + file_line_col: &(&str, u32, u32)) -> ! { let (file, line, col) = *file_line_col; let panics = update_panic_count(1); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9b84713b0f9..7349745fefe 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -475,6 +475,9 @@ declare_features! ( // 'a: { break 'a; } (active, label_break_value, "1.28.0", Some(48594), None), + + // #[panic_implementation] + (active, panic_implementation, "1.28.0", Some(44489), None), ); declare_features! ( @@ -1069,6 +1072,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "attribute is currently unstable", cfg_fn!(wasm_custom_section))), + // RFC 2070 + ("panic_implementation", Normal, Gated(Stability::Unstable, + "panic_implementation", + "#[panic_implementation] is an unstable feature", + cfg_fn!(panic_implementation))), + // Crate level attributes ("crate_name", CrateLevel, Ungated), ("crate_type", CrateLevel, Ungated), diff --git a/src/test/compile-fail/duplicate_entry_error.rs b/src/test/compile-fail/duplicate_entry_error.rs index 485519e8c3d..176aa7cca53 100644 --- a/src/test/compile-fail/duplicate_entry_error.rs +++ b/src/test/compile-fail/duplicate_entry_error.rs @@ -14,9 +14,11 @@ #![feature(lang_items)] -#[lang = "panic_fmt"] -fn panic_fmt() -> ! { -//~^ ERROR: duplicate lang item found: `panic_fmt`. +use std::panic::PanicInfo; + +#[lang = "panic_impl"] +fn panic_impl(info: &PanicInfo) -> ! { +//~^ ERROR: duplicate lang item found: `panic_impl`. loop {} } diff --git a/src/test/compile-fail/feature-gate-panic-implementation.rs b/src/test/compile-fail/feature-gate-panic-implementation.rs new file mode 100644 index 00000000000..ae9fbc7b13b --- /dev/null +++ b/src/test/compile-fail/feature-gate-panic-implementation.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![no_std] +#![no_main] + +use core::panic::PanicInfo; + +#[panic_implementation] //~ ERROR #[panic_implementation] is an unstable feature (see issue #44489) +fn panic(info: &PanicInfo) -> ! { + loop {} +} diff --git a/src/test/compile-fail/no_owned_box_lang_item.rs b/src/test/compile-fail/no_owned_box_lang_item.rs index 72eb687adc6..1c2bf1573dc 100644 --- a/src/test/compile-fail/no_owned_box_lang_item.rs +++ b/src/test/compile-fail/no_owned_box_lang_item.rs @@ -21,4 +21,4 @@ fn main() { #[lang = "eh_personality"] extern fn eh_personality() {} #[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {} -#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } +#[lang = "panic_impl"] fn panic_impl() -> ! { loop {} } diff --git a/src/test/compile-fail/panic-implementation-bad-signature-1.rs b/src/test/compile-fail/panic-implementation-bad-signature-1.rs new file mode 100644 index 00000000000..fec11fdbd7b --- /dev/null +++ b/src/test/compile-fail/panic-implementation-bad-signature-1.rs @@ -0,0 +1,24 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![feature(panic_implementation)] +#![no_std] +#![no_main] + +use core::panic::PanicInfo; + +#[panic_implementation] +fn panic( + info: PanicInfo, //~ ERROR argument should be `&PanicInfo` +) -> () //~ ERROR return type should be `!` +{ +} diff --git a/src/test/compile-fail/panic-implementation-bad-signature-2.rs b/src/test/compile-fail/panic-implementation-bad-signature-2.rs new file mode 100644 index 00000000000..2a628c05699 --- /dev/null +++ b/src/test/compile-fail/panic-implementation-bad-signature-2.rs @@ -0,0 +1,25 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![feature(panic_implementation)] +#![no_std] +#![no_main] + +use core::panic::PanicInfo; + +#[panic_implementation] +fn panic( + info: &'static PanicInfo, //~ ERROR argument should be `&PanicInfo` +) -> ! +{ + loop {} +} diff --git a/src/test/compile-fail/panic-implementation-bad-signature-3.rs b/src/test/compile-fail/panic-implementation-bad-signature-3.rs new file mode 100644 index 00000000000..29337025b70 --- /dev/null +++ b/src/test/compile-fail/panic-implementation-bad-signature-3.rs @@ -0,0 +1,22 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![feature(panic_implementation)] +#![no_std] +#![no_main] + +use core::panic::PanicInfo; + +#[panic_implementation] +fn panic() -> ! { //~ ERROR function should have one argument + loop {} +} diff --git a/src/test/compile-fail/panic-implementation-duplicate.rs b/src/test/compile-fail/panic-implementation-duplicate.rs new file mode 100644 index 00000000000..017113af409 --- /dev/null +++ b/src/test/compile-fail/panic-implementation-duplicate.rs @@ -0,0 +1,28 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![feature(lang_items)] +#![feature(panic_implementation)] +#![no_std] +#![no_main] + +use core::panic::PanicInfo; + +#[panic_implementation] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +#[lang = "panic_impl"] +fn panic2(info: &PanicInfo) -> ! { //~ ERROR duplicate lang item found: `panic_impl`. + loop {} +} diff --git a/src/test/compile-fail/panic-implementation-requires-panic-info.rs b/src/test/compile-fail/panic-implementation-requires-panic-info.rs new file mode 100644 index 00000000000..597f44d9832 --- /dev/null +++ b/src/test/compile-fail/panic-implementation-requires-panic-info.rs @@ -0,0 +1,26 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort +// error-pattern: language item required, but not found: `panic_info` + +#![feature(lang_items)] +#![feature(no_core)] +#![feature(panic_implementation)] +#![no_core] +#![no_main] + +#[panic_implementation] +fn panic() -> ! { + loop {} +} + +#[lang = "sized"] +trait Sized {} diff --git a/src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-lang-items.rs b/src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-lang-items.rs index fbf70b3d3fe..d9848a554ab 100644 --- a/src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-lang-items.rs +++ b/src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-lang-items.rs @@ -15,8 +15,10 @@ #![no_std] #![feature(lang_items)] -#[lang = "panic_fmt"] -fn panic_fmt() {} +use core::panic::PanicInfo; + +#[lang = "panic_impl"] +fn panic_impl(info: &PanicInfo) -> ! { loop {} } #[lang = "eh_personality"] fn eh_personality() {} #[lang = "eh_unwind_resume"] diff --git a/src/test/compile-fail/weak-lang-item.rs b/src/test/compile-fail/weak-lang-item.rs index 8579611b938..7b988c3595f 100644 --- a/src/test/compile-fail/weak-lang-item.rs +++ b/src/test/compile-fail/weak-lang-item.rs @@ -9,7 +9,7 @@ // except according to those terms. // aux-build:weak-lang-items.rs -// error-pattern: language item required, but not found: `panic_fmt` +// error-pattern: language item required, but not found: `panic_impl` // error-pattern: language item required, but not found: `eh_personality` // ignore-wasm32-bare compiled with panic=abort, personality not required diff --git a/src/test/ui/error-codes/E0152.rs b/src/test/ui/error-codes/E0152.rs index ae501b94e3f..8fbad7b3ff3 100644 --- a/src/test/ui/error-codes/E0152.rs +++ b/src/test/ui/error-codes/E0152.rs @@ -10,7 +10,7 @@ #![feature(lang_items)] -#[lang = "panic_fmt"] +#[lang = "panic_impl"] struct Foo; //~ ERROR E0152 fn main() { diff --git a/src/test/ui/error-codes/E0152.stderr b/src/test/ui/error-codes/E0152.stderr index f67022bd6d3..c7f5f362efb 100644 --- a/src/test/ui/error-codes/E0152.stderr +++ b/src/test/ui/error-codes/E0152.stderr @@ -1,4 +1,4 @@ -error[E0152]: duplicate lang item found: `panic_fmt`. +error[E0152]: duplicate lang item found: `panic_impl`. --> $DIR/E0152.rs:14:1 | LL | struct Foo; //~ ERROR E0152 -- cgit 1.4.1-3-g733a5 From 63f18e108af98be931465fa0d2e7e998c5542aab Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 30 Apr 2018 10:57:11 +0200 Subject: s/panic_fmt/panic_impl/g in docs --- .../src/language-features/lang-items.md | 25 ++++++++++------------ .../unstable-book/src/language-features/used.md | 10 ++++++--- src/libcore/lib.rs | 2 +- src/librustc/diagnostics.rs | 6 +++--- 4 files changed, 22 insertions(+), 21 deletions(-) (limited to 'src/libcore') diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md index 6a7aea7f1c2..bac619fd4a3 100644 --- a/src/doc/unstable-book/src/language-features/lang-items.md +++ b/src/doc/unstable-book/src/language-features/lang-items.md @@ -19,6 +19,7 @@ sugar for dynamic allocations via `malloc` and `free`: #![feature(lang_items, box_syntax, start, libc, core_intrinsics)] #![no_std] use core::intrinsics; +use core::panic::PanicInfo; extern crate libc; @@ -50,7 +51,7 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize { } #[lang = "eh_personality"] extern fn rust_eh_personality() {} -#[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { unsafe { intrinsics::abort() } } +#[lang = "panic_impl"] extern fn rust_begin_panic(info: &PanicInfo) -> ! { unsafe { intrinsics::abort() } } #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} #[no_mangle] pub extern fn rust_eh_register_frames () {} #[no_mangle] pub extern fn rust_eh_unregister_frames () {} @@ -110,6 +111,7 @@ in the same format as C: #![feature(start)] #![no_std] use core::intrinsics; +use core::panic::PanicInfo; // Pull in the system libc library for what crt0.o likely requires. extern crate libc; @@ -134,12 +136,9 @@ pub extern fn rust_eh_personality() { pub extern fn rust_eh_unwind_resume() { } -#[lang = "panic_fmt"] +#[lang = "panic_impl"] #[no_mangle] -pub extern fn rust_begin_panic(_msg: core::fmt::Arguments, - _file: &'static str, - _line: u32, - _column: u32) -> ! { +pub extern fn rust_begin_panic(info: &PanicInfo) -> ! { unsafe { intrinsics::abort() } } ``` @@ -155,6 +154,7 @@ compiler's name mangling too: #![no_std] #![no_main] use core::intrinsics; +use core::panic::PanicInfo; // Pull in the system libc library for what crt0.o likely requires. extern crate libc; @@ -179,12 +179,9 @@ pub extern fn rust_eh_personality() { pub extern fn rust_eh_unwind_resume() { } -#[lang = "panic_fmt"] +#[lang = "panic_impl"] #[no_mangle] -pub extern fn rust_begin_panic(_msg: core::fmt::Arguments, - _file: &'static str, - _line: u32, - _column: u32) -> ! { +pub extern fn rust_begin_panic(info: &PanicInfo) -> ! { unsafe { intrinsics::abort() } } ``` @@ -215,7 +212,7 @@ called. The language item's name is `eh_personality`. The second function, `rust_begin_panic`, is also used by the failure mechanisms of the compiler. When a panic happens, this controls the message that's displayed on -the screen. While the language item's name is `panic_fmt`, the symbol name is +the screen. While the language item's name is `panic_impl`, the symbol name is `rust_begin_panic`. A third function, `rust_eh_unwind_resume`, is also needed if the `custom_unwind_resume` @@ -259,8 +256,8 @@ the source code. - `msvc_try_filter`: `libpanic_unwind/seh.rs` (SEH) - `panic`: `libcore/panicking.rs` - `panic_bounds_check`: `libcore/panicking.rs` - - `panic_fmt`: `libcore/panicking.rs` - - `panic_fmt`: `libstd/panicking.rs` + - `panic_impl`: `libcore/panicking.rs` + - `panic_impl`: `libstd/panicking.rs` - Allocations - `owned_box`: `liballoc/boxed.rs` - `exchange_malloc`: `liballoc/heap.rs` diff --git a/src/doc/unstable-book/src/language-features/used.md b/src/doc/unstable-book/src/language-features/used.md index 75a8b2774f4..c3b7f2e41e1 100644 --- a/src/doc/unstable-book/src/language-features/used.md +++ b/src/doc/unstable-book/src/language-features/used.md @@ -87,11 +87,13 @@ This condition can be met using `#[used]` and `#[link_section]` plus a linker script. ``` rust,ignore -#![feature(lang_items)] +#![feature(panic_implementation)] #![feature(used)] #![no_main] #![no_std] +use core::panic::PanicInfo; + extern "C" fn reset_handler() -> ! { loop {} } @@ -100,8 +102,10 @@ extern "C" fn reset_handler() -> ! { #[used] static RESET_HANDLER: extern "C" fn() -> ! = reset_handler; -#[lang = "panic_fmt"] -fn panic_fmt() {} +#[panic_implementation] +fn panic_impl(info: &PanicInfo) -> ! { + loop {} +} ``` ``` text diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 32cf31231c3..e6ab64a3312 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -41,7 +41,7 @@ //! dictate the panic message, the file at which panic was invoked, and the //! line and column inside the file. It is up to consumers of this core //! library to define this panic function; it is only required to never -//! return. This requires a `lang` attribute named `panic_fmt`. +//! return. This requires a `lang` attribute named `panic_impl`. //! //! * `rust_eh_personality` - is used by the failure mechanisms of the //! compiler. This is often mapped to GCC's personality function, but crates diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 2662e709991..61f05ca3473 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -637,8 +637,8 @@ Erroneous code example: ```compile_fail,E0152 #![feature(lang_items)] -#[lang = "panic_fmt"] -struct Foo; // error: duplicate lang item found: `panic_fmt` +#[lang = "panic_impl"] +struct Foo; // error: duplicate lang item found: `panic_impl` ``` Lang items are already implemented in the standard library. Unless you are @@ -824,7 +824,7 @@ A list of available external lang items is available in #![feature(lang_items)] extern "C" { - #[lang = "panic_fmt"] // ok! + #[lang = "panic_impl"] // ok! fn cake(); } ``` -- cgit 1.4.1-3-g733a5 From b442348d53ca37b6d22cd6e40c305d89f7782538 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 1 May 2018 03:03:20 +0200 Subject: remove unused `struct NoPayload` --- src/libcore/panicking.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 1470a01e0e6..71a1eb2f7a4 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -101,8 +101,6 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) #[cfg(not(stage0))] #[cold] #[inline(never)] pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { - struct NoPayload; - let (file, line, col) = *file_line_col; let pi = PanicInfo::internal_constructor( Some(&fmt), -- cgit 1.4.1-3-g733a5 From eb1936141611afa8ad9034c4093e1539df36548c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 1 May 2018 03:04:42 +0200 Subject: document that `panic_impl` never passes the FFI boundary --- src/libcore/panicking.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 71a1eb2f7a4..4b4fa73c478 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -42,9 +42,10 @@ use fmt; #[cfg(not(stage0))] use panic::{Location, PanicInfo}; +// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call #[cfg(not(stage0))] #[allow(improper_ctypes)] // PanicInfo contains a trait object which is not FFI safe -extern "C" { +extern "Rust" { #[lang = "panic_impl"] fn panic_impl(pi: &PanicInfo) -> !; } -- cgit 1.4.1-3-g733a5 From 430ad769008c0aaa40949a1d98a6f0e18e35ec65 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 16 May 2018 14:07:58 +0200 Subject: undo payload in core::panic! changes --- src/libcore/macros.rs | 22 ---------- src/libcore/panicking.rs | 32 +++----------- src/libstd/panicking.rs | 109 +++++++++++++---------------------------------- 3 files changed, 37 insertions(+), 126 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index f98626d939d..c830c22ee5f 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -9,7 +9,6 @@ // except according to those terms. /// Entry point of thread panic, for details, see std::macros -#[cfg(stage0)] #[macro_export] #[allow_internal_unstable] #[stable(feature = "core", since = "1.6.0")] @@ -29,27 +28,6 @@ macro_rules! panic { }); } -/// Entry point of thread panic, for details, see std::macros -#[cfg(not(stage0))] -#[macro_export] -#[allow_internal_unstable] -#[stable(feature = "core", since = "1.6.0")] -macro_rules! panic { - () => ( - panic!("explicit panic") - ); - ($msg:expr) => ({ - $crate::panicking::panic_payload($msg, &(file!(), line!(), __rust_unstable_column!())) - }); - ($msg:expr,) => ( - panic!($msg) - ); - ($fmt:expr, $($arg:tt)+) => ({ - $crate::panicking::panic_fmt(format_args!($fmt, $($arg)*), - &(file!(), line!(), __rust_unstable_column!())) - }); -} - /// Asserts that two expressions are equal to each other (using [`PartialEq`]). /// /// On panic, this macro will print the values of the expressions with their diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 4b4fa73c478..0d4f8d1141e 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -36,35 +36,10 @@ and related macros", issue = "0")] -#[cfg(not(stage0))] -use any::Any; use fmt; #[cfg(not(stage0))] use panic::{Location, PanicInfo}; -// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call -#[cfg(not(stage0))] -#[allow(improper_ctypes)] // PanicInfo contains a trait object which is not FFI safe -extern "Rust" { - #[lang = "panic_impl"] - fn panic_impl(pi: &PanicInfo) -> !; -} - -#[cfg(not(stage0))] -#[cold] #[inline(never)] -pub fn panic_payload(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! -where - M: Any + Send, -{ - let (file, line, col) = *file_line_col; - let mut pi = PanicInfo::internal_constructor( - None, - Location::internal_constructor(file, line, col), - ); - pi.set_payload(&msg); - unsafe { panic_impl(&pi) } -} - #[cold] #[inline(never)] // this is the slow path, always #[lang = "panic"] pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! { @@ -102,6 +77,13 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) #[cfg(not(stage0))] #[cold] #[inline(never)] pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { + // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call + #[allow(improper_ctypes)] // PanicInfo contains a trait object which is not FFI safe + extern "Rust" { + #[lang = "panic_impl"] + fn panic_impl(pi: &PanicInfo) -> !; + } + let (file, line, col) = *file_line_col; let pi = PanicInfo::internal_constructor( Some(&fmt), diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 1f80fb6f738..9d8052143b9 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -186,7 +186,7 @@ fn default_hook(info: &PanicInfo) { let location = info.location().unwrap(); // The current implementation always returns Some - let msg = match info.payload().downcast_ref::<&str>() { + let msg = match info.payload().downcast_ref::<&'static str>() { Some(s) => *s, None => match info.payload().downcast_ref::() { Some(s) => &s[..], @@ -351,44 +351,45 @@ pub fn rust_begin_panic(info: &PanicInfo) -> ! { #[inline(never)] #[cold] pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { - use fmt::Write; - // We do two allocations here, unfortunately. But (a) they're // required with the current scheme, and (b) we don't handle // panic + OOM properly anyway (see comment in begin_panic // below). rust_panic_with_hook(&mut PanicPayload::new(msg), Some(msg), file_line_col); +} + +// NOTE(stage0) move into `continue_panic_fmt` on next stage0 update +struct PanicPayload<'a> { + inner: &'a fmt::Arguments<'a>, + string: Option, +} - struct PanicPayload<'a> { - inner: &'a fmt::Arguments<'a>, - string: Option, +impl<'a> PanicPayload<'a> { + fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> { + PanicPayload { inner, string: None } } - impl<'a> PanicPayload<'a> { - fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> { - PanicPayload { inner, string: None } - } + fn fill(&mut self) -> &mut String { + use fmt::Write; - fn fill(&mut self) -> &mut String { - let inner = self.inner; - self.string.get_or_insert_with(|| { - let mut s = String::new(); - drop(s.write_fmt(*inner)); - s - }) - } + let inner = self.inner; + self.string.get_or_insert_with(|| { + let mut s = String::new(); + drop(s.write_fmt(*inner)); + s + }) } +} - unsafe impl<'a> BoxMeUp for PanicPayload<'a> { - fn box_me_up(&mut self) -> *mut (Any + Send) { - let contents = mem::replace(self.fill(), String::new()); - Box::into_raw(Box::new(contents)) - } +unsafe impl<'a> BoxMeUp for PanicPayload<'a> { + fn box_me_up(&mut self) -> *mut (Any + Send) { + let contents = mem::replace(self.fill(), String::new()); + Box::into_raw(Box::new(contents)) + } - fn get(&mut self) -> &(Any + Send) { - self.fill() - } + fn get(&mut self) -> &(Any + Send) { + self.fill() } } @@ -415,68 +416,18 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, #[cfg(not(stage0))] fn continue_panic_fmt(info: &PanicInfo) -> ! { - use fmt::Write; - // We do two allocations here, unfortunately. But (a) they're // required with the current scheme, and (b) we don't handle // panic + OOM properly anyway (see comment in begin_panic // below). let loc = info.location().unwrap(); // The current implementation always returns Some + let msg = info.message().unwrap(); // The current implementation always returns Some let file_line_col = (loc.file(), loc.line(), loc.column()); rust_panic_with_hook( - &mut PanicPayload::new(info.payload(), info.message()), + &mut PanicPayload::new(msg), info.message(), &file_line_col); - - struct PanicPayload<'a> { - payload: &'a (Any + Send), - msg: Option<&'a fmt::Arguments<'a>>, - string: Option, - } - - impl<'a> PanicPayload<'a> { - fn new(payload: &'a (Any + Send), msg: Option<&'a fmt::Arguments<'a>>) -> PanicPayload<'a> { - PanicPayload { payload, msg, string: None } - } - - fn fill(&mut self) -> Option<&mut String> { - if let Some(msg) = self.msg.cloned() { - Some(self.string.get_or_insert_with(|| { - let mut s = String::new(); - drop(s.write_fmt(msg)); - s - })) - } else { - None - } - } - } - - unsafe impl<'a> BoxMeUp for PanicPayload<'a> { - fn box_me_up(&mut self) -> *mut (Any + Send) { - if let Some(string) = self.fill() { - let contents = mem::replace(string, String::new()); - Box::into_raw(Box::new(contents)) - } else if let Some(s) = self.payload.downcast_ref::<&str>() { - Box::into_raw(Box::new(s.to_owned())) - } else if let Some(s) = self.payload.downcast_ref::() { - Box::into_raw(Box::new(s.clone())) - } else { - // We can't go from &(Any+Send) to Box so the payload is lost here - struct NoPayload; - Box::into_raw(Box::new(NoPayload)) - } - } - - fn get(&mut self) -> &(Any + Send) { - if let Some(s) = self.fill() { - s - } else { - self.payload - } - } - } } /// This is the entry point of panicking for panic!() and assert!(). @@ -484,7 +435,7 @@ fn continue_panic_fmt(info: &PanicInfo) -> ! { reason = "used by the panic! macro", issue = "0")] #[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible -pub fn begin_panic(msg: M, file_line_col: &(&str, u32, u32)) -> ! { +pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! { // Note that this should be the only allocation performed in this code path. // Currently this means that panic!() on OOM will invoke this code path, // but then again we're not really ready for panic on OOM anyway. If -- cgit 1.4.1-3-g733a5 From adaf8e6abfac277a8e5e835bbcd704b2848ae2af Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sun, 3 Jun 2018 17:33:49 +0300 Subject: Move TrustedLen and FusedIterator impl of Iter/IterMut into macro --- src/libcore/slice/mod.rs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index ab986e4c86d..f1ad5b169f0 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2513,6 +2513,12 @@ macro_rules! iterator { accum } } + + #[stable(feature = "fused", since = "1.26.0")] + impl<'a, T> FusedIterator for $name<'a, T> {} + + #[unstable(feature = "trusted_len", issue = "37572")] + unsafe impl<'a, T> TrustedLen for $name<'a, T> {} } } @@ -2639,12 +2645,6 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for Iter<'a, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl<'a, T> TrustedLen for Iter<'a, T> {} - #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Clone for Iter<'a, T> { fn clone(&self) -> Iter<'a, T> { Iter { ptr: self.ptr, end: self.end, _marker: self._marker } } @@ -2767,13 +2767,6 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> { } } -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for IterMut<'a, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl<'a, T> TrustedLen for IterMut<'a, T> {} - - // Return the number of elements of `T` from `start` to `end`. // Return the arithmetic difference if `T` is zero size. #[inline(always)] -- cgit 1.4.1-3-g733a5 From 325c676677081b5f680938a8618ca3db71a6de84 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sun, 3 Jun 2018 17:34:23 +0300 Subject: Remove mention of Slice/SliceMut traits from IterMut documentation These don't exist anymore. --- src/libcore/slice/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index f1ad5b169f0..29f86a88fc2 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2706,9 +2706,7 @@ impl<'a, T> IterMut<'a, T> { /// View the underlying data as a subslice of the original data. /// /// To avoid creating `&mut` references that alias, this is forced - /// to consume the iterator. Consider using the `Slice` and - /// `SliceMut` implementations for obtaining slices with more - /// restricted lifetimes that do not consume the iterator. + /// to consume the iterator. /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 10cf7bb328345373b1fe59e4d323bef65d06765a Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sun, 3 Jun 2018 17:38:49 +0300 Subject: Implement TrustedLen for Windows and the 4 Chunks iterators --- src/libcore/slice/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 29f86a88fc2..1dec7c3020d 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -3362,6 +3362,9 @@ impl<'a, T> DoubleEndedIterator for Windows<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Windows<'a, T> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for Windows<'a, T> {} + #[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Windows<'a, T> {} @@ -3481,6 +3484,9 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Chunks<'a, T> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for Chunks<'a, T> {} + #[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Chunks<'a, T> {} @@ -3597,6 +3603,9 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for ChunksMut<'a, T> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for ChunksMut<'a, T> {} + #[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for ChunksMut<'a, T> {} @@ -3707,6 +3716,9 @@ impl<'a, T> ExactSizeIterator for ExactChunks<'a, T> { } } +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for ExactChunks<'a, T> {} + #[unstable(feature = "exact_chunks", issue = "47115")] impl<'a, T> FusedIterator for ExactChunks<'a, T> {} @@ -3804,6 +3816,9 @@ impl<'a, T> ExactSizeIterator for ExactChunksMut<'a, T> { } } +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for ExactChunksMut<'a, T> {} + #[unstable(feature = "exact_chunks", issue = "47115")] impl<'a, T> FusedIterator for ExactChunksMut<'a, T> {} -- cgit 1.4.1-3-g733a5 From 804984836eb98fd61bc5f03aff8756a9c1cf2fa4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 3 Jun 2018 17:04:48 +0200 Subject: Reexport fmt::Alignment into std --- src/liballoc/fmt.rs | 2 ++ src/libcore/fmt/mod.rs | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs index a4e5373d907..b49ec0ae252 100644 --- a/src/liballoc/fmt.rs +++ b/src/liballoc/fmt.rs @@ -531,6 +531,8 @@ pub use core::fmt::Error; pub use core::fmt::{write, ArgumentV1, Arguments}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; +#[stable(feature = "fmt_flags_align", since = "1.28.0")] +pub use core::fmt::{Alignment}; use string; diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 0515eeed30b..d91bf463383 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1436,8 +1436,7 @@ impl<'a> Formatter<'a> { /// ``` /// extern crate core; /// - /// use std::fmt; - /// use core::fmt::Alignment; + /// use std::fmt::{self, Alignment}; /// /// struct Foo; /// -- cgit 1.4.1-3-g733a5 From eb3a73484b5d5b8cadbf92074c2cbe6a38cb11b1 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Tue, 29 May 2018 10:41:33 +0300 Subject: Move slice::exact_chunks directly above exact_chunks_mut for more consistent docs order See https://github.com/rust-lang/rust/issues/47115#issuecomment-392532855 --- src/libcore/slice/mod.rs | 70 ++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 35 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index c5792d62aa9..63f9a8097ba 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -691,41 +691,6 @@ impl [T] { Chunks { v: self, chunk_size: chunk_size } } - /// Returns an iterator over `chunk_size` elements of the slice at a - /// time. The chunks are slices and do not overlap. If `chunk_size` does - /// not divide the length of the slice, then the last up to `chunk_size-1` - /// elements will be omitted. - /// - /// Due to each chunk having exactly `chunk_size` elements, the compiler - /// can often optimize the resulting code better than in the case of - /// [`chunks`]. - /// - /// # Panics - /// - /// Panics if `chunk_size` is 0. - /// - /// # Examples - /// - /// ``` - /// #![feature(exact_chunks)] - /// - /// let slice = ['l', 'o', 'r', 'e', 'm']; - /// let mut iter = slice.exact_chunks(2); - /// assert_eq!(iter.next().unwrap(), &['l', 'o']); - /// assert_eq!(iter.next().unwrap(), &['r', 'e']); - /// assert!(iter.next().is_none()); - /// ``` - /// - /// [`chunks`]: #method.chunks - #[unstable(feature = "exact_chunks", issue = "47115")] - #[inline] - pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks { - assert!(chunk_size != 0); - let rem = self.len() % chunk_size; - let len = self.len() - rem; - ExactChunks { v: &self[..len], chunk_size: chunk_size} - } - /// Returns an iterator over `chunk_size` elements of the slice at a time. /// The chunks are mutable slices, and do not overlap. If `chunk_size` does /// not divide the length of the slice, then the last chunk will not @@ -761,6 +726,41 @@ impl [T] { ChunksMut { v: self, chunk_size: chunk_size } } + /// Returns an iterator over `chunk_size` elements of the slice at a + /// time. The chunks are slices and do not overlap. If `chunk_size` does + /// not divide the length of the slice, then the last up to `chunk_size-1` + /// elements will be omitted. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler + /// can often optimize the resulting code better than in the case of + /// [`chunks`]. + /// + /// # Panics + /// + /// Panics if `chunk_size` is 0. + /// + /// # Examples + /// + /// ``` + /// #![feature(exact_chunks)] + /// + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.exact_chunks(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`chunks`]: #method.chunks + #[unstable(feature = "exact_chunks", issue = "47115")] + #[inline] + pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks { + assert!(chunk_size != 0); + let rem = self.len() % chunk_size; + let len = self.len() - rem; + ExactChunks { v: &self[..len], chunk_size: chunk_size} + } + /// Returns an iterator over `chunk_size` elements of the slice at a time. /// The chunks are mutable slices, and do not overlap. If `chunk_size` does /// not divide the length of the slice, then the last up to `chunk_size-1` -- cgit 1.4.1-3-g733a5 From 903624fb8d845afac62b1fca2d9114c04ef35fea Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Mon, 4 Jun 2018 09:02:58 +0300 Subject: Add ExactChunks::remainder and ExactChunks::into_remainder These allow to get the leftover items of the slice that are not being iterated as part of the iterator due to not filling a complete chunk. The mutable version consumes the slice because otherwise we would either a) have to borrow the iterator instead of taking the lifetime of the underlying slice, which is not what *any* of the other iterator functions is doing, or b) would allow returning multiple mutable references to the same data The current behaviour of consuming the iterator is consistent with IterMut::into_slice for the normal iterator. --- src/libcore/slice/mod.rs | 48 ++++++++++++++++++++++++++++++++++++++-------- src/libcore/tests/slice.rs | 14 ++++++++++++++ 2 files changed, 54 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 63f9a8097ba..e5e47e4f653 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -729,7 +729,8 @@ impl [T] { /// Returns an iterator over `chunk_size` elements of the slice at a /// time. The chunks are slices and do not overlap. If `chunk_size` does /// not divide the length of the slice, then the last up to `chunk_size-1` - /// elements will be omitted. + /// elements will be omitted and can be retrieved from the `remainder` + /// function of the iterator. /// /// Due to each chunk having exactly `chunk_size` elements, the compiler /// can often optimize the resulting code better than in the case of @@ -758,14 +759,15 @@ impl [T] { assert!(chunk_size != 0); let rem = self.len() % chunk_size; let len = self.len() - rem; - ExactChunks { v: &self[..len], chunk_size: chunk_size} + let (fst, snd) = self.split_at(len); + ExactChunks { v: fst, rem: snd, chunk_size: chunk_size} } /// Returns an iterator over `chunk_size` elements of the slice at a time. /// The chunks are mutable slices, and do not overlap. If `chunk_size` does /// not divide the length of the slice, then the last up to `chunk_size-1` - /// elements will be omitted. - /// + /// elements will be omitted and can be retrieved from the `into_remainder` + /// function of the iterator. /// /// Due to each chunk having exactly `chunk_size` elements, the compiler /// can often optimize the resulting code better than in the case of @@ -799,7 +801,8 @@ impl [T] { assert!(chunk_size != 0); let rem = self.len() % chunk_size; let len = self.len() - rem; - ExactChunksMut { v: &mut self[..len], chunk_size: chunk_size} + let (fst, snd) = self.split_at_mut(len); + ExactChunksMut { v: fst, rem: snd, chunk_size: chunk_size} } /// Divides one slice into two at an index. @@ -3654,25 +3657,39 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { /// time). /// /// When the slice len is not evenly divided by the chunk size, the last -/// up to `chunk_size-1` elements will be omitted. +/// up to `chunk_size-1` elements will be omitted but can be retrieved from +/// the [`remainder`] function from the iterator. /// /// This struct is created by the [`exact_chunks`] method on [slices]. /// /// [`exact_chunks`]: ../../std/primitive.slice.html#method.exact_chunks +/// [`remainder`]: ../../std/slice/struct.ExactChunks.html#method.remainder /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] #[unstable(feature = "exact_chunks", issue = "47115")] pub struct ExactChunks<'a, T:'a> { v: &'a [T], + rem: &'a [T], chunk_size: usize } +#[unstable(feature = "exact_chunks", issue = "47115")] +impl<'a, T> ExactChunks<'a, T> { + /// Return the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `chunk_size-1` + /// elements. + pub fn remainder(&self) -> &'a [T] { + self.rem + } +} + // FIXME(#26925) Remove in favor of `#[derive(Clone)]` #[unstable(feature = "exact_chunks", issue = "47115")] impl<'a, T> Clone for ExactChunks<'a, T> { fn clone(&self) -> ExactChunks<'a, T> { ExactChunks { v: self.v, + rem: self.rem, chunk_size: self.chunk_size, } } @@ -3760,20 +3777,35 @@ unsafe impl<'a, T> TrustedRandomAccess for ExactChunks<'a, T> { } /// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` -/// elements at a time). When the slice len is not evenly divided by the chunk -/// size, the last up to `chunk_size-1` elements will be omitted. +/// elements at a time). +/// +/// When the slice len is not evenly divided by the chunk size, the last up to +/// `chunk_size-1` elements will be omitted but can be retrieved from the +/// [`into_remainder`] function from the iterator. /// /// This struct is created by the [`exact_chunks_mut`] method on [slices]. /// /// [`exact_chunks_mut`]: ../../std/primitive.slice.html#method.exact_chunks_mut +/// [`into_remainder`]: ../../std/slice/struct.ExactChunksMut.html#method.into_remainder /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] #[unstable(feature = "exact_chunks", issue = "47115")] pub struct ExactChunksMut<'a, T:'a> { v: &'a mut [T], + rem: &'a mut [T], chunk_size: usize } +#[unstable(feature = "exact_chunks", issue = "47115")] +impl<'a, T> ExactChunksMut<'a, T> { + /// Return the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `chunk_size-1` + /// elements. + pub fn into_remainder(self) -> &'a mut [T] { + self.rem + } +} + #[unstable(feature = "exact_chunks", issue = "47115")] impl<'a, T> Iterator for ExactChunksMut<'a, T> { type Item = &'a mut [T]; diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index fcd79222e16..cf937244911 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -259,6 +259,13 @@ fn test_exact_chunks_last() { assert_eq!(c2.last().unwrap(), &[2, 3]); } +#[test] +fn test_exact_chunks_remainder() { + let v: &[i32] = &[0, 1, 2, 3, 4]; + let c = v.exact_chunks(2); + assert_eq!(c.remainder(), &[4]); +} + #[test] fn test_exact_chunks_zip() { let v1: &[i32] = &[0, 1, 2, 3, 4]; @@ -310,6 +317,13 @@ fn test_exact_chunks_mut_last() { assert_eq!(c2.last().unwrap(), &[2, 3]); } +#[test] +fn test_exact_chunks_mut_remainder() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c = v.exact_chunks_mut(2); + assert_eq!(c.into_remainder(), &[4]); +} + #[test] fn test_exact_chunks_mut_zip() { let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; -- cgit 1.4.1-3-g733a5 From e7c122c5b58d4db2262b1f4325d9fe82d1423ad8 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 6 Jun 2018 12:54:25 +0200 Subject: Revert "Remove TryFrom impls that might become conditionally-infallible with a portability lint" This reverts commit 837d6c70233715a0ae8e15c703d40e3046a2f36a. Fixes https://github.com/rust-lang/rust/issues/49415 --- src/libcore/iter/range.rs | 75 +------------------------ src/libcore/num/mod.rs | 70 ++++++++++++++++++++---- src/libcore/tests/num/mod.rs | 127 +++++++++++++++++++++++++++++++++++++++++++ src/libstd/io/cursor.rs | 20 +------ 4 files changed, 191 insertions(+), 101 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 5896322f111..0b279f66b88 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -91,7 +91,7 @@ macro_rules! step_impl_unsigned { #[inline] #[allow(unreachable_patterns)] fn add_usize(&self, n: usize) -> Option { - match <$t>::private_try_from(n) { + match <$t>::try_from(n) { Ok(n_as_t) => self.checked_add(n_as_t), Err(_) => None, } @@ -123,7 +123,7 @@ macro_rules! step_impl_signed { #[inline] #[allow(unreachable_patterns)] fn add_usize(&self, n: usize) -> Option { - match <$unsigned>::private_try_from(n) { + match <$unsigned>::try_from(n) { Ok(n_as_unsigned) => { // Wrapping in unsigned space handles cases like // `-120_i8.add_usize(200) == Some(80_i8)`, @@ -461,74 +461,3 @@ impl DoubleEndedIterator for ops::RangeInclusive { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::RangeInclusive {} - -/// Compensate removal of some impls per -/// https://github.com/rust-lang/rust/pull/49305#issuecomment-376293243 -trait PrivateTryFromUsize: Sized { - fn private_try_from(n: usize) -> Result; -} - -impl PrivateTryFromUsize for T where T: TryFrom { - #[inline] - fn private_try_from(n: usize) -> Result { - T::try_from(n).map_err(|_| ()) - } -} - -// no possible bounds violation -macro_rules! try_from_unbounded { - ($($target:ty),*) => {$( - impl PrivateTryFromUsize for $target { - #[inline] - fn private_try_from(value: usize) -> Result { - Ok(value as $target) - } - } - )*} -} - -// unsigned to signed (only positive bound) -#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] -macro_rules! try_from_upper_bounded { - ($($target:ty),*) => {$( - impl PrivateTryFromUsize for $target { - #[inline] - fn private_try_from(u: usize) -> Result<$target, ()> { - if u > (<$target>::max_value() as usize) { - Err(()) - } else { - Ok(u as $target) - } - } - } - )*} -} - - -#[cfg(target_pointer_width = "16")] -mod ptr_try_from_impls { - use super::PrivateTryFromUsize; - - try_from_unbounded!(u16, u32, u64, u128); - try_from_unbounded!(i32, i64, i128); -} - -#[cfg(target_pointer_width = "32")] -mod ptr_try_from_impls { - use super::PrivateTryFromUsize; - - try_from_upper_bounded!(u16); - try_from_unbounded!(u32, u64, u128); - try_from_upper_bounded!(i32); - try_from_unbounded!(i64, i128); -} - -#[cfg(target_pointer_width = "64")] -mod ptr_try_from_impls { - use super::PrivateTryFromUsize; - - try_from_upper_bounded!(u16, u32); - try_from_unbounded!(u64, u128); - try_from_upper_bounded!(i32, i64); - try_from_unbounded!(i128); -} diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 26dd08b10b9..2389f6d4e1f 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4413,6 +4413,21 @@ impl From for TryFromIntError { } } +// no possible bounds violation +macro_rules! try_from_unbounded { + ($source:ty, $($target:ty),*) => {$( + #[unstable(feature = "try_from", issue = "33417")] + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + #[inline] + fn try_from(value: $source) -> Result { + Ok(value as $target) + } + } + )*} +} + // only negative bounds macro_rules! try_from_lower_bounded { ($source:ty, $($target:ty),*) => {$( @@ -4511,20 +4526,27 @@ try_from_both_bounded!(i128, u64, u32, u16, u8); try_from_upper_bounded!(usize, isize); try_from_lower_bounded!(isize, usize); -try_from_upper_bounded!(usize, u8); -try_from_upper_bounded!(usize, i8, i16); -try_from_both_bounded!(isize, u8); -try_from_both_bounded!(isize, i8); - #[cfg(target_pointer_width = "16")] mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - // Fallible across platfoms, only implementation differs + try_from_upper_bounded!(usize, u8); + try_from_unbounded!(usize, u16, u32, u64, u128); + try_from_upper_bounded!(usize, i8, i16); + try_from_unbounded!(usize, i32, i64, i128); + + try_from_both_bounded!(isize, u8); try_from_lower_bounded!(isize, u16, u32, u64, u128); + try_from_both_bounded!(isize, i8); + try_from_unbounded!(isize, i16, i32, i64, i128); + + rev!(try_from_upper_bounded, usize, u32, u64, u128); rev!(try_from_lower_bounded, usize, i8, i16); rev!(try_from_both_bounded, usize, i32, i64, i128); + + rev!(try_from_upper_bounded, isize, u16, u32, u64, u128); + rev!(try_from_both_bounded, isize, i32, i64, i128); } #[cfg(target_pointer_width = "32")] @@ -4532,11 +4554,25 @@ mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - // Fallible across platfoms, only implementation differs - try_from_both_bounded!(isize, u16); + try_from_upper_bounded!(usize, u8, u16); + try_from_unbounded!(usize, u32, u64, u128); + try_from_upper_bounded!(usize, i8, i16, i32); + try_from_unbounded!(usize, i64, i128); + + try_from_both_bounded!(isize, u8, u16); try_from_lower_bounded!(isize, u32, u64, u128); + try_from_both_bounded!(isize, i8, i16); + try_from_unbounded!(isize, i32, i64, i128); + + rev!(try_from_unbounded, usize, u32); + rev!(try_from_upper_bounded, usize, u64, u128); rev!(try_from_lower_bounded, usize, i8, i16, i32); rev!(try_from_both_bounded, usize, i64, i128); + + rev!(try_from_unbounded, isize, u16); + rev!(try_from_upper_bounded, isize, u32, u64, u128); + rev!(try_from_unbounded, isize, i32); + rev!(try_from_both_bounded, isize, i64, i128); } #[cfg(target_pointer_width = "64")] @@ -4544,11 +4580,25 @@ mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - // Fallible across platfoms, only implementation differs - try_from_both_bounded!(isize, u16, u32); + try_from_upper_bounded!(usize, u8, u16, u32); + try_from_unbounded!(usize, u64, u128); + try_from_upper_bounded!(usize, i8, i16, i32, i64); + try_from_unbounded!(usize, i128); + + try_from_both_bounded!(isize, u8, u16, u32); try_from_lower_bounded!(isize, u64, u128); + try_from_both_bounded!(isize, i8, i16, i32); + try_from_unbounded!(isize, i64, i128); + + rev!(try_from_unbounded, usize, u32, u64); + rev!(try_from_upper_bounded, usize, u128); rev!(try_from_lower_bounded, usize, i8, i16, i32, i64); rev!(try_from_both_bounded, usize, i128); + + rev!(try_from_unbounded, isize, u16, u32); + rev!(try_from_upper_bounded, isize, u64, u128); + rev!(try_from_unbounded, isize, i32, i64); + rev!(try_from_both_bounded, isize, i128); } #[doc(hidden)] diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index b5e6a019a22..00aed25aa1a 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -37,6 +37,15 @@ mod flt2dec; mod dec2flt; mod bignum; + +/// Adds the attribute to all items in the block. +macro_rules! cfg_block { + ($(#[$attr:meta]{$($it:item)*})*) => {$($( + #[$attr] + $it + )*)*} +} + /// Groups items that assume the pointer width is either 16/32/64, and has to be altered if /// support for larger/smaller pointer widths are added in the future. macro_rules! assume_usize_width { @@ -330,6 +339,42 @@ assume_usize_width! { test_impl_try_from_always_ok! { test_try_u16usize, u16, usize } test_impl_try_from_always_ok! { test_try_i16isize, i16, isize } + + test_impl_try_from_always_ok! { test_try_usizeu64, usize, u64 } + test_impl_try_from_always_ok! { test_try_usizeu128, usize, u128 } + test_impl_try_from_always_ok! { test_try_usizei128, usize, i128 } + + test_impl_try_from_always_ok! { test_try_isizei64, isize, i64 } + test_impl_try_from_always_ok! { test_try_isizei128, isize, i128 } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_always_ok! { test_try_usizeu16, usize, u16 } + test_impl_try_from_always_ok! { test_try_isizei16, isize, i16 } + test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } + test_impl_try_from_always_ok! { test_try_usizei32, usize, i32 } + test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } + test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } + test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } + test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } + test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } + test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } + test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } + test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } + test_impl_try_from_always_ok! { test_try_u32isize, u32, isize } + test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } + test_impl_try_from_always_ok! { test_try_u64usize, u64, usize } + test_impl_try_from_always_ok! { test_try_i64isize, i64, isize } + } + ); } /// Conversions where max of $source can be represented as $target, @@ -378,6 +423,24 @@ assume_usize_width! { test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu64, isize, u64 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu128, isize, u128 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeusize, isize, usize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu16, isize, u16 } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } + + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64usize, i64, usize } + } + ); } /// Conversions where max of $source can not be represented as $target, @@ -419,9 +482,29 @@ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i64, u128, i64 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i128, u128, i128 } assume_usize_width! { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64isize, u64, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128isize, u128, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei8, usize, i8 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei16, usize, i16 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizeisize, usize, isize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16isize, u16, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei64, usize, i64 } + } + ); } /// Conversions where min/max of $source can not be represented as $target. @@ -481,6 +564,34 @@ test_impl_try_from_same_sign_err! { test_try_i128i64, i128, i64 } assume_usize_width! { test_impl_try_from_same_sign_err! { test_try_usizeu8, usize, u8 } + test_impl_try_from_same_sign_err! { test_try_u128usize, u128, usize } + test_impl_try_from_same_sign_err! { test_try_i128isize, i128, isize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_same_sign_err! { test_try_u32usize, u32, usize } + test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } + + test_impl_try_from_same_sign_err! { test_try_i32isize, i32, isize } + test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } + test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } + + test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } + test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } + test_impl_try_from_same_sign_err! { test_try_usizeu32, usize, u32 } + + test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } + test_impl_try_from_same_sign_err! { test_try_isizei32, isize, i32 } + } + ); } /// Conversions where neither the min nor the max of $source can be represented by @@ -525,6 +636,22 @@ test_impl_try_from_signed_to_unsigned_err! { test_try_i128u64, i128, u64 } assume_usize_width! { test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu8, isize, u8 } test_impl_try_from_signed_to_unsigned_err! { test_try_i128usize, i128, usize } + + cfg_block! { + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_i32usize, i32, usize } + test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } + } + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } + + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } + } + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu32, isize, u32 } + } + } } macro_rules! test_float { diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 8ac52572810..aadd33b3954 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -10,6 +10,7 @@ use io::prelude::*; +use core::convert::TryInto; use cmp; use io::{self, Initializer, SeekFrom, Error, ErrorKind}; @@ -259,26 +260,9 @@ fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result Result { - if n <= (::max_value() as u64) { - Ok(n as usize) - } else { - Err(()) - } -} - -#[cfg(any(target_pointer_width = "64"))] -fn try_into(n: u64) -> Result { - Ok(n as usize) -} - // Resizing write implementation fn vec_write(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> io::Result { - let pos: usize = try_into(*pos_mut).map_err(|_| { + let pos: usize = (*pos_mut).try_into().map_err(|_| { Error::new(ErrorKind::InvalidInput, "cursor position exceeds maximum possible vector length") })?; -- cgit 1.4.1-3-g733a5 From 5c7ca77b173e170f7440ba2cb5898cfc33874681 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 6 Jun 2018 13:46:51 +0200 Subject: Make the size of Option a documented guarantee. Closes #49137, the tracking issue for `NonZero*`, as this was the last remaining open question. Note that `ptr::NonNull` already documents a similar guarantee. --- src/libcore/num/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 26dd08b10b9..c2da9006a8a 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -39,10 +39,10 @@ macro_rules! nonzero_integers { $( /// An integer that is known not to equal zero. /// - /// This may enable some memory layout optimization such as: + /// This enables some memory layout optimization. + /// For example, `Option` is the same size as `u32`: /// /// ```rust - /// # #![feature(nonzero)] /// use std::mem::size_of; /// assert_eq!(size_of::>(), size_of::()); /// ``` -- cgit 1.4.1-3-g733a5 From a6055c885917093faf37bcb834350df7b6ddca82 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 30 May 2018 18:23:10 -0700 Subject: Add Future and task system to the standard library --- src/liballoc/boxed.rs | 93 +++++++ src/liballoc/lib.rs | 6 + src/liballoc/task.rs | 140 +++++++++++ src/libcore/future.rs | 93 +++++++ src/libcore/lib.rs | 5 + src/libcore/task.rs | 513 +++++++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 16 ++ src/test/run-pass/futures-api.rs | 95 ++++++++ 8 files changed, 961 insertions(+) create mode 100644 src/liballoc/task.rs create mode 100644 src/libcore/future.rs create mode 100644 src/libcore/task.rs create mode 100644 src/test/run-pass/futures-api.rs (limited to 'src/libcore') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index a83ce7f379f..a64b94b6517 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -59,12 +59,14 @@ use core::any::Any; use core::borrow; use core::cmp::Ordering; use core::fmt; +use core::future::Future; use core::hash::{Hash, Hasher}; use core::iter::FusedIterator; use core::marker::{Unpin, Unsize}; use core::mem::{self, PinMut}; use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; use core::ptr::{self, NonNull, Unique}; +use core::task::{Context, Poll, UnsafePoll, TaskObj}; use core::convert::From; use raw_vec::RawVec; @@ -755,6 +757,7 @@ impl Generator for Box /// A pinned, heap allocated reference. #[unstable(feature = "pin", issue = "49150")] #[fundamental] +#[repr(transparent)] pub struct PinBox { inner: Box, } @@ -771,14 +774,72 @@ impl PinBox { #[unstable(feature = "pin", issue = "49150")] impl PinBox { /// Get a pinned reference to the data in this PinBox. + #[inline] pub fn as_pin_mut<'a>(&'a mut self) -> PinMut<'a, T> { unsafe { PinMut::new_unchecked(&mut *self.inner) } } + /// Constructs a `PinBox` from a raw pointer. + /// + /// After calling this function, the raw pointer is owned by the + /// resulting `PinBox`. Specifically, the `PinBox` destructor will call + /// the destructor of `T` and free the allocated memory. Since the + /// way `PinBox` allocates and releases memory is unspecified, the + /// only valid pointer to pass to this function is the one taken + /// from another `PinBox` via the [`PinBox::into_raw`] function. + /// + /// This function is unsafe because improper use may lead to + /// memory problems. For example, a double-free may occur if the + /// function is called twice on the same raw pointer. + /// + /// [`PinBox::into_raw`]: struct.PinBox.html#method.into_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(pin)] + /// use std::boxed::PinBox; + /// let x = PinBox::new(5); + /// let ptr = PinBox::into_raw(x); + /// let x = unsafe { PinBox::from_raw(ptr) }; + /// ``` + #[inline] + pub unsafe fn from_raw(raw: *mut T) -> Self { + PinBox { inner: Box::from_raw(raw) } + } + + /// Consumes the `PinBox`, returning the wrapped raw pointer. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `PinBox`. In particular, the + /// caller should properly destroy `T` and release the memory. The + /// proper way to do so is to convert the raw pointer back into a + /// `PinBox` with the [`PinBox::from_raw`] function. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `PinBox::into_raw(b)` instead of `b.into_raw()`. This + /// is so that there is no conflict with a method on the inner type. + /// + /// [`PinBox::from_raw`]: struct.PinBox.html#method.from_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(pin)] + /// use std::boxed::PinBox; + /// let x = PinBox::new(5); + /// let ptr = PinBox::into_raw(x); + /// ``` + #[inline] + pub fn into_raw(b: PinBox) -> *mut T { + Box::into_raw(b.inner) + } + /// Get a mutable reference to the data inside this PinBox. /// /// This function is unsafe. Users must guarantee that the data is never /// moved out of this reference. + #[inline] pub unsafe fn get_mut<'a>(this: &'a mut PinBox) -> &'a mut T { &mut *this.inner } @@ -787,6 +848,7 @@ impl PinBox { /// /// This function is unsafe. Users must guarantee that the data is never /// moved out of the box. + #[inline] pub unsafe fn unpin(this: PinBox) -> Box { this.inner } @@ -851,3 +913,34 @@ impl, U: ?Sized> CoerceUnsized> for PinBox {} #[unstable(feature = "pin", issue = "49150")] impl Unpin for PinBox {} + +#[unstable(feature = "futures_api", issue = "50547")] +unsafe impl + Send + 'static> UnsafePoll for PinBox { + fn into_raw(self) -> *mut () { + PinBox::into_raw(self) as *mut () + } + + unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()> { + let ptr = task as *mut F; + let pin: PinMut = PinMut::new_unchecked(&mut *ptr); + pin.poll(cx) + } + + unsafe fn drop(task: *mut ()) { + drop(PinBox::from_raw(task as *mut F)) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +impl + Send + 'static> From> for TaskObj { + fn from(boxed: PinBox) -> Self { + TaskObj::from_poll_task(boxed) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +impl + Send + 'static> From> for TaskObj { + fn from(boxed: Box) -> Self { + TaskObj::from_poll_task(PinBox::from(boxed)) + } +} diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 91de3ad0c39..e0729d3a467 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -95,6 +95,7 @@ #![feature(fmt_internals)] #![feature(from_ref)] #![feature(fundamental)] +#![feature(futures_api)] #![feature(lang_items)] #![feature(libc)] #![feature(needs_allocator)] @@ -103,6 +104,7 @@ #![feature(pin)] #![feature(ptr_internals)] #![feature(ptr_offset_from)] +#![feature(repr_transparent)] #![feature(rustc_attrs)] #![feature(slice_get_slice)] #![feature(specialization)] @@ -156,6 +158,10 @@ pub mod heap { pub use alloc::*; } +#[unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] +pub mod task; // Primitive types using the heaps above diff --git a/src/liballoc/task.rs b/src/liballoc/task.rs new file mode 100644 index 00000000000..7b1947b56b8 --- /dev/null +++ b/src/liballoc/task.rs @@ -0,0 +1,140 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Types and Traits for working with asynchronous tasks. + +pub use core::task::*; + +#[cfg(target_has_atomic = "ptr")] +pub use self::if_arc::*; + +#[cfg(target_has_atomic = "ptr")] +mod if_arc { + use super::*; + use arc::Arc; + use core::marker::PhantomData; + use core::mem; + use core::ptr::{self, NonNull}; + + /// A way of waking up a specific task. + /// + /// Any task executor must provide a way of signaling that a task it owns + /// is ready to be `poll`ed again. Executors do so by implementing this trait. + pub trait Wake: Send + Sync { + /// Indicates that the associated task is ready to make progress and should + /// be `poll`ed. + /// + /// Executors generally maintain a queue of "ready" tasks; `wake` should place + /// the associated task onto this queue. + fn wake(arc_self: &Arc); + + /// Indicates that the associated task is ready to make progress and should + /// be `poll`ed. This function is like `wake`, but can only be called from the + /// thread on which this `Wake` was created. + /// + /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place + /// the associated task onto this queue. + #[inline] + unsafe fn wake_local(arc_self: &Arc) { + Self::wake(arc_self); + } + } + + #[cfg(target_has_atomic = "ptr")] + struct ArcWrapped(PhantomData); + + unsafe impl UnsafeWake for ArcWrapped { + #[inline] + unsafe fn clone_raw(&self) -> Waker { + let me: *const ArcWrapped = self; + let arc = (*(&me as *const *const ArcWrapped as *const Arc)).clone(); + Waker::from(arc) + } + + #[inline] + unsafe fn drop_raw(&self) { + let mut me: *const ArcWrapped = self; + let me = &mut me as *mut *const ArcWrapped as *mut Arc; + ptr::drop_in_place(me); + } + + #[inline] + unsafe fn wake(&self) { + let me: *const ArcWrapped = self; + T::wake(&*(&me as *const *const ArcWrapped as *const Arc)) + } + + #[inline] + unsafe fn wake_local(&self) { + let me: *const ArcWrapped = self; + T::wake_local(&*(&me as *const *const ArcWrapped as *const Arc)) + } + } + + impl From> for Waker + where T: Wake + 'static, + { + fn from(rc: Arc) -> Self { + unsafe { + let ptr = mem::transmute::, NonNull>>(rc); + Waker::new(ptr) + } + } + } + + /// Creates a `LocalWaker` from a local `wake`. + /// + /// This function requires that `wake` is "local" (created on the current thread). + /// The resulting `LocalWaker` will call `wake.wake_local()` when awoken, and + /// will call `wake.wake()` if awoken after being converted to a `Waker`. + #[inline] + pub unsafe fn local_waker(wake: Arc) -> LocalWaker { + let ptr = mem::transmute::, NonNull>>(wake); + LocalWaker::new(ptr) + } + + struct NonLocalAsLocal(ArcWrapped); + + unsafe impl UnsafeWake for NonLocalAsLocal { + #[inline] + unsafe fn clone_raw(&self) -> Waker { + self.0.clone_raw() + } + + #[inline] + unsafe fn drop_raw(&self) { + self.0.drop_raw() + } + + #[inline] + unsafe fn wake(&self) { + self.0.wake() + } + + #[inline] + unsafe fn wake_local(&self) { + // Since we're nonlocal, we can't call wake_local + self.0.wake() + } + } + + /// Creates a `LocalWaker` from a non-local `wake`. + /// + /// This function is similar to `local_waker`, but does not require that `wake` + /// is local to the current thread. The resulting `LocalWaker` will call + /// `wake.wake()` when awoken. + #[inline] + pub fn local_waker_from_nonlocal(wake: Arc) -> LocalWaker { + unsafe { + let ptr = mem::transmute::, NonNull>>(wake); + LocalWaker::new(ptr) + } + } +} diff --git a/src/libcore/future.rs b/src/libcore/future.rs new file mode 100644 index 00000000000..b4d087f8edb --- /dev/null +++ b/src/libcore/future.rs @@ -0,0 +1,93 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +//! Asynchronous values. + +use mem::PinMut; +use task::{self, Poll}; + +/// A future represents an asychronous computation. +/// +/// A future is a value that may not have finished computing yet. This kind of +/// "asynchronous value" makes it possible for a thread to continue doing useful +/// work while it waits for the value to become available. +/// +/// # The `poll` method +/// +/// The core method of future, `poll`, *attempts* to resolve the future into a +/// final value. This method does not block if the value is not ready. Instead, +/// the current task is scheduled to be woken up when it's possible to make +/// further progress by `poll`ing again. The wake up is performed using +/// `cx.waker()`, a handle for waking up the current task. +/// +/// When using a future, you generally won't call `poll` directly, but instead +/// `await!` the value. +pub trait Future { + /// The result of the `Future`. + type Output; + + /// Attempt to resolve the future to a final value, registering + /// the current task for wakeup if the value is not yet available. + /// + /// # Return value + /// + /// This function returns: + /// + /// - `Poll::Pending` if the future is not ready yet + /// - `Poll::Ready(val)` with the result `val` of this future if it finished + /// successfully. + /// + /// Once a future has finished, clients should not `poll` it again. + /// + /// When a future is not ready yet, `poll` returns + /// [`Poll::Pending`](::task::Poll). The future will *also* register the + /// interest of the current task in the value being produced. For example, + /// if the future represents the availability of data on a socket, then the + /// task is recorded so that when data arrives, it is woken up (via + /// [`cx.waker()`](::task::Context::waker)). Once a task has been woken up, + /// it should attempt to `poll` the future again, which may or may not + /// produce a final value. + /// + /// Note that if `Pending` is returned it only means that the *current* task + /// (represented by the argument `cx`) will receive a notification. Tasks + /// from previous calls to `poll` will *not* receive notifications. + /// + /// # Runtime characteristics + /// + /// Futures alone are *inert*; they must be *actively* `poll`ed to make + /// progress, meaning that each time the current task is woken up, it should + /// actively re-`poll` pending futures that it still has an interest in. + /// + /// The `poll` function is not called repeatedly in a tight loop for + /// futures, but only whenever the future itself is ready, as signaled via + /// the `Waker` inside `task::Context`. If you're familiar with the + /// `poll(2)` or `select(2)` syscalls on Unix it's worth noting that futures + /// typically do *not* suffer the same problems of "all wakeups must poll + /// all events"; they are more like `epoll(4)`. + /// + /// An implementation of `poll` should strive to return quickly, and must + /// *never* block. Returning quickly prevents unnecessarily clogging up + /// threads or event loops. If it is known ahead of time that a call to + /// `poll` may end up taking awhile, the work should be offloaded to a + /// thread pool (or something similar) to ensure that `poll` can return + /// quickly. + /// + /// # Panics + /// + /// Once a future has completed (returned `Ready` from `poll`), + /// then any future calls to `poll` may panic, block forever, or otherwise + /// cause bad behavior. The `Future` trait itself provides no guarantees + /// about the behavior of `poll` after a future has completed. + fn poll(self: PinMut, cx: &mut task::Context) -> Poll; +} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 32cf31231c3..38a769cd11a 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -100,6 +100,7 @@ #![feature(optin_builtin_traits)] #![feature(prelude_import)] #![feature(repr_simd, platform_intrinsics)] +#![feature(repr_transparent)] #![feature(rustc_attrs)] #![feature(rustc_const_unstable)] #![feature(simd_ffi)] @@ -206,6 +207,10 @@ pub mod time; pub mod unicode; +/* Async */ +pub mod future; +pub mod task; + /* Heap memory allocator trait */ #[allow(missing_docs)] pub mod alloc; diff --git a/src/libcore/task.rs b/src/libcore/task.rs new file mode 100644 index 00000000000..e46a6d41d7a --- /dev/null +++ b/src/libcore/task.rs @@ -0,0 +1,513 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +//! Types and Traits for working with asynchronous tasks. + +use fmt; +use ptr::NonNull; + +/// Indicates whether a value is available or if the current task has been +/// scheduled to receive a wakeup instead. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum Poll { + /// Represents that a value is immediately ready. + Ready(T), + + /// Represents that a value is not ready yet. + /// + /// When a function returns `Pending`, the function *must* also + /// ensure that the current task is scheduled to be awoken when + /// progress can be made. + Pending, +} + +/// A `Waker` is a handle for waking up a task by notifying its executor that it +/// is ready to be run. +/// +/// This handle contains a trait object pointing to an instance of the `UnsafeWake` +/// trait, allowing notifications to get routed through it. +#[repr(transparent)] +pub struct Waker { + inner: NonNull, +} + +unsafe impl Send for Waker {} +unsafe impl Sync for Waker {} + +impl Waker { + /// Constructs a new `Waker` directly. + /// + /// Note that most code will not need to call this. Implementers of the + /// `UnsafeWake` trait will typically provide a wrapper that calls this + /// but you otherwise shouldn't call it directly. + /// + /// If you're working with the standard library then it's recommended to + /// use the `Waker::from` function instead which works with the safe + /// `Arc` type and the safe `Wake` trait. + #[inline] + pub unsafe fn new(inner: NonNull) -> Self { + Waker { inner: inner } + } + + /// Wake up the task associated with this `Waker`. + #[inline] + pub fn wake(&self) { + unsafe { self.inner.as_ref().wake() } + } + + /// Returns whether or not this `Waker` and `other` awaken the same task. + /// + /// This function works on a best-effort basis, and may return false even + /// when the `Waker`s would awaken the same task. However, if this function + /// returns true, it is guaranteed that the `Waker`s will awaken the same + /// task. + /// + /// This function is primarily used for optimization purposes. + #[inline] + pub fn will_wake(&self, other: &Waker) -> bool { + self.inner == other.inner + } +} + +impl Clone for Waker { + #[inline] + fn clone(&self) -> Self { + unsafe { + self.inner.as_ref().clone_raw() + } + } +} + +impl fmt::Debug for Waker { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Waker") + .finish() + } +} + +impl Drop for Waker { + #[inline] + fn drop(&mut self) { + unsafe { + self.inner.as_ref().drop_raw() + } + } +} + +/// A `LocalWaker` is a handle for waking up a task by notifying its executor that it +/// is ready to be run. +/// +/// This is similar to the `Waker` type, but cannot be sent across threads. +/// Task executors can use this type to implement more optimized singlethreaded wakeup +/// behavior. +#[repr(transparent)] +pub struct LocalWaker { + inner: NonNull, +} + +impl !Send for LocalWaker {} +impl !Sync for LocalWaker {} + +impl LocalWaker { + /// Constructs a new `LocalWaker` directly. + /// + /// Note that most code will not need to call this. Implementers of the + /// `UnsafeWake` trait will typically provide a wrapper that calls this + /// but you otherwise shouldn't call it directly. + /// + /// If you're working with the standard library then it's recommended to + /// use the `LocalWaker::from` function instead which works with the safe + /// `Rc` type and the safe `LocalWake` trait. + /// + /// For this function to be used safely, it must be sound to call `inner.wake_local()` + /// on the current thread. + #[inline] + pub unsafe fn new(inner: NonNull) -> Self { + LocalWaker { inner: inner } + } + + /// Wake up the task associated with this `LocalWaker`. + #[inline] + pub fn wake(&self) { + unsafe { self.inner.as_ref().wake_local() } + } + + /// Returns whether or not this `LocalWaker` and `other` `LocalWaker` awaken the same task. + /// + /// This function works on a best-effort basis, and may return false even + /// when the `LocalWaker`s would awaken the same task. However, if this function + /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same + /// task. + /// + /// This function is primarily used for optimization purposes. + #[inline] + pub fn will_wake(&self, other: &LocalWaker) -> bool { + self.inner == other.inner + } + + /// Returns whether or not this `LocalWaker` and `other` `Waker` awaken the same task. + /// + /// This function works on a best-effort basis, and may return false even + /// when the `Waker`s would awaken the same task. However, if this function + /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same + /// task. + /// + /// This function is primarily used for optimization purposes. + #[inline] + pub fn will_wake_nonlocal(&self, other: &Waker) -> bool { + self.inner == other.inner + } +} + +impl From for Waker { + #[inline] + fn from(local_waker: LocalWaker) -> Self { + Waker { inner: local_waker.inner } + } +} + +impl Clone for LocalWaker { + #[inline] + fn clone(&self) -> Self { + unsafe { + LocalWaker { inner: self.inner.as_ref().clone_raw().inner } + } + } +} + +impl fmt::Debug for LocalWaker { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Waker") + .finish() + } +} + +impl Drop for LocalWaker { + #[inline] + fn drop(&mut self) { + unsafe { + self.inner.as_ref().drop_raw() + } + } +} + +/// An unsafe trait for implementing custom memory management for a `Waker` or `LocalWaker`. +/// +/// A `Waker` conceptually is a cloneable trait object for `Wake`, and is +/// most often essentially just `Arc`. However, in some contexts +/// (particularly `no_std`), it's desirable to avoid `Arc` in favor of some +/// custom memory management strategy. This trait is designed to allow for such +/// customization. +/// +/// When using `std`, a default implementation of the `UnsafeWake` trait is provided for +/// `Arc` where `T: Wake` and `Rc` where `T: LocalWake`. +/// +/// Although the methods on `UnsafeWake` take pointers rather than references, +pub unsafe trait UnsafeWake: Send + Sync { + /// Creates a clone of this `UnsafeWake` and stores it behind a `Waker`. + /// + /// This function will create a new uniquely owned handle that under the + /// hood references the same notification instance. In other words calls + /// to `wake` on the returned handle should be equivalent to calls to + /// `wake` on this handle. + /// + /// # Unsafety + /// + /// This function is unsafe to call because it's asserting the `UnsafeWake` + /// value is in a consistent state, i.e. hasn't been dropped. + unsafe fn clone_raw(&self) -> Waker; + + /// Drops this instance of `UnsafeWake`, deallocating resources + /// associated with it. + /// + /// FIXME(cramertj) + /// This method is intended to have a signature such as: + /// + /// ```ignore (not-a-doctest) + /// fn drop_raw(self: *mut Self); + /// ``` + /// + /// Unfortunately in Rust today that signature is not object safe. + /// Nevertheless it's recommended to implement this function *as if* that + /// were its signature. As such it is not safe to call on an invalid + /// pointer, nor is the validity of the pointer guaranteed after this + /// function returns. + /// + /// # Unsafety + /// + /// This function is unsafe to call because it's asserting the `UnsafeWake` + /// value is in a consistent state, i.e. hasn't been dropped. + unsafe fn drop_raw(&self); + + /// Indicates that the associated task is ready to make progress and should + /// be `poll`ed. + /// + /// Executors generally maintain a queue of "ready" tasks; `wake` should place + /// the associated task onto this queue. + /// + /// # Panics + /// + /// Implementations should avoid panicking, but clients should also be prepared + /// for panics. + /// + /// # Unsafety + /// + /// This function is unsafe to call because it's asserting the `UnsafeWake` + /// value is in a consistent state, i.e. hasn't been dropped. + unsafe fn wake(&self); + + /// Indicates that the associated task is ready to make progress and should + /// be `poll`ed. This function is the same as `wake`, but can only be called + /// from the thread that this `UnsafeWake` is "local" to. This allows for + /// implementors to provide specialized wakeup behavior specific to the current + /// thread. This function is called by `LocalWaker::wake`. + /// + /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place + /// the associated task onto this queue. + /// + /// # Panics + /// + /// Implementations should avoid panicking, but clients should also be prepared + /// for panics. + /// + /// # Unsafety + /// + /// This function is unsafe to call because it's asserting the `UnsafeWake` + /// value is in a consistent state, i.e. hasn't been dropped, and that the + /// `UnsafeWake` hasn't moved from the thread on which it was created. + unsafe fn wake_local(&self) { + self.wake() + } +} + +/// Information about the currently-running task. +/// +/// Contexts are always tied to the stack, since they are set up specifically +/// when performing a single `poll` step on a task. +pub struct Context<'a> { + local_waker: &'a LocalWaker, + executor: &'a mut Executor, +} + +impl<'a> fmt::Debug for Context<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Context") + .finish() + } +} + +impl<'a> Context<'a> { + /// Create a new task `Context` with the provided `local_waker`, `waker`, and `executor`. + #[inline] + pub fn new(local_waker: &'a LocalWaker, executor: &'a mut Executor) -> Context<'a> { + Context { + local_waker, + executor, + } + } + + /// Get the `LocalWaker` associated with the current task. + #[inline] + pub fn local_waker(&self) -> &'a LocalWaker { + self.local_waker + } + + /// Get the `Waker` associated with the current task. + #[inline] + pub fn waker(&self) -> &'a Waker { + unsafe { &*(self.local_waker as *const LocalWaker as *const Waker) } + } + + /// Get the default executor associated with this task. + /// + /// This method is useful primarily if you want to explicitly handle + /// spawn failures. + #[inline] + pub fn executor(&mut self) -> &mut Executor { + self.executor + } + + /// Produce a context like the current one, but using the given waker instead. + /// + /// This advanced method is primarily used when building "internal + /// schedulers" within a task, where you want to provide some customized + /// wakeup logic. + #[inline] + pub fn with_waker<'b>(&'b mut self, local_waker: &'b LocalWaker) -> Context<'b> { + Context { + local_waker, + executor: self.executor, + } + } + + /// Produce a context like the current one, but using the given executor + /// instead. + /// + /// This advanced method is primarily used when building "internal + /// schedulers" within a task. + #[inline] + pub fn with_executor<'b, E>(&'b mut self, executor: &'b mut E) -> Context<'b> + where E: Executor + { + Context { + local_waker: self.local_waker, + executor: executor, + } + } +} + +/// A task executor. +/// +/// A *task* is a `()`-producing async value that runs at the top level, and will +/// be `poll`ed until completion. It's also the unit at which wake-up +/// notifications occur. Executors, such as thread pools, allow tasks to be +/// spawned and are responsible for putting tasks onto ready queues when +/// they are woken up, and polling them when they are ready. +pub trait Executor { + /// Spawn the given task, polling it until completion. + /// + /// # Errors + /// + /// The executor may be unable to spawn tasks, either because it has + /// been shut down or is resource-constrained. + fn spawn_obj(&mut self, task: TaskObj) -> Result<(), SpawnObjError>; + + /// Determine whether the executor is able to spawn new tasks. + /// + /// # Returns + /// + /// An `Ok` return means the executor is *likely* (but not guaranteed) + /// to accept a subsequent spawn attempt. Likewise, an `Err` return + /// means that `spawn` is likely, but not guaranteed, to yield an error. + #[inline] + fn status(&self) -> Result<(), SpawnErrorKind> { + Ok(()) + } +} + +/// A custom trait object for polling tasks, roughly akin to +/// `Box + Send>`. +pub struct TaskObj { + ptr: *mut (), + poll: unsafe fn(*mut (), &mut Context) -> Poll<()>, + drop: unsafe fn(*mut ()), +} + +impl fmt::Debug for TaskObj { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("TaskObj") + .finish() + } +} + +unsafe impl Send for TaskObj {} +unsafe impl Sync for TaskObj {} + +/// A custom implementation of a task trait object for `TaskObj`, providing +/// a hand-rolled vtable. +/// +/// This custom representation is typically used only in `no_std` contexts, +/// where the default `Box`-based implementation is not available. +/// +/// The implementor must guarantee that it is safe to call `poll` repeatedly (in +/// a non-concurrent fashion) with the result of `into_raw` until `drop` is +/// called. +pub unsafe trait UnsafePoll: Send + 'static { + /// Convert a owned instance into a (conceptually owned) void pointer. + fn into_raw(self) -> *mut (); + + /// Poll the task represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to repeatedly call + /// `poll` with the result of `into_raw` until `drop` is called; such calls + /// are not, however, allowed to race with each other or with calls to `drop`. + unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()>; + + /// Drops the task represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to call this + /// function once per `into_raw` invocation; that call cannot race with + /// other calls to `drop` or `poll`. + unsafe fn drop(task: *mut ()); +} + +impl TaskObj { + /// Create a `TaskObj` from a custom trait object representation. + #[inline] + pub fn from_poll_task(t: T) -> TaskObj { + TaskObj { + ptr: t.into_raw(), + poll: T::poll, + drop: T::drop, + } + } + + /// Poll the task. + /// + /// The semantics here are identical to that for futures, but unlike + /// futures only an `&mut self` reference is needed here. + #[inline] + pub fn poll_task(&mut self, cx: &mut Context) -> Poll<()> { + unsafe { + (self.poll)(self.ptr, cx) + } + } +} + +impl Drop for TaskObj { + fn drop(&mut self) { + unsafe { + (self.drop)(self.ptr) + } + } +} + +/// Provides the reason that an executor was unable to spawn. +pub struct SpawnErrorKind { + _hidden: (), +} + +impl fmt::Debug for SpawnErrorKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("SpawnErrorKind") + .field(&"shutdown") + .finish() + } +} + +impl SpawnErrorKind { + /// Spawning is failing because the executor has been shut down. + pub fn shutdown() -> SpawnErrorKind { + SpawnErrorKind { _hidden: () } + } + + /// Check whether this error is the `shutdown` error. + pub fn is_shutdown(&self) -> bool { + true + } +} + +/// The result of a failed spawn +#[derive(Debug)] +pub struct SpawnObjError { + /// The kind of error + pub kind: SpawnErrorKind, + + /// The task for which spawning was attempted + pub task: TaskObj, +} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f7d06852f27..f7ad709e6e7 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -261,6 +261,7 @@ #![feature(float_from_str_radix)] #![feature(fn_traits)] #![feature(fnbox)] +#![feature(futures_api)] #![feature(hashmap_internals)] #![feature(heap_api)] #![feature(int_error_internals)] @@ -282,6 +283,7 @@ #![feature(panic_internals)] #![feature(panic_unwind)] #![feature(peek)] +#![feature(pin)] #![feature(placement_new_protocol)] #![feature(prelude_import)] #![feature(ptr_internals)] @@ -457,6 +459,20 @@ pub use core::u128; #[stable(feature = "core_hint", since = "1.27.0")] pub use core::hint; +#[unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] +pub mod task { + //! Types and Traits for working with asynchronous tasks. + pub use core::task::*; + pub use alloc_crate::task::*; +} + +#[unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] +pub use core::future; + pub mod f32; pub mod f64; diff --git a/src/test/run-pass/futures-api.rs b/src/test/run-pass/futures-api.rs new file mode 100644 index 00000000000..3b5a1725b66 --- /dev/null +++ b/src/test/run-pass/futures-api.rs @@ -0,0 +1,95 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(arbitrary_self_types, futures_api, pin)] +#![allow(unused)] + +use std::boxed::PinBox; +use std::future::Future; +use std::mem::PinMut; +use std::rc::Rc; +use std::sync::{ + Arc, + atomic::{self, AtomicUsize}, +}; +use std::task::{ + Context, Poll, + Wake, Waker, LocalWaker, + Executor, TaskObj, SpawnObjError, + local_waker, local_waker_from_nonlocal, +}; + +struct Counter { + local_wakes: AtomicUsize, + nonlocal_wakes: AtomicUsize, +} + +impl Wake for Counter { + fn wake(this: &Arc) { + this.nonlocal_wakes.fetch_add(1, atomic::Ordering::SeqCst); + } + + unsafe fn wake_local(this: &Arc) { + this.local_wakes.fetch_add(1, atomic::Ordering::SeqCst); + } +} + +struct NoopExecutor; + +impl Executor for NoopExecutor { + fn spawn_obj(&mut self, _: TaskObj) -> Result<(), SpawnObjError> { + Ok(()) + } +} + +struct MyFuture; + +impl Future for MyFuture { + type Output = (); + fn poll(self: PinMut, cx: &mut Context) -> Poll { + // Ensure all the methods work appropriately + cx.waker().wake(); + cx.waker().wake(); + cx.local_waker().wake(); + cx.executor().spawn_obj(PinBox::new(MyFuture).into()).unwrap(); + Poll::Ready(()) + } +} + +fn test_local_waker() { + let counter = Arc::new(Counter { + local_wakes: AtomicUsize::new(0), + nonlocal_wakes: AtomicUsize::new(0), + }); + let waker = unsafe { local_waker(counter.clone()) }; + let executor = &mut NoopExecutor; + let cx = &mut Context::new(&waker, executor); + assert_eq!(Poll::Ready(()), PinMut::new(&mut MyFuture).poll(cx)); + assert_eq!(1, counter.local_wakes.load(atomic::Ordering::SeqCst)); + assert_eq!(2, counter.nonlocal_wakes.load(atomic::Ordering::SeqCst)); +} + +fn test_local_as_nonlocal_waker() { + let counter = Arc::new(Counter { + local_wakes: AtomicUsize::new(0), + nonlocal_wakes: AtomicUsize::new(0), + }); + let waker: LocalWaker = local_waker_from_nonlocal(counter.clone()); + let executor = &mut NoopExecutor; + let cx = &mut Context::new(&waker, executor); + assert_eq!(Poll::Ready(()), PinMut::new(&mut MyFuture).poll(cx)); + assert_eq!(0, counter.local_wakes.load(atomic::Ordering::SeqCst)); + assert_eq!(3, counter.nonlocal_wakes.load(atomic::Ordering::SeqCst)); +} + +fn main() { + test_local_waker(); + test_local_as_nonlocal_waker(); +} -- cgit 1.4.1-3-g733a5 From 579099ab5788ef839d784365c1d3724b8391c074 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Jun 2018 23:53:30 +0200 Subject: Improve docs for slice::from_raw_parts --- src/libcore/slice/mod.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 63f9a8097ba..bfab7a4cdda 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -3873,9 +3873,11 @@ unsafe impl<'a, T> TrustedRandomAccess for ExactChunksMut<'a, T> { /// valid for `len` elements, nor whether the lifetime inferred is a suitable /// lifetime for the returned slice. /// -/// `p` must be non-null and aligned, even for zero-length slices, as is -/// required for all references. However, for zero-length slices, `p` can be -/// a bogus non-dereferencable pointer such as [`NonNull::dangling()`]. +/// `data` must be non-null and aligned, even for zero-length slices. The +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. /// /// # Caveat /// @@ -3910,8 +3912,8 @@ pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { /// /// This function is unsafe for the same reasons as `from_raw_parts`, as well /// as not being able to provide a non-aliasing guarantee of the returned -/// mutable slice. `p` must be non-null and aligned even for zero-length slices as with -/// `from_raw_parts`. +/// mutable slice. `data` must be non-null and aligned even for zero-length +/// slices as with `from_raw_parts`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { -- cgit 1.4.1-3-g733a5 From 9a8fa2cf92c4f1fb5ebed287bf6eab81f9d8a804 Mon Sep 17 00:00:00 2001 From: bstrie Date: Fri, 8 Jun 2018 19:20:28 +0000 Subject: Document size_of for 128-bit integers We might want to consider separately documenting the alignment of primitives, rather than just their size, since 128-bit integers, unlike all other primitives, have an alignment that is not identical to their size (size_of is 16, align_of is 8) --- src/libcore/mem.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 9fed4990345..31635ffa53c 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -194,10 +194,12 @@ pub fn forget(t: T) { /// u16 | 2 /// u32 | 4 /// u64 | 8 +/// u128 | 16 /// i8 | 1 /// i16 | 2 /// i32 | 4 /// i64 | 8 +/// i128 | 16 /// f32 | 4 /// f64 | 8 /// char | 4 -- cgit 1.4.1-3-g733a5 From 6e5c18e8dc94a679126d276884a3ad4b9a3e0934 Mon Sep 17 00:00:00 2001 From: tinaun Date: Fri, 8 Jun 2018 16:45:27 -0400 Subject: add a few blanket future impls to std --- src/liballoc/boxed.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/liballoc/lib.rs | 1 + src/libcore/future.rs | 17 +++++++++++++++++ src/libcore/task.rs | 6 ++++++ src/libstd/lib.rs | 1 + src/libstd/panic.rs | 18 ++++++++++++++++++ 6 files changed, 82 insertions(+) (limited to 'src/libcore') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index a64b94b6517..896d9dee3ee 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -914,6 +914,45 @@ impl, U: ?Sized> CoerceUnsized> for PinBox {} #[unstable(feature = "pin", issue = "49150")] impl Unpin for PinBox {} +#[unstable(feature = "futures_api", issue = "50547")] +impl<'a, F: ?Sized + Future + Unpin> Future for Box { + type Output = F::Output; + + fn poll(mut self: PinMut, cx: &mut Context) -> Poll { + PinMut::new(&mut **self).poll(cx) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +impl<'a, F: ?Sized + Future> Future for PinBox { + type Output = F::Output; + + fn poll(mut self: PinMut, cx: &mut Context) -> Poll { + self.as_pin_mut().poll(cx) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +unsafe impl + Send + 'static> UnsafePoll for Box { + fn into_raw(self) -> *mut () { + unsafe { + mem::transmute(self) + } + } + + unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()> { + let ptr: *mut F = mem::transmute(task); + let pin: PinMut = PinMut::new_unchecked(&mut *ptr); + pin.poll(cx) + } + + unsafe fn drop(task: *mut ()) { + let ptr: *mut F = mem::transmute(task); + let boxed = Box::from_raw(ptr); + drop(boxed) + } +} + #[unstable(feature = "futures_api", issue = "50547")] unsafe impl + Send + 'static> UnsafePoll for PinBox { fn into_raw(self) -> *mut () { diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 242c7d2e70f..a1139189c9a 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -80,6 +80,7 @@ #![cfg_attr(test, feature(rand, test))] #![feature(allocator_api)] #![feature(allow_internal_unstable)] +#![feature(arbitrary_self_types)] #![feature(ascii_ctype)] #![feature(box_into_raw_non_null)] #![feature(box_patterns)] diff --git a/src/libcore/future.rs b/src/libcore/future.rs index b4d087f8edb..a8c8f69411e 100644 --- a/src/libcore/future.rs +++ b/src/libcore/future.rs @@ -15,6 +15,7 @@ //! Asynchronous values. use mem::PinMut; +use marker::Unpin; use task::{self, Poll}; /// A future represents an asychronous computation. @@ -91,3 +92,19 @@ pub trait Future { /// about the behavior of `poll` after a future has completed. fn poll(self: PinMut, cx: &mut task::Context) -> Poll; } + +impl<'a, F: ?Sized + Future + Unpin> Future for &'a mut F { + type Output = F::Output; + + fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { + F::poll(PinMut::new(&mut **self), cx) + } +} + +impl<'a, F: ?Sized + Future> Future for PinMut<'a, F> { + type Output = F::Output; + + fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { + F::poll((*self).reborrow(), cx) + } +} diff --git a/src/libcore/task.rs b/src/libcore/task.rs index e46a6d41d7a..ab1c1da5790 100644 --- a/src/libcore/task.rs +++ b/src/libcore/task.rs @@ -32,6 +32,12 @@ pub enum Poll { Pending, } +impl From for Poll { + fn from(t: T) -> Poll { + Poll::Ready(t) + } +} + /// A `Waker` is a handle for waking up a task by notifying its executor that it /// is ready to be run. /// diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 7bbc99b83be..bb23fe5fa91 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -239,6 +239,7 @@ #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] #![feature(align_offset)] +#![feature(arbitrary_self_types)] #![feature(array_error_internals)] #![feature(ascii_ctype)] #![feature(asm)] diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 229034eb779..b70de73991f 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -15,11 +15,14 @@ use any::Any; use cell::UnsafeCell; use fmt; +use future::Future; +use mem::PinMut; use ops::{Deref, DerefMut}; use panicking; use ptr::{Unique, NonNull}; use rc::Rc; use sync::{Arc, Mutex, RwLock, atomic}; +use task::{self, Poll}; use thread::Result; #[stable(feature = "panic_hooks", since = "1.10.0")] @@ -315,6 +318,21 @@ impl fmt::Debug for AssertUnwindSafe { } } +#[unstable(feature = "futures_api", issue = "50547")] +impl<'a, F: Future> Future for AssertUnwindSafe { + type Output = F::Output; + + fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { + unsafe { + let pinned_field = PinMut::new_unchecked( + &mut PinMut::get_mut(self.reborrow()).0 + ); + + pinned_field.poll(cx) + } + } +} + /// Invokes a closure, capturing the cause of an unwinding panic if one occurs. /// /// This function will return `Ok` with the closure's result if the closure -- cgit 1.4.1-3-g733a5 From fb507cadf32e1eacccc07c1c3511636fd6378f7b Mon Sep 17 00:00:00 2001 From: tinaun Date: Fri, 8 Jun 2018 23:24:52 -0400 Subject: add inherent methods to Poll --- src/libcore/task.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/libstd/panic.rs | 2 +- 2 files changed, 50 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/task.rs b/src/libcore/task.rs index ab1c1da5790..bef6d3677d0 100644 --- a/src/libcore/task.rs +++ b/src/libcore/task.rs @@ -32,6 +32,55 @@ pub enum Poll { Pending, } +impl Poll { + /// Change the ready value of this `Poll` with the closure provided + pub fn map(self, f: F) -> Poll + where F: FnOnce(T) -> U + { + match self { + Poll::Ready(t) => Poll::Ready(f(t)), + Poll::Pending => Poll::Pending, + } + } + + /// Returns whether this is `Poll::Ready` + pub fn is_ready(&self) -> bool { + match *self { + Poll::Ready(_) => true, + Poll::Pending => false, + } + } + + /// Returns whether this is `Poll::Pending` + pub fn is_pending(&self) -> bool { + !self.is_ready() + } +} + +impl Poll> { + /// Change the success value of this `Poll` with the closure provided + pub fn map_ok(self, f: F) -> Poll> + where F: FnOnce(T) -> U + { + match self { + Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))), + Poll::Ready(Err(e)) => Poll::Ready(Err(e)), + Poll::Pending => Poll::Pending, + } + } + + /// Change the error value of this `Poll` with the closure provided + pub fn map_err(self, f: F) -> Poll> + where F: FnOnce(E) -> U + { + match self { + Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)), + Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))), + Poll::Pending => Poll::Pending, + } + } +} + impl From for Poll { fn from(t: T) -> Poll { Poll::Ready(t) diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 8aee15b5eda..4b5a063ea73 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -327,7 +327,7 @@ impl<'a, F: Future> Future for AssertUnwindSafe { let pinned_field = PinMut::new_unchecked( &mut PinMut::get_mut(self.reborrow()).0 ); - + pinned_field.poll(cx) } } -- cgit 1.4.1-3-g733a5 From 426f06f8fea9783a63aa61b418ab0ecb723a5ad9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Jun 2018 10:40:51 +0200 Subject: Be more precise about why references need to be non-null and aligned --- src/libcore/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index bfab7a4cdda..6f4c130d8f3 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -3873,7 +3873,7 @@ unsafe impl<'a, T> TrustedRandomAccess for ExactChunksMut<'a, T> { /// valid for `len` elements, nor whether the lifetime inferred is a suitable /// lifetime for the returned slice. /// -/// `data` must be non-null and aligned, even for zero-length slices. The +/// `data` must be non-null and aligned, even for zero-length slices. One /// reason for this is that enum layout optimizations may rely on references /// (including slices of any length) being aligned and non-null to distinguish /// them from other data. You can obtain a pointer that is usable as `data` -- cgit 1.4.1-3-g733a5 From 553a44a5cc0aa766d60e878c87d3860f4a2cacdd Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Sun, 10 Jun 2018 13:16:34 +0200 Subject: add some docs to conversions --- src/libcore/num/mod.rs | 52 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 13 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index c2da9006a8a..1168126c47c 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4709,30 +4709,56 @@ pub use num::dec2flt::ParseFloatError; // Conversions T -> T are covered by a blanket impl and therefore excluded // Some conversions from and to usize/isize are not implemented due to portability concerns macro_rules! impl_from { - ($Small: ty, $Large: ty, #[$attr:meta]) => { + ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => { #[$attr] + #[doc = $doc] impl From<$Small> for $Large { #[inline] fn from(small: $Small) -> $Large { small as $Large } } + }; + ($Small: ty, $Large: ty, #[$attr:meta]) => { + impl_from!($Small, + $Large, + #[$attr], + concat!("Converts `", + stringify!($Small), + "` to `", + stringify!($Large), + "` losslessly.")); } } +macro_rules! impl_from_bool { + ($target: ty, #[$attr:meta]) => { + impl_from!(bool, $target, #[$attr], concat!("Converts a `bool` to a `", + stringify!($target), "`. The resulting value is `0` for `false` and `1` for `true` +values. + +# Examples + +``` +assert_eq!(", stringify!($target), "::from(true), 1); +assert_eq!(", stringify!($target), "::from(false), 0); +```")); + }; +} + // Bool -> Any -impl_from! { bool, u8, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from! { bool, u16, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from! { bool, u32, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from! { bool, u64, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from! { bool, u128, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from! { bool, usize, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from! { bool, i8, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from! { bool, i16, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from! { bool, i32, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from! { bool, i64, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from! { bool, i128, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from! { bool, isize, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u8, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u16, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u32, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u64, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u128, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { usize, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i8, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i16, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i32, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i64, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i128, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { isize, #[stable(feature = "from_bool", since = "1.28.0")] } // Unsigned -> Unsigned impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -- cgit 1.4.1-3-g733a5 From f81e34b8256578272a7e58e17352884608be6843 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 11 Jun 2018 10:54:30 -0700 Subject: Regenerate character tables for Unicode 11 --- src/libcore/unicode/printable.rs | 198 ++-- src/libcore/unicode/tables.rs | 2136 ++++++++++++++++++++------------------ 2 files changed, 1214 insertions(+), 1120 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/unicode/printable.rs b/src/libcore/unicode/printable.rs index 4426c32eebc..519dd17bb9b 100644 --- a/src/libcore/unicode/printable.rs +++ b/src/libcore/unicode/printable.rs @@ -83,14 +83,14 @@ pub(crate) fn is_printable(x: char) -> bool { const SINGLETONS0U: &'static [(u8, u8)] = &[ (0x00, 1), (0x03, 5), - (0x05, 8), + (0x05, 6), (0x06, 3), - (0x07, 4), + (0x07, 6), (0x08, 8), - (0x09, 16), - (0x0a, 27), + (0x09, 17), + (0x0a, 28), (0x0b, 25), - (0x0c, 22), + (0x0c, 20), (0x0d, 18), (0x0e, 22), (0x0f, 4), @@ -102,18 +102,17 @@ const SINGLETONS0U: &'static [(u8, u8)] = &[ (0x18, 2), (0x19, 3), (0x1a, 7), + (0x1c, 2), (0x1d, 1), (0x1f, 22), (0x20, 3), - (0x2b, 5), + (0x2b, 6), (0x2c, 2), (0x2d, 11), (0x2e, 1), (0x30, 3), - (0x31, 3), + (0x31, 2), (0x32, 2), - (0xa7, 1), - (0xa8, 2), (0xa9, 2), (0xaa, 4), (0xab, 8), @@ -125,19 +124,19 @@ const SINGLETONS0U: &'static [(u8, u8)] = &[ ]; const SINGLETONS0L: &'static [u8] = &[ 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, - 0x58, 0x60, 0x88, 0x8b, 0x8c, 0x90, 0x1c, 0x1d, - 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0x2e, 0x2f, 0x3f, + 0x58, 0x8b, 0x8c, 0x90, 0x1c, 0x1d, 0xdd, 0x0e, + 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f, 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1, 0xba, 0xbb, 0xc5, 0xc6, - 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0x04, 0x11, 0x12, - 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, - 0x4a, 0x5d, 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, - 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, 0xe4, 0xe5, - 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, - 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, - 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, 0xc9, 0xce, - 0xcf, 0x04, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, - 0x64, 0x65, 0x84, 0x8d, 0x91, 0xa9, 0xb4, 0xba, + 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04, + 0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, + 0x3d, 0x49, 0x4a, 0x5d, 0x84, 0x8e, 0x92, 0xa9, + 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, + 0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, + 0x29, 0x31, 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, + 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, + 0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, + 0x57, 0x64, 0x65, 0x8d, 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x04, 0x0d, 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x81, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, 0xd7, 0xf0, @@ -150,18 +149,18 @@ const SINGLETONS0L: &'static [u8] = &[ 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, - 0x7e, 0xae, 0xaf, 0xfa, 0x16, 0x17, 0x1e, 0x1f, - 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, - 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, - 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0x74, 0x75, 0x96, - 0x97, 0xc9, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, - 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, - 0x40, 0x97, 0x98, 0x2f, 0x30, 0x8f, 0x1f, 0xff, - 0xaf, 0xfe, 0xff, 0xce, 0xff, 0x4e, 0x4f, 0x5a, - 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, - 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, - 0x90, 0x91, 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, - 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff, + 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16, 0x17, + 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, + 0x5c, 0x5e, 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, + 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0x74, + 0x75, 0x96, 0x97, 0xc9, 0xff, 0x2f, 0x5f, 0x26, + 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, + 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, + 0x1f, 0xff, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, + 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, 0xef, + 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, + 0x91, 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, + 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff, ]; const SINGLETONS1U: &'static [(u8, u8)] = &[ (0x00, 6), @@ -170,17 +169,18 @@ const SINGLETONS1U: &'static [(u8, u8)] = &[ (0x04, 2), (0x08, 8), (0x09, 2), - (0x0a, 3), + (0x0a, 5), (0x0b, 2), (0x10, 1), (0x11, 4), (0x12, 5), - (0x13, 18), + (0x13, 17), (0x14, 2), (0x15, 2), - (0x1a, 3), + (0x17, 2), + (0x1a, 2), (0x1c, 5), - (0x1d, 4), + (0x1d, 8), (0x24, 1), (0x6a, 3), (0x6b, 2), @@ -195,51 +195,49 @@ const SINGLETONS1U: &'static [(u8, u8)] = &[ (0xe8, 2), (0xee, 32), (0xf0, 4), - (0xf1, 1), - (0xf9, 1), + (0xf9, 4), ]; const SINGLETONS1L: &'static [u8] = &[ 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07, 0x09, 0x36, 0x3d, 0x3e, - 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x56, - 0x57, 0xbd, 0x35, 0xce, 0xcf, 0xe0, 0x12, 0x87, - 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, - 0x29, 0x31, 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, - 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5a, 0x5c, 0xb6, - 0xb7, 0x84, 0x85, 0x9d, 0x09, 0x37, 0x90, 0x91, - 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x6f, 0x5f, 0xee, - 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, 0x28, 0x55, - 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, - 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, - 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, 0xcd, - 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0xc5, 0xc6, - 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, - 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53, 0x55, 0x56, - 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, - 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, - 0xaf, 0xb0, 0xc0, 0xd0, 0x2f, 0x3f, + 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36, + 0x37, 0x56, 0x57, 0xbd, 0x35, 0xce, 0xcf, 0xe0, + 0x12, 0x87, 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, + 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, 0x45, 0x46, + 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5a, 0x5c, + 0xb6, 0xb7, 0x1b, 0x1c, 0x84, 0x85, 0x09, 0x37, + 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66, + 0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, + 0x62, 0x9a, 0x9b, 0x27, 0x28, 0x55, 0x9d, 0xa0, + 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc, + 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, + 0x45, 0x51, 0xa6, 0xa7, 0xcc, 0xcd, 0xa0, 0x07, + 0x19, 0x1a, 0x22, 0x25, 0xc5, 0xc6, 0x04, 0x20, + 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, + 0x4a, 0x4c, 0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, + 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, 0x6b, 0x73, + 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, + 0xc0, 0xd0, 0x3f, 0x71, 0x72, 0x7b, ]; const NORMAL0: &'static [u8] = &[ 0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, - 0x1b, 0x05, - 0x05, 0x11, + 0x1b, 0x04, + 0x06, 0x11, 0x81, 0xac, 0x0e, - 0x3b, 0x05, - 0x6b, 0x35, - 0x1e, 0x16, - 0x80, 0xdf, 0x03, + 0x80, 0xab, 0x35, + 0x1e, 0x15, + 0x80, 0xe0, 0x03, 0x19, 0x08, 0x01, 0x04, - 0x22, 0x03, - 0x0a, 0x04, + 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01, 0x07, 0x06, 0x07, - 0x10, 0x0b, + 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x08, @@ -286,7 +284,7 @@ const NORMAL0: &'static [u8] = &[ 0x6a, 0x06, 0x0a, 0x06, 0x1a, 0x06, - 0x58, 0x08, + 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, @@ -304,8 +302,8 @@ const NORMAL0: &'static [u8] = &[ 0x74, 0x08, 0x3c, 0x03, 0x0f, 0x03, - 0x3c, 0x37, - 0x08, 0x08, + 0x3c, 0x07, + 0x38, 0x08, 0x2a, 0x06, 0x82, 0xff, 0x11, 0x18, 0x08, @@ -316,15 +314,12 @@ const NORMAL0: &'static [u8] = &[ 0x80, 0x8c, 0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, - 0x87, 0x5a, 0x03, - 0x16, 0x19, - 0x04, 0x10, - 0x80, 0xf4, 0x05, + 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b, 0x07, 0x02, 0x0e, 0x18, 0x09, - 0x80, 0xaa, 0x36, + 0x80, 0xaf, 0x31, 0x74, 0x0c, 0x80, 0xd6, 0x1a, 0x0c, 0x05, @@ -332,12 +327,12 @@ const NORMAL0: &'static [u8] = &[ 0x80, 0xb6, 0x05, 0x24, 0x0c, 0x9b, 0xc6, 0x0a, - 0xd2, 0x2b, 0x15, + 0xd2, 0x30, 0x10, 0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, - 0x80, 0xb8, 0x3f, + 0x80, 0xba, 0x3d, 0x35, 0x04, 0x0a, 0x06, 0x38, 0x08, @@ -402,9 +397,8 @@ const NORMAL1: &'static [u8] = &[ 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, - 0x28, 0x04, - 0x03, 0x04, - 0x09, 0x08, + 0x2f, 0x04, + 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, @@ -417,14 +411,17 @@ const NORMAL1: &'static [u8] = &[ 0x49, 0x37, 0x33, 0x0d, 0x33, 0x07, - 0x06, 0x81, 0x60, - 0x1f, 0x81, 0x81, + 0x2e, 0x08, + 0x0a, 0x81, 0x26, + 0x1f, 0x80, 0x81, + 0x28, 0x08, + 0x2a, 0x80, 0xa6, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e, 0x19, 0x07, 0x0a, 0x06, - 0x44, 0x0c, + 0x47, 0x09, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41, @@ -435,7 +432,7 @@ const NORMAL1: &'static [u8] = &[ 0x01, 0x05, 0x10, 0x03, 0x05, 0x80, 0x8b, - 0x5e, 0x22, + 0x5f, 0x21, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22, @@ -444,9 +441,9 @@ const NORMAL1: &'static [u8] = &[ 0x0d, 0x13, 0x38, 0x08, 0x0a, 0x36, - 0x1a, 0x03, - 0x0f, 0x04, - 0x10, 0x81, 0x60, + 0x2c, 0x04, + 0x10, 0x80, 0xc0, + 0x3c, 0x64, 0x53, 0x0c, 0x01, 0x81, 0x00, 0x48, 0x08, @@ -457,7 +454,10 @@ const NORMAL1: &'static [u8] = &[ 0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, - 0x0a, 0x82, 0xa6, + 0x0a, 0x06, + 0x39, 0x07, + 0x0a, 0x81, 0x36, + 0x19, 0x81, 0x07, 0x83, 0x9a, 0x66, 0x75, 0x0b, 0x80, 0xc4, 0x8a, 0xbc, @@ -469,12 +469,13 @@ const NORMAL1: &'static [u8] = &[ 0x26, 0x0a, 0x46, 0x0a, 0x28, 0x05, - 0x13, 0x83, 0x70, + 0x13, 0x82, 0xb0, + 0x5b, 0x65, 0x45, 0x0b, 0x2f, 0x10, 0x11, 0x40, 0x02, 0x1e, - 0x97, 0xed, 0x13, + 0x97, 0xf2, 0x0e, 0x82, 0xf3, 0xa5, 0x0d, 0x81, 0x1f, 0x51, 0x81, 0x8c, 0x89, 0x04, @@ -485,9 +486,10 @@ const NORMAL1: &'static [u8] = &[ 0x80, 0xf6, 0x0a, 0x73, 0x08, 0x6e, 0x17, - 0x46, 0x80, 0xba, + 0x46, 0x80, 0x9a, + 0x14, 0x0c, 0x57, 0x09, - 0x12, 0x80, 0x8e, + 0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50, @@ -495,7 +497,8 @@ const NORMAL1: &'static [u8] = &[ 0x80, 0xd7, 0x29, 0x4b, 0x05, 0x0a, 0x04, - 0x02, 0x84, 0xa0, + 0x02, 0x83, 0x11, + 0x44, 0x81, 0x4b, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05, @@ -514,18 +517,19 @@ const NORMAL1: &'static [u8] = &[ 0x06, 0x80, 0x9a, 0x83, 0xd5, 0x0b, 0x0d, 0x03, - 0x09, 0x07, + 0x0a, 0x06, 0x74, 0x0c, - 0x55, 0x2b, + 0x59, 0x27, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x1e, 0x52, 0x0c, 0x04, - 0x3d, 0x03, - 0x1c, 0x14, - 0x18, 0x28, - 0x01, 0x0f, - 0x17, 0x86, 0x19, + 0x67, 0x03, + 0x29, 0x0d, + 0x0a, 0x06, + 0x03, 0x0d, + 0x30, 0x60, + 0x0e, 0x85, 0x92, ]; diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs index e3d27474b9a..32668ea93dd 100644 --- a/src/libcore/unicode/tables.rs +++ b/src/libcore/unicode/tables.rs @@ -19,7 +19,7 @@ use unicode::bool_trie::{BoolTrie, SmallBoolTrie}; /// `char` and `str` methods are based on. #[unstable(feature = "unicode_version", issue = "49726")] pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { - major: 10, + major: 11, minor: 0, micro: 0, _priv: (), @@ -105,10 +105,10 @@ pub mod general_category { ], r5: &[ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 7, 0, 0, 8, 0, 0, 0, 6, 0, 0, 0, 0, 0, 8, 0, 8, 0, 0, 0, - 0, 0, 8, 0, 9, 6, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, - 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 6, 0, 5, 7, 0, 0, 8, 0, 0, 0, 5, 0, 0, 0, 0, 0, 8, 0, 8, 0, 0, 0, + 0, 0, 8, 0, 9, 5, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, + 0, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -123,7 +123,7 @@ pub mod general_category { ], r6: &[ 0x0000000000000000, 0x001fffffffffffff, 0x0000000000000402, 0x00000000003e0000, - 0x000003ff00000000, 0x0000ffc000000000, 0x03ff000000000000, 0xffc0000000000000, + 0x000003ff00000000, 0x03ff000000000000, 0x0000ffc000000000, 0xffc0000000000000, 0x0000000003ff0000, 0x00000000000003ff, 0xffffffffffffffff, 0x00007fffffffffff, 0xffffffffffffc000 ], @@ -143,7 +143,7 @@ pub mod derived_property { 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, 0x0000000000000000, 0xbcdf000000000020, 0xfffffffbffffd740, 0xffbfffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, - 0xfffeffffffffffff, 0xfffffffe027fffff, 0xbfff0000000000ff, 0x000707ffffff00b6, + 0xfffeffffffffffff, 0xffffffff027fffff, 0xbfff0000000001ff, 0x000787ffffff00b6, 0xffffffff07ff0000, 0xffffc000feffffff, 0xffffffffffffffff, 0x9c00e1fe1fefffff, 0xffffffffffff0000, 0xffffffffffffe000, 0x0003ffffffffffff, 0x043007fffffffc00 ], @@ -152,10 +152,10 @@ pub mod derived_property { 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36, 37, 38, 39, 40, 41, 42, 43, 44, 36, 36, 36, 36, 36, 36, 36, 36, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 31, 63, 64, 65, 66, 55, 67, 68, 69, 36, 36, 36, 70, 36, 36, - 36, 36, 71, 72, 73, 74, 31, 75, 76, 31, 77, 78, 68, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 79, 80, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 81, 82, 36, 83, 84, 85, 86, 87, 88, 31, 31, 31, - 31, 31, 31, 31, 89, 44, 90, 91, 92, 36, 93, 94, 31, 31, 31, 31, 31, 31, 31, 31, 36, 36, + 36, 36, 71, 72, 73, 74, 31, 75, 76, 31, 77, 78, 79, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 80, 81, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 82, 83, 36, 84, 85, 86, 87, 88, 89, 31, 31, 31, + 31, 31, 31, 31, 90, 44, 91, 92, 93, 36, 94, 95, 31, 31, 31, 31, 31, 31, 31, 31, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, @@ -175,9 +175,9 @@ pub mod derived_property { 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 95, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 96, 97, 36, 36, 36, 36, 98, 99, 36, 100, 101, 36, 102, - 103, 104, 105, 36, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 36, 95, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 96, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 97, 98, 36, 36, 36, 36, 99, 100, 36, 96, 101, 36, 102, + 103, 104, 105, 36, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 36, 117, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, @@ -185,15 +185,15 @@ pub mod derived_property { 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 117, 118, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 118, 119, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 36, 36, 36, 36, 36, 119, 36, 120, 121, 122, 123, 124, 36, 36, 36, 36, 125, 126, 127, - 128, 31, 129, 36, 130, 131, 132, 113, 133 + 36, 36, 36, 36, 36, 120, 36, 121, 122, 123, 124, 125, 36, 36, 36, 36, 126, 127, 128, + 129, 31, 130, 36, 131, 132, 133, 113, 134 ], r3: &[ 0x00001ffffcffffff, 0x000007ff01ffffff, 0x3fdfffff00000000, 0xffff03f8fff00000, @@ -209,27 +209,27 @@ pub mod derived_property { 0xffffffffff3dffff, 0x0000000087ffffff, 0xffffffff0000ffff, 0x3f3fffffffffffff, 0xfffffffffffffffe, 0xffff9fffffffffff, 0xffffffff07fffffe, 0x01ffc7ffffffffff, 0x000fffff000fdfff, 0x000ddfff000fffff, 0xffcfffffffffffff, 0x00000000108001ff, - 0xffffffff00000000, 0x00ffffffffffffff, 0xffff07ffffffffff, 0x003fffffffffffff, + 0xffffffff00000000, 0x01ffffffffffffff, 0xffff07ffffffffff, 0x003fffffffffffff, 0x01ff0fff7fffffff, 0x001f3fffffff0000, 0xffff0fffffffffff, 0x00000000000003ff, 0xffffffff0fffffff, 0x001ffffe7fffffff, 0x0000008000000000, 0xffefffffffffffff, 0x0000000000000fef, 0xfc00f3ffffffffff, 0x0003ffbfffffffff, 0x3ffffffffc00e000, - 0x00000000000001ff, 0x006fde0000000000, 0x001fff8000000000, 0xffffffff3f3fffff, + 0xe7ffffffffff01ff, 0x006fde0000000000, 0x001fff8000000000, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8002000000000000, - 0x000000001fff0000, 0xf3ffbd503e2ffc84, 0xffffffff000043e0, 0xffc0000000000000, - 0x000003ffffffffff, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, - 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, - 0x0000800000000000, 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, - 0xfffe7fffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, - 0x0000000000001fff, 0x3fffffffffff0000, 0x00000c00ffff1fff, 0x8ff07fffffffffff, - 0x0000ffffffffffff, 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000, - 0x000000fffffff7bb, 0x000fffffffffffff, 0x28fc00000000002f, 0xffff07fffffffc00, + 0x000000001fff0000, 0xf3ffbd503e2ffc84, 0xffffffff000043e0, 0x00000000000001ff, + 0xffc0000000000000, 0x000003ffffffffff, 0xffff7fffffffffff, 0xffffffff7fffffff, + 0x000c781fffffffff, 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, + 0xffffffff7f7f7f7f, 0x0000800000000000, 0x1f3e03fe000000e0, 0xfffffffee07fffff, + 0xf7ffffffffffffff, 0xfffeffffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, + 0x0000ffffffffffff, 0x0000000000001fff, 0x3fffffffffff0000, 0x00000c00ffff1fff, + 0x8ff07fffffffffff, 0xfffffffcff800000, 0x03fffffffffff9ff, 0xff80000000000000, + 0x000000fffffff7bb, 0x000fffffffffffff, 0x68fc00000000002f, 0xffff07fffffffc00, 0x1fffffff0007ffff, 0xfff7ffffffffffff, 0x7c00ffdf00008000, 0x007fffffffffffff, 0xc47fffff00003fff, 0x7fffffffffffffff, 0x003cffff38000005, 0xffff7f7f007e7e7e, - 0xffff003ff7ffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, 0xffff3fffffffffff, - 0x0000000003ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb, 0x0003ffffffffffff, - 0xfffffffffff80000, 0x3fffffffffffffff, 0xffffffffffff0000, 0xfffffffffffcffff, - 0x0fff0000000000ff, 0xffdf000000000000, 0x1fffffffffffffff, 0x07fffffe00000000, - 0xffffffc007fffffe, 0x000000001cfcfcfc + 0xffff003ff7ffffff, 0x000007ffffffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, + 0xffff3fffffffffff, 0x0000000003ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb, + 0x0003ffffffffffff, 0xfffffffffff80000, 0x3fffffffffffffff, 0xffffffffffff0000, + 0xfffffffffffcffff, 0x0fff0000000000ff, 0xffdf000000000000, 0x1fffffffffffffff, + 0x07fffffe00000000, 0xffffffc007fffffe, 0x000000001cfcfcfc ], r4: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 13, 14, @@ -245,45 +245,45 @@ pub mod derived_property { r5: &[ 0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 13, 14, 15, 4, 4, 2, 2, 2, 2, 16, 17, 4, 4, 18, 19, 20, 21, 22, 4, 23, 4, 24, 25, 26, 27, 28, 29, 30, 4, 2, 31, 32, - 32, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 33, 34, 35, 32, 36, 2, 37, 38, 4, 39, 40, 41, - 42, 4, 4, 2, 43, 2, 44, 4, 4, 45, 46, 47, 48, 28, 4, 49, 4, 4, 4, 4, 4, 50, 51, 4, 4, 4, - 4, 52, 53, 54, 55, 4, 4, 4, 4, 56, 57, 58, 4, 59, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 61, 4, 2, 62, 2, 2, 2, 63, 4, 4, 4, 4, 4, 4, 4, + 32, 33, 4, 4, 4, 4, 4, 4, 4, 34, 35, 4, 4, 2, 35, 36, 37, 32, 38, 2, 39, 40, 4, 41, 42, + 43, 44, 4, 4, 2, 45, 2, 46, 4, 4, 47, 48, 49, 50, 28, 4, 51, 4, 4, 4, 52, 4, 53, 54, 4, + 4, 4, 4, 55, 56, 57, 52, 4, 4, 4, 4, 58, 59, 60, 4, 61, 62, 63, 4, 4, 4, 4, 64, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 65, 4, 2, 66, 2, 2, 2, 67, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 62, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 66, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 68, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, - 2, 2, 2, 2, 2, 2, 55, 20, 4, 65, 16, 66, 67, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 68, 69, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 71, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 72, 2, 2, 2, 2, 2, 73, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 2, 74, 75, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 76, 77, 78, 79, 80, 2, 2, 2, 2, 81, 82, 83, 84, 85, 86, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 87, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 2, 2, 2, 88, 2, 89, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 90, 91, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 72, 93, 94, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 52, 20, 4, 69, 16, 70, 71, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, + 4, 2, 72, 73, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 75, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 76, 2, 2, 2, 2, 2, + 77, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 2, 78, 79, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 80, 81, 82, 83, 84, 2, 2, 2, 2, 85, 86, 87, 88, 89, + 90, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 91, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 92, 2, 93, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 94, 95, 96, 4, 4, 4, 4, 4, 4, 4, 4, 4, 76, 97, 98, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 95, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 99, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 96, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, 4, 4, 4, 4, + 2, 100, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 101, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 98, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 102, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ], r6: &[ 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, @@ -292,18 +292,19 @@ pub mod derived_property { 0xffff00003fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, 0x0000000fffffffff, 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, 0xc0ffffffffffffff, - 0x000ffffffeeff06f, 0x1fffffff00000000, 0x000000001fffffff, 0x0000001ffffffeff, + 0x003ffffffeeff06f, 0x1fffffff00000000, 0x000000001fffffff, 0x0000001ffffffeff, 0x003fffffffffffff, 0x0007ffff003fffff, 0x000000000003ffff, 0x00000000000001ff, - 0x0007ffffffffffff, 0x000000000000003f, 0x01fffffffffffffc, 0x000001ffffff0000, - 0x0047ffffffff0000, 0x000000001400001e, 0x409ffffffffbffff, 0xffff01ffbfffbd7f, - 0x000001ffffffffff, 0xe3edfdfffff99fef, 0x0000000fe081199f, 0x00000000000007bb, - 0x00000000000000b3, 0x7f3fffffffffffff, 0x000000003f000000, 0x7fffffffffffffff, - 0x0000000000000011, 0x000007ffe3ffffff, 0xffffffff00000000, 0x80000000ffffffff, - 0x7fe7ffffffffffff, 0xffffffffffff0000, 0x0000000000ffffcf, 0x01ffffffffffffff, - 0x7f7ffffffffffdff, 0xfffc000000000001, 0x007ffefffffcffff, 0xb47ffffffffffb7f, - 0x00000000000000cb, 0x0000000003ffffff, 0x00007fffffffffff, 0x000000000000000f, + 0x0007ffffffffffff, 0x000000ffffffffff, 0xffff00801fffffff, 0x000000000000003f, + 0x01fffffffffffffc, 0x000001ffffff0000, 0x0047ffffffff0070, 0x000000001400001e, + 0x409ffffffffbffff, 0xffff01ffbfffbd7f, 0x000001ffffffffff, 0xe3edfdfffff99fef, + 0x0000000fe081199f, 0x00000000000007bb, 0x00000000000000b3, 0x7f3fffffffffffff, + 0x000000003f000000, 0x7fffffffffffffff, 0x0000000000000011, 0x000007ffe7ffffff, + 0x01ffffffffffffff, 0xffffffff00000000, 0x80000000ffffffff, 0x7fe7ffffffffffff, + 0xffffffffffff0000, 0x0000000020ffffcf, 0x7f7ffffffffffdff, 0xfffc000000000001, + 0x007ffefffffcffff, 0xb47ffffffffffb7f, 0xfffffdbf000000cb, 0x00000000017b7fff, + 0x007fffff00000000, 0x0000000003ffffff, 0x00007fffffffffff, 0x000000000000000f, 0x000000000000007f, 0x00003fffffff0000, 0xe0fffff80000000f, 0x000000000000ffff, - 0x7fffffffffff001f, 0x00000000fff80000, 0x0000000300000000, 0x00001fffffffffff, + 0x7fffffffffff001f, 0x00000000fff80000, 0x0000000300000000, 0x0003ffffffffffff, 0xffff000000000000, 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000043ff01ff, 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, @@ -327,16 +328,16 @@ pub mod derived_property { 0x0000000000000000, 0x0000000000000000, 0x00000000000003f8, 0x0000000000000000, 0x0000000000000000, 0x0000000002000000, 0xbffffffffffe0000, 0x00100000000000b6, 0x0000000017ff003f, 0x00010000fffff801, 0x0000000000000000, 0x00003dffbfc00000, - 0xffff000000028000, 0x00000000000007ff, 0x0001ffc000000000, 0x043ff80000000000 + 0xffff000000028000, 0x00000000000007ff, 0x0001ffc000000000, 0x243ff80000000000 ], r2: [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 15, 16, 11, 17, 18, 7, 2, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 34, 35, 36, 37, 38, 39, 2, 40, 2, 2, 2, 41, 42, 43, 2, - 44, 45, 46, 47, 48, 49, 2, 50, 51, 52, 53, 54, 2, 2, 2, 2, 2, 2, 55, 56, 57, 58, 59, 60, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 15, 16, 11, 17, 18, 19, 2, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 34, 35, 36, 37, 38, 39, 40, 2, 41, 2, 2, 2, 42, 43, 44, 2, + 45, 46, 47, 48, 49, 50, 2, 51, 52, 53, 54, 55, 2, 2, 2, 2, 2, 2, 56, 57, 58, 59, 60, 61, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 61, 2, 62, 2, 63, 2, 64, 65, 2, 2, 2, 2, - 2, 2, 2, 66, 2, 67, 68, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 62, 2, 63, 2, 64, 2, 65, 66, 2, 2, 2, 2, + 2, 2, 2, 67, 2, 68, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -351,9 +352,9 @@ pub mod derived_property { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 49, 2, 2, 2, 2, 70, 71, 72, 73, 74, 75, 76, 77, 78, 2, 2, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 2, 88, 2, 89, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 50, 2, 2, 2, 2, 71, 72, 73, 74, 75, 76, 77, 78, 79, 2, 2, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 2, 89, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -364,35 +365,36 @@ pub mod derived_property { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 90, 2, 91, 92, 2, 2, 2, 2, 2, 2, 2, 2, 93, 94, 2, 95, - 96, 97, 98, 99 + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 91, 2, 92, 93, 2, 2, 2, 2, 2, 2, 2, 2, 94, 95, 2, 96, + 97, 98, 99, 100 ], r3: &[ - 0x00003fffffc00000, 0x000000000e000000, 0x0000000000000000, 0xfffffffffff00000, - 0x1400000000000007, 0x0002000c00fe21fe, 0x1000000000000002, 0x0000000c0000201e, + 0x00003fffffc00000, 0x000000000e000000, 0x0000000000000000, 0xfffffffffff80000, + 0x1400000000000007, 0x0002000c00fe21fe, 0x1000000000000002, 0x4000000c0000201e, 0x1000000000000006, 0x0023000000023986, 0xfc00000c000021be, 0x9000000000000002, - 0x0000000c0040201e, 0x0000000000000004, 0x0000000000002001, 0xc000000000000001, - 0x0000000c00603dc1, 0x0000000c00003040, 0x1800000000000003, 0x00000000005c0400, - 0x07f2000000000000, 0x0000000000007fc0, 0x1bf2000000000000, 0x0000000000003f40, - 0x02a0000003000000, 0x7ffe000000000000, 0x1ffffffffeffe0df, 0x0000000000000040, - 0x66fde00000000000, 0x001e0001c3000000, 0x0000000020002064, 0x1000000000000000, - 0x00000000e0000000, 0x001c0000001c0000, 0x000c0000000c0000, 0x3fb0000000000000, - 0x00000000208ffe40, 0x0000000000007800, 0x0000000000000008, 0x0000020000000060, - 0x0e04018700000000, 0x0000000009800000, 0x9ff81fe57f400000, 0x7fff008000000000, - 0x17d000000000000f, 0x000ff80000000004, 0x00003b3c00000003, 0x0003a34000000000, - 0x00cff00000000000, 0x3f00000000000000, 0x031021fdfff70000, 0xfffff00000000000, - 0x010007ffffffffff, 0xfffffffff8000000, 0xfbffffffffffffff, 0xa000000000000000, - 0x6000e000e000e003, 0x00007c900300f800, 0x8002ffdf00000000, 0x000000001fff0000, - 0x0001ffffffff0000, 0x3000000000000000, 0x0003800000000000, 0x8000800000000000, - 0xffffffff00000000, 0x0000800000000000, 0x083e3c0000000020, 0x000000007e000000, - 0x7000000000000000, 0x0000000000200000, 0x0000000000001000, 0xbff7800000000000, - 0x00000000f0000000, 0x0003000000000000, 0x00000003ffffffff, 0x0001000000000000, - 0x0000000000000700, 0x0300000000000000, 0x0000006000000844, 0x0003ffff00000030, - 0x00003fc000000000, 0x000000000003ff80, 0x13c8000000000007, 0x0000006000008000, - 0x00667e0000000000, 0x1001000000001008, 0xc19d000000000000, 0x0058300020000002, - 0x00000000f8000000, 0x0000212000000000, 0x0000000040000000, 0xfffc000000000000, - 0x0000000000000003, 0x0000ffff0008ffff, 0x0000000000240000, 0x8000000000000000, - 0x4000000004004080, 0x0001000000000001, 0x00000000c0000000, 0x0e00000800000000 + 0x0000000c0040201e, 0x0000000000000004, 0x0000000000002001, 0xc000000000000011, + 0x0000000c00603dc1, 0x0000000c00003040, 0x1800000000000003, 0x0000000c0000201e, + 0x00000000005c0400, 0x07f2000000000000, 0x0000000000007fc0, 0x1bf2000000000000, + 0x0000000000003f40, 0x02a0000003000000, 0x7ffe000000000000, 0x1ffffffffeffe0df, + 0x0000000000000040, 0x66fde00000000000, 0x001e0001c3000000, 0x0000000020002064, + 0x1000000000000000, 0x00000000e0000000, 0x001c0000001c0000, 0x000c0000000c0000, + 0x3fb0000000000000, 0x00000000208ffe40, 0x0000000000007800, 0x0000000000000008, + 0x0000020000000060, 0x0e04018700000000, 0x0000000009800000, 0x9ff81fe57f400000, + 0x7fff008000000000, 0x17d000000000000f, 0x000ff80000000004, 0x00003b3c00000003, + 0x0003a34000000000, 0x00cff00000000000, 0x3f00000000000000, 0x031021fdfff70000, + 0xfffff00000000000, 0x010007ffffffffff, 0xfffffffff8000000, 0xfbffffffffffffff, + 0xa000000000000000, 0x6000e000e000e003, 0x00007c900300f800, 0x8002ffdf00000000, + 0x000000001fff0000, 0x0001ffffffff0000, 0x3000000000000000, 0x0003800000000000, + 0x8000800000000000, 0xffffffff00000000, 0x0000800000000000, 0x083e3c0000000020, + 0x000000007e000000, 0x7000000000000000, 0x0000000000200000, 0x0000000000001000, + 0xbff7800000000000, 0x00000000f0000000, 0x0003000000000000, 0x00000003ffffffff, + 0x0001000000000000, 0x0000000000000700, 0x0300000000000000, 0x0000006000000844, + 0x8003ffff00000030, 0x00003fc000000000, 0x000000000003ff80, 0x13c8000000000007, + 0x0000006000008000, 0x00667e0000000000, 0x1001000000001008, 0xc19d000000000000, + 0x0058300020000002, 0x00000000f8000000, 0x0000212000000000, 0x0000000040000000, + 0xfffc000000000000, 0x0000000000000003, 0x0000ffff0008ffff, 0x0000000000240000, + 0x8000000000000000, 0x4000000004004080, 0x0001000000000001, 0x00000000c0000000, + 0x0e00000800000000 ], r4: [ 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 4, 2, 5, 6, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -407,42 +409,43 @@ pub mod derived_property { ], r5: &[ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 6, 7, 8, 0, 9, 10, 11, 12, 13, 0, 0, 14, 15, 16, 0, 0, 17, 18, 19, 20, - 0, 0, 21, 22, 23, 24, 25, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 0, 0, 0, - 0, 0, 30, 0, 31, 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 17, 18, 19, 0, 0, 20, 21, 22, + 23, 0, 0, 24, 25, 26, 27, 28, 0, 29, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 31, 32, 33, 0, 0, + 0, 0, 0, 34, 0, 35, 0, 36, 37, 38, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 48, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 43, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 50, 51, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 50, 51, 0, 0, 51, 51, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 56, 57, 0, 0, 57, 57, 57, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], r6: &[ 0x0000000000000000, 0x2000000000000000, 0x0000000100000000, 0x07c0000000000000, - 0x870000000000f06e, 0x0000006000000000, 0xff00000000000002, 0x800000000000007f, - 0x2678000000000003, 0x001fef8000000007, 0x0008000000000000, 0x7fc0000000000003, - 0x0000000000001c00, 0x40d3800000000000, 0x000007f880000000, 0x1000000000000003, - 0x001f1fc000000001, 0xff00000000000000, 0x000000000000005c, 0x85f8000000000000, - 0x000000000000000d, 0xb03c000000000000, 0x0000000030000001, 0xa7f8000000000000, - 0x0000000000000001, 0x00bf280000000000, 0x00000fbce0000000, 0x79f800000000067e, + 0x870000000000f06e, 0x0000006000000000, 0x000000f000000000, 0x000000000001ffc0, + 0xff00000000000002, 0x800000000000007f, 0x2678000000000003, 0x0000000000002000, + 0x001fef8000000007, 0x0008000000000000, 0x7fc0000000000003, 0x0000000000001e00, + 0x40d3800000000000, 0x000007f880000000, 0x1800000000000003, 0x001f1fc000000001, + 0xff00000000000000, 0x000000004000005c, 0x85f8000000000000, 0x000000000000000d, + 0xb03c000000000000, 0x0000000030000001, 0xa7f8000000000000, 0x0000000000000001, + 0x00bf280000000000, 0x00000fbce0000000, 0x06ff800000000000, 0x79f80000000007fe, 0x000000000e7e0080, 0x00000000037ffc00, 0xbf7f000000000000, 0x006dfcfffffc0000, - 0xb47e000000000000, 0x00000000000000bf, 0x001f000000000000, 0x007f000000000000, - 0x000000000000000f, 0x00000000ffff8000, 0x0000000300000000, 0x0000000f60000000, - 0xfff8038000000000, 0x00003c0000000fe7, 0x000000000000001c, 0xf87fffffffffffff, - 0x00201fffffffffff, 0x0000fffef8000010, 0x000007dbf9ffff7f, 0x00000000007f0000, - 0x00000000000007f0, 0xf800000000000000, 0xffffffff00000002, 0xffffffffffffffff, - 0x0000ffffffffffff + 0xb47e000000000000, 0x00000000000000bf, 0x0000000000a30000, 0x0018000000000000, + 0x001f000000000000, 0x007f000000000000, 0x000000000000000f, 0x00000000ffff8000, + 0x0000000300000000, 0x0000000f60000000, 0xfff8038000000000, 0x00003c0000000fe7, + 0x000000000000001c, 0xf87fffffffffffff, 0x00201fffffffffff, 0x0000fffef8000010, + 0x000007dbf9ffff7f, 0x00000000007f0000, 0x00000000000007f0, 0xf800000000000000, + 0xffffffff00000002, 0xffffffffffffffff, 0x0000ffffffffffff ], }; @@ -457,7 +460,7 @@ pub mod derived_property { 0xffffffffffffffff, 0xffffffffffffffff, 0x01ffffffffefffff, 0x0000001f00000003, 0x0000000000000000, 0xbccf000000000020, 0xfffffffbffffd740, 0xffbfffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, - 0xfffeffffffffffff, 0xfffffffe007fffff, 0x00000000000000ff, 0x0000000000000000, + 0xfffeffffffffffff, 0xffffffff007fffff, 0x00000000000001ff, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ], @@ -499,17 +502,17 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 29, 30, 0, 0 ], r3: &[ - 0x0000000000000000, 0xffffffff00000000, 0x00000000000020bf, 0x3f3fffffffffffff, - 0x00000000000001ff, 0xffffffffffffffff, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, + 0x0000000000000000, 0xffffffff00000000, 0xe7ffffffffff20bf, 0x3f3fffffffffffff, + 0xe7ffffffffff01ff, 0xffffffffffffffff, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8002000000000000, 0x000000001fff0000, 0xf21fbd503e2ffc84, 0xffffffff000043e0, 0x0000000000000018, 0xffc0000000000000, 0x000003ffffffffff, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, 0x000020bfffffffff, 0x00003fffffffffff, 0x000000003fffffff, 0xfffffffc00000000, - 0x00ff7fffffff78ff, 0x0700000000000000, 0xffff000000000000, 0xffff003ff7ffffff, + 0x03ffffffffff78ff, 0x0700000000000000, 0xffff000000000000, 0xffff003ff7ffffff, 0x0000000000f8007f, 0x07fffffe00000000, 0x0000000007fffffe ], r4: [ - 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 4, 5, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -527,13 +530,15 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 8, 9, 10, 11, 12, 1, 1, 1, 1, 13, 14, 15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 8, 9, 10, 11, 12, 1, 1, 1, 1, 13, 14, 15, 16, 17, + 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 3, 20, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 20, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], r6: &[ 0x0000000000000000, 0xffffffffffffffff, 0x000000000000ffff, 0xffff000000000000, @@ -558,16 +563,16 @@ pub mod derived_property { 0x0000000000000000, 0x0000000000000000, 0x00000000000003f8, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0xbffffffffffe0000, 0x00000000000000b6, 0x0000000007ff0000, 0x00010000fffff800, 0x0000000000000000, 0x00003d9f9fc00000, - 0xffff000000020000, 0x00000000000007ff, 0x0001ffc000000000, 0x000ff80000000000 + 0xffff000000020000, 0x00000000000007ff, 0x0001ffc000000000, 0x200ff80000000000 ], r2: [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 7, 2, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 34, 35, 36, 37, 2, 38, 2, 39, 2, 2, 2, 40, 41, 42, 2, 43, - 44, 45, 46, 47, 2, 2, 48, 2, 2, 2, 49, 2, 2, 2, 2, 2, 2, 2, 2, 50, 2, 2, 51, 2, 2, 2, 2, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 2, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 34, 35, 36, 37, 38, 2, 39, 2, 40, 2, 2, 2, 41, 42, 43, 2, 44, + 45, 46, 47, 48, 2, 2, 49, 2, 2, 2, 50, 2, 2, 2, 2, 2, 2, 2, 2, 51, 2, 2, 52, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 52, 2, 53, 2, 54, 2, 2, 2, 2, 2, 2, 2, 2, 55, - 2, 56, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 53, 2, 54, 2, 55, 2, 2, 2, 2, 2, 2, 2, 2, 56, + 2, 57, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -583,8 +588,8 @@ pub mod derived_property { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 57, 58, 59, 2, 2, 2, 2, 60, 2, 2, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 2, 2, 2, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 58, 59, 60, 2, 2, 2, 2, 61, 2, 2, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 2, 2, 2, 71, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -595,28 +600,28 @@ pub mod derived_property { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 71, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 72, 2, 2, 2, 2, 2, 58, 2 + 2, 2, 2, 2, 72, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 73, 2, 2, 2, 2, 2, 59, 2 ], r3: &[ - 0x00003eeffbc00000, 0x000000000e000000, 0x0000000000000000, 0xfffffffbfff00000, - 0x1400000000000007, 0x0000000c00fe21fe, 0x5000000000000002, 0x0000000c0080201e, + 0x00003eeffbc00000, 0x000000000e000000, 0x0000000000000000, 0xfffffffbfff80000, + 0x1400000000000007, 0x0000000c00fe21fe, 0x5000000000000002, 0x4000000c0080201e, 0x1000000000000006, 0x0023000000023986, 0xfc00000c000021be, 0xd000000000000002, - 0x0000000c00c0201e, 0x4000000000000004, 0x0000000000802001, 0xc000000000000001, + 0x0000000c00c0201e, 0x4000000000000004, 0x0000000000802001, 0xc000000000000011, 0x0000000c00603dc1, 0x9000000000000002, 0x0000000c00603044, 0x5800000000000003, - 0x00000000805c8400, 0x07f2000000000000, 0x0000000000007f80, 0x1bf2000000000000, - 0x0000000000003f00, 0x02a0000003000000, 0x7ffe000000000000, 0x1ffffffffeffe0df, - 0x0000000000000040, 0x66fde00000000000, 0x001e0001c3000000, 0x0000000020002064, - 0x00000000e0000000, 0x001c0000001c0000, 0x000c0000000c0000, 0x3fb0000000000000, - 0x00000000200ffe40, 0x0000000000003800, 0x0000020000000060, 0x0e04018700000000, - 0x0000000009800000, 0x9ff81fe57f400000, 0x7fff000000000000, 0x17d000000000000f, - 0x000ff80000000004, 0x00003b3c00000003, 0x0003a34000000000, 0x00cff00000000000, - 0x031021fdfff70000, 0xfbffffffffffffff, 0x0000000000001000, 0x0001ffffffff0000, - 0x0003800000000000, 0x8000000000000000, 0xffffffff00000000, 0x0000fc0000000000, - 0x0000000006000000, 0x3ff7800000000000, 0x00000000c0000000, 0x0003000000000000, - 0x0000006000000844, 0x0003ffff00000030, 0x00003fc000000000, 0x000000000003ff80, - 0x13c8000000000007, 0x0000002000000000, 0x00667e0000000000, 0x1000000000001008, - 0xc19d000000000000, 0x0040300000000002, 0x0000212000000000, 0x0000000040000000, - 0x0000ffff0000ffff + 0x0000000c0080201e, 0x00000000805c8400, 0x07f2000000000000, 0x0000000000007f80, + 0x1bf2000000000000, 0x0000000000003f00, 0x02a0000003000000, 0x7ffe000000000000, + 0x1ffffffffeffe0df, 0x0000000000000040, 0x66fde00000000000, 0x001e0001c3000000, + 0x0000000020002064, 0x00000000e0000000, 0x001c0000001c0000, 0x000c0000000c0000, + 0x3fb0000000000000, 0x00000000200ffe40, 0x0000000000003800, 0x0000020000000060, + 0x0e04018700000000, 0x0000000009800000, 0x9ff81fe57f400000, 0x7fff000000000000, + 0x17d000000000000f, 0x000ff80000000004, 0x00003b3c00000003, 0x0003a34000000000, + 0x00cff00000000000, 0x031021fdfff70000, 0xfbffffffffffffff, 0x0000000000001000, + 0x0001ffffffff0000, 0x0003800000000000, 0x8000000000000000, 0xffffffff00000000, + 0x0000fc0000000000, 0x0000000006000000, 0x3ff7800000000000, 0x00000000c0000000, + 0x0003000000000000, 0x0000006000000844, 0x8003ffff00000030, 0x00003fc000000000, + 0x000000000003ff80, 0x13c8000000000007, 0x0000002000000000, 0x00667e0000000000, + 0x1000000000001008, 0xc19d000000000000, 0x0040300000000002, 0x0000212000000000, + 0x0000000040000000, 0x0000ffff0000ffff ], r4: [ 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 4, 2, 5, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -631,38 +636,40 @@ pub mod derived_property { ], r5: &[ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 6, 7, 8, 0, 9, 10, 11, 12, 13, 0, 0, 14, 15, 16, 0, 0, 17, 18, 19, 20, - 0, 0, 21, 22, 23, 24, 25, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 0, 0, 0, - 0, 0, 30, 0, 31, 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 43, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 46, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 48, 0, 0, 48, 48, - 48, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 0, 0, 8, 9, 10, 0, 11, 12, 13, 14, 15, 0, 0, 16, 17, 18, 0, 0, 19, 20, 21, + 22, 0, 0, 23, 24, 25, 26, 27, 0, 28, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 30, 31, 32, 0, 0, + 0, 0, 0, 33, 0, 34, 0, 35, 36, 37, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 53, 0, 0, + 53, 53, 53, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 ], r6: &[ 0x0000000000000000, 0x2000000000000000, 0x0000000100000000, 0x07c0000000000000, - 0x870000000000f06e, 0x0000006000000000, 0xff00000000000002, 0x800000000000007f, - 0x0678000000000003, 0x001fef8000000007, 0x0008000000000000, 0x7fc0000000000003, - 0x0000000000001c00, 0x40d3800000000000, 0x000007f880000000, 0x5000000000000003, - 0x001f1fc000800001, 0xff00000000000000, 0x000000000000005c, 0xa5f9000000000000, - 0x000000000000000d, 0xb03c800000000000, 0x0000000030000001, 0xa7f8000000000000, - 0x0000000000000001, 0x00bf280000000000, 0x00000fbce0000000, 0x79f800000000067e, - 0x000000000e7e0080, 0x00000000037ffc00, 0xbf7f000000000000, 0x006dfcfffffc0000, - 0xb47e000000000000, 0x00000000000000bf, 0x001f000000000000, 0x007f000000000000, - 0x0000000000078000, 0x0000000060000000, 0xf807c3a000000000, 0x00003c0000000fe7, - 0x000000000000001c, 0xf87fffffffffffff, 0x00201fffffffffff, 0x0000fffef8000010, - 0x000007dbf9ffff7f, 0x00000000007f0000, 0x00000000000007f0, 0xffffffff00000000, - 0xffffffffffffffff, 0x0000ffffffffffff + 0x870000000000f06e, 0x0000006000000000, 0x000000f000000000, 0x000000000001ffc0, + 0xff00000000000002, 0x800000000000007f, 0x0678000000000003, 0x001fef8000000007, + 0x0008000000000000, 0x7fc0000000000003, 0x0000000000001e00, 0x40d3800000000000, + 0x000007f880000000, 0x5800000000000003, 0x001f1fc000800001, 0xff00000000000000, + 0x000000004000005c, 0xa5f9000000000000, 0x000000000000000d, 0xb03c800000000000, + 0x0000000030000001, 0xa7f8000000000000, 0x0000000000000001, 0x00bf280000000000, + 0x00000fbce0000000, 0x06ff800000000000, 0x79f80000000007fe, 0x000000000e7e0080, + 0x00000000037ffc00, 0xbf7f000000000000, 0x006dfcfffffc0000, 0xb47e000000000000, + 0x00000000000000bf, 0x0000000000a30000, 0x0018000000000000, 0x001f000000000000, + 0x007f000000000000, 0x0000000000078000, 0x0000000060000000, 0xf807c3a000000000, + 0x00003c0000000fe7, 0x000000000000001c, 0xf87fffffffffffff, 0x00201fffffffffff, + 0x0000fffef8000010, 0x000007dbf9ffff7f, 0x00000000007f0000, 0x00000000000007f0, + 0xffffffff00000000, 0xffffffffffffffff, 0x0000ffffffffffff ], }; @@ -677,17 +684,17 @@ pub mod derived_property { 0x93faaaaaaaaaaaaa, 0xffffffffffffaa85, 0x01ffffffffefffff, 0x0000001f00000003, 0x0000000000000000, 0x3c8a000000000020, 0xfffff00000010000, 0x192faaaaaae37fff, 0xffff000000000000, 0xaaaaaaaaffffffff, 0xaaaaaaaaaaaaa802, 0xaaaaaaaaaaaad554, - 0x0000aaaaaaaaaaaa, 0xfffffffe00000000, 0x00000000000000ff, 0x0000000000000000, + 0x0000aaaaaaaaaaaa, 0xffffffff00000000, 0x00000000000001ff, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ], r2: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 3, 3, - 0, 4, 4, 5, 4, 6, 7, 8, 9, 0, 10, 11, 0, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16, 17, 4, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 4, 4, 4, + 0, 5, 5, 6, 5, 7, 8, 9, 10, 0, 11, 12, 0, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 18, 5, 19, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -703,8 +710,8 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 0, - 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 26, 3, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22, + 0, 23, 24, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 27, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -715,21 +722,21 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 28, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0 ], r3: &[ - 0x0000000000000000, 0x3f00000000000000, 0x00000000000001ff, 0xffffffffffffffff, - 0xaaaaaaaaaaaaaaaa, 0xaaaaaaaabfeaaaaa, 0x00ff00ff003f00ff, 0x3fff00ff00ff003f, - 0x40df00ff00ff00ff, 0x00dc00ff00cf00dc, 0x8002000000000000, 0x000000001fff0000, - 0x321080000008c400, 0xffff0000000043c0, 0x0000000000000010, 0x000003ffffff0000, - 0xffff000000000000, 0x3fda15627fffffff, 0x0008501aaaaaaaaa, 0x000020bfffffffff, - 0x00002aaaaaaaaaaa, 0x000000003aaaaaaa, 0xaaabaaa800000000, 0x95ffaaaaaaaaaaaa, - 0x00a002aaaaba50aa, 0x0700000000000000, 0xffff003ff7ffffff, 0x0000000000f8007f, - 0x0000000007fffffe + 0x0000000000000000, 0xe7ffffffffff0000, 0x3f00000000000000, 0x00000000000001ff, + 0xffffffffffffffff, 0xaaaaaaaaaaaaaaaa, 0xaaaaaaaabfeaaaaa, 0x00ff00ff003f00ff, + 0x3fff00ff00ff003f, 0x40df00ff00ff00ff, 0x00dc00ff00cf00dc, 0x8002000000000000, + 0x000000001fff0000, 0x321080000008c400, 0xffff0000000043c0, 0x0000000000000010, + 0x000003ffffff0000, 0xffff000000000000, 0x3fda15627fffffff, 0x0008501aaaaaaaaa, + 0x000020bfffffffff, 0x00002aaaaaaaaaaa, 0x000000003aaaaaaa, 0xaaabaaa800000000, + 0x95ffaaaaaaaaaaaa, 0x02a082aaaaba50aa, 0x0700000000000000, 0xffff003ff7ffffff, + 0x0000000000f8007f, 0x0000000007fffffe ], r4: [ - 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 4, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -747,19 +754,22 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], r6: &[ 0x0000000000000000, 0xffffff0000000000, 0x000000000000ffff, 0x0fffffffff000000, - 0x0007ffffffffffff, 0x00000000ffffffff, 0x000ffffffc000000, 0x000000ffffdfc000, - 0xebc000000ffffffc, 0xfffffc000000ffef, 0x00ffffffc000000f, 0x00000ffffffc0000, - 0xfc000000ffffffc0, 0xffffc000000fffff, 0x0ffffffc000000ff, 0x0000ffffffc00000, - 0x0000003ffffffc00, 0xf0000003f7fffffc, 0xffc000000fdfffff, 0xffff0000003f7fff, - 0xfffffc000000fdff, 0x0000000000000bf7, 0xfffffffc00000000, 0x000000000000000f + 0x0007ffffffffffff, 0x00000000ffffffff, 0xffffffff00000000, 0x000ffffffc000000, + 0x000000ffffdfc000, 0xebc000000ffffffc, 0xfffffc000000ffef, 0x00ffffffc000000f, + 0x00000ffffffc0000, 0xfc000000ffffffc0, 0xffffc000000fffff, 0x0ffffffc000000ff, + 0x0000ffffffc00000, 0x0000003ffffffc00, 0xf0000003f7fffffc, 0xffc000000fdfffff, + 0xffff0000003f7fff, 0xfffffc000000fdff, 0x0000000000000bf7, 0xfffffffc00000000, + 0x000000000000000f ], }; @@ -781,10 +791,10 @@ pub mod derived_property { r2: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 4, 4, 5, 4, 6, 7, 8, 9, 0, 0, 0, 0, 10, 11, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 15, 16, 4, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, + 0, 5, 5, 6, 5, 7, 8, 9, 10, 0, 0, 0, 0, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, + 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16, 17, 5, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -800,8 +810,8 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 19, 0, - 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 0, + 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -813,18 +823,19 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 23, 0, 0, 0 + 0, 0, 0, 0, 0, 24, 0, 0, 0 ], r3: &[ 0x0000000000000000, 0xffffffff00000000, 0x00000000000020bf, 0x003fffffffffffff, - 0x5555555555555555, 0x5555555540155555, 0xff00ff003f00ff00, 0x0000ff00aa003f00, - 0x0f00000000000000, 0x0f001f000f000f00, 0xc00f3d503e273884, 0x0000ffff00000020, - 0x0000000000000008, 0xffc0000000000000, 0x000000000000ffff, 0x00007fffffffffff, - 0xc025ea9d00000000, 0x0004280555555555, 0x0000155555555555, 0x0000000005555555, - 0x5554555400000000, 0x6a00555555555555, 0x005f7d5555452855, 0x07fffffe00000000 + 0xe7ffffffffff0000, 0x5555555555555555, 0x5555555540155555, 0xff00ff003f00ff00, + 0x0000ff00aa003f00, 0x0f00000000000000, 0x0f001f000f000f00, 0xc00f3d503e273884, + 0x0000ffff00000020, 0x0000000000000008, 0xffc0000000000000, 0x000000000000ffff, + 0x00007fffffffffff, 0xc025ea9d00000000, 0x0004280555555555, 0x0000155555555555, + 0x0000000005555555, 0x5554555400000000, 0x6a00555555555555, 0x015f7d5555452855, + 0x07fffffe00000000 ], r4: [ - 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 4, 5, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -842,22 +853,24 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 24, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], r6: &[ 0x0000000000000000, 0x000000ffffffffff, 0xffff000000000000, 0x00000000000fffff, - 0x0007ffffffffffff, 0xffffffff00000000, 0xfff0000003ffffff, 0xffffff0000003fff, - 0x003fde64d0000003, 0x000003ffffff0000, 0x7b0000001fdfe7b0, 0xfffff0000001fc5f, - 0x03ffffff0000003f, 0x00003ffffff00000, 0xf0000003ffffff00, 0xffff0000003fffff, - 0xffffff00000003ff, 0x07fffffc00000001, 0x001ffffff0000000, 0x00007fffffc00000, - 0x000001ffffff0000, 0x0000000000000400, 0x00000003ffffffff, 0xffff03ffffff03ff, - 0x00000000000003ff + 0x0007ffffffffffff, 0xffffffff00000000, 0x00000000ffffffff, 0xfff0000003ffffff, + 0xffffff0000003fff, 0x003fde64d0000003, 0x000003ffffff0000, 0x7b0000001fdfe7b0, + 0xfffff0000001fc5f, 0x03ffffff0000003f, 0x00003ffffff00000, 0xf0000003ffffff00, + 0xffff0000003fffff, 0xffffff00000003ff, 0x07fffffc00000001, 0x001ffffff0000000, + 0x00007fffffc00000, 0x000001ffffff0000, 0x0000000000000400, 0x00000003ffffffff, + 0xffff03ffffff03ff, 0x00000000000003ff ], }; @@ -872,19 +885,19 @@ pub mod derived_property { 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, 0xffffffffffffffff, 0xb8dfffffffffffff, 0xfffffffbffffd7c0, 0xffbfffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffcfb, 0xffffffffffffffff, - 0xfffeffffffffffff, 0xfffffffe027fffff, 0xbffffffffffe00ff, 0x000707ffffff00b6, + 0xfffeffffffffffff, 0xffffffff027fffff, 0xbffffffffffe01ff, 0x000787ffffff00b6, 0xffffffff07ff0000, 0xffffc3ffffffffff, 0xffffffffffffffff, 0x9ffffdff9fefffff, - 0xffffffffffff0000, 0xffffffffffffe7ff, 0x0003ffffffffffff, 0x043fffffffffffff + 0xffffffffffff0000, 0xffffffffffffe7ff, 0x0003ffffffffffff, 0x243fffffffffffff ], r2: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 4, 32, 33, 34, 4, 4, 4, 4, 4, 35, 36, 37, 38, 39, 40, 41, 42, 4, 4, 4, 4, 4, 4, 4, 4, 43, 44, 45, 46, 47, 4, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 4, 61, 4, 62, 50, 63, 64, 65, 4, 4, 4, 66, 4, 4, 4, 4, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 64, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 56, 57, 58, 59, 60, 4, 61, 4, 62, 63, 64, 65, 66, 4, 4, 4, 67, 4, 4, 4, 4, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 77, 78, 4, 79, 80, 81, 82, 83, 60, 60, 60, 60, 60, 60, 60, 60, 84, - 42, 85, 86, 87, 4, 88, 89, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 60, 60, 60, 60, 60, 79, 80, 4, 81, 82, 83, 84, 85, 60, 60, 60, 60, 60, 60, 60, 60, 86, + 42, 87, 88, 89, 4, 90, 91, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, @@ -899,30 +912,30 @@ pub mod derived_property { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 90, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 91, 92, 4, 4, 4, 4, 93, 94, 4, 95, 96, 4, 97, 98, 99, 62, 4, 100, 101, - 102, 4, 103, 104, 105, 4, 106, 107, 108, 4, 109, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 93, 94, 4, 4, 4, 4, 95, 96, 4, 97, 98, 4, 99, 100, 101, 62, 4, 102, 103, + 104, 4, 105, 106, 107, 4, 108, 109, 110, 4, 111, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 110, 111, 60, 60, 60, 60, 60, 60, 60, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 112, 113, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 101, 4, 112, - 113, 114, 95, 115, 4, 116, 4, 4, 117, 118, 119, 120, 121, 122, 4, 123, 124, 125, 126, - 127 + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 103, 4, 114, + 115, 116, 97, 117, 4, 118, 4, 4, 119, 120, 121, 122, 123, 124, 4, 125, 126, 127, 128, + 129 ], r3: &[ - 0x00003fffffffffff, 0x000007ff0fffffff, 0x3fdfffff00000000, 0xfffffffbfff00000, - 0xffffffffffffffff, 0xfffeffcfffffffff, 0xf3c5fdfffff99fef, 0x1003ffcfb080799f, + 0x00003fffffffffff, 0x000007ff0fffffff, 0x3fdfffff00000000, 0xfffffffbfff80000, + 0xffffffffffffffff, 0xfffeffcfffffffff, 0xf3c5fdfffff99fef, 0x5003ffcfb080799f, 0xd36dfdfffff987ee, 0x003fffc05e023987, 0xf3edfdfffffbbfee, 0xfe00ffcf00013bbf, 0xf3edfdfffff99fee, 0x0002ffcfb0c0399f, 0xc3ffc718d63dc7ec, 0x0000ffc000813dc7, - 0xe3fffdfffffddfef, 0x0000ffcf07603ddf, 0xf3effdfffffddfef, 0x0006ffcf40603ddf, + 0xe3fffdfffffddfff, 0x0000ffcf07603ddf, 0xf3effdfffffddfef, 0x0006ffcf40603ddf, 0xfffffffffffddfef, 0xfc00ffcf80f07ddf, 0x2ffbfffffc7fffec, 0x000cffc0ff5f847f, 0x07fffffffffffffe, 0x0000000003ff7fff, 0x3bffecaefef02596, 0x00000000f3ff3f5f, 0xc2a003ff03000001, 0xfffe1ffffffffeff, 0x1ffffffffeffffdf, 0x0000000000000040, @@ -930,26 +943,27 @@ pub mod derived_property { 0x7f3dffffffff3dff, 0xffffffffff7fff3d, 0xffffffffff3dffff, 0x0003fe00e7ffffff, 0xffffffff0000ffff, 0x3f3fffffffffffff, 0xfffffffffffffffe, 0xffff9fffffffffff, 0xffffffff07fffffe, 0x01ffc7ffffffffff, 0x001fffff001fdfff, 0x000ddfff000fffff, - 0x000003ff308fffff, 0xffffffff03ff3800, 0x00ffffffffffffff, 0xffff07ffffffffff, + 0x000003ff308fffff, 0xffffffff03ff3800, 0x01ffffffffffffff, 0xffff07ffffffffff, 0x003fffffffffffff, 0x0fff0fff7fffffff, 0x001f3fffffffffc0, 0xffff0fffffffffff, 0x0000000007ff03ff, 0xffffffff0fffffff, 0x9fffffff7fffffff, 0x3fff008003ff03ff, - 0x0000000000000000, 0x000ff80003ff0fff, 0x000fffffffffffff, 0x3fffffffffffe3ff, - 0x00000000000001ff, 0x03fffffffff70000, 0xfbffffffffffffff, 0xffffffff3f3fffff, - 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8000000000000000, - 0x8002000000100001, 0x000000001fff0000, 0x0001ffe21fff0000, 0xf3fffd503f2ffc84, - 0xffffffff000043e0, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000ff81fffffffff, - 0xffff20bfffffffff, 0x800080ffffffffff, 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, - 0x1f3efffe000000e0, 0xfffffffee67fffff, 0xf7ffffffffffffff, 0xfffe7fffffffffe0, - 0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, 0x0000000000001fff, - 0x3fffffffffff0000, 0x00000fffffff1fff, 0xbff0ffffffffffff, 0x0003ffffffffffff, - 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000, 0x000000ffffffffff, - 0x28ffffff03ff003f, 0xffff3fffffffffff, 0x1fffffff000fffff, 0x7fffffff03ff8001, - 0x007fffffffffffff, 0xfc7fffff03ff3fff, 0x007cffff38000007, 0xffff7f7f007e7e7e, - 0xffff003ff7ffffff, 0x03ff37ffffffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, - 0x0000000003ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb, 0xfffffffffff80000, - 0xfffffff03fffffff, 0x3fffffffffffffff, 0xffffffffffff0000, 0xfffffffffffcffff, - 0x03ff0000000000ff, 0x0018ffff0000ffff, 0xaa8a00000000e000, 0x1fffffffffffffff, - 0x87fffffe03ff0000, 0xffffffc007fffffe, 0x7fffffffffffffff, 0x000000001cfcfcfc + 0x0000000000000000, 0x000ff80003ff0fff, 0x000fffffffffffff, 0x00ffffffffffffff, + 0x3fffffffffffe3ff, 0xe7ffffffffff01ff, 0x03fffffffff70000, 0xfbffffffffffffff, + 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, + 0x8000000000000000, 0x8002000000100001, 0x000000001fff0000, 0x0001ffe21fff0000, + 0xf3fffd503f2ffc84, 0xffffffff000043e0, 0x00000000000001ff, 0xffff7fffffffffff, + 0xffffffff7fffffff, 0x000ff81fffffffff, 0xffff20bfffffffff, 0x800080ffffffffff, + 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, 0x1f3efffe000000e0, 0xfffffffee67fffff, + 0xf7ffffffffffffff, 0xfffeffffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, + 0x0000ffffffffffff, 0x0000000000001fff, 0x3fffffffffff0000, 0x00000fffffff1fff, + 0xbff0ffffffffffff, 0x0003ffffffffffff, 0xfffffffcff800000, 0x03fffffffffff9ff, + 0xff80000000000000, 0x000000ffffffffff, 0xe8ffffff03ff003f, 0xffff3fffffffffff, + 0x1fffffff000fffff, 0x7fffffff03ff8001, 0x007fffffffffffff, 0xfc7fffff03ff3fff, + 0x007cffff38000007, 0xffff7f7f007e7e7e, 0xffff003ff7ffffff, 0x03ff37ffffffffff, + 0xffff000fffffffff, 0x0ffffffffffff87f, 0x0000000003ffffff, 0x5f7ffdffe0f8007f, + 0xffffffffffffffdb, 0xfffffffffff80000, 0xfffffff03fffffff, 0x3fffffffffffffff, + 0xffffffffffff0000, 0xfffffffffffcffff, 0x03ff0000000000ff, 0x0018ffff0000ffff, + 0xaa8a00000000e000, 0x1fffffffffffffff, 0x87fffffe03ff0000, 0xffffffc007fffffe, + 0x7fffffffffffffff, 0x000000001cfcfcfc ], r4: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 13, @@ -965,45 +979,45 @@ pub mod derived_property { r5: &[ 0, 1, 2, 3, 4, 5, 4, 6, 4, 4, 7, 8, 9, 10, 11, 12, 2, 2, 13, 14, 15, 16, 4, 4, 2, 2, 2, 2, 17, 18, 4, 4, 19, 20, 21, 22, 23, 4, 24, 4, 25, 26, 27, 28, 29, 30, 31, 4, 2, 32, 33, - 33, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 34, 3, 35, 36, 37, 2, 38, 39, 4, 40, 41, 42, - 43, 4, 4, 2, 44, 2, 45, 4, 4, 46, 47, 2, 48, 49, 50, 51, 4, 4, 4, 4, 4, 52, 53, 4, 4, 4, - 4, 54, 55, 56, 57, 4, 4, 4, 4, 58, 59, 60, 4, 61, 62, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 63, 4, 2, 64, 2, 2, 2, 65, 4, 4, 4, 4, 4, 4, 4, + 33, 34, 4, 4, 4, 4, 4, 4, 4, 35, 36, 4, 4, 2, 37, 3, 38, 39, 40, 2, 41, 42, 4, 43, 44, + 45, 46, 4, 4, 2, 47, 2, 48, 4, 4, 49, 50, 2, 51, 52, 53, 54, 4, 4, 4, 3, 4, 55, 56, 4, + 4, 4, 4, 57, 58, 59, 60, 4, 4, 4, 4, 61, 62, 63, 4, 64, 65, 66, 4, 4, 4, 4, 67, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 68, 4, 2, 69, 2, 2, 2, 70, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 66, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 71, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, - 2, 2, 2, 2, 2, 2, 57, 67, 4, 68, 17, 69, 70, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 71, 72, 73, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 60, 72, 4, 73, 17, 74, 75, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, + 4, 2, 76, 77, 78, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 21, 75, 2, 2, 2, 2, 2, 76, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 2, 77, 78, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 79, 80, 4, 4, 81, 4, 4, 4, 4, 4, 4, 2, 82, 83, 84, 85, 86, 2, 2, 2, 2, 87, 88, 89, 90, - 91, 92, 4, 4, 4, 4, 4, 4, 4, 4, 93, 94, 95, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 96, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 97, 2, 44, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 98, 99, 100, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 101, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 79, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 21, 80, 2, 2, 2, 2, 2, + 81, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 2, 82, 83, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 84, 85, 4, 4, 86, 4, 4, 4, 4, 4, 4, 2, 87, 88, 89, 90, 91, 2, 2, 2, 2, 92, 93, 94, 95, + 96, 97, 4, 4, 4, 4, 4, 4, 4, 4, 98, 99, 100, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 101, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 102, 2, 103, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 104, 105, 106, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 107, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 102, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 108, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 103, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 109, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 104, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 105, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 110, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 111, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ], r6: &[ 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, @@ -1012,27 +1026,28 @@ pub mod derived_property { 0x00000000003eff0f, 0xffff03ff3fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, 0x0000000fffffffff, 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, - 0xc0ffffffffffffff, 0x870ffffffeeff06f, 0x1fffffff00000000, 0x000000001fffffff, + 0xc0ffffffffffffff, 0x873ffffffeeff06f, 0x1fffffff00000000, 0x000000001fffffff, 0x0000007ffffffeff, 0x003fffffffffffff, 0x0007ffff003fffff, 0x000000000003ffff, - 0x00000000000001ff, 0x0007ffffffffffff, 0x8000ffc00000007f, 0x03ff01ffffff0000, - 0xffdfffffffffffff, 0x004fffffffff0000, 0x0000000017ff1c1f, 0x40fffffffffbffff, - 0xffff01ffbfffbd7f, 0x03ff07ffffffffff, 0xf3edfdfffff99fef, 0x001f1fcfe081399f, - 0x0000000003ff07ff, 0x0000000003ff00bf, 0xff3fffffffffffff, 0x000000003f000001, - 0x0000000003ff0011, 0x00ffffffffffffff, 0x00000000000003ff, 0x03ff0fffe3ffffff, - 0xffffffff00000000, 0x800003ffffffffff, 0x7fffffffffffffff, 0xffffffffffff0080, - 0x0000000003ffffcf, 0x01ffffffffffffff, 0xff7ffffffffffdff, 0xfffc000003ff0001, - 0x007ffefffffcffff, 0xb47ffffffffffb7f, 0x0000000003ff00ff, 0x0000000003ffffff, - 0x00007fffffffffff, 0x000000000000000f, 0x000000000000007f, 0x000003ff7fffffff, - 0x001f3fffffff0000, 0xe0fffff803ff000f, 0x000000000000ffff, 0x7fffffffffff001f, - 0x00000000ffff8000, 0x0000000300000000, 0x00001fffffffffff, 0xffff000000000000, - 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000063ff01ff, 0xf807e3e000000000, - 0x00003c0000000fe7, 0x000000000000001c, 0xffffffffffdfffff, 0xebffde64dfffffff, - 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffff3fffffffff, - 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, 0xfffffdfffffffdff, - 0xffffffffffffcff7, 0xf87fffffffffffff, 0x00201fffffffffff, 0x0000fffef8000010, - 0x000007dbf9ffff7f, 0x00000000007f001f, 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, - 0x0ffffbee0ffffbff, 0x00000000007fffff, 0xffff0003ffffffff, 0x00000001ffffffff, - 0x000000003fffffff, 0x0000ffffffffffff + 0x00000000000001ff, 0x0007ffffffffffff, 0x03ff00ffffffffff, 0xffff00801fffffff, + 0x000000000001ffff, 0x8000ffc00000007f, 0x03ff01ffffff0000, 0xffdfffffffffffff, + 0x004fffffffff0070, 0x0000000017ff1e1f, 0x40fffffffffbffff, 0xffff01ffbfffbd7f, + 0x03ff07ffffffffff, 0xfbedfdfffff99fef, 0x001f1fcfe081399f, 0x0000000043ff07ff, + 0x0000000003ff00bf, 0xff3fffffffffffff, 0x000000003f000001, 0x0000000003ff0011, + 0x00ffffffffffffff, 0x00000000000003ff, 0x03ff0fffe7ffffff, 0xffffffff00000000, + 0x800003ffffffffff, 0x7fffffffffffffff, 0xffffffffffff0080, 0x0000000023ffffcf, + 0x01ffffffffffffff, 0xff7ffffffffffdff, 0xfffc000003ff0001, 0x007ffefffffcffff, + 0xb47ffffffffffb7f, 0xfffffdbf03ff00ff, 0x000003ff01fb7fff, 0x007fffff00000000, + 0x0000000003ffffff, 0x00007fffffffffff, 0x000000000000000f, 0x000000000000007f, + 0x000003ff7fffffff, 0x001f3fffffff0000, 0xe0fffff803ff000f, 0x000000000000ffff, + 0x7fffffffffff001f, 0x00000000ffff8000, 0x0000000300000000, 0x0003ffffffffffff, + 0xffff000000000000, 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000063ff01ff, + 0xf807e3e000000000, 0x00003c0000000fe7, 0x000000000000001c, 0xffffffffffdfffff, + 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, + 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, + 0xfffffdfffffffdff, 0xffffffffffffcff7, 0xf87fffffffffffff, 0x00201fffffffffff, + 0x0000fffef8000010, 0x000007dbf9ffff7f, 0x00000000007f001f, 0x0000000003ff07ff, + 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0x00000000007fffff, + 0xffff0003ffffffff, 0x00000001ffffffff, 0x000000003fffffff, 0x0000ffffffffffff ], }; @@ -1047,7 +1062,7 @@ pub mod derived_property { 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, 0x0000000000000000, 0xb8df000000000000, 0xfffffffbffffd740, 0xffbfffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, - 0xfffeffffffffffff, 0xfffffffe027fffff, 0x00000000000000ff, 0x000707ffffff0000, + 0xfffeffffffffffff, 0xffffffff027fffff, 0x00000000000001ff, 0x000787ffffff0000, 0xffffffff00000000, 0xfffec000000007ff, 0xffffffffffffffff, 0x9c00c060002fffff, 0x0000fffffffd0000, 0xffffffffffffe000, 0x0002003fffffffff, 0x043007fffffffc00 ], @@ -1056,9 +1071,9 @@ pub mod derived_property { 24, 23, 25, 26, 27, 28, 29, 3, 30, 31, 32, 33, 34, 34, 34, 34, 34, 35, 36, 37, 38, 39, 40, 41, 42, 34, 34, 34, 34, 34, 34, 34, 34, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 3, 61, 62, 63, 64, 65, 66, 67, 68, 34, 34, 34, 3, 34, 34, - 34, 34, 69, 70, 71, 72, 3, 73, 74, 3, 75, 76, 67, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 77, - 78, 34, 79, 80, 81, 82, 83, 3, 3, 3, 3, 3, 3, 3, 3, 84, 42, 85, 86, 87, 34, 88, 89, 3, + 34, 34, 69, 70, 71, 72, 3, 73, 74, 3, 75, 76, 77, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 78, + 79, 34, 80, 81, 82, 83, 84, 3, 3, 3, 3, 3, 3, 3, 3, 85, 42, 86, 87, 88, 34, 89, 90, 3, 3, 3, 3, 3, 3, 3, 3, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, @@ -1078,9 +1093,9 @@ pub mod derived_property { 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 90, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 91, 92, 34, 34, 34, 34, 93, - 94, 95, 96, 97, 34, 98, 99, 100, 48, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 91, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 92, 93, 34, 34, 34, 34, 94, + 95, 96, 91, 97, 34, 98, 99, 100, 48, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 34, 113, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, @@ -1110,20 +1125,20 @@ pub mod derived_property { 0x7f3dffffffff3dff, 0xffffffffff7fff3d, 0xffffffffff3dffff, 0x0000000007ffffff, 0xffffffff0000ffff, 0x3f3fffffffffffff, 0xfffffffffffffffe, 0xffff9fffffffffff, 0xffffffff07fffffe, 0x01ffc7ffffffffff, 0x0003ffff0003dfff, 0x0001dfff0003ffff, - 0x000fffffffffffff, 0x0000000010800000, 0xffffffff00000000, 0x00ffffffffffffff, + 0x000fffffffffffff, 0x0000000010800000, 0xffffffff00000000, 0x01ffffffffffffff, 0xffff05ffffffffff, 0x003fffffffffffff, 0x000000007fffffff, 0x001f3fffffff0000, 0xffff0fffffffffff, 0x00000000000003ff, 0xffffffff007fffff, 0x00000000001fffff, 0x0000008000000000, 0x000fffffffffffe0, 0x0000000000000fe0, 0xfc00c001fffffff8, - 0x0000003fffffffff, 0x0000000fffffffff, 0x3ffffffffc00e000, 0x00000000000001ff, + 0x0000003fffffffff, 0x0000000fffffffff, 0x3ffffffffc00e000, 0xe7ffffffffff01ff, 0x0063de0000000000, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8002000000000000, 0x000000001fff0000, 0xf3fffd503f2ffc84, - 0xffffffff000043e0, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, - 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, 0x000000007f7f7f7f, - 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, 0xfffe7fffffffffe0, - 0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, 0x0000000000001fff, - 0x3fffffffffff0000, 0x00000c00ffff1fff, 0x80007fffffffffff, 0xffffffff3fffffff, - 0x0000ffffffffffff, 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000, - 0x00000007fffff7bb, 0x000ffffffffffffc, 0x28fc000000000000, 0xffff003ffffffc00, + 0xffffffff000043e0, 0x00000000000001ff, 0xffff7fffffffffff, 0xffffffff7fffffff, + 0x000c781fffffffff, 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, + 0x000000007f7f7f7f, 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, + 0xfffeffffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, 0x0000ffffffffffff, + 0x0000000000001fff, 0x3fffffffffff0000, 0x00000c00ffff1fff, 0x80007fffffffffff, + 0xffffffff3fffffff, 0xfffffffcff800000, 0x03fffffffffff9ff, 0xff80000000000000, + 0x00000007fffff7bb, 0x000ffffffffffffc, 0x68fc000000000000, 0xffff003ffffffc00, 0x1fffffff0000007f, 0x0007fffffffffff0, 0x7c00ffdf00008000, 0x000001ffffffffff, 0xc47fffff00000ff7, 0x3e62ffffffffffff, 0x001c07ff38000005, 0xffff7f7f007e7e7e, 0xffff003ff7ffffff, 0x00000007ffffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, @@ -1147,42 +1162,42 @@ pub mod derived_property { r5: &[ 0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 13, 14, 15, 4, 4, 2, 2, 2, 2, 16, 17, 4, 4, 18, 19, 20, 21, 22, 4, 23, 4, 24, 25, 26, 27, 28, 29, 30, 4, 2, 31, 32, - 32, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 33, 4, 34, 35, 36, 37, 38, 39, 40, 4, 41, 20, - 42, 43, 4, 4, 5, 44, 45, 46, 4, 4, 47, 48, 45, 49, 50, 4, 51, 4, 4, 4, 4, 4, 52, 53, 4, - 4, 4, 4, 54, 55, 56, 57, 4, 4, 4, 4, 58, 59, 60, 4, 61, 62, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 51, 4, 2, 47, 2, 2, 2, 63, 4, 4, 4, 4, 4, + 32, 15, 4, 4, 4, 4, 4, 4, 4, 33, 34, 4, 4, 35, 4, 36, 37, 38, 39, 40, 41, 42, 4, 43, 20, + 44, 45, 4, 4, 5, 46, 47, 48, 4, 4, 49, 50, 47, 51, 52, 4, 53, 4, 4, 4, 54, 4, 55, 56, 4, + 4, 4, 4, 57, 58, 59, 60, 4, 4, 4, 4, 61, 62, 63, 4, 64, 65, 66, 4, 4, 4, 4, 67, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 68, 4, 2, 49, 2, 2, 2, 69, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 47, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 49, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 2, 2, 2, 2, 2, 2, 2, 2, 57, 20, 4, 65, 45, 66, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 2, 67, 68, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 60, 20, 4, 71, 47, 72, 63, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, + 4, 2, 73, 74, 75, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 71, 2, 2, 2, 2, 2, - 72, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 2, 73, 74, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 75, 76, 77, 78, 79, 2, 2, 2, 2, 80, 81, 82, 83, 84, - 85, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 76, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 77, 2, 2, 2, 2, 2, + 78, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 2, 79, 80, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 81, 82, 83, 84, 85, 2, 2, 2, 2, 86, 87, 88, 89, 90, + 91, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 86, 2, 63, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 87, 88, 89, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 92, 2, 69, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 93, 94, 95, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 96, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 91, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 98, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 93, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 99, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ], r6: &[ @@ -1192,24 +1207,25 @@ pub mod derived_property { 0xffff00003fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, 0x0000000fffffffff, 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, 0xc0ffffffffffffff, - 0x000ffffffeef0001, 0x1fffffff00000000, 0x000000001fffffff, 0x0000001ffffffeff, + 0x003ffffffeef0001, 0x1fffffff00000000, 0x000000001fffffff, 0x0000001ffffffeff, 0x003fffffffffffff, 0x0007ffff003fffff, 0x000000000003ffff, 0x00000000000001ff, - 0x0007ffffffffffff, 0x00fffffffffffff8, 0x0000fffffffffff8, 0x000001ffffff0000, - 0x0000007ffffffff8, 0x0047ffffffff0000, 0x0007fffffffffff8, 0x000000001400001e, - 0x00000ffffffbffff, 0xffff01ffbfffbd7f, 0x23edfdfffff99fe0, 0x00000003e0010000, - 0x0000000000000780, 0x0000ffffffffffff, 0x00000000000000b0, 0x00007fffffffffff, - 0x000000000f000000, 0x0000000000000010, 0x000007ffffffffff, 0x0000000003ffffff, - 0xffffffff00000000, 0x80000000ffffffff, 0x0407fffffffff801, 0xfffffffff0010000, - 0x00000000000003cf, 0x01ffffffffffffff, 0x00007ffffffffdff, 0xfffc000000000001, - 0x000000000000ffff, 0x0001fffffffffb7f, 0x0000000000000040, 0x000000000000000f, - 0x000000000000007f, 0x00003fffffff0000, 0xe0fffff80000000f, 0x000000000001001f, - 0x00000000fff80000, 0x0000000300000000, 0x00001fffffffffff, 0xffff000000000000, - 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000003ff01ff, 0xffffffffffdfffff, - 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, - 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, - 0xfffffdfffffffdff, 0x0000000000000ff7, 0x000000000000001f, 0x0af7fe96ffffffef, - 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0x00000000007fffff, 0xffff0003ffffffff, - 0x00000001ffffffff, 0x000000003fffffff + 0x0007ffffffffffff, 0xffff00801fffffff, 0x000000000000003f, 0x00fffffffffffff8, + 0x0000fffffffffff8, 0x000001ffffff0000, 0x0000007ffffffff8, 0x0047ffffffff0010, + 0x0007fffffffffff8, 0x000000001400001e, 0x00000ffffffbffff, 0xffff01ffbfffbd7f, + 0x23edfdfffff99fe0, 0x00000003e0010000, 0x0000000000000780, 0x0000ffffffffffff, + 0x00000000000000b0, 0x00007fffffffffff, 0x000000000f000000, 0x0000000000000010, + 0x000007ffffffffff, 0x0000000007ffffff, 0x00000fffffffffff, 0xffffffff00000000, + 0x80000000ffffffff, 0x0407fffffffff801, 0xfffffffff0010000, 0x00000000200003cf, + 0x01ffffffffffffff, 0x00007ffffffffdff, 0xfffc000000000001, 0x000000000000ffff, + 0x0001fffffffffb7f, 0xfffffdbf00000040, 0x00000000010003ff, 0x0007ffff00000000, + 0x0000000003ffffff, 0x000000000000000f, 0x000000000000007f, 0x00003fffffff0000, + 0xe0fffff80000000f, 0x000000000001001f, 0x00000000fff80000, 0x0000000300000000, + 0x0003ffffffffffff, 0xffff000000000000, 0x0fffffffffffffff, 0x1fff07ffffffffff, + 0x0000000003ff01ff, 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, + 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd, + 0xffdfffffffdfffff, 0xffff7fffffff7fff, 0xfffffdfffffffdff, 0x0000000000000ff7, + 0x000000000000001f, 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, + 0x00000000007fffff, 0xffff0003ffffffff, 0x00000001ffffffff, 0x000000003fffffff ], }; @@ -1534,332 +1550,369 @@ pub mod conversions { ('\u{13ee}', ['\u{abbe}', '\0', '\0']), ('\u{13ef}', ['\u{abbf}', '\0', '\0']), ('\u{13f0}', ['\u{13f8}', '\0', '\0']), ('\u{13f1}', ['\u{13f9}', '\0', '\0']), ('\u{13f2}', ['\u{13fa}', '\0', '\0']), ('\u{13f3}', ['\u{13fb}', '\0', '\0']), ('\u{13f4}', ['\u{13fc}', '\0', - '\0']), ('\u{13f5}', ['\u{13fd}', '\0', '\0']), ('\u{1e00}', ['\u{1e01}', '\0', '\0']), - ('\u{1e02}', ['\u{1e03}', '\0', '\0']), ('\u{1e04}', ['\u{1e05}', '\0', '\0']), ('\u{1e06}', - ['\u{1e07}', '\0', '\0']), ('\u{1e08}', ['\u{1e09}', '\0', '\0']), ('\u{1e0a}', ['\u{1e0b}', - '\0', '\0']), ('\u{1e0c}', ['\u{1e0d}', '\0', '\0']), ('\u{1e0e}', ['\u{1e0f}', '\0', - '\0']), ('\u{1e10}', ['\u{1e11}', '\0', '\0']), ('\u{1e12}', ['\u{1e13}', '\0', '\0']), - ('\u{1e14}', ['\u{1e15}', '\0', '\0']), ('\u{1e16}', ['\u{1e17}', '\0', '\0']), ('\u{1e18}', - ['\u{1e19}', '\0', '\0']), ('\u{1e1a}', ['\u{1e1b}', '\0', '\0']), ('\u{1e1c}', ['\u{1e1d}', - '\0', '\0']), ('\u{1e1e}', ['\u{1e1f}', '\0', '\0']), ('\u{1e20}', ['\u{1e21}', '\0', - '\0']), ('\u{1e22}', ['\u{1e23}', '\0', '\0']), ('\u{1e24}', ['\u{1e25}', '\0', '\0']), - ('\u{1e26}', ['\u{1e27}', '\0', '\0']), ('\u{1e28}', ['\u{1e29}', '\0', '\0']), ('\u{1e2a}', - ['\u{1e2b}', '\0', '\0']), ('\u{1e2c}', ['\u{1e2d}', '\0', '\0']), ('\u{1e2e}', ['\u{1e2f}', - '\0', '\0']), ('\u{1e30}', ['\u{1e31}', '\0', '\0']), ('\u{1e32}', ['\u{1e33}', '\0', - '\0']), ('\u{1e34}', ['\u{1e35}', '\0', '\0']), ('\u{1e36}', ['\u{1e37}', '\0', '\0']), - ('\u{1e38}', ['\u{1e39}', '\0', '\0']), ('\u{1e3a}', ['\u{1e3b}', '\0', '\0']), ('\u{1e3c}', - ['\u{1e3d}', '\0', '\0']), ('\u{1e3e}', ['\u{1e3f}', '\0', '\0']), ('\u{1e40}', ['\u{1e41}', - '\0', '\0']), ('\u{1e42}', ['\u{1e43}', '\0', '\0']), ('\u{1e44}', ['\u{1e45}', '\0', - '\0']), ('\u{1e46}', ['\u{1e47}', '\0', '\0']), ('\u{1e48}', ['\u{1e49}', '\0', '\0']), - ('\u{1e4a}', ['\u{1e4b}', '\0', '\0']), ('\u{1e4c}', ['\u{1e4d}', '\0', '\0']), ('\u{1e4e}', - ['\u{1e4f}', '\0', '\0']), ('\u{1e50}', ['\u{1e51}', '\0', '\0']), ('\u{1e52}', ['\u{1e53}', - '\0', '\0']), ('\u{1e54}', ['\u{1e55}', '\0', '\0']), ('\u{1e56}', ['\u{1e57}', '\0', - '\0']), ('\u{1e58}', ['\u{1e59}', '\0', '\0']), ('\u{1e5a}', ['\u{1e5b}', '\0', '\0']), - ('\u{1e5c}', ['\u{1e5d}', '\0', '\0']), ('\u{1e5e}', ['\u{1e5f}', '\0', '\0']), ('\u{1e60}', - ['\u{1e61}', '\0', '\0']), ('\u{1e62}', ['\u{1e63}', '\0', '\0']), ('\u{1e64}', ['\u{1e65}', - '\0', '\0']), ('\u{1e66}', ['\u{1e67}', '\0', '\0']), ('\u{1e68}', ['\u{1e69}', '\0', - '\0']), ('\u{1e6a}', ['\u{1e6b}', '\0', '\0']), ('\u{1e6c}', ['\u{1e6d}', '\0', '\0']), - ('\u{1e6e}', ['\u{1e6f}', '\0', '\0']), ('\u{1e70}', ['\u{1e71}', '\0', '\0']), ('\u{1e72}', - ['\u{1e73}', '\0', '\0']), ('\u{1e74}', ['\u{1e75}', '\0', '\0']), ('\u{1e76}', ['\u{1e77}', - '\0', '\0']), ('\u{1e78}', ['\u{1e79}', '\0', '\0']), ('\u{1e7a}', ['\u{1e7b}', '\0', - '\0']), ('\u{1e7c}', ['\u{1e7d}', '\0', '\0']), ('\u{1e7e}', ['\u{1e7f}', '\0', '\0']), - ('\u{1e80}', ['\u{1e81}', '\0', '\0']), ('\u{1e82}', ['\u{1e83}', '\0', '\0']), ('\u{1e84}', - ['\u{1e85}', '\0', '\0']), ('\u{1e86}', ['\u{1e87}', '\0', '\0']), ('\u{1e88}', ['\u{1e89}', - '\0', '\0']), ('\u{1e8a}', ['\u{1e8b}', '\0', '\0']), ('\u{1e8c}', ['\u{1e8d}', '\0', - '\0']), ('\u{1e8e}', ['\u{1e8f}', '\0', '\0']), ('\u{1e90}', ['\u{1e91}', '\0', '\0']), - ('\u{1e92}', ['\u{1e93}', '\0', '\0']), ('\u{1e94}', ['\u{1e95}', '\0', '\0']), ('\u{1e9e}', - ['\u{df}', '\0', '\0']), ('\u{1ea0}', ['\u{1ea1}', '\0', '\0']), ('\u{1ea2}', ['\u{1ea3}', - '\0', '\0']), ('\u{1ea4}', ['\u{1ea5}', '\0', '\0']), ('\u{1ea6}', ['\u{1ea7}', '\0', - '\0']), ('\u{1ea8}', ['\u{1ea9}', '\0', '\0']), ('\u{1eaa}', ['\u{1eab}', '\0', '\0']), - ('\u{1eac}', ['\u{1ead}', '\0', '\0']), ('\u{1eae}', ['\u{1eaf}', '\0', '\0']), ('\u{1eb0}', - ['\u{1eb1}', '\0', '\0']), ('\u{1eb2}', ['\u{1eb3}', '\0', '\0']), ('\u{1eb4}', ['\u{1eb5}', - '\0', '\0']), ('\u{1eb6}', ['\u{1eb7}', '\0', '\0']), ('\u{1eb8}', ['\u{1eb9}', '\0', - '\0']), ('\u{1eba}', ['\u{1ebb}', '\0', '\0']), ('\u{1ebc}', ['\u{1ebd}', '\0', '\0']), - ('\u{1ebe}', ['\u{1ebf}', '\0', '\0']), ('\u{1ec0}', ['\u{1ec1}', '\0', '\0']), ('\u{1ec2}', - ['\u{1ec3}', '\0', '\0']), ('\u{1ec4}', ['\u{1ec5}', '\0', '\0']), ('\u{1ec6}', ['\u{1ec7}', - '\0', '\0']), ('\u{1ec8}', ['\u{1ec9}', '\0', '\0']), ('\u{1eca}', ['\u{1ecb}', '\0', - '\0']), ('\u{1ecc}', ['\u{1ecd}', '\0', '\0']), ('\u{1ece}', ['\u{1ecf}', '\0', '\0']), - ('\u{1ed0}', ['\u{1ed1}', '\0', '\0']), ('\u{1ed2}', ['\u{1ed3}', '\0', '\0']), ('\u{1ed4}', - ['\u{1ed5}', '\0', '\0']), ('\u{1ed6}', ['\u{1ed7}', '\0', '\0']), ('\u{1ed8}', ['\u{1ed9}', - '\0', '\0']), ('\u{1eda}', ['\u{1edb}', '\0', '\0']), ('\u{1edc}', ['\u{1edd}', '\0', - '\0']), ('\u{1ede}', ['\u{1edf}', '\0', '\0']), ('\u{1ee0}', ['\u{1ee1}', '\0', '\0']), - ('\u{1ee2}', ['\u{1ee3}', '\0', '\0']), ('\u{1ee4}', ['\u{1ee5}', '\0', '\0']), ('\u{1ee6}', - ['\u{1ee7}', '\0', '\0']), ('\u{1ee8}', ['\u{1ee9}', '\0', '\0']), ('\u{1eea}', ['\u{1eeb}', - '\0', '\0']), ('\u{1eec}', ['\u{1eed}', '\0', '\0']), ('\u{1eee}', ['\u{1eef}', '\0', - '\0']), ('\u{1ef0}', ['\u{1ef1}', '\0', '\0']), ('\u{1ef2}', ['\u{1ef3}', '\0', '\0']), - ('\u{1ef4}', ['\u{1ef5}', '\0', '\0']), ('\u{1ef6}', ['\u{1ef7}', '\0', '\0']), ('\u{1ef8}', - ['\u{1ef9}', '\0', '\0']), ('\u{1efa}', ['\u{1efb}', '\0', '\0']), ('\u{1efc}', ['\u{1efd}', - '\0', '\0']), ('\u{1efe}', ['\u{1eff}', '\0', '\0']), ('\u{1f08}', ['\u{1f00}', '\0', - '\0']), ('\u{1f09}', ['\u{1f01}', '\0', '\0']), ('\u{1f0a}', ['\u{1f02}', '\0', '\0']), - ('\u{1f0b}', ['\u{1f03}', '\0', '\0']), ('\u{1f0c}', ['\u{1f04}', '\0', '\0']), ('\u{1f0d}', - ['\u{1f05}', '\0', '\0']), ('\u{1f0e}', ['\u{1f06}', '\0', '\0']), ('\u{1f0f}', ['\u{1f07}', - '\0', '\0']), ('\u{1f18}', ['\u{1f10}', '\0', '\0']), ('\u{1f19}', ['\u{1f11}', '\0', - '\0']), ('\u{1f1a}', ['\u{1f12}', '\0', '\0']), ('\u{1f1b}', ['\u{1f13}', '\0', '\0']), - ('\u{1f1c}', ['\u{1f14}', '\0', '\0']), ('\u{1f1d}', ['\u{1f15}', '\0', '\0']), ('\u{1f28}', - ['\u{1f20}', '\0', '\0']), ('\u{1f29}', ['\u{1f21}', '\0', '\0']), ('\u{1f2a}', ['\u{1f22}', - '\0', '\0']), ('\u{1f2b}', ['\u{1f23}', '\0', '\0']), ('\u{1f2c}', ['\u{1f24}', '\0', - '\0']), ('\u{1f2d}', ['\u{1f25}', '\0', '\0']), ('\u{1f2e}', ['\u{1f26}', '\0', '\0']), - ('\u{1f2f}', ['\u{1f27}', '\0', '\0']), ('\u{1f38}', ['\u{1f30}', '\0', '\0']), ('\u{1f39}', - ['\u{1f31}', '\0', '\0']), ('\u{1f3a}', ['\u{1f32}', '\0', '\0']), ('\u{1f3b}', ['\u{1f33}', - '\0', '\0']), ('\u{1f3c}', ['\u{1f34}', '\0', '\0']), ('\u{1f3d}', ['\u{1f35}', '\0', - '\0']), ('\u{1f3e}', ['\u{1f36}', '\0', '\0']), ('\u{1f3f}', ['\u{1f37}', '\0', '\0']), - ('\u{1f48}', ['\u{1f40}', '\0', '\0']), ('\u{1f49}', ['\u{1f41}', '\0', '\0']), ('\u{1f4a}', - ['\u{1f42}', '\0', '\0']), ('\u{1f4b}', ['\u{1f43}', '\0', '\0']), ('\u{1f4c}', ['\u{1f44}', - '\0', '\0']), ('\u{1f4d}', ['\u{1f45}', '\0', '\0']), ('\u{1f59}', ['\u{1f51}', '\0', - '\0']), ('\u{1f5b}', ['\u{1f53}', '\0', '\0']), ('\u{1f5d}', ['\u{1f55}', '\0', '\0']), - ('\u{1f5f}', ['\u{1f57}', '\0', '\0']), ('\u{1f68}', ['\u{1f60}', '\0', '\0']), ('\u{1f69}', - ['\u{1f61}', '\0', '\0']), ('\u{1f6a}', ['\u{1f62}', '\0', '\0']), ('\u{1f6b}', ['\u{1f63}', - '\0', '\0']), ('\u{1f6c}', ['\u{1f64}', '\0', '\0']), ('\u{1f6d}', ['\u{1f65}', '\0', - '\0']), ('\u{1f6e}', ['\u{1f66}', '\0', '\0']), ('\u{1f6f}', ['\u{1f67}', '\0', '\0']), - ('\u{1f88}', ['\u{1f80}', '\0', '\0']), ('\u{1f89}', ['\u{1f81}', '\0', '\0']), ('\u{1f8a}', - ['\u{1f82}', '\0', '\0']), ('\u{1f8b}', ['\u{1f83}', '\0', '\0']), ('\u{1f8c}', ['\u{1f84}', - '\0', '\0']), ('\u{1f8d}', ['\u{1f85}', '\0', '\0']), ('\u{1f8e}', ['\u{1f86}', '\0', - '\0']), ('\u{1f8f}', ['\u{1f87}', '\0', '\0']), ('\u{1f98}', ['\u{1f90}', '\0', '\0']), - ('\u{1f99}', ['\u{1f91}', '\0', '\0']), ('\u{1f9a}', ['\u{1f92}', '\0', '\0']), ('\u{1f9b}', - ['\u{1f93}', '\0', '\0']), ('\u{1f9c}', ['\u{1f94}', '\0', '\0']), ('\u{1f9d}', ['\u{1f95}', - '\0', '\0']), ('\u{1f9e}', ['\u{1f96}', '\0', '\0']), ('\u{1f9f}', ['\u{1f97}', '\0', - '\0']), ('\u{1fa8}', ['\u{1fa0}', '\0', '\0']), ('\u{1fa9}', ['\u{1fa1}', '\0', '\0']), - ('\u{1faa}', ['\u{1fa2}', '\0', '\0']), ('\u{1fab}', ['\u{1fa3}', '\0', '\0']), ('\u{1fac}', - ['\u{1fa4}', '\0', '\0']), ('\u{1fad}', ['\u{1fa5}', '\0', '\0']), ('\u{1fae}', ['\u{1fa6}', - '\0', '\0']), ('\u{1faf}', ['\u{1fa7}', '\0', '\0']), ('\u{1fb8}', ['\u{1fb0}', '\0', - '\0']), ('\u{1fb9}', ['\u{1fb1}', '\0', '\0']), ('\u{1fba}', ['\u{1f70}', '\0', '\0']), - ('\u{1fbb}', ['\u{1f71}', '\0', '\0']), ('\u{1fbc}', ['\u{1fb3}', '\0', '\0']), ('\u{1fc8}', - ['\u{1f72}', '\0', '\0']), ('\u{1fc9}', ['\u{1f73}', '\0', '\0']), ('\u{1fca}', ['\u{1f74}', - '\0', '\0']), ('\u{1fcb}', ['\u{1f75}', '\0', '\0']), ('\u{1fcc}', ['\u{1fc3}', '\0', - '\0']), ('\u{1fd8}', ['\u{1fd0}', '\0', '\0']), ('\u{1fd9}', ['\u{1fd1}', '\0', '\0']), - ('\u{1fda}', ['\u{1f76}', '\0', '\0']), ('\u{1fdb}', ['\u{1f77}', '\0', '\0']), ('\u{1fe8}', - ['\u{1fe0}', '\0', '\0']), ('\u{1fe9}', ['\u{1fe1}', '\0', '\0']), ('\u{1fea}', ['\u{1f7a}', - '\0', '\0']), ('\u{1feb}', ['\u{1f7b}', '\0', '\0']), ('\u{1fec}', ['\u{1fe5}', '\0', - '\0']), ('\u{1ff8}', ['\u{1f78}', '\0', '\0']), ('\u{1ff9}', ['\u{1f79}', '\0', '\0']), - ('\u{1ffa}', ['\u{1f7c}', '\0', '\0']), ('\u{1ffb}', ['\u{1f7d}', '\0', '\0']), ('\u{1ffc}', - ['\u{1ff3}', '\0', '\0']), ('\u{2126}', ['\u{3c9}', '\0', '\0']), ('\u{212a}', ['\u{6b}', - '\0', '\0']), ('\u{212b}', ['\u{e5}', '\0', '\0']), ('\u{2132}', ['\u{214e}', '\0', '\0']), - ('\u{2160}', ['\u{2170}', '\0', '\0']), ('\u{2161}', ['\u{2171}', '\0', '\0']), ('\u{2162}', - ['\u{2172}', '\0', '\0']), ('\u{2163}', ['\u{2173}', '\0', '\0']), ('\u{2164}', ['\u{2174}', - '\0', '\0']), ('\u{2165}', ['\u{2175}', '\0', '\0']), ('\u{2166}', ['\u{2176}', '\0', - '\0']), ('\u{2167}', ['\u{2177}', '\0', '\0']), ('\u{2168}', ['\u{2178}', '\0', '\0']), - ('\u{2169}', ['\u{2179}', '\0', '\0']), ('\u{216a}', ['\u{217a}', '\0', '\0']), ('\u{216b}', - ['\u{217b}', '\0', '\0']), ('\u{216c}', ['\u{217c}', '\0', '\0']), ('\u{216d}', ['\u{217d}', - '\0', '\0']), ('\u{216e}', ['\u{217e}', '\0', '\0']), ('\u{216f}', ['\u{217f}', '\0', - '\0']), ('\u{2183}', ['\u{2184}', '\0', '\0']), ('\u{24b6}', ['\u{24d0}', '\0', '\0']), - ('\u{24b7}', ['\u{24d1}', '\0', '\0']), ('\u{24b8}', ['\u{24d2}', '\0', '\0']), ('\u{24b9}', - ['\u{24d3}', '\0', '\0']), ('\u{24ba}', ['\u{24d4}', '\0', '\0']), ('\u{24bb}', ['\u{24d5}', - '\0', '\0']), ('\u{24bc}', ['\u{24d6}', '\0', '\0']), ('\u{24bd}', ['\u{24d7}', '\0', - '\0']), ('\u{24be}', ['\u{24d8}', '\0', '\0']), ('\u{24bf}', ['\u{24d9}', '\0', '\0']), - ('\u{24c0}', ['\u{24da}', '\0', '\0']), ('\u{24c1}', ['\u{24db}', '\0', '\0']), ('\u{24c2}', - ['\u{24dc}', '\0', '\0']), ('\u{24c3}', ['\u{24dd}', '\0', '\0']), ('\u{24c4}', ['\u{24de}', - '\0', '\0']), ('\u{24c5}', ['\u{24df}', '\0', '\0']), ('\u{24c6}', ['\u{24e0}', '\0', - '\0']), ('\u{24c7}', ['\u{24e1}', '\0', '\0']), ('\u{24c8}', ['\u{24e2}', '\0', '\0']), - ('\u{24c9}', ['\u{24e3}', '\0', '\0']), ('\u{24ca}', ['\u{24e4}', '\0', '\0']), ('\u{24cb}', - ['\u{24e5}', '\0', '\0']), ('\u{24cc}', ['\u{24e6}', '\0', '\0']), ('\u{24cd}', ['\u{24e7}', - '\0', '\0']), ('\u{24ce}', ['\u{24e8}', '\0', '\0']), ('\u{24cf}', ['\u{24e9}', '\0', - '\0']), ('\u{2c00}', ['\u{2c30}', '\0', '\0']), ('\u{2c01}', ['\u{2c31}', '\0', '\0']), - ('\u{2c02}', ['\u{2c32}', '\0', '\0']), ('\u{2c03}', ['\u{2c33}', '\0', '\0']), ('\u{2c04}', - ['\u{2c34}', '\0', '\0']), ('\u{2c05}', ['\u{2c35}', '\0', '\0']), ('\u{2c06}', ['\u{2c36}', - '\0', '\0']), ('\u{2c07}', ['\u{2c37}', '\0', '\0']), ('\u{2c08}', ['\u{2c38}', '\0', - '\0']), ('\u{2c09}', ['\u{2c39}', '\0', '\0']), ('\u{2c0a}', ['\u{2c3a}', '\0', '\0']), - ('\u{2c0b}', ['\u{2c3b}', '\0', '\0']), ('\u{2c0c}', ['\u{2c3c}', '\0', '\0']), ('\u{2c0d}', - ['\u{2c3d}', '\0', '\0']), ('\u{2c0e}', ['\u{2c3e}', '\0', '\0']), ('\u{2c0f}', ['\u{2c3f}', - '\0', '\0']), ('\u{2c10}', ['\u{2c40}', '\0', '\0']), ('\u{2c11}', ['\u{2c41}', '\0', - '\0']), ('\u{2c12}', ['\u{2c42}', '\0', '\0']), ('\u{2c13}', ['\u{2c43}', '\0', '\0']), - ('\u{2c14}', ['\u{2c44}', '\0', '\0']), ('\u{2c15}', ['\u{2c45}', '\0', '\0']), ('\u{2c16}', - ['\u{2c46}', '\0', '\0']), ('\u{2c17}', ['\u{2c47}', '\0', '\0']), ('\u{2c18}', ['\u{2c48}', - '\0', '\0']), ('\u{2c19}', ['\u{2c49}', '\0', '\0']), ('\u{2c1a}', ['\u{2c4a}', '\0', - '\0']), ('\u{2c1b}', ['\u{2c4b}', '\0', '\0']), ('\u{2c1c}', ['\u{2c4c}', '\0', '\0']), - ('\u{2c1d}', ['\u{2c4d}', '\0', '\0']), ('\u{2c1e}', ['\u{2c4e}', '\0', '\0']), ('\u{2c1f}', - ['\u{2c4f}', '\0', '\0']), ('\u{2c20}', ['\u{2c50}', '\0', '\0']), ('\u{2c21}', ['\u{2c51}', - '\0', '\0']), ('\u{2c22}', ['\u{2c52}', '\0', '\0']), ('\u{2c23}', ['\u{2c53}', '\0', - '\0']), ('\u{2c24}', ['\u{2c54}', '\0', '\0']), ('\u{2c25}', ['\u{2c55}', '\0', '\0']), - ('\u{2c26}', ['\u{2c56}', '\0', '\0']), ('\u{2c27}', ['\u{2c57}', '\0', '\0']), ('\u{2c28}', - ['\u{2c58}', '\0', '\0']), ('\u{2c29}', ['\u{2c59}', '\0', '\0']), ('\u{2c2a}', ['\u{2c5a}', - '\0', '\0']), ('\u{2c2b}', ['\u{2c5b}', '\0', '\0']), ('\u{2c2c}', ['\u{2c5c}', '\0', - '\0']), ('\u{2c2d}', ['\u{2c5d}', '\0', '\0']), ('\u{2c2e}', ['\u{2c5e}', '\0', '\0']), - ('\u{2c60}', ['\u{2c61}', '\0', '\0']), ('\u{2c62}', ['\u{26b}', '\0', '\0']), ('\u{2c63}', - ['\u{1d7d}', '\0', '\0']), ('\u{2c64}', ['\u{27d}', '\0', '\0']), ('\u{2c67}', ['\u{2c68}', - '\0', '\0']), ('\u{2c69}', ['\u{2c6a}', '\0', '\0']), ('\u{2c6b}', ['\u{2c6c}', '\0', - '\0']), ('\u{2c6d}', ['\u{251}', '\0', '\0']), ('\u{2c6e}', ['\u{271}', '\0', '\0']), - ('\u{2c6f}', ['\u{250}', '\0', '\0']), ('\u{2c70}', ['\u{252}', '\0', '\0']), ('\u{2c72}', - ['\u{2c73}', '\0', '\0']), ('\u{2c75}', ['\u{2c76}', '\0', '\0']), ('\u{2c7e}', ['\u{23f}', - '\0', '\0']), ('\u{2c7f}', ['\u{240}', '\0', '\0']), ('\u{2c80}', ['\u{2c81}', '\0', '\0']), - ('\u{2c82}', ['\u{2c83}', '\0', '\0']), ('\u{2c84}', ['\u{2c85}', '\0', '\0']), ('\u{2c86}', - ['\u{2c87}', '\0', '\0']), ('\u{2c88}', ['\u{2c89}', '\0', '\0']), ('\u{2c8a}', ['\u{2c8b}', - '\0', '\0']), ('\u{2c8c}', ['\u{2c8d}', '\0', '\0']), ('\u{2c8e}', ['\u{2c8f}', '\0', - '\0']), ('\u{2c90}', ['\u{2c91}', '\0', '\0']), ('\u{2c92}', ['\u{2c93}', '\0', '\0']), - ('\u{2c94}', ['\u{2c95}', '\0', '\0']), ('\u{2c96}', ['\u{2c97}', '\0', '\0']), ('\u{2c98}', - ['\u{2c99}', '\0', '\0']), ('\u{2c9a}', ['\u{2c9b}', '\0', '\0']), ('\u{2c9c}', ['\u{2c9d}', - '\0', '\0']), ('\u{2c9e}', ['\u{2c9f}', '\0', '\0']), ('\u{2ca0}', ['\u{2ca1}', '\0', - '\0']), ('\u{2ca2}', ['\u{2ca3}', '\0', '\0']), ('\u{2ca4}', ['\u{2ca5}', '\0', '\0']), - ('\u{2ca6}', ['\u{2ca7}', '\0', '\0']), ('\u{2ca8}', ['\u{2ca9}', '\0', '\0']), ('\u{2caa}', - ['\u{2cab}', '\0', '\0']), ('\u{2cac}', ['\u{2cad}', '\0', '\0']), ('\u{2cae}', ['\u{2caf}', - '\0', '\0']), ('\u{2cb0}', ['\u{2cb1}', '\0', '\0']), ('\u{2cb2}', ['\u{2cb3}', '\0', - '\0']), ('\u{2cb4}', ['\u{2cb5}', '\0', '\0']), ('\u{2cb6}', ['\u{2cb7}', '\0', '\0']), - ('\u{2cb8}', ['\u{2cb9}', '\0', '\0']), ('\u{2cba}', ['\u{2cbb}', '\0', '\0']), ('\u{2cbc}', - ['\u{2cbd}', '\0', '\0']), ('\u{2cbe}', ['\u{2cbf}', '\0', '\0']), ('\u{2cc0}', ['\u{2cc1}', - '\0', '\0']), ('\u{2cc2}', ['\u{2cc3}', '\0', '\0']), ('\u{2cc4}', ['\u{2cc5}', '\0', - '\0']), ('\u{2cc6}', ['\u{2cc7}', '\0', '\0']), ('\u{2cc8}', ['\u{2cc9}', '\0', '\0']), - ('\u{2cca}', ['\u{2ccb}', '\0', '\0']), ('\u{2ccc}', ['\u{2ccd}', '\0', '\0']), ('\u{2cce}', - ['\u{2ccf}', '\0', '\0']), ('\u{2cd0}', ['\u{2cd1}', '\0', '\0']), ('\u{2cd2}', ['\u{2cd3}', - '\0', '\0']), ('\u{2cd4}', ['\u{2cd5}', '\0', '\0']), ('\u{2cd6}', ['\u{2cd7}', '\0', - '\0']), ('\u{2cd8}', ['\u{2cd9}', '\0', '\0']), ('\u{2cda}', ['\u{2cdb}', '\0', '\0']), - ('\u{2cdc}', ['\u{2cdd}', '\0', '\0']), ('\u{2cde}', ['\u{2cdf}', '\0', '\0']), ('\u{2ce0}', - ['\u{2ce1}', '\0', '\0']), ('\u{2ce2}', ['\u{2ce3}', '\0', '\0']), ('\u{2ceb}', ['\u{2cec}', - '\0', '\0']), ('\u{2ced}', ['\u{2cee}', '\0', '\0']), ('\u{2cf2}', ['\u{2cf3}', '\0', - '\0']), ('\u{a640}', ['\u{a641}', '\0', '\0']), ('\u{a642}', ['\u{a643}', '\0', '\0']), - ('\u{a644}', ['\u{a645}', '\0', '\0']), ('\u{a646}', ['\u{a647}', '\0', '\0']), ('\u{a648}', - ['\u{a649}', '\0', '\0']), ('\u{a64a}', ['\u{a64b}', '\0', '\0']), ('\u{a64c}', ['\u{a64d}', - '\0', '\0']), ('\u{a64e}', ['\u{a64f}', '\0', '\0']), ('\u{a650}', ['\u{a651}', '\0', - '\0']), ('\u{a652}', ['\u{a653}', '\0', '\0']), ('\u{a654}', ['\u{a655}', '\0', '\0']), - ('\u{a656}', ['\u{a657}', '\0', '\0']), ('\u{a658}', ['\u{a659}', '\0', '\0']), ('\u{a65a}', - ['\u{a65b}', '\0', '\0']), ('\u{a65c}', ['\u{a65d}', '\0', '\0']), ('\u{a65e}', ['\u{a65f}', - '\0', '\0']), ('\u{a660}', ['\u{a661}', '\0', '\0']), ('\u{a662}', ['\u{a663}', '\0', - '\0']), ('\u{a664}', ['\u{a665}', '\0', '\0']), ('\u{a666}', ['\u{a667}', '\0', '\0']), - ('\u{a668}', ['\u{a669}', '\0', '\0']), ('\u{a66a}', ['\u{a66b}', '\0', '\0']), ('\u{a66c}', - ['\u{a66d}', '\0', '\0']), ('\u{a680}', ['\u{a681}', '\0', '\0']), ('\u{a682}', ['\u{a683}', - '\0', '\0']), ('\u{a684}', ['\u{a685}', '\0', '\0']), ('\u{a686}', ['\u{a687}', '\0', - '\0']), ('\u{a688}', ['\u{a689}', '\0', '\0']), ('\u{a68a}', ['\u{a68b}', '\0', '\0']), - ('\u{a68c}', ['\u{a68d}', '\0', '\0']), ('\u{a68e}', ['\u{a68f}', '\0', '\0']), ('\u{a690}', - ['\u{a691}', '\0', '\0']), ('\u{a692}', ['\u{a693}', '\0', '\0']), ('\u{a694}', ['\u{a695}', - '\0', '\0']), ('\u{a696}', ['\u{a697}', '\0', '\0']), ('\u{a698}', ['\u{a699}', '\0', - '\0']), ('\u{a69a}', ['\u{a69b}', '\0', '\0']), ('\u{a722}', ['\u{a723}', '\0', '\0']), - ('\u{a724}', ['\u{a725}', '\0', '\0']), ('\u{a726}', ['\u{a727}', '\0', '\0']), ('\u{a728}', - ['\u{a729}', '\0', '\0']), ('\u{a72a}', ['\u{a72b}', '\0', '\0']), ('\u{a72c}', ['\u{a72d}', - '\0', '\0']), ('\u{a72e}', ['\u{a72f}', '\0', '\0']), ('\u{a732}', ['\u{a733}', '\0', - '\0']), ('\u{a734}', ['\u{a735}', '\0', '\0']), ('\u{a736}', ['\u{a737}', '\0', '\0']), - ('\u{a738}', ['\u{a739}', '\0', '\0']), ('\u{a73a}', ['\u{a73b}', '\0', '\0']), ('\u{a73c}', - ['\u{a73d}', '\0', '\0']), ('\u{a73e}', ['\u{a73f}', '\0', '\0']), ('\u{a740}', ['\u{a741}', - '\0', '\0']), ('\u{a742}', ['\u{a743}', '\0', '\0']), ('\u{a744}', ['\u{a745}', '\0', - '\0']), ('\u{a746}', ['\u{a747}', '\0', '\0']), ('\u{a748}', ['\u{a749}', '\0', '\0']), - ('\u{a74a}', ['\u{a74b}', '\0', '\0']), ('\u{a74c}', ['\u{a74d}', '\0', '\0']), ('\u{a74e}', - ['\u{a74f}', '\0', '\0']), ('\u{a750}', ['\u{a751}', '\0', '\0']), ('\u{a752}', ['\u{a753}', - '\0', '\0']), ('\u{a754}', ['\u{a755}', '\0', '\0']), ('\u{a756}', ['\u{a757}', '\0', - '\0']), ('\u{a758}', ['\u{a759}', '\0', '\0']), ('\u{a75a}', ['\u{a75b}', '\0', '\0']), - ('\u{a75c}', ['\u{a75d}', '\0', '\0']), ('\u{a75e}', ['\u{a75f}', '\0', '\0']), ('\u{a760}', - ['\u{a761}', '\0', '\0']), ('\u{a762}', ['\u{a763}', '\0', '\0']), ('\u{a764}', ['\u{a765}', - '\0', '\0']), ('\u{a766}', ['\u{a767}', '\0', '\0']), ('\u{a768}', ['\u{a769}', '\0', - '\0']), ('\u{a76a}', ['\u{a76b}', '\0', '\0']), ('\u{a76c}', ['\u{a76d}', '\0', '\0']), - ('\u{a76e}', ['\u{a76f}', '\0', '\0']), ('\u{a779}', ['\u{a77a}', '\0', '\0']), ('\u{a77b}', - ['\u{a77c}', '\0', '\0']), ('\u{a77d}', ['\u{1d79}', '\0', '\0']), ('\u{a77e}', ['\u{a77f}', - '\0', '\0']), ('\u{a780}', ['\u{a781}', '\0', '\0']), ('\u{a782}', ['\u{a783}', '\0', - '\0']), ('\u{a784}', ['\u{a785}', '\0', '\0']), ('\u{a786}', ['\u{a787}', '\0', '\0']), - ('\u{a78b}', ['\u{a78c}', '\0', '\0']), ('\u{a78d}', ['\u{265}', '\0', '\0']), ('\u{a790}', - ['\u{a791}', '\0', '\0']), ('\u{a792}', ['\u{a793}', '\0', '\0']), ('\u{a796}', ['\u{a797}', - '\0', '\0']), ('\u{a798}', ['\u{a799}', '\0', '\0']), ('\u{a79a}', ['\u{a79b}', '\0', - '\0']), ('\u{a79c}', ['\u{a79d}', '\0', '\0']), ('\u{a79e}', ['\u{a79f}', '\0', '\0']), - ('\u{a7a0}', ['\u{a7a1}', '\0', '\0']), ('\u{a7a2}', ['\u{a7a3}', '\0', '\0']), ('\u{a7a4}', - ['\u{a7a5}', '\0', '\0']), ('\u{a7a6}', ['\u{a7a7}', '\0', '\0']), ('\u{a7a8}', ['\u{a7a9}', - '\0', '\0']), ('\u{a7aa}', ['\u{266}', '\0', '\0']), ('\u{a7ab}', ['\u{25c}', '\0', '\0']), - ('\u{a7ac}', ['\u{261}', '\0', '\0']), ('\u{a7ad}', ['\u{26c}', '\0', '\0']), ('\u{a7ae}', - ['\u{26a}', '\0', '\0']), ('\u{a7b0}', ['\u{29e}', '\0', '\0']), ('\u{a7b1}', ['\u{287}', - '\0', '\0']), ('\u{a7b2}', ['\u{29d}', '\0', '\0']), ('\u{a7b3}', ['\u{ab53}', '\0', '\0']), - ('\u{a7b4}', ['\u{a7b5}', '\0', '\0']), ('\u{a7b6}', ['\u{a7b7}', '\0', '\0']), ('\u{ff21}', - ['\u{ff41}', '\0', '\0']), ('\u{ff22}', ['\u{ff42}', '\0', '\0']), ('\u{ff23}', ['\u{ff43}', - '\0', '\0']), ('\u{ff24}', ['\u{ff44}', '\0', '\0']), ('\u{ff25}', ['\u{ff45}', '\0', - '\0']), ('\u{ff26}', ['\u{ff46}', '\0', '\0']), ('\u{ff27}', ['\u{ff47}', '\0', '\0']), - ('\u{ff28}', ['\u{ff48}', '\0', '\0']), ('\u{ff29}', ['\u{ff49}', '\0', '\0']), ('\u{ff2a}', - ['\u{ff4a}', '\0', '\0']), ('\u{ff2b}', ['\u{ff4b}', '\0', '\0']), ('\u{ff2c}', ['\u{ff4c}', - '\0', '\0']), ('\u{ff2d}', ['\u{ff4d}', '\0', '\0']), ('\u{ff2e}', ['\u{ff4e}', '\0', - '\0']), ('\u{ff2f}', ['\u{ff4f}', '\0', '\0']), ('\u{ff30}', ['\u{ff50}', '\0', '\0']), - ('\u{ff31}', ['\u{ff51}', '\0', '\0']), ('\u{ff32}', ['\u{ff52}', '\0', '\0']), ('\u{ff33}', - ['\u{ff53}', '\0', '\0']), ('\u{ff34}', ['\u{ff54}', '\0', '\0']), ('\u{ff35}', ['\u{ff55}', - '\0', '\0']), ('\u{ff36}', ['\u{ff56}', '\0', '\0']), ('\u{ff37}', ['\u{ff57}', '\0', - '\0']), ('\u{ff38}', ['\u{ff58}', '\0', '\0']), ('\u{ff39}', ['\u{ff59}', '\0', '\0']), - ('\u{ff3a}', ['\u{ff5a}', '\0', '\0']), ('\u{10400}', ['\u{10428}', '\0', '\0']), - ('\u{10401}', ['\u{10429}', '\0', '\0']), ('\u{10402}', ['\u{1042a}', '\0', '\0']), - ('\u{10403}', ['\u{1042b}', '\0', '\0']), ('\u{10404}', ['\u{1042c}', '\0', '\0']), - ('\u{10405}', ['\u{1042d}', '\0', '\0']), ('\u{10406}', ['\u{1042e}', '\0', '\0']), - ('\u{10407}', ['\u{1042f}', '\0', '\0']), ('\u{10408}', ['\u{10430}', '\0', '\0']), - ('\u{10409}', ['\u{10431}', '\0', '\0']), ('\u{1040a}', ['\u{10432}', '\0', '\0']), - ('\u{1040b}', ['\u{10433}', '\0', '\0']), ('\u{1040c}', ['\u{10434}', '\0', '\0']), - ('\u{1040d}', ['\u{10435}', '\0', '\0']), ('\u{1040e}', ['\u{10436}', '\0', '\0']), - ('\u{1040f}', ['\u{10437}', '\0', '\0']), ('\u{10410}', ['\u{10438}', '\0', '\0']), - ('\u{10411}', ['\u{10439}', '\0', '\0']), ('\u{10412}', ['\u{1043a}', '\0', '\0']), - ('\u{10413}', ['\u{1043b}', '\0', '\0']), ('\u{10414}', ['\u{1043c}', '\0', '\0']), - ('\u{10415}', ['\u{1043d}', '\0', '\0']), ('\u{10416}', ['\u{1043e}', '\0', '\0']), - ('\u{10417}', ['\u{1043f}', '\0', '\0']), ('\u{10418}', ['\u{10440}', '\0', '\0']), - ('\u{10419}', ['\u{10441}', '\0', '\0']), ('\u{1041a}', ['\u{10442}', '\0', '\0']), - ('\u{1041b}', ['\u{10443}', '\0', '\0']), ('\u{1041c}', ['\u{10444}', '\0', '\0']), - ('\u{1041d}', ['\u{10445}', '\0', '\0']), ('\u{1041e}', ['\u{10446}', '\0', '\0']), - ('\u{1041f}', ['\u{10447}', '\0', '\0']), ('\u{10420}', ['\u{10448}', '\0', '\0']), - ('\u{10421}', ['\u{10449}', '\0', '\0']), ('\u{10422}', ['\u{1044a}', '\0', '\0']), - ('\u{10423}', ['\u{1044b}', '\0', '\0']), ('\u{10424}', ['\u{1044c}', '\0', '\0']), - ('\u{10425}', ['\u{1044d}', '\0', '\0']), ('\u{10426}', ['\u{1044e}', '\0', '\0']), - ('\u{10427}', ['\u{1044f}', '\0', '\0']), ('\u{104b0}', ['\u{104d8}', '\0', '\0']), - ('\u{104b1}', ['\u{104d9}', '\0', '\0']), ('\u{104b2}', ['\u{104da}', '\0', '\0']), - ('\u{104b3}', ['\u{104db}', '\0', '\0']), ('\u{104b4}', ['\u{104dc}', '\0', '\0']), - ('\u{104b5}', ['\u{104dd}', '\0', '\0']), ('\u{104b6}', ['\u{104de}', '\0', '\0']), - ('\u{104b7}', ['\u{104df}', '\0', '\0']), ('\u{104b8}', ['\u{104e0}', '\0', '\0']), - ('\u{104b9}', ['\u{104e1}', '\0', '\0']), ('\u{104ba}', ['\u{104e2}', '\0', '\0']), - ('\u{104bb}', ['\u{104e3}', '\0', '\0']), ('\u{104bc}', ['\u{104e4}', '\0', '\0']), - ('\u{104bd}', ['\u{104e5}', '\0', '\0']), ('\u{104be}', ['\u{104e6}', '\0', '\0']), - ('\u{104bf}', ['\u{104e7}', '\0', '\0']), ('\u{104c0}', ['\u{104e8}', '\0', '\0']), - ('\u{104c1}', ['\u{104e9}', '\0', '\0']), ('\u{104c2}', ['\u{104ea}', '\0', '\0']), - ('\u{104c3}', ['\u{104eb}', '\0', '\0']), ('\u{104c4}', ['\u{104ec}', '\0', '\0']), - ('\u{104c5}', ['\u{104ed}', '\0', '\0']), ('\u{104c6}', ['\u{104ee}', '\0', '\0']), - ('\u{104c7}', ['\u{104ef}', '\0', '\0']), ('\u{104c8}', ['\u{104f0}', '\0', '\0']), - ('\u{104c9}', ['\u{104f1}', '\0', '\0']), ('\u{104ca}', ['\u{104f2}', '\0', '\0']), - ('\u{104cb}', ['\u{104f3}', '\0', '\0']), ('\u{104cc}', ['\u{104f4}', '\0', '\0']), - ('\u{104cd}', ['\u{104f5}', '\0', '\0']), ('\u{104ce}', ['\u{104f6}', '\0', '\0']), - ('\u{104cf}', ['\u{104f7}', '\0', '\0']), ('\u{104d0}', ['\u{104f8}', '\0', '\0']), - ('\u{104d1}', ['\u{104f9}', '\0', '\0']), ('\u{104d2}', ['\u{104fa}', '\0', '\0']), - ('\u{104d3}', ['\u{104fb}', '\0', '\0']), ('\u{10c80}', ['\u{10cc0}', '\0', '\0']), - ('\u{10c81}', ['\u{10cc1}', '\0', '\0']), ('\u{10c82}', ['\u{10cc2}', '\0', '\0']), - ('\u{10c83}', ['\u{10cc3}', '\0', '\0']), ('\u{10c84}', ['\u{10cc4}', '\0', '\0']), - ('\u{10c85}', ['\u{10cc5}', '\0', '\0']), ('\u{10c86}', ['\u{10cc6}', '\0', '\0']), - ('\u{10c87}', ['\u{10cc7}', '\0', '\0']), ('\u{10c88}', ['\u{10cc8}', '\0', '\0']), - ('\u{10c89}', ['\u{10cc9}', '\0', '\0']), ('\u{10c8a}', ['\u{10cca}', '\0', '\0']), - ('\u{10c8b}', ['\u{10ccb}', '\0', '\0']), ('\u{10c8c}', ['\u{10ccc}', '\0', '\0']), - ('\u{10c8d}', ['\u{10ccd}', '\0', '\0']), ('\u{10c8e}', ['\u{10cce}', '\0', '\0']), - ('\u{10c8f}', ['\u{10ccf}', '\0', '\0']), ('\u{10c90}', ['\u{10cd0}', '\0', '\0']), - ('\u{10c91}', ['\u{10cd1}', '\0', '\0']), ('\u{10c92}', ['\u{10cd2}', '\0', '\0']), - ('\u{10c93}', ['\u{10cd3}', '\0', '\0']), ('\u{10c94}', ['\u{10cd4}', '\0', '\0']), - ('\u{10c95}', ['\u{10cd5}', '\0', '\0']), ('\u{10c96}', ['\u{10cd6}', '\0', '\0']), - ('\u{10c97}', ['\u{10cd7}', '\0', '\0']), ('\u{10c98}', ['\u{10cd8}', '\0', '\0']), - ('\u{10c99}', ['\u{10cd9}', '\0', '\0']), ('\u{10c9a}', ['\u{10cda}', '\0', '\0']), - ('\u{10c9b}', ['\u{10cdb}', '\0', '\0']), ('\u{10c9c}', ['\u{10cdc}', '\0', '\0']), - ('\u{10c9d}', ['\u{10cdd}', '\0', '\0']), ('\u{10c9e}', ['\u{10cde}', '\0', '\0']), - ('\u{10c9f}', ['\u{10cdf}', '\0', '\0']), ('\u{10ca0}', ['\u{10ce0}', '\0', '\0']), - ('\u{10ca1}', ['\u{10ce1}', '\0', '\0']), ('\u{10ca2}', ['\u{10ce2}', '\0', '\0']), - ('\u{10ca3}', ['\u{10ce3}', '\0', '\0']), ('\u{10ca4}', ['\u{10ce4}', '\0', '\0']), - ('\u{10ca5}', ['\u{10ce5}', '\0', '\0']), ('\u{10ca6}', ['\u{10ce6}', '\0', '\0']), - ('\u{10ca7}', ['\u{10ce7}', '\0', '\0']), ('\u{10ca8}', ['\u{10ce8}', '\0', '\0']), - ('\u{10ca9}', ['\u{10ce9}', '\0', '\0']), ('\u{10caa}', ['\u{10cea}', '\0', '\0']), - ('\u{10cab}', ['\u{10ceb}', '\0', '\0']), ('\u{10cac}', ['\u{10cec}', '\0', '\0']), - ('\u{10cad}', ['\u{10ced}', '\0', '\0']), ('\u{10cae}', ['\u{10cee}', '\0', '\0']), - ('\u{10caf}', ['\u{10cef}', '\0', '\0']), ('\u{10cb0}', ['\u{10cf0}', '\0', '\0']), - ('\u{10cb1}', ['\u{10cf1}', '\0', '\0']), ('\u{10cb2}', ['\u{10cf2}', '\0', '\0']), - ('\u{118a0}', ['\u{118c0}', '\0', '\0']), ('\u{118a1}', ['\u{118c1}', '\0', '\0']), - ('\u{118a2}', ['\u{118c2}', '\0', '\0']), ('\u{118a3}', ['\u{118c3}', '\0', '\0']), - ('\u{118a4}', ['\u{118c4}', '\0', '\0']), ('\u{118a5}', ['\u{118c5}', '\0', '\0']), - ('\u{118a6}', ['\u{118c6}', '\0', '\0']), ('\u{118a7}', ['\u{118c7}', '\0', '\0']), - ('\u{118a8}', ['\u{118c8}', '\0', '\0']), ('\u{118a9}', ['\u{118c9}', '\0', '\0']), - ('\u{118aa}', ['\u{118ca}', '\0', '\0']), ('\u{118ab}', ['\u{118cb}', '\0', '\0']), - ('\u{118ac}', ['\u{118cc}', '\0', '\0']), ('\u{118ad}', ['\u{118cd}', '\0', '\0']), - ('\u{118ae}', ['\u{118ce}', '\0', '\0']), ('\u{118af}', ['\u{118cf}', '\0', '\0']), - ('\u{118b0}', ['\u{118d0}', '\0', '\0']), ('\u{118b1}', ['\u{118d1}', '\0', '\0']), - ('\u{118b2}', ['\u{118d2}', '\0', '\0']), ('\u{118b3}', ['\u{118d3}', '\0', '\0']), - ('\u{118b4}', ['\u{118d4}', '\0', '\0']), ('\u{118b5}', ['\u{118d5}', '\0', '\0']), - ('\u{118b6}', ['\u{118d6}', '\0', '\0']), ('\u{118b7}', ['\u{118d7}', '\0', '\0']), - ('\u{118b8}', ['\u{118d8}', '\0', '\0']), ('\u{118b9}', ['\u{118d9}', '\0', '\0']), - ('\u{118ba}', ['\u{118da}', '\0', '\0']), ('\u{118bb}', ['\u{118db}', '\0', '\0']), - ('\u{118bc}', ['\u{118dc}', '\0', '\0']), ('\u{118bd}', ['\u{118dd}', '\0', '\0']), - ('\u{118be}', ['\u{118de}', '\0', '\0']), ('\u{118bf}', ['\u{118df}', '\0', '\0']), - ('\u{1e900}', ['\u{1e922}', '\0', '\0']), ('\u{1e901}', ['\u{1e923}', '\0', '\0']), - ('\u{1e902}', ['\u{1e924}', '\0', '\0']), ('\u{1e903}', ['\u{1e925}', '\0', '\0']), - ('\u{1e904}', ['\u{1e926}', '\0', '\0']), ('\u{1e905}', ['\u{1e927}', '\0', '\0']), - ('\u{1e906}', ['\u{1e928}', '\0', '\0']), ('\u{1e907}', ['\u{1e929}', '\0', '\0']), - ('\u{1e908}', ['\u{1e92a}', '\0', '\0']), ('\u{1e909}', ['\u{1e92b}', '\0', '\0']), - ('\u{1e90a}', ['\u{1e92c}', '\0', '\0']), ('\u{1e90b}', ['\u{1e92d}', '\0', '\0']), - ('\u{1e90c}', ['\u{1e92e}', '\0', '\0']), ('\u{1e90d}', ['\u{1e92f}', '\0', '\0']), - ('\u{1e90e}', ['\u{1e930}', '\0', '\0']), ('\u{1e90f}', ['\u{1e931}', '\0', '\0']), - ('\u{1e910}', ['\u{1e932}', '\0', '\0']), ('\u{1e911}', ['\u{1e933}', '\0', '\0']), - ('\u{1e912}', ['\u{1e934}', '\0', '\0']), ('\u{1e913}', ['\u{1e935}', '\0', '\0']), - ('\u{1e914}', ['\u{1e936}', '\0', '\0']), ('\u{1e915}', ['\u{1e937}', '\0', '\0']), - ('\u{1e916}', ['\u{1e938}', '\0', '\0']), ('\u{1e917}', ['\u{1e939}', '\0', '\0']), - ('\u{1e918}', ['\u{1e93a}', '\0', '\0']), ('\u{1e919}', ['\u{1e93b}', '\0', '\0']), - ('\u{1e91a}', ['\u{1e93c}', '\0', '\0']), ('\u{1e91b}', ['\u{1e93d}', '\0', '\0']), - ('\u{1e91c}', ['\u{1e93e}', '\0', '\0']), ('\u{1e91d}', ['\u{1e93f}', '\0', '\0']), - ('\u{1e91e}', ['\u{1e940}', '\0', '\0']), ('\u{1e91f}', ['\u{1e941}', '\0', '\0']), - ('\u{1e920}', ['\u{1e942}', '\0', '\0']), ('\u{1e921}', ['\u{1e943}', '\0', '\0']) + '\0']), ('\u{13f5}', ['\u{13fd}', '\0', '\0']), ('\u{1c90}', ['\u{10d0}', '\0', '\0']), + ('\u{1c91}', ['\u{10d1}', '\0', '\0']), ('\u{1c92}', ['\u{10d2}', '\0', '\0']), ('\u{1c93}', + ['\u{10d3}', '\0', '\0']), ('\u{1c94}', ['\u{10d4}', '\0', '\0']), ('\u{1c95}', ['\u{10d5}', + '\0', '\0']), ('\u{1c96}', ['\u{10d6}', '\0', '\0']), ('\u{1c97}', ['\u{10d7}', '\0', + '\0']), ('\u{1c98}', ['\u{10d8}', '\0', '\0']), ('\u{1c99}', ['\u{10d9}', '\0', '\0']), + ('\u{1c9a}', ['\u{10da}', '\0', '\0']), ('\u{1c9b}', ['\u{10db}', '\0', '\0']), ('\u{1c9c}', + ['\u{10dc}', '\0', '\0']), ('\u{1c9d}', ['\u{10dd}', '\0', '\0']), ('\u{1c9e}', ['\u{10de}', + '\0', '\0']), ('\u{1c9f}', ['\u{10df}', '\0', '\0']), ('\u{1ca0}', ['\u{10e0}', '\0', + '\0']), ('\u{1ca1}', ['\u{10e1}', '\0', '\0']), ('\u{1ca2}', ['\u{10e2}', '\0', '\0']), + ('\u{1ca3}', ['\u{10e3}', '\0', '\0']), ('\u{1ca4}', ['\u{10e4}', '\0', '\0']), ('\u{1ca5}', + ['\u{10e5}', '\0', '\0']), ('\u{1ca6}', ['\u{10e6}', '\0', '\0']), ('\u{1ca7}', ['\u{10e7}', + '\0', '\0']), ('\u{1ca8}', ['\u{10e8}', '\0', '\0']), ('\u{1ca9}', ['\u{10e9}', '\0', + '\0']), ('\u{1caa}', ['\u{10ea}', '\0', '\0']), ('\u{1cab}', ['\u{10eb}', '\0', '\0']), + ('\u{1cac}', ['\u{10ec}', '\0', '\0']), ('\u{1cad}', ['\u{10ed}', '\0', '\0']), ('\u{1cae}', + ['\u{10ee}', '\0', '\0']), ('\u{1caf}', ['\u{10ef}', '\0', '\0']), ('\u{1cb0}', ['\u{10f0}', + '\0', '\0']), ('\u{1cb1}', ['\u{10f1}', '\0', '\0']), ('\u{1cb2}', ['\u{10f2}', '\0', + '\0']), ('\u{1cb3}', ['\u{10f3}', '\0', '\0']), ('\u{1cb4}', ['\u{10f4}', '\0', '\0']), + ('\u{1cb5}', ['\u{10f5}', '\0', '\0']), ('\u{1cb6}', ['\u{10f6}', '\0', '\0']), ('\u{1cb7}', + ['\u{10f7}', '\0', '\0']), ('\u{1cb8}', ['\u{10f8}', '\0', '\0']), ('\u{1cb9}', ['\u{10f9}', + '\0', '\0']), ('\u{1cba}', ['\u{10fa}', '\0', '\0']), ('\u{1cbd}', ['\u{10fd}', '\0', + '\0']), ('\u{1cbe}', ['\u{10fe}', '\0', '\0']), ('\u{1cbf}', ['\u{10ff}', '\0', '\0']), + ('\u{1e00}', ['\u{1e01}', '\0', '\0']), ('\u{1e02}', ['\u{1e03}', '\0', '\0']), ('\u{1e04}', + ['\u{1e05}', '\0', '\0']), ('\u{1e06}', ['\u{1e07}', '\0', '\0']), ('\u{1e08}', ['\u{1e09}', + '\0', '\0']), ('\u{1e0a}', ['\u{1e0b}', '\0', '\0']), ('\u{1e0c}', ['\u{1e0d}', '\0', + '\0']), ('\u{1e0e}', ['\u{1e0f}', '\0', '\0']), ('\u{1e10}', ['\u{1e11}', '\0', '\0']), + ('\u{1e12}', ['\u{1e13}', '\0', '\0']), ('\u{1e14}', ['\u{1e15}', '\0', '\0']), ('\u{1e16}', + ['\u{1e17}', '\0', '\0']), ('\u{1e18}', ['\u{1e19}', '\0', '\0']), ('\u{1e1a}', ['\u{1e1b}', + '\0', '\0']), ('\u{1e1c}', ['\u{1e1d}', '\0', '\0']), ('\u{1e1e}', ['\u{1e1f}', '\0', + '\0']), ('\u{1e20}', ['\u{1e21}', '\0', '\0']), ('\u{1e22}', ['\u{1e23}', '\0', '\0']), + ('\u{1e24}', ['\u{1e25}', '\0', '\0']), ('\u{1e26}', ['\u{1e27}', '\0', '\0']), ('\u{1e28}', + ['\u{1e29}', '\0', '\0']), ('\u{1e2a}', ['\u{1e2b}', '\0', '\0']), ('\u{1e2c}', ['\u{1e2d}', + '\0', '\0']), ('\u{1e2e}', ['\u{1e2f}', '\0', '\0']), ('\u{1e30}', ['\u{1e31}', '\0', + '\0']), ('\u{1e32}', ['\u{1e33}', '\0', '\0']), ('\u{1e34}', ['\u{1e35}', '\0', '\0']), + ('\u{1e36}', ['\u{1e37}', '\0', '\0']), ('\u{1e38}', ['\u{1e39}', '\0', '\0']), ('\u{1e3a}', + ['\u{1e3b}', '\0', '\0']), ('\u{1e3c}', ['\u{1e3d}', '\0', '\0']), ('\u{1e3e}', ['\u{1e3f}', + '\0', '\0']), ('\u{1e40}', ['\u{1e41}', '\0', '\0']), ('\u{1e42}', ['\u{1e43}', '\0', + '\0']), ('\u{1e44}', ['\u{1e45}', '\0', '\0']), ('\u{1e46}', ['\u{1e47}', '\0', '\0']), + ('\u{1e48}', ['\u{1e49}', '\0', '\0']), ('\u{1e4a}', ['\u{1e4b}', '\0', '\0']), ('\u{1e4c}', + ['\u{1e4d}', '\0', '\0']), ('\u{1e4e}', ['\u{1e4f}', '\0', '\0']), ('\u{1e50}', ['\u{1e51}', + '\0', '\0']), ('\u{1e52}', ['\u{1e53}', '\0', '\0']), ('\u{1e54}', ['\u{1e55}', '\0', + '\0']), ('\u{1e56}', ['\u{1e57}', '\0', '\0']), ('\u{1e58}', ['\u{1e59}', '\0', '\0']), + ('\u{1e5a}', ['\u{1e5b}', '\0', '\0']), ('\u{1e5c}', ['\u{1e5d}', '\0', '\0']), ('\u{1e5e}', + ['\u{1e5f}', '\0', '\0']), ('\u{1e60}', ['\u{1e61}', '\0', '\0']), ('\u{1e62}', ['\u{1e63}', + '\0', '\0']), ('\u{1e64}', ['\u{1e65}', '\0', '\0']), ('\u{1e66}', ['\u{1e67}', '\0', + '\0']), ('\u{1e68}', ['\u{1e69}', '\0', '\0']), ('\u{1e6a}', ['\u{1e6b}', '\0', '\0']), + ('\u{1e6c}', ['\u{1e6d}', '\0', '\0']), ('\u{1e6e}', ['\u{1e6f}', '\0', '\0']), ('\u{1e70}', + ['\u{1e71}', '\0', '\0']), ('\u{1e72}', ['\u{1e73}', '\0', '\0']), ('\u{1e74}', ['\u{1e75}', + '\0', '\0']), ('\u{1e76}', ['\u{1e77}', '\0', '\0']), ('\u{1e78}', ['\u{1e79}', '\0', + '\0']), ('\u{1e7a}', ['\u{1e7b}', '\0', '\0']), ('\u{1e7c}', ['\u{1e7d}', '\0', '\0']), + ('\u{1e7e}', ['\u{1e7f}', '\0', '\0']), ('\u{1e80}', ['\u{1e81}', '\0', '\0']), ('\u{1e82}', + ['\u{1e83}', '\0', '\0']), ('\u{1e84}', ['\u{1e85}', '\0', '\0']), ('\u{1e86}', ['\u{1e87}', + '\0', '\0']), ('\u{1e88}', ['\u{1e89}', '\0', '\0']), ('\u{1e8a}', ['\u{1e8b}', '\0', + '\0']), ('\u{1e8c}', ['\u{1e8d}', '\0', '\0']), ('\u{1e8e}', ['\u{1e8f}', '\0', '\0']), + ('\u{1e90}', ['\u{1e91}', '\0', '\0']), ('\u{1e92}', ['\u{1e93}', '\0', '\0']), ('\u{1e94}', + ['\u{1e95}', '\0', '\0']), ('\u{1e9e}', ['\u{df}', '\0', '\0']), ('\u{1ea0}', ['\u{1ea1}', + '\0', '\0']), ('\u{1ea2}', ['\u{1ea3}', '\0', '\0']), ('\u{1ea4}', ['\u{1ea5}', '\0', + '\0']), ('\u{1ea6}', ['\u{1ea7}', '\0', '\0']), ('\u{1ea8}', ['\u{1ea9}', '\0', '\0']), + ('\u{1eaa}', ['\u{1eab}', '\0', '\0']), ('\u{1eac}', ['\u{1ead}', '\0', '\0']), ('\u{1eae}', + ['\u{1eaf}', '\0', '\0']), ('\u{1eb0}', ['\u{1eb1}', '\0', '\0']), ('\u{1eb2}', ['\u{1eb3}', + '\0', '\0']), ('\u{1eb4}', ['\u{1eb5}', '\0', '\0']), ('\u{1eb6}', ['\u{1eb7}', '\0', + '\0']), ('\u{1eb8}', ['\u{1eb9}', '\0', '\0']), ('\u{1eba}', ['\u{1ebb}', '\0', '\0']), + ('\u{1ebc}', ['\u{1ebd}', '\0', '\0']), ('\u{1ebe}', ['\u{1ebf}', '\0', '\0']), ('\u{1ec0}', + ['\u{1ec1}', '\0', '\0']), ('\u{1ec2}', ['\u{1ec3}', '\0', '\0']), ('\u{1ec4}', ['\u{1ec5}', + '\0', '\0']), ('\u{1ec6}', ['\u{1ec7}', '\0', '\0']), ('\u{1ec8}', ['\u{1ec9}', '\0', + '\0']), ('\u{1eca}', ['\u{1ecb}', '\0', '\0']), ('\u{1ecc}', ['\u{1ecd}', '\0', '\0']), + ('\u{1ece}', ['\u{1ecf}', '\0', '\0']), ('\u{1ed0}', ['\u{1ed1}', '\0', '\0']), ('\u{1ed2}', + ['\u{1ed3}', '\0', '\0']), ('\u{1ed4}', ['\u{1ed5}', '\0', '\0']), ('\u{1ed6}', ['\u{1ed7}', + '\0', '\0']), ('\u{1ed8}', ['\u{1ed9}', '\0', '\0']), ('\u{1eda}', ['\u{1edb}', '\0', + '\0']), ('\u{1edc}', ['\u{1edd}', '\0', '\0']), ('\u{1ede}', ['\u{1edf}', '\0', '\0']), + ('\u{1ee0}', ['\u{1ee1}', '\0', '\0']), ('\u{1ee2}', ['\u{1ee3}', '\0', '\0']), ('\u{1ee4}', + ['\u{1ee5}', '\0', '\0']), ('\u{1ee6}', ['\u{1ee7}', '\0', '\0']), ('\u{1ee8}', ['\u{1ee9}', + '\0', '\0']), ('\u{1eea}', ['\u{1eeb}', '\0', '\0']), ('\u{1eec}', ['\u{1eed}', '\0', + '\0']), ('\u{1eee}', ['\u{1eef}', '\0', '\0']), ('\u{1ef0}', ['\u{1ef1}', '\0', '\0']), + ('\u{1ef2}', ['\u{1ef3}', '\0', '\0']), ('\u{1ef4}', ['\u{1ef5}', '\0', '\0']), ('\u{1ef6}', + ['\u{1ef7}', '\0', '\0']), ('\u{1ef8}', ['\u{1ef9}', '\0', '\0']), ('\u{1efa}', ['\u{1efb}', + '\0', '\0']), ('\u{1efc}', ['\u{1efd}', '\0', '\0']), ('\u{1efe}', ['\u{1eff}', '\0', + '\0']), ('\u{1f08}', ['\u{1f00}', '\0', '\0']), ('\u{1f09}', ['\u{1f01}', '\0', '\0']), + ('\u{1f0a}', ['\u{1f02}', '\0', '\0']), ('\u{1f0b}', ['\u{1f03}', '\0', '\0']), ('\u{1f0c}', + ['\u{1f04}', '\0', '\0']), ('\u{1f0d}', ['\u{1f05}', '\0', '\0']), ('\u{1f0e}', ['\u{1f06}', + '\0', '\0']), ('\u{1f0f}', ['\u{1f07}', '\0', '\0']), ('\u{1f18}', ['\u{1f10}', '\0', + '\0']), ('\u{1f19}', ['\u{1f11}', '\0', '\0']), ('\u{1f1a}', ['\u{1f12}', '\0', '\0']), + ('\u{1f1b}', ['\u{1f13}', '\0', '\0']), ('\u{1f1c}', ['\u{1f14}', '\0', '\0']), ('\u{1f1d}', + ['\u{1f15}', '\0', '\0']), ('\u{1f28}', ['\u{1f20}', '\0', '\0']), ('\u{1f29}', ['\u{1f21}', + '\0', '\0']), ('\u{1f2a}', ['\u{1f22}', '\0', '\0']), ('\u{1f2b}', ['\u{1f23}', '\0', + '\0']), ('\u{1f2c}', ['\u{1f24}', '\0', '\0']), ('\u{1f2d}', ['\u{1f25}', '\0', '\0']), + ('\u{1f2e}', ['\u{1f26}', '\0', '\0']), ('\u{1f2f}', ['\u{1f27}', '\0', '\0']), ('\u{1f38}', + ['\u{1f30}', '\0', '\0']), ('\u{1f39}', ['\u{1f31}', '\0', '\0']), ('\u{1f3a}', ['\u{1f32}', + '\0', '\0']), ('\u{1f3b}', ['\u{1f33}', '\0', '\0']), ('\u{1f3c}', ['\u{1f34}', '\0', + '\0']), ('\u{1f3d}', ['\u{1f35}', '\0', '\0']), ('\u{1f3e}', ['\u{1f36}', '\0', '\0']), + ('\u{1f3f}', ['\u{1f37}', '\0', '\0']), ('\u{1f48}', ['\u{1f40}', '\0', '\0']), ('\u{1f49}', + ['\u{1f41}', '\0', '\0']), ('\u{1f4a}', ['\u{1f42}', '\0', '\0']), ('\u{1f4b}', ['\u{1f43}', + '\0', '\0']), ('\u{1f4c}', ['\u{1f44}', '\0', '\0']), ('\u{1f4d}', ['\u{1f45}', '\0', + '\0']), ('\u{1f59}', ['\u{1f51}', '\0', '\0']), ('\u{1f5b}', ['\u{1f53}', '\0', '\0']), + ('\u{1f5d}', ['\u{1f55}', '\0', '\0']), ('\u{1f5f}', ['\u{1f57}', '\0', '\0']), ('\u{1f68}', + ['\u{1f60}', '\0', '\0']), ('\u{1f69}', ['\u{1f61}', '\0', '\0']), ('\u{1f6a}', ['\u{1f62}', + '\0', '\0']), ('\u{1f6b}', ['\u{1f63}', '\0', '\0']), ('\u{1f6c}', ['\u{1f64}', '\0', + '\0']), ('\u{1f6d}', ['\u{1f65}', '\0', '\0']), ('\u{1f6e}', ['\u{1f66}', '\0', '\0']), + ('\u{1f6f}', ['\u{1f67}', '\0', '\0']), ('\u{1f88}', ['\u{1f80}', '\0', '\0']), ('\u{1f89}', + ['\u{1f81}', '\0', '\0']), ('\u{1f8a}', ['\u{1f82}', '\0', '\0']), ('\u{1f8b}', ['\u{1f83}', + '\0', '\0']), ('\u{1f8c}', ['\u{1f84}', '\0', '\0']), ('\u{1f8d}', ['\u{1f85}', '\0', + '\0']), ('\u{1f8e}', ['\u{1f86}', '\0', '\0']), ('\u{1f8f}', ['\u{1f87}', '\0', '\0']), + ('\u{1f98}', ['\u{1f90}', '\0', '\0']), ('\u{1f99}', ['\u{1f91}', '\0', '\0']), ('\u{1f9a}', + ['\u{1f92}', '\0', '\0']), ('\u{1f9b}', ['\u{1f93}', '\0', '\0']), ('\u{1f9c}', ['\u{1f94}', + '\0', '\0']), ('\u{1f9d}', ['\u{1f95}', '\0', '\0']), ('\u{1f9e}', ['\u{1f96}', '\0', + '\0']), ('\u{1f9f}', ['\u{1f97}', '\0', '\0']), ('\u{1fa8}', ['\u{1fa0}', '\0', '\0']), + ('\u{1fa9}', ['\u{1fa1}', '\0', '\0']), ('\u{1faa}', ['\u{1fa2}', '\0', '\0']), ('\u{1fab}', + ['\u{1fa3}', '\0', '\0']), ('\u{1fac}', ['\u{1fa4}', '\0', '\0']), ('\u{1fad}', ['\u{1fa5}', + '\0', '\0']), ('\u{1fae}', ['\u{1fa6}', '\0', '\0']), ('\u{1faf}', ['\u{1fa7}', '\0', + '\0']), ('\u{1fb8}', ['\u{1fb0}', '\0', '\0']), ('\u{1fb9}', ['\u{1fb1}', '\0', '\0']), + ('\u{1fba}', ['\u{1f70}', '\0', '\0']), ('\u{1fbb}', ['\u{1f71}', '\0', '\0']), ('\u{1fbc}', + ['\u{1fb3}', '\0', '\0']), ('\u{1fc8}', ['\u{1f72}', '\0', '\0']), ('\u{1fc9}', ['\u{1f73}', + '\0', '\0']), ('\u{1fca}', ['\u{1f74}', '\0', '\0']), ('\u{1fcb}', ['\u{1f75}', '\0', + '\0']), ('\u{1fcc}', ['\u{1fc3}', '\0', '\0']), ('\u{1fd8}', ['\u{1fd0}', '\0', '\0']), + ('\u{1fd9}', ['\u{1fd1}', '\0', '\0']), ('\u{1fda}', ['\u{1f76}', '\0', '\0']), ('\u{1fdb}', + ['\u{1f77}', '\0', '\0']), ('\u{1fe8}', ['\u{1fe0}', '\0', '\0']), ('\u{1fe9}', ['\u{1fe1}', + '\0', '\0']), ('\u{1fea}', ['\u{1f7a}', '\0', '\0']), ('\u{1feb}', ['\u{1f7b}', '\0', + '\0']), ('\u{1fec}', ['\u{1fe5}', '\0', '\0']), ('\u{1ff8}', ['\u{1f78}', '\0', '\0']), + ('\u{1ff9}', ['\u{1f79}', '\0', '\0']), ('\u{1ffa}', ['\u{1f7c}', '\0', '\0']), ('\u{1ffb}', + ['\u{1f7d}', '\0', '\0']), ('\u{1ffc}', ['\u{1ff3}', '\0', '\0']), ('\u{2126}', ['\u{3c9}', + '\0', '\0']), ('\u{212a}', ['\u{6b}', '\0', '\0']), ('\u{212b}', ['\u{e5}', '\0', '\0']), + ('\u{2132}', ['\u{214e}', '\0', '\0']), ('\u{2160}', ['\u{2170}', '\0', '\0']), ('\u{2161}', + ['\u{2171}', '\0', '\0']), ('\u{2162}', ['\u{2172}', '\0', '\0']), ('\u{2163}', ['\u{2173}', + '\0', '\0']), ('\u{2164}', ['\u{2174}', '\0', '\0']), ('\u{2165}', ['\u{2175}', '\0', + '\0']), ('\u{2166}', ['\u{2176}', '\0', '\0']), ('\u{2167}', ['\u{2177}', '\0', '\0']), + ('\u{2168}', ['\u{2178}', '\0', '\0']), ('\u{2169}', ['\u{2179}', '\0', '\0']), ('\u{216a}', + ['\u{217a}', '\0', '\0']), ('\u{216b}', ['\u{217b}', '\0', '\0']), ('\u{216c}', ['\u{217c}', + '\0', '\0']), ('\u{216d}', ['\u{217d}', '\0', '\0']), ('\u{216e}', ['\u{217e}', '\0', + '\0']), ('\u{216f}', ['\u{217f}', '\0', '\0']), ('\u{2183}', ['\u{2184}', '\0', '\0']), + ('\u{24b6}', ['\u{24d0}', '\0', '\0']), ('\u{24b7}', ['\u{24d1}', '\0', '\0']), ('\u{24b8}', + ['\u{24d2}', '\0', '\0']), ('\u{24b9}', ['\u{24d3}', '\0', '\0']), ('\u{24ba}', ['\u{24d4}', + '\0', '\0']), ('\u{24bb}', ['\u{24d5}', '\0', '\0']), ('\u{24bc}', ['\u{24d6}', '\0', + '\0']), ('\u{24bd}', ['\u{24d7}', '\0', '\0']), ('\u{24be}', ['\u{24d8}', '\0', '\0']), + ('\u{24bf}', ['\u{24d9}', '\0', '\0']), ('\u{24c0}', ['\u{24da}', '\0', '\0']), ('\u{24c1}', + ['\u{24db}', '\0', '\0']), ('\u{24c2}', ['\u{24dc}', '\0', '\0']), ('\u{24c3}', ['\u{24dd}', + '\0', '\0']), ('\u{24c4}', ['\u{24de}', '\0', '\0']), ('\u{24c5}', ['\u{24df}', '\0', + '\0']), ('\u{24c6}', ['\u{24e0}', '\0', '\0']), ('\u{24c7}', ['\u{24e1}', '\0', '\0']), + ('\u{24c8}', ['\u{24e2}', '\0', '\0']), ('\u{24c9}', ['\u{24e3}', '\0', '\0']), ('\u{24ca}', + ['\u{24e4}', '\0', '\0']), ('\u{24cb}', ['\u{24e5}', '\0', '\0']), ('\u{24cc}', ['\u{24e6}', + '\0', '\0']), ('\u{24cd}', ['\u{24e7}', '\0', '\0']), ('\u{24ce}', ['\u{24e8}', '\0', + '\0']), ('\u{24cf}', ['\u{24e9}', '\0', '\0']), ('\u{2c00}', ['\u{2c30}', '\0', '\0']), + ('\u{2c01}', ['\u{2c31}', '\0', '\0']), ('\u{2c02}', ['\u{2c32}', '\0', '\0']), ('\u{2c03}', + ['\u{2c33}', '\0', '\0']), ('\u{2c04}', ['\u{2c34}', '\0', '\0']), ('\u{2c05}', ['\u{2c35}', + '\0', '\0']), ('\u{2c06}', ['\u{2c36}', '\0', '\0']), ('\u{2c07}', ['\u{2c37}', '\0', + '\0']), ('\u{2c08}', ['\u{2c38}', '\0', '\0']), ('\u{2c09}', ['\u{2c39}', '\0', '\0']), + ('\u{2c0a}', ['\u{2c3a}', '\0', '\0']), ('\u{2c0b}', ['\u{2c3b}', '\0', '\0']), ('\u{2c0c}', + ['\u{2c3c}', '\0', '\0']), ('\u{2c0d}', ['\u{2c3d}', '\0', '\0']), ('\u{2c0e}', ['\u{2c3e}', + '\0', '\0']), ('\u{2c0f}', ['\u{2c3f}', '\0', '\0']), ('\u{2c10}', ['\u{2c40}', '\0', + '\0']), ('\u{2c11}', ['\u{2c41}', '\0', '\0']), ('\u{2c12}', ['\u{2c42}', '\0', '\0']), + ('\u{2c13}', ['\u{2c43}', '\0', '\0']), ('\u{2c14}', ['\u{2c44}', '\0', '\0']), ('\u{2c15}', + ['\u{2c45}', '\0', '\0']), ('\u{2c16}', ['\u{2c46}', '\0', '\0']), ('\u{2c17}', ['\u{2c47}', + '\0', '\0']), ('\u{2c18}', ['\u{2c48}', '\0', '\0']), ('\u{2c19}', ['\u{2c49}', '\0', + '\0']), ('\u{2c1a}', ['\u{2c4a}', '\0', '\0']), ('\u{2c1b}', ['\u{2c4b}', '\0', '\0']), + ('\u{2c1c}', ['\u{2c4c}', '\0', '\0']), ('\u{2c1d}', ['\u{2c4d}', '\0', '\0']), ('\u{2c1e}', + ['\u{2c4e}', '\0', '\0']), ('\u{2c1f}', ['\u{2c4f}', '\0', '\0']), ('\u{2c20}', ['\u{2c50}', + '\0', '\0']), ('\u{2c21}', ['\u{2c51}', '\0', '\0']), ('\u{2c22}', ['\u{2c52}', '\0', + '\0']), ('\u{2c23}', ['\u{2c53}', '\0', '\0']), ('\u{2c24}', ['\u{2c54}', '\0', '\0']), + ('\u{2c25}', ['\u{2c55}', '\0', '\0']), ('\u{2c26}', ['\u{2c56}', '\0', '\0']), ('\u{2c27}', + ['\u{2c57}', '\0', '\0']), ('\u{2c28}', ['\u{2c58}', '\0', '\0']), ('\u{2c29}', ['\u{2c59}', + '\0', '\0']), ('\u{2c2a}', ['\u{2c5a}', '\0', '\0']), ('\u{2c2b}', ['\u{2c5b}', '\0', + '\0']), ('\u{2c2c}', ['\u{2c5c}', '\0', '\0']), ('\u{2c2d}', ['\u{2c5d}', '\0', '\0']), + ('\u{2c2e}', ['\u{2c5e}', '\0', '\0']), ('\u{2c60}', ['\u{2c61}', '\0', '\0']), ('\u{2c62}', + ['\u{26b}', '\0', '\0']), ('\u{2c63}', ['\u{1d7d}', '\0', '\0']), ('\u{2c64}', ['\u{27d}', + '\0', '\0']), ('\u{2c67}', ['\u{2c68}', '\0', '\0']), ('\u{2c69}', ['\u{2c6a}', '\0', + '\0']), ('\u{2c6b}', ['\u{2c6c}', '\0', '\0']), ('\u{2c6d}', ['\u{251}', '\0', '\0']), + ('\u{2c6e}', ['\u{271}', '\0', '\0']), ('\u{2c6f}', ['\u{250}', '\0', '\0']), ('\u{2c70}', + ['\u{252}', '\0', '\0']), ('\u{2c72}', ['\u{2c73}', '\0', '\0']), ('\u{2c75}', ['\u{2c76}', + '\0', '\0']), ('\u{2c7e}', ['\u{23f}', '\0', '\0']), ('\u{2c7f}', ['\u{240}', '\0', '\0']), + ('\u{2c80}', ['\u{2c81}', '\0', '\0']), ('\u{2c82}', ['\u{2c83}', '\0', '\0']), ('\u{2c84}', + ['\u{2c85}', '\0', '\0']), ('\u{2c86}', ['\u{2c87}', '\0', '\0']), ('\u{2c88}', ['\u{2c89}', + '\0', '\0']), ('\u{2c8a}', ['\u{2c8b}', '\0', '\0']), ('\u{2c8c}', ['\u{2c8d}', '\0', + '\0']), ('\u{2c8e}', ['\u{2c8f}', '\0', '\0']), ('\u{2c90}', ['\u{2c91}', '\0', '\0']), + ('\u{2c92}', ['\u{2c93}', '\0', '\0']), ('\u{2c94}', ['\u{2c95}', '\0', '\0']), ('\u{2c96}', + ['\u{2c97}', '\0', '\0']), ('\u{2c98}', ['\u{2c99}', '\0', '\0']), ('\u{2c9a}', ['\u{2c9b}', + '\0', '\0']), ('\u{2c9c}', ['\u{2c9d}', '\0', '\0']), ('\u{2c9e}', ['\u{2c9f}', '\0', + '\0']), ('\u{2ca0}', ['\u{2ca1}', '\0', '\0']), ('\u{2ca2}', ['\u{2ca3}', '\0', '\0']), + ('\u{2ca4}', ['\u{2ca5}', '\0', '\0']), ('\u{2ca6}', ['\u{2ca7}', '\0', '\0']), ('\u{2ca8}', + ['\u{2ca9}', '\0', '\0']), ('\u{2caa}', ['\u{2cab}', '\0', '\0']), ('\u{2cac}', ['\u{2cad}', + '\0', '\0']), ('\u{2cae}', ['\u{2caf}', '\0', '\0']), ('\u{2cb0}', ['\u{2cb1}', '\0', + '\0']), ('\u{2cb2}', ['\u{2cb3}', '\0', '\0']), ('\u{2cb4}', ['\u{2cb5}', '\0', '\0']), + ('\u{2cb6}', ['\u{2cb7}', '\0', '\0']), ('\u{2cb8}', ['\u{2cb9}', '\0', '\0']), ('\u{2cba}', + ['\u{2cbb}', '\0', '\0']), ('\u{2cbc}', ['\u{2cbd}', '\0', '\0']), ('\u{2cbe}', ['\u{2cbf}', + '\0', '\0']), ('\u{2cc0}', ['\u{2cc1}', '\0', '\0']), ('\u{2cc2}', ['\u{2cc3}', '\0', + '\0']), ('\u{2cc4}', ['\u{2cc5}', '\0', '\0']), ('\u{2cc6}', ['\u{2cc7}', '\0', '\0']), + ('\u{2cc8}', ['\u{2cc9}', '\0', '\0']), ('\u{2cca}', ['\u{2ccb}', '\0', '\0']), ('\u{2ccc}', + ['\u{2ccd}', '\0', '\0']), ('\u{2cce}', ['\u{2ccf}', '\0', '\0']), ('\u{2cd0}', ['\u{2cd1}', + '\0', '\0']), ('\u{2cd2}', ['\u{2cd3}', '\0', '\0']), ('\u{2cd4}', ['\u{2cd5}', '\0', + '\0']), ('\u{2cd6}', ['\u{2cd7}', '\0', '\0']), ('\u{2cd8}', ['\u{2cd9}', '\0', '\0']), + ('\u{2cda}', ['\u{2cdb}', '\0', '\0']), ('\u{2cdc}', ['\u{2cdd}', '\0', '\0']), ('\u{2cde}', + ['\u{2cdf}', '\0', '\0']), ('\u{2ce0}', ['\u{2ce1}', '\0', '\0']), ('\u{2ce2}', ['\u{2ce3}', + '\0', '\0']), ('\u{2ceb}', ['\u{2cec}', '\0', '\0']), ('\u{2ced}', ['\u{2cee}', '\0', + '\0']), ('\u{2cf2}', ['\u{2cf3}', '\0', '\0']), ('\u{a640}', ['\u{a641}', '\0', '\0']), + ('\u{a642}', ['\u{a643}', '\0', '\0']), ('\u{a644}', ['\u{a645}', '\0', '\0']), ('\u{a646}', + ['\u{a647}', '\0', '\0']), ('\u{a648}', ['\u{a649}', '\0', '\0']), ('\u{a64a}', ['\u{a64b}', + '\0', '\0']), ('\u{a64c}', ['\u{a64d}', '\0', '\0']), ('\u{a64e}', ['\u{a64f}', '\0', + '\0']), ('\u{a650}', ['\u{a651}', '\0', '\0']), ('\u{a652}', ['\u{a653}', '\0', '\0']), + ('\u{a654}', ['\u{a655}', '\0', '\0']), ('\u{a656}', ['\u{a657}', '\0', '\0']), ('\u{a658}', + ['\u{a659}', '\0', '\0']), ('\u{a65a}', ['\u{a65b}', '\0', '\0']), ('\u{a65c}', ['\u{a65d}', + '\0', '\0']), ('\u{a65e}', ['\u{a65f}', '\0', '\0']), ('\u{a660}', ['\u{a661}', '\0', + '\0']), ('\u{a662}', ['\u{a663}', '\0', '\0']), ('\u{a664}', ['\u{a665}', '\0', '\0']), + ('\u{a666}', ['\u{a667}', '\0', '\0']), ('\u{a668}', ['\u{a669}', '\0', '\0']), ('\u{a66a}', + ['\u{a66b}', '\0', '\0']), ('\u{a66c}', ['\u{a66d}', '\0', '\0']), ('\u{a680}', ['\u{a681}', + '\0', '\0']), ('\u{a682}', ['\u{a683}', '\0', '\0']), ('\u{a684}', ['\u{a685}', '\0', + '\0']), ('\u{a686}', ['\u{a687}', '\0', '\0']), ('\u{a688}', ['\u{a689}', '\0', '\0']), + ('\u{a68a}', ['\u{a68b}', '\0', '\0']), ('\u{a68c}', ['\u{a68d}', '\0', '\0']), ('\u{a68e}', + ['\u{a68f}', '\0', '\0']), ('\u{a690}', ['\u{a691}', '\0', '\0']), ('\u{a692}', ['\u{a693}', + '\0', '\0']), ('\u{a694}', ['\u{a695}', '\0', '\0']), ('\u{a696}', ['\u{a697}', '\0', + '\0']), ('\u{a698}', ['\u{a699}', '\0', '\0']), ('\u{a69a}', ['\u{a69b}', '\0', '\0']), + ('\u{a722}', ['\u{a723}', '\0', '\0']), ('\u{a724}', ['\u{a725}', '\0', '\0']), ('\u{a726}', + ['\u{a727}', '\0', '\0']), ('\u{a728}', ['\u{a729}', '\0', '\0']), ('\u{a72a}', ['\u{a72b}', + '\0', '\0']), ('\u{a72c}', ['\u{a72d}', '\0', '\0']), ('\u{a72e}', ['\u{a72f}', '\0', + '\0']), ('\u{a732}', ['\u{a733}', '\0', '\0']), ('\u{a734}', ['\u{a735}', '\0', '\0']), + ('\u{a736}', ['\u{a737}', '\0', '\0']), ('\u{a738}', ['\u{a739}', '\0', '\0']), ('\u{a73a}', + ['\u{a73b}', '\0', '\0']), ('\u{a73c}', ['\u{a73d}', '\0', '\0']), ('\u{a73e}', ['\u{a73f}', + '\0', '\0']), ('\u{a740}', ['\u{a741}', '\0', '\0']), ('\u{a742}', ['\u{a743}', '\0', + '\0']), ('\u{a744}', ['\u{a745}', '\0', '\0']), ('\u{a746}', ['\u{a747}', '\0', '\0']), + ('\u{a748}', ['\u{a749}', '\0', '\0']), ('\u{a74a}', ['\u{a74b}', '\0', '\0']), ('\u{a74c}', + ['\u{a74d}', '\0', '\0']), ('\u{a74e}', ['\u{a74f}', '\0', '\0']), ('\u{a750}', ['\u{a751}', + '\0', '\0']), ('\u{a752}', ['\u{a753}', '\0', '\0']), ('\u{a754}', ['\u{a755}', '\0', + '\0']), ('\u{a756}', ['\u{a757}', '\0', '\0']), ('\u{a758}', ['\u{a759}', '\0', '\0']), + ('\u{a75a}', ['\u{a75b}', '\0', '\0']), ('\u{a75c}', ['\u{a75d}', '\0', '\0']), ('\u{a75e}', + ['\u{a75f}', '\0', '\0']), ('\u{a760}', ['\u{a761}', '\0', '\0']), ('\u{a762}', ['\u{a763}', + '\0', '\0']), ('\u{a764}', ['\u{a765}', '\0', '\0']), ('\u{a766}', ['\u{a767}', '\0', + '\0']), ('\u{a768}', ['\u{a769}', '\0', '\0']), ('\u{a76a}', ['\u{a76b}', '\0', '\0']), + ('\u{a76c}', ['\u{a76d}', '\0', '\0']), ('\u{a76e}', ['\u{a76f}', '\0', '\0']), ('\u{a779}', + ['\u{a77a}', '\0', '\0']), ('\u{a77b}', ['\u{a77c}', '\0', '\0']), ('\u{a77d}', ['\u{1d79}', + '\0', '\0']), ('\u{a77e}', ['\u{a77f}', '\0', '\0']), ('\u{a780}', ['\u{a781}', '\0', + '\0']), ('\u{a782}', ['\u{a783}', '\0', '\0']), ('\u{a784}', ['\u{a785}', '\0', '\0']), + ('\u{a786}', ['\u{a787}', '\0', '\0']), ('\u{a78b}', ['\u{a78c}', '\0', '\0']), ('\u{a78d}', + ['\u{265}', '\0', '\0']), ('\u{a790}', ['\u{a791}', '\0', '\0']), ('\u{a792}', ['\u{a793}', + '\0', '\0']), ('\u{a796}', ['\u{a797}', '\0', '\0']), ('\u{a798}', ['\u{a799}', '\0', + '\0']), ('\u{a79a}', ['\u{a79b}', '\0', '\0']), ('\u{a79c}', ['\u{a79d}', '\0', '\0']), + ('\u{a79e}', ['\u{a79f}', '\0', '\0']), ('\u{a7a0}', ['\u{a7a1}', '\0', '\0']), ('\u{a7a2}', + ['\u{a7a3}', '\0', '\0']), ('\u{a7a4}', ['\u{a7a5}', '\0', '\0']), ('\u{a7a6}', ['\u{a7a7}', + '\0', '\0']), ('\u{a7a8}', ['\u{a7a9}', '\0', '\0']), ('\u{a7aa}', ['\u{266}', '\0', '\0']), + ('\u{a7ab}', ['\u{25c}', '\0', '\0']), ('\u{a7ac}', ['\u{261}', '\0', '\0']), ('\u{a7ad}', + ['\u{26c}', '\0', '\0']), ('\u{a7ae}', ['\u{26a}', '\0', '\0']), ('\u{a7b0}', ['\u{29e}', + '\0', '\0']), ('\u{a7b1}', ['\u{287}', '\0', '\0']), ('\u{a7b2}', ['\u{29d}', '\0', '\0']), + ('\u{a7b3}', ['\u{ab53}', '\0', '\0']), ('\u{a7b4}', ['\u{a7b5}', '\0', '\0']), ('\u{a7b6}', + ['\u{a7b7}', '\0', '\0']), ('\u{a7b8}', ['\u{a7b9}', '\0', '\0']), ('\u{ff21}', ['\u{ff41}', + '\0', '\0']), ('\u{ff22}', ['\u{ff42}', '\0', '\0']), ('\u{ff23}', ['\u{ff43}', '\0', + '\0']), ('\u{ff24}', ['\u{ff44}', '\0', '\0']), ('\u{ff25}', ['\u{ff45}', '\0', '\0']), + ('\u{ff26}', ['\u{ff46}', '\0', '\0']), ('\u{ff27}', ['\u{ff47}', '\0', '\0']), ('\u{ff28}', + ['\u{ff48}', '\0', '\0']), ('\u{ff29}', ['\u{ff49}', '\0', '\0']), ('\u{ff2a}', ['\u{ff4a}', + '\0', '\0']), ('\u{ff2b}', ['\u{ff4b}', '\0', '\0']), ('\u{ff2c}', ['\u{ff4c}', '\0', + '\0']), ('\u{ff2d}', ['\u{ff4d}', '\0', '\0']), ('\u{ff2e}', ['\u{ff4e}', '\0', '\0']), + ('\u{ff2f}', ['\u{ff4f}', '\0', '\0']), ('\u{ff30}', ['\u{ff50}', '\0', '\0']), ('\u{ff31}', + ['\u{ff51}', '\0', '\0']), ('\u{ff32}', ['\u{ff52}', '\0', '\0']), ('\u{ff33}', ['\u{ff53}', + '\0', '\0']), ('\u{ff34}', ['\u{ff54}', '\0', '\0']), ('\u{ff35}', ['\u{ff55}', '\0', + '\0']), ('\u{ff36}', ['\u{ff56}', '\0', '\0']), ('\u{ff37}', ['\u{ff57}', '\0', '\0']), + ('\u{ff38}', ['\u{ff58}', '\0', '\0']), ('\u{ff39}', ['\u{ff59}', '\0', '\0']), ('\u{ff3a}', + ['\u{ff5a}', '\0', '\0']), ('\u{10400}', ['\u{10428}', '\0', '\0']), ('\u{10401}', + ['\u{10429}', '\0', '\0']), ('\u{10402}', ['\u{1042a}', '\0', '\0']), ('\u{10403}', + ['\u{1042b}', '\0', '\0']), ('\u{10404}', ['\u{1042c}', '\0', '\0']), ('\u{10405}', + ['\u{1042d}', '\0', '\0']), ('\u{10406}', ['\u{1042e}', '\0', '\0']), ('\u{10407}', + ['\u{1042f}', '\0', '\0']), ('\u{10408}', ['\u{10430}', '\0', '\0']), ('\u{10409}', + ['\u{10431}', '\0', '\0']), ('\u{1040a}', ['\u{10432}', '\0', '\0']), ('\u{1040b}', + ['\u{10433}', '\0', '\0']), ('\u{1040c}', ['\u{10434}', '\0', '\0']), ('\u{1040d}', + ['\u{10435}', '\0', '\0']), ('\u{1040e}', ['\u{10436}', '\0', '\0']), ('\u{1040f}', + ['\u{10437}', '\0', '\0']), ('\u{10410}', ['\u{10438}', '\0', '\0']), ('\u{10411}', + ['\u{10439}', '\0', '\0']), ('\u{10412}', ['\u{1043a}', '\0', '\0']), ('\u{10413}', + ['\u{1043b}', '\0', '\0']), ('\u{10414}', ['\u{1043c}', '\0', '\0']), ('\u{10415}', + ['\u{1043d}', '\0', '\0']), ('\u{10416}', ['\u{1043e}', '\0', '\0']), ('\u{10417}', + ['\u{1043f}', '\0', '\0']), ('\u{10418}', ['\u{10440}', '\0', '\0']), ('\u{10419}', + ['\u{10441}', '\0', '\0']), ('\u{1041a}', ['\u{10442}', '\0', '\0']), ('\u{1041b}', + ['\u{10443}', '\0', '\0']), ('\u{1041c}', ['\u{10444}', '\0', '\0']), ('\u{1041d}', + ['\u{10445}', '\0', '\0']), ('\u{1041e}', ['\u{10446}', '\0', '\0']), ('\u{1041f}', + ['\u{10447}', '\0', '\0']), ('\u{10420}', ['\u{10448}', '\0', '\0']), ('\u{10421}', + ['\u{10449}', '\0', '\0']), ('\u{10422}', ['\u{1044a}', '\0', '\0']), ('\u{10423}', + ['\u{1044b}', '\0', '\0']), ('\u{10424}', ['\u{1044c}', '\0', '\0']), ('\u{10425}', + ['\u{1044d}', '\0', '\0']), ('\u{10426}', ['\u{1044e}', '\0', '\0']), ('\u{10427}', + ['\u{1044f}', '\0', '\0']), ('\u{104b0}', ['\u{104d8}', '\0', '\0']), ('\u{104b1}', + ['\u{104d9}', '\0', '\0']), ('\u{104b2}', ['\u{104da}', '\0', '\0']), ('\u{104b3}', + ['\u{104db}', '\0', '\0']), ('\u{104b4}', ['\u{104dc}', '\0', '\0']), ('\u{104b5}', + ['\u{104dd}', '\0', '\0']), ('\u{104b6}', ['\u{104de}', '\0', '\0']), ('\u{104b7}', + ['\u{104df}', '\0', '\0']), ('\u{104b8}', ['\u{104e0}', '\0', '\0']), ('\u{104b9}', + ['\u{104e1}', '\0', '\0']), ('\u{104ba}', ['\u{104e2}', '\0', '\0']), ('\u{104bb}', + ['\u{104e3}', '\0', '\0']), ('\u{104bc}', ['\u{104e4}', '\0', '\0']), ('\u{104bd}', + ['\u{104e5}', '\0', '\0']), ('\u{104be}', ['\u{104e6}', '\0', '\0']), ('\u{104bf}', + ['\u{104e7}', '\0', '\0']), ('\u{104c0}', ['\u{104e8}', '\0', '\0']), ('\u{104c1}', + ['\u{104e9}', '\0', '\0']), ('\u{104c2}', ['\u{104ea}', '\0', '\0']), ('\u{104c3}', + ['\u{104eb}', '\0', '\0']), ('\u{104c4}', ['\u{104ec}', '\0', '\0']), ('\u{104c5}', + ['\u{104ed}', '\0', '\0']), ('\u{104c6}', ['\u{104ee}', '\0', '\0']), ('\u{104c7}', + ['\u{104ef}', '\0', '\0']), ('\u{104c8}', ['\u{104f0}', '\0', '\0']), ('\u{104c9}', + ['\u{104f1}', '\0', '\0']), ('\u{104ca}', ['\u{104f2}', '\0', '\0']), ('\u{104cb}', + ['\u{104f3}', '\0', '\0']), ('\u{104cc}', ['\u{104f4}', '\0', '\0']), ('\u{104cd}', + ['\u{104f5}', '\0', '\0']), ('\u{104ce}', ['\u{104f6}', '\0', '\0']), ('\u{104cf}', + ['\u{104f7}', '\0', '\0']), ('\u{104d0}', ['\u{104f8}', '\0', '\0']), ('\u{104d1}', + ['\u{104f9}', '\0', '\0']), ('\u{104d2}', ['\u{104fa}', '\0', '\0']), ('\u{104d3}', + ['\u{104fb}', '\0', '\0']), ('\u{10c80}', ['\u{10cc0}', '\0', '\0']), ('\u{10c81}', + ['\u{10cc1}', '\0', '\0']), ('\u{10c82}', ['\u{10cc2}', '\0', '\0']), ('\u{10c83}', + ['\u{10cc3}', '\0', '\0']), ('\u{10c84}', ['\u{10cc4}', '\0', '\0']), ('\u{10c85}', + ['\u{10cc5}', '\0', '\0']), ('\u{10c86}', ['\u{10cc6}', '\0', '\0']), ('\u{10c87}', + ['\u{10cc7}', '\0', '\0']), ('\u{10c88}', ['\u{10cc8}', '\0', '\0']), ('\u{10c89}', + ['\u{10cc9}', '\0', '\0']), ('\u{10c8a}', ['\u{10cca}', '\0', '\0']), ('\u{10c8b}', + ['\u{10ccb}', '\0', '\0']), ('\u{10c8c}', ['\u{10ccc}', '\0', '\0']), ('\u{10c8d}', + ['\u{10ccd}', '\0', '\0']), ('\u{10c8e}', ['\u{10cce}', '\0', '\0']), ('\u{10c8f}', + ['\u{10ccf}', '\0', '\0']), ('\u{10c90}', ['\u{10cd0}', '\0', '\0']), ('\u{10c91}', + ['\u{10cd1}', '\0', '\0']), ('\u{10c92}', ['\u{10cd2}', '\0', '\0']), ('\u{10c93}', + ['\u{10cd3}', '\0', '\0']), ('\u{10c94}', ['\u{10cd4}', '\0', '\0']), ('\u{10c95}', + ['\u{10cd5}', '\0', '\0']), ('\u{10c96}', ['\u{10cd6}', '\0', '\0']), ('\u{10c97}', + ['\u{10cd7}', '\0', '\0']), ('\u{10c98}', ['\u{10cd8}', '\0', '\0']), ('\u{10c99}', + ['\u{10cd9}', '\0', '\0']), ('\u{10c9a}', ['\u{10cda}', '\0', '\0']), ('\u{10c9b}', + ['\u{10cdb}', '\0', '\0']), ('\u{10c9c}', ['\u{10cdc}', '\0', '\0']), ('\u{10c9d}', + ['\u{10cdd}', '\0', '\0']), ('\u{10c9e}', ['\u{10cde}', '\0', '\0']), ('\u{10c9f}', + ['\u{10cdf}', '\0', '\0']), ('\u{10ca0}', ['\u{10ce0}', '\0', '\0']), ('\u{10ca1}', + ['\u{10ce1}', '\0', '\0']), ('\u{10ca2}', ['\u{10ce2}', '\0', '\0']), ('\u{10ca3}', + ['\u{10ce3}', '\0', '\0']), ('\u{10ca4}', ['\u{10ce4}', '\0', '\0']), ('\u{10ca5}', + ['\u{10ce5}', '\0', '\0']), ('\u{10ca6}', ['\u{10ce6}', '\0', '\0']), ('\u{10ca7}', + ['\u{10ce7}', '\0', '\0']), ('\u{10ca8}', ['\u{10ce8}', '\0', '\0']), ('\u{10ca9}', + ['\u{10ce9}', '\0', '\0']), ('\u{10caa}', ['\u{10cea}', '\0', '\0']), ('\u{10cab}', + ['\u{10ceb}', '\0', '\0']), ('\u{10cac}', ['\u{10cec}', '\0', '\0']), ('\u{10cad}', + ['\u{10ced}', '\0', '\0']), ('\u{10cae}', ['\u{10cee}', '\0', '\0']), ('\u{10caf}', + ['\u{10cef}', '\0', '\0']), ('\u{10cb0}', ['\u{10cf0}', '\0', '\0']), ('\u{10cb1}', + ['\u{10cf1}', '\0', '\0']), ('\u{10cb2}', ['\u{10cf2}', '\0', '\0']), ('\u{118a0}', + ['\u{118c0}', '\0', '\0']), ('\u{118a1}', ['\u{118c1}', '\0', '\0']), ('\u{118a2}', + ['\u{118c2}', '\0', '\0']), ('\u{118a3}', ['\u{118c3}', '\0', '\0']), ('\u{118a4}', + ['\u{118c4}', '\0', '\0']), ('\u{118a5}', ['\u{118c5}', '\0', '\0']), ('\u{118a6}', + ['\u{118c6}', '\0', '\0']), ('\u{118a7}', ['\u{118c7}', '\0', '\0']), ('\u{118a8}', + ['\u{118c8}', '\0', '\0']), ('\u{118a9}', ['\u{118c9}', '\0', '\0']), ('\u{118aa}', + ['\u{118ca}', '\0', '\0']), ('\u{118ab}', ['\u{118cb}', '\0', '\0']), ('\u{118ac}', + ['\u{118cc}', '\0', '\0']), ('\u{118ad}', ['\u{118cd}', '\0', '\0']), ('\u{118ae}', + ['\u{118ce}', '\0', '\0']), ('\u{118af}', ['\u{118cf}', '\0', '\0']), ('\u{118b0}', + ['\u{118d0}', '\0', '\0']), ('\u{118b1}', ['\u{118d1}', '\0', '\0']), ('\u{118b2}', + ['\u{118d2}', '\0', '\0']), ('\u{118b3}', ['\u{118d3}', '\0', '\0']), ('\u{118b4}', + ['\u{118d4}', '\0', '\0']), ('\u{118b5}', ['\u{118d5}', '\0', '\0']), ('\u{118b6}', + ['\u{118d6}', '\0', '\0']), ('\u{118b7}', ['\u{118d7}', '\0', '\0']), ('\u{118b8}', + ['\u{118d8}', '\0', '\0']), ('\u{118b9}', ['\u{118d9}', '\0', '\0']), ('\u{118ba}', + ['\u{118da}', '\0', '\0']), ('\u{118bb}', ['\u{118db}', '\0', '\0']), ('\u{118bc}', + ['\u{118dc}', '\0', '\0']), ('\u{118bd}', ['\u{118dd}', '\0', '\0']), ('\u{118be}', + ['\u{118de}', '\0', '\0']), ('\u{118bf}', ['\u{118df}', '\0', '\0']), ('\u{16e40}', + ['\u{16e60}', '\0', '\0']), ('\u{16e41}', ['\u{16e61}', '\0', '\0']), ('\u{16e42}', + ['\u{16e62}', '\0', '\0']), ('\u{16e43}', ['\u{16e63}', '\0', '\0']), ('\u{16e44}', + ['\u{16e64}', '\0', '\0']), ('\u{16e45}', ['\u{16e65}', '\0', '\0']), ('\u{16e46}', + ['\u{16e66}', '\0', '\0']), ('\u{16e47}', ['\u{16e67}', '\0', '\0']), ('\u{16e48}', + ['\u{16e68}', '\0', '\0']), ('\u{16e49}', ['\u{16e69}', '\0', '\0']), ('\u{16e4a}', + ['\u{16e6a}', '\0', '\0']), ('\u{16e4b}', ['\u{16e6b}', '\0', '\0']), ('\u{16e4c}', + ['\u{16e6c}', '\0', '\0']), ('\u{16e4d}', ['\u{16e6d}', '\0', '\0']), ('\u{16e4e}', + ['\u{16e6e}', '\0', '\0']), ('\u{16e4f}', ['\u{16e6f}', '\0', '\0']), ('\u{16e50}', + ['\u{16e70}', '\0', '\0']), ('\u{16e51}', ['\u{16e71}', '\0', '\0']), ('\u{16e52}', + ['\u{16e72}', '\0', '\0']), ('\u{16e53}', ['\u{16e73}', '\0', '\0']), ('\u{16e54}', + ['\u{16e74}', '\0', '\0']), ('\u{16e55}', ['\u{16e75}', '\0', '\0']), ('\u{16e56}', + ['\u{16e76}', '\0', '\0']), ('\u{16e57}', ['\u{16e77}', '\0', '\0']), ('\u{16e58}', + ['\u{16e78}', '\0', '\0']), ('\u{16e59}', ['\u{16e79}', '\0', '\0']), ('\u{16e5a}', + ['\u{16e7a}', '\0', '\0']), ('\u{16e5b}', ['\u{16e7b}', '\0', '\0']), ('\u{16e5c}', + ['\u{16e7c}', '\0', '\0']), ('\u{16e5d}', ['\u{16e7d}', '\0', '\0']), ('\u{16e5e}', + ['\u{16e7e}', '\0', '\0']), ('\u{16e5f}', ['\u{16e7f}', '\0', '\0']), ('\u{1e900}', + ['\u{1e922}', '\0', '\0']), ('\u{1e901}', ['\u{1e923}', '\0', '\0']), ('\u{1e902}', + ['\u{1e924}', '\0', '\0']), ('\u{1e903}', ['\u{1e925}', '\0', '\0']), ('\u{1e904}', + ['\u{1e926}', '\0', '\0']), ('\u{1e905}', ['\u{1e927}', '\0', '\0']), ('\u{1e906}', + ['\u{1e928}', '\0', '\0']), ('\u{1e907}', ['\u{1e929}', '\0', '\0']), ('\u{1e908}', + ['\u{1e92a}', '\0', '\0']), ('\u{1e909}', ['\u{1e92b}', '\0', '\0']), ('\u{1e90a}', + ['\u{1e92c}', '\0', '\0']), ('\u{1e90b}', ['\u{1e92d}', '\0', '\0']), ('\u{1e90c}', + ['\u{1e92e}', '\0', '\0']), ('\u{1e90d}', ['\u{1e92f}', '\0', '\0']), ('\u{1e90e}', + ['\u{1e930}', '\0', '\0']), ('\u{1e90f}', ['\u{1e931}', '\0', '\0']), ('\u{1e910}', + ['\u{1e932}', '\0', '\0']), ('\u{1e911}', ['\u{1e933}', '\0', '\0']), ('\u{1e912}', + ['\u{1e934}', '\0', '\0']), ('\u{1e913}', ['\u{1e935}', '\0', '\0']), ('\u{1e914}', + ['\u{1e936}', '\0', '\0']), ('\u{1e915}', ['\u{1e937}', '\0', '\0']), ('\u{1e916}', + ['\u{1e938}', '\0', '\0']), ('\u{1e917}', ['\u{1e939}', '\0', '\0']), ('\u{1e918}', + ['\u{1e93a}', '\0', '\0']), ('\u{1e919}', ['\u{1e93b}', '\0', '\0']), ('\u{1e91a}', + ['\u{1e93c}', '\0', '\0']), ('\u{1e91b}', ['\u{1e93d}', '\0', '\0']), ('\u{1e91c}', + ['\u{1e93e}', '\0', '\0']), ('\u{1e91d}', ['\u{1e93f}', '\0', '\0']), ('\u{1e91e}', + ['\u{1e940}', '\0', '\0']), ('\u{1e91f}', ['\u{1e941}', '\0', '\0']), ('\u{1e920}', + ['\u{1e942}', '\0', '\0']), ('\u{1e921}', ['\u{1e943}', '\0', '\0']) ]; const to_uppercase_table: &[(char, [char; 3])] = &[ @@ -2076,325 +2129,346 @@ pub mod conversions { ['\u{550}', '\0', '\0']), ('\u{581}', ['\u{551}', '\0', '\0']), ('\u{582}', ['\u{552}', '\0', '\0']), ('\u{583}', ['\u{553}', '\0', '\0']), ('\u{584}', ['\u{554}', '\0', '\0']), ('\u{585}', ['\u{555}', '\0', '\0']), ('\u{586}', ['\u{556}', '\0', '\0']), ('\u{587}', - ['\u{535}', '\u{552}', '\0']), ('\u{13f8}', ['\u{13f0}', '\0', '\0']), ('\u{13f9}', - ['\u{13f1}', '\0', '\0']), ('\u{13fa}', ['\u{13f2}', '\0', '\0']), ('\u{13fb}', ['\u{13f3}', - '\0', '\0']), ('\u{13fc}', ['\u{13f4}', '\0', '\0']), ('\u{13fd}', ['\u{13f5}', '\0', - '\0']), ('\u{1c80}', ['\u{412}', '\0', '\0']), ('\u{1c81}', ['\u{414}', '\0', '\0']), - ('\u{1c82}', ['\u{41e}', '\0', '\0']), ('\u{1c83}', ['\u{421}', '\0', '\0']), ('\u{1c84}', - ['\u{422}', '\0', '\0']), ('\u{1c85}', ['\u{422}', '\0', '\0']), ('\u{1c86}', ['\u{42a}', - '\0', '\0']), ('\u{1c87}', ['\u{462}', '\0', '\0']), ('\u{1c88}', ['\u{a64a}', '\0', '\0']), - ('\u{1d79}', ['\u{a77d}', '\0', '\0']), ('\u{1d7d}', ['\u{2c63}', '\0', '\0']), ('\u{1e01}', - ['\u{1e00}', '\0', '\0']), ('\u{1e03}', ['\u{1e02}', '\0', '\0']), ('\u{1e05}', ['\u{1e04}', - '\0', '\0']), ('\u{1e07}', ['\u{1e06}', '\0', '\0']), ('\u{1e09}', ['\u{1e08}', '\0', - '\0']), ('\u{1e0b}', ['\u{1e0a}', '\0', '\0']), ('\u{1e0d}', ['\u{1e0c}', '\0', '\0']), - ('\u{1e0f}', ['\u{1e0e}', '\0', '\0']), ('\u{1e11}', ['\u{1e10}', '\0', '\0']), ('\u{1e13}', - ['\u{1e12}', '\0', '\0']), ('\u{1e15}', ['\u{1e14}', '\0', '\0']), ('\u{1e17}', ['\u{1e16}', - '\0', '\0']), ('\u{1e19}', ['\u{1e18}', '\0', '\0']), ('\u{1e1b}', ['\u{1e1a}', '\0', - '\0']), ('\u{1e1d}', ['\u{1e1c}', '\0', '\0']), ('\u{1e1f}', ['\u{1e1e}', '\0', '\0']), - ('\u{1e21}', ['\u{1e20}', '\0', '\0']), ('\u{1e23}', ['\u{1e22}', '\0', '\0']), ('\u{1e25}', - ['\u{1e24}', '\0', '\0']), ('\u{1e27}', ['\u{1e26}', '\0', '\0']), ('\u{1e29}', ['\u{1e28}', - '\0', '\0']), ('\u{1e2b}', ['\u{1e2a}', '\0', '\0']), ('\u{1e2d}', ['\u{1e2c}', '\0', - '\0']), ('\u{1e2f}', ['\u{1e2e}', '\0', '\0']), ('\u{1e31}', ['\u{1e30}', '\0', '\0']), - ('\u{1e33}', ['\u{1e32}', '\0', '\0']), ('\u{1e35}', ['\u{1e34}', '\0', '\0']), ('\u{1e37}', - ['\u{1e36}', '\0', '\0']), ('\u{1e39}', ['\u{1e38}', '\0', '\0']), ('\u{1e3b}', ['\u{1e3a}', - '\0', '\0']), ('\u{1e3d}', ['\u{1e3c}', '\0', '\0']), ('\u{1e3f}', ['\u{1e3e}', '\0', - '\0']), ('\u{1e41}', ['\u{1e40}', '\0', '\0']), ('\u{1e43}', ['\u{1e42}', '\0', '\0']), - ('\u{1e45}', ['\u{1e44}', '\0', '\0']), ('\u{1e47}', ['\u{1e46}', '\0', '\0']), ('\u{1e49}', - ['\u{1e48}', '\0', '\0']), ('\u{1e4b}', ['\u{1e4a}', '\0', '\0']), ('\u{1e4d}', ['\u{1e4c}', - '\0', '\0']), ('\u{1e4f}', ['\u{1e4e}', '\0', '\0']), ('\u{1e51}', ['\u{1e50}', '\0', - '\0']), ('\u{1e53}', ['\u{1e52}', '\0', '\0']), ('\u{1e55}', ['\u{1e54}', '\0', '\0']), - ('\u{1e57}', ['\u{1e56}', '\0', '\0']), ('\u{1e59}', ['\u{1e58}', '\0', '\0']), ('\u{1e5b}', - ['\u{1e5a}', '\0', '\0']), ('\u{1e5d}', ['\u{1e5c}', '\0', '\0']), ('\u{1e5f}', ['\u{1e5e}', - '\0', '\0']), ('\u{1e61}', ['\u{1e60}', '\0', '\0']), ('\u{1e63}', ['\u{1e62}', '\0', - '\0']), ('\u{1e65}', ['\u{1e64}', '\0', '\0']), ('\u{1e67}', ['\u{1e66}', '\0', '\0']), - ('\u{1e69}', ['\u{1e68}', '\0', '\0']), ('\u{1e6b}', ['\u{1e6a}', '\0', '\0']), ('\u{1e6d}', - ['\u{1e6c}', '\0', '\0']), ('\u{1e6f}', ['\u{1e6e}', '\0', '\0']), ('\u{1e71}', ['\u{1e70}', - '\0', '\0']), ('\u{1e73}', ['\u{1e72}', '\0', '\0']), ('\u{1e75}', ['\u{1e74}', '\0', - '\0']), ('\u{1e77}', ['\u{1e76}', '\0', '\0']), ('\u{1e79}', ['\u{1e78}', '\0', '\0']), - ('\u{1e7b}', ['\u{1e7a}', '\0', '\0']), ('\u{1e7d}', ['\u{1e7c}', '\0', '\0']), ('\u{1e7f}', - ['\u{1e7e}', '\0', '\0']), ('\u{1e81}', ['\u{1e80}', '\0', '\0']), ('\u{1e83}', ['\u{1e82}', - '\0', '\0']), ('\u{1e85}', ['\u{1e84}', '\0', '\0']), ('\u{1e87}', ['\u{1e86}', '\0', - '\0']), ('\u{1e89}', ['\u{1e88}', '\0', '\0']), ('\u{1e8b}', ['\u{1e8a}', '\0', '\0']), - ('\u{1e8d}', ['\u{1e8c}', '\0', '\0']), ('\u{1e8f}', ['\u{1e8e}', '\0', '\0']), ('\u{1e91}', - ['\u{1e90}', '\0', '\0']), ('\u{1e93}', ['\u{1e92}', '\0', '\0']), ('\u{1e95}', ['\u{1e94}', - '\0', '\0']), ('\u{1e96}', ['\u{48}', '\u{331}', '\0']), ('\u{1e97}', ['\u{54}', '\u{308}', - '\0']), ('\u{1e98}', ['\u{57}', '\u{30a}', '\0']), ('\u{1e99}', ['\u{59}', '\u{30a}', - '\0']), ('\u{1e9a}', ['\u{41}', '\u{2be}', '\0']), ('\u{1e9b}', ['\u{1e60}', '\0', '\0']), - ('\u{1ea1}', ['\u{1ea0}', '\0', '\0']), ('\u{1ea3}', ['\u{1ea2}', '\0', '\0']), ('\u{1ea5}', - ['\u{1ea4}', '\0', '\0']), ('\u{1ea7}', ['\u{1ea6}', '\0', '\0']), ('\u{1ea9}', ['\u{1ea8}', - '\0', '\0']), ('\u{1eab}', ['\u{1eaa}', '\0', '\0']), ('\u{1ead}', ['\u{1eac}', '\0', - '\0']), ('\u{1eaf}', ['\u{1eae}', '\0', '\0']), ('\u{1eb1}', ['\u{1eb0}', '\0', '\0']), - ('\u{1eb3}', ['\u{1eb2}', '\0', '\0']), ('\u{1eb5}', ['\u{1eb4}', '\0', '\0']), ('\u{1eb7}', - ['\u{1eb6}', '\0', '\0']), ('\u{1eb9}', ['\u{1eb8}', '\0', '\0']), ('\u{1ebb}', ['\u{1eba}', - '\0', '\0']), ('\u{1ebd}', ['\u{1ebc}', '\0', '\0']), ('\u{1ebf}', ['\u{1ebe}', '\0', - '\0']), ('\u{1ec1}', ['\u{1ec0}', '\0', '\0']), ('\u{1ec3}', ['\u{1ec2}', '\0', '\0']), - ('\u{1ec5}', ['\u{1ec4}', '\0', '\0']), ('\u{1ec7}', ['\u{1ec6}', '\0', '\0']), ('\u{1ec9}', - ['\u{1ec8}', '\0', '\0']), ('\u{1ecb}', ['\u{1eca}', '\0', '\0']), ('\u{1ecd}', ['\u{1ecc}', - '\0', '\0']), ('\u{1ecf}', ['\u{1ece}', '\0', '\0']), ('\u{1ed1}', ['\u{1ed0}', '\0', - '\0']), ('\u{1ed3}', ['\u{1ed2}', '\0', '\0']), ('\u{1ed5}', ['\u{1ed4}', '\0', '\0']), - ('\u{1ed7}', ['\u{1ed6}', '\0', '\0']), ('\u{1ed9}', ['\u{1ed8}', '\0', '\0']), ('\u{1edb}', - ['\u{1eda}', '\0', '\0']), ('\u{1edd}', ['\u{1edc}', '\0', '\0']), ('\u{1edf}', ['\u{1ede}', - '\0', '\0']), ('\u{1ee1}', ['\u{1ee0}', '\0', '\0']), ('\u{1ee3}', ['\u{1ee2}', '\0', - '\0']), ('\u{1ee5}', ['\u{1ee4}', '\0', '\0']), ('\u{1ee7}', ['\u{1ee6}', '\0', '\0']), - ('\u{1ee9}', ['\u{1ee8}', '\0', '\0']), ('\u{1eeb}', ['\u{1eea}', '\0', '\0']), ('\u{1eed}', - ['\u{1eec}', '\0', '\0']), ('\u{1eef}', ['\u{1eee}', '\0', '\0']), ('\u{1ef1}', ['\u{1ef0}', - '\0', '\0']), ('\u{1ef3}', ['\u{1ef2}', '\0', '\0']), ('\u{1ef5}', ['\u{1ef4}', '\0', - '\0']), ('\u{1ef7}', ['\u{1ef6}', '\0', '\0']), ('\u{1ef9}', ['\u{1ef8}', '\0', '\0']), - ('\u{1efb}', ['\u{1efa}', '\0', '\0']), ('\u{1efd}', ['\u{1efc}', '\0', '\0']), ('\u{1eff}', - ['\u{1efe}', '\0', '\0']), ('\u{1f00}', ['\u{1f08}', '\0', '\0']), ('\u{1f01}', ['\u{1f09}', - '\0', '\0']), ('\u{1f02}', ['\u{1f0a}', '\0', '\0']), ('\u{1f03}', ['\u{1f0b}', '\0', - '\0']), ('\u{1f04}', ['\u{1f0c}', '\0', '\0']), ('\u{1f05}', ['\u{1f0d}', '\0', '\0']), - ('\u{1f06}', ['\u{1f0e}', '\0', '\0']), ('\u{1f07}', ['\u{1f0f}', '\0', '\0']), ('\u{1f10}', - ['\u{1f18}', '\0', '\0']), ('\u{1f11}', ['\u{1f19}', '\0', '\0']), ('\u{1f12}', ['\u{1f1a}', - '\0', '\0']), ('\u{1f13}', ['\u{1f1b}', '\0', '\0']), ('\u{1f14}', ['\u{1f1c}', '\0', - '\0']), ('\u{1f15}', ['\u{1f1d}', '\0', '\0']), ('\u{1f20}', ['\u{1f28}', '\0', '\0']), - ('\u{1f21}', ['\u{1f29}', '\0', '\0']), ('\u{1f22}', ['\u{1f2a}', '\0', '\0']), ('\u{1f23}', - ['\u{1f2b}', '\0', '\0']), ('\u{1f24}', ['\u{1f2c}', '\0', '\0']), ('\u{1f25}', ['\u{1f2d}', - '\0', '\0']), ('\u{1f26}', ['\u{1f2e}', '\0', '\0']), ('\u{1f27}', ['\u{1f2f}', '\0', - '\0']), ('\u{1f30}', ['\u{1f38}', '\0', '\0']), ('\u{1f31}', ['\u{1f39}', '\0', '\0']), - ('\u{1f32}', ['\u{1f3a}', '\0', '\0']), ('\u{1f33}', ['\u{1f3b}', '\0', '\0']), ('\u{1f34}', - ['\u{1f3c}', '\0', '\0']), ('\u{1f35}', ['\u{1f3d}', '\0', '\0']), ('\u{1f36}', ['\u{1f3e}', - '\0', '\0']), ('\u{1f37}', ['\u{1f3f}', '\0', '\0']), ('\u{1f40}', ['\u{1f48}', '\0', - '\0']), ('\u{1f41}', ['\u{1f49}', '\0', '\0']), ('\u{1f42}', ['\u{1f4a}', '\0', '\0']), - ('\u{1f43}', ['\u{1f4b}', '\0', '\0']), ('\u{1f44}', ['\u{1f4c}', '\0', '\0']), ('\u{1f45}', - ['\u{1f4d}', '\0', '\0']), ('\u{1f50}', ['\u{3a5}', '\u{313}', '\0']), ('\u{1f51}', - ['\u{1f59}', '\0', '\0']), ('\u{1f52}', ['\u{3a5}', '\u{313}', '\u{300}']), ('\u{1f53}', - ['\u{1f5b}', '\0', '\0']), ('\u{1f54}', ['\u{3a5}', '\u{313}', '\u{301}']), ('\u{1f55}', - ['\u{1f5d}', '\0', '\0']), ('\u{1f56}', ['\u{3a5}', '\u{313}', '\u{342}']), ('\u{1f57}', - ['\u{1f5f}', '\0', '\0']), ('\u{1f60}', ['\u{1f68}', '\0', '\0']), ('\u{1f61}', ['\u{1f69}', - '\0', '\0']), ('\u{1f62}', ['\u{1f6a}', '\0', '\0']), ('\u{1f63}', ['\u{1f6b}', '\0', - '\0']), ('\u{1f64}', ['\u{1f6c}', '\0', '\0']), ('\u{1f65}', ['\u{1f6d}', '\0', '\0']), - ('\u{1f66}', ['\u{1f6e}', '\0', '\0']), ('\u{1f67}', ['\u{1f6f}', '\0', '\0']), ('\u{1f70}', - ['\u{1fba}', '\0', '\0']), ('\u{1f71}', ['\u{1fbb}', '\0', '\0']), ('\u{1f72}', ['\u{1fc8}', - '\0', '\0']), ('\u{1f73}', ['\u{1fc9}', '\0', '\0']), ('\u{1f74}', ['\u{1fca}', '\0', - '\0']), ('\u{1f75}', ['\u{1fcb}', '\0', '\0']), ('\u{1f76}', ['\u{1fda}', '\0', '\0']), - ('\u{1f77}', ['\u{1fdb}', '\0', '\0']), ('\u{1f78}', ['\u{1ff8}', '\0', '\0']), ('\u{1f79}', - ['\u{1ff9}', '\0', '\0']), ('\u{1f7a}', ['\u{1fea}', '\0', '\0']), ('\u{1f7b}', ['\u{1feb}', - '\0', '\0']), ('\u{1f7c}', ['\u{1ffa}', '\0', '\0']), ('\u{1f7d}', ['\u{1ffb}', '\0', - '\0']), ('\u{1f80}', ['\u{1f08}', '\u{399}', '\0']), ('\u{1f81}', ['\u{1f09}', '\u{399}', - '\0']), ('\u{1f82}', ['\u{1f0a}', '\u{399}', '\0']), ('\u{1f83}', ['\u{1f0b}', '\u{399}', - '\0']), ('\u{1f84}', ['\u{1f0c}', '\u{399}', '\0']), ('\u{1f85}', ['\u{1f0d}', '\u{399}', - '\0']), ('\u{1f86}', ['\u{1f0e}', '\u{399}', '\0']), ('\u{1f87}', ['\u{1f0f}', '\u{399}', - '\0']), ('\u{1f88}', ['\u{1f08}', '\u{399}', '\0']), ('\u{1f89}', ['\u{1f09}', '\u{399}', - '\0']), ('\u{1f8a}', ['\u{1f0a}', '\u{399}', '\0']), ('\u{1f8b}', ['\u{1f0b}', '\u{399}', - '\0']), ('\u{1f8c}', ['\u{1f0c}', '\u{399}', '\0']), ('\u{1f8d}', ['\u{1f0d}', '\u{399}', - '\0']), ('\u{1f8e}', ['\u{1f0e}', '\u{399}', '\0']), ('\u{1f8f}', ['\u{1f0f}', '\u{399}', - '\0']), ('\u{1f90}', ['\u{1f28}', '\u{399}', '\0']), ('\u{1f91}', ['\u{1f29}', '\u{399}', - '\0']), ('\u{1f92}', ['\u{1f2a}', '\u{399}', '\0']), ('\u{1f93}', ['\u{1f2b}', '\u{399}', - '\0']), ('\u{1f94}', ['\u{1f2c}', '\u{399}', '\0']), ('\u{1f95}', ['\u{1f2d}', '\u{399}', - '\0']), ('\u{1f96}', ['\u{1f2e}', '\u{399}', '\0']), ('\u{1f97}', ['\u{1f2f}', '\u{399}', - '\0']), ('\u{1f98}', ['\u{1f28}', '\u{399}', '\0']), ('\u{1f99}', ['\u{1f29}', '\u{399}', - '\0']), ('\u{1f9a}', ['\u{1f2a}', '\u{399}', '\0']), ('\u{1f9b}', ['\u{1f2b}', '\u{399}', - '\0']), ('\u{1f9c}', ['\u{1f2c}', '\u{399}', '\0']), ('\u{1f9d}', ['\u{1f2d}', '\u{399}', - '\0']), ('\u{1f9e}', ['\u{1f2e}', '\u{399}', '\0']), ('\u{1f9f}', ['\u{1f2f}', '\u{399}', - '\0']), ('\u{1fa0}', ['\u{1f68}', '\u{399}', '\0']), ('\u{1fa1}', ['\u{1f69}', '\u{399}', - '\0']), ('\u{1fa2}', ['\u{1f6a}', '\u{399}', '\0']), ('\u{1fa3}', ['\u{1f6b}', '\u{399}', - '\0']), ('\u{1fa4}', ['\u{1f6c}', '\u{399}', '\0']), ('\u{1fa5}', ['\u{1f6d}', '\u{399}', - '\0']), ('\u{1fa6}', ['\u{1f6e}', '\u{399}', '\0']), ('\u{1fa7}', ['\u{1f6f}', '\u{399}', - '\0']), ('\u{1fa8}', ['\u{1f68}', '\u{399}', '\0']), ('\u{1fa9}', ['\u{1f69}', '\u{399}', - '\0']), ('\u{1faa}', ['\u{1f6a}', '\u{399}', '\0']), ('\u{1fab}', ['\u{1f6b}', '\u{399}', - '\0']), ('\u{1fac}', ['\u{1f6c}', '\u{399}', '\0']), ('\u{1fad}', ['\u{1f6d}', '\u{399}', - '\0']), ('\u{1fae}', ['\u{1f6e}', '\u{399}', '\0']), ('\u{1faf}', ['\u{1f6f}', '\u{399}', - '\0']), ('\u{1fb0}', ['\u{1fb8}', '\0', '\0']), ('\u{1fb1}', ['\u{1fb9}', '\0', '\0']), - ('\u{1fb2}', ['\u{1fba}', '\u{399}', '\0']), ('\u{1fb3}', ['\u{391}', '\u{399}', '\0']), - ('\u{1fb4}', ['\u{386}', '\u{399}', '\0']), ('\u{1fb6}', ['\u{391}', '\u{342}', '\0']), - ('\u{1fb7}', ['\u{391}', '\u{342}', '\u{399}']), ('\u{1fbc}', ['\u{391}', '\u{399}', '\0']), - ('\u{1fbe}', ['\u{399}', '\0', '\0']), ('\u{1fc2}', ['\u{1fca}', '\u{399}', '\0']), - ('\u{1fc3}', ['\u{397}', '\u{399}', '\0']), ('\u{1fc4}', ['\u{389}', '\u{399}', '\0']), - ('\u{1fc6}', ['\u{397}', '\u{342}', '\0']), ('\u{1fc7}', ['\u{397}', '\u{342}', '\u{399}']), - ('\u{1fcc}', ['\u{397}', '\u{399}', '\0']), ('\u{1fd0}', ['\u{1fd8}', '\0', '\0']), - ('\u{1fd1}', ['\u{1fd9}', '\0', '\0']), ('\u{1fd2}', ['\u{399}', '\u{308}', '\u{300}']), - ('\u{1fd3}', ['\u{399}', '\u{308}', '\u{301}']), ('\u{1fd6}', ['\u{399}', '\u{342}', '\0']), - ('\u{1fd7}', ['\u{399}', '\u{308}', '\u{342}']), ('\u{1fe0}', ['\u{1fe8}', '\0', '\0']), - ('\u{1fe1}', ['\u{1fe9}', '\0', '\0']), ('\u{1fe2}', ['\u{3a5}', '\u{308}', '\u{300}']), - ('\u{1fe3}', ['\u{3a5}', '\u{308}', '\u{301}']), ('\u{1fe4}', ['\u{3a1}', '\u{313}', '\0']), - ('\u{1fe5}', ['\u{1fec}', '\0', '\0']), ('\u{1fe6}', ['\u{3a5}', '\u{342}', '\0']), - ('\u{1fe7}', ['\u{3a5}', '\u{308}', '\u{342}']), ('\u{1ff2}', ['\u{1ffa}', '\u{399}', - '\0']), ('\u{1ff3}', ['\u{3a9}', '\u{399}', '\0']), ('\u{1ff4}', ['\u{38f}', '\u{399}', - '\0']), ('\u{1ff6}', ['\u{3a9}', '\u{342}', '\0']), ('\u{1ff7}', ['\u{3a9}', '\u{342}', - '\u{399}']), ('\u{1ffc}', ['\u{3a9}', '\u{399}', '\0']), ('\u{214e}', ['\u{2132}', '\0', - '\0']), ('\u{2170}', ['\u{2160}', '\0', '\0']), ('\u{2171}', ['\u{2161}', '\0', '\0']), - ('\u{2172}', ['\u{2162}', '\0', '\0']), ('\u{2173}', ['\u{2163}', '\0', '\0']), ('\u{2174}', - ['\u{2164}', '\0', '\0']), ('\u{2175}', ['\u{2165}', '\0', '\0']), ('\u{2176}', ['\u{2166}', - '\0', '\0']), ('\u{2177}', ['\u{2167}', '\0', '\0']), ('\u{2178}', ['\u{2168}', '\0', - '\0']), ('\u{2179}', ['\u{2169}', '\0', '\0']), ('\u{217a}', ['\u{216a}', '\0', '\0']), - ('\u{217b}', ['\u{216b}', '\0', '\0']), ('\u{217c}', ['\u{216c}', '\0', '\0']), ('\u{217d}', - ['\u{216d}', '\0', '\0']), ('\u{217e}', ['\u{216e}', '\0', '\0']), ('\u{217f}', ['\u{216f}', - '\0', '\0']), ('\u{2184}', ['\u{2183}', '\0', '\0']), ('\u{24d0}', ['\u{24b6}', '\0', - '\0']), ('\u{24d1}', ['\u{24b7}', '\0', '\0']), ('\u{24d2}', ['\u{24b8}', '\0', '\0']), - ('\u{24d3}', ['\u{24b9}', '\0', '\0']), ('\u{24d4}', ['\u{24ba}', '\0', '\0']), ('\u{24d5}', - ['\u{24bb}', '\0', '\0']), ('\u{24d6}', ['\u{24bc}', '\0', '\0']), ('\u{24d7}', ['\u{24bd}', - '\0', '\0']), ('\u{24d8}', ['\u{24be}', '\0', '\0']), ('\u{24d9}', ['\u{24bf}', '\0', - '\0']), ('\u{24da}', ['\u{24c0}', '\0', '\0']), ('\u{24db}', ['\u{24c1}', '\0', '\0']), - ('\u{24dc}', ['\u{24c2}', '\0', '\0']), ('\u{24dd}', ['\u{24c3}', '\0', '\0']), ('\u{24de}', - ['\u{24c4}', '\0', '\0']), ('\u{24df}', ['\u{24c5}', '\0', '\0']), ('\u{24e0}', ['\u{24c6}', - '\0', '\0']), ('\u{24e1}', ['\u{24c7}', '\0', '\0']), ('\u{24e2}', ['\u{24c8}', '\0', - '\0']), ('\u{24e3}', ['\u{24c9}', '\0', '\0']), ('\u{24e4}', ['\u{24ca}', '\0', '\0']), - ('\u{24e5}', ['\u{24cb}', '\0', '\0']), ('\u{24e6}', ['\u{24cc}', '\0', '\0']), ('\u{24e7}', - ['\u{24cd}', '\0', '\0']), ('\u{24e8}', ['\u{24ce}', '\0', '\0']), ('\u{24e9}', ['\u{24cf}', - '\0', '\0']), ('\u{2c30}', ['\u{2c00}', '\0', '\0']), ('\u{2c31}', ['\u{2c01}', '\0', - '\0']), ('\u{2c32}', ['\u{2c02}', '\0', '\0']), ('\u{2c33}', ['\u{2c03}', '\0', '\0']), - ('\u{2c34}', ['\u{2c04}', '\0', '\0']), ('\u{2c35}', ['\u{2c05}', '\0', '\0']), ('\u{2c36}', - ['\u{2c06}', '\0', '\0']), ('\u{2c37}', ['\u{2c07}', '\0', '\0']), ('\u{2c38}', ['\u{2c08}', - '\0', '\0']), ('\u{2c39}', ['\u{2c09}', '\0', '\0']), ('\u{2c3a}', ['\u{2c0a}', '\0', - '\0']), ('\u{2c3b}', ['\u{2c0b}', '\0', '\0']), ('\u{2c3c}', ['\u{2c0c}', '\0', '\0']), - ('\u{2c3d}', ['\u{2c0d}', '\0', '\0']), ('\u{2c3e}', ['\u{2c0e}', '\0', '\0']), ('\u{2c3f}', - ['\u{2c0f}', '\0', '\0']), ('\u{2c40}', ['\u{2c10}', '\0', '\0']), ('\u{2c41}', ['\u{2c11}', - '\0', '\0']), ('\u{2c42}', ['\u{2c12}', '\0', '\0']), ('\u{2c43}', ['\u{2c13}', '\0', - '\0']), ('\u{2c44}', ['\u{2c14}', '\0', '\0']), ('\u{2c45}', ['\u{2c15}', '\0', '\0']), - ('\u{2c46}', ['\u{2c16}', '\0', '\0']), ('\u{2c47}', ['\u{2c17}', '\0', '\0']), ('\u{2c48}', - ['\u{2c18}', '\0', '\0']), ('\u{2c49}', ['\u{2c19}', '\0', '\0']), ('\u{2c4a}', ['\u{2c1a}', - '\0', '\0']), ('\u{2c4b}', ['\u{2c1b}', '\0', '\0']), ('\u{2c4c}', ['\u{2c1c}', '\0', - '\0']), ('\u{2c4d}', ['\u{2c1d}', '\0', '\0']), ('\u{2c4e}', ['\u{2c1e}', '\0', '\0']), - ('\u{2c4f}', ['\u{2c1f}', '\0', '\0']), ('\u{2c50}', ['\u{2c20}', '\0', '\0']), ('\u{2c51}', - ['\u{2c21}', '\0', '\0']), ('\u{2c52}', ['\u{2c22}', '\0', '\0']), ('\u{2c53}', ['\u{2c23}', - '\0', '\0']), ('\u{2c54}', ['\u{2c24}', '\0', '\0']), ('\u{2c55}', ['\u{2c25}', '\0', - '\0']), ('\u{2c56}', ['\u{2c26}', '\0', '\0']), ('\u{2c57}', ['\u{2c27}', '\0', '\0']), - ('\u{2c58}', ['\u{2c28}', '\0', '\0']), ('\u{2c59}', ['\u{2c29}', '\0', '\0']), ('\u{2c5a}', - ['\u{2c2a}', '\0', '\0']), ('\u{2c5b}', ['\u{2c2b}', '\0', '\0']), ('\u{2c5c}', ['\u{2c2c}', - '\0', '\0']), ('\u{2c5d}', ['\u{2c2d}', '\0', '\0']), ('\u{2c5e}', ['\u{2c2e}', '\0', - '\0']), ('\u{2c61}', ['\u{2c60}', '\0', '\0']), ('\u{2c65}', ['\u{23a}', '\0', '\0']), - ('\u{2c66}', ['\u{23e}', '\0', '\0']), ('\u{2c68}', ['\u{2c67}', '\0', '\0']), ('\u{2c6a}', - ['\u{2c69}', '\0', '\0']), ('\u{2c6c}', ['\u{2c6b}', '\0', '\0']), ('\u{2c73}', ['\u{2c72}', - '\0', '\0']), ('\u{2c76}', ['\u{2c75}', '\0', '\0']), ('\u{2c81}', ['\u{2c80}', '\0', - '\0']), ('\u{2c83}', ['\u{2c82}', '\0', '\0']), ('\u{2c85}', ['\u{2c84}', '\0', '\0']), - ('\u{2c87}', ['\u{2c86}', '\0', '\0']), ('\u{2c89}', ['\u{2c88}', '\0', '\0']), ('\u{2c8b}', - ['\u{2c8a}', '\0', '\0']), ('\u{2c8d}', ['\u{2c8c}', '\0', '\0']), ('\u{2c8f}', ['\u{2c8e}', - '\0', '\0']), ('\u{2c91}', ['\u{2c90}', '\0', '\0']), ('\u{2c93}', ['\u{2c92}', '\0', - '\0']), ('\u{2c95}', ['\u{2c94}', '\0', '\0']), ('\u{2c97}', ['\u{2c96}', '\0', '\0']), - ('\u{2c99}', ['\u{2c98}', '\0', '\0']), ('\u{2c9b}', ['\u{2c9a}', '\0', '\0']), ('\u{2c9d}', - ['\u{2c9c}', '\0', '\0']), ('\u{2c9f}', ['\u{2c9e}', '\0', '\0']), ('\u{2ca1}', ['\u{2ca0}', - '\0', '\0']), ('\u{2ca3}', ['\u{2ca2}', '\0', '\0']), ('\u{2ca5}', ['\u{2ca4}', '\0', - '\0']), ('\u{2ca7}', ['\u{2ca6}', '\0', '\0']), ('\u{2ca9}', ['\u{2ca8}', '\0', '\0']), - ('\u{2cab}', ['\u{2caa}', '\0', '\0']), ('\u{2cad}', ['\u{2cac}', '\0', '\0']), ('\u{2caf}', - ['\u{2cae}', '\0', '\0']), ('\u{2cb1}', ['\u{2cb0}', '\0', '\0']), ('\u{2cb3}', ['\u{2cb2}', - '\0', '\0']), ('\u{2cb5}', ['\u{2cb4}', '\0', '\0']), ('\u{2cb7}', ['\u{2cb6}', '\0', - '\0']), ('\u{2cb9}', ['\u{2cb8}', '\0', '\0']), ('\u{2cbb}', ['\u{2cba}', '\0', '\0']), - ('\u{2cbd}', ['\u{2cbc}', '\0', '\0']), ('\u{2cbf}', ['\u{2cbe}', '\0', '\0']), ('\u{2cc1}', - ['\u{2cc0}', '\0', '\0']), ('\u{2cc3}', ['\u{2cc2}', '\0', '\0']), ('\u{2cc5}', ['\u{2cc4}', - '\0', '\0']), ('\u{2cc7}', ['\u{2cc6}', '\0', '\0']), ('\u{2cc9}', ['\u{2cc8}', '\0', - '\0']), ('\u{2ccb}', ['\u{2cca}', '\0', '\0']), ('\u{2ccd}', ['\u{2ccc}', '\0', '\0']), - ('\u{2ccf}', ['\u{2cce}', '\0', '\0']), ('\u{2cd1}', ['\u{2cd0}', '\0', '\0']), ('\u{2cd3}', - ['\u{2cd2}', '\0', '\0']), ('\u{2cd5}', ['\u{2cd4}', '\0', '\0']), ('\u{2cd7}', ['\u{2cd6}', - '\0', '\0']), ('\u{2cd9}', ['\u{2cd8}', '\0', '\0']), ('\u{2cdb}', ['\u{2cda}', '\0', - '\0']), ('\u{2cdd}', ['\u{2cdc}', '\0', '\0']), ('\u{2cdf}', ['\u{2cde}', '\0', '\0']), - ('\u{2ce1}', ['\u{2ce0}', '\0', '\0']), ('\u{2ce3}', ['\u{2ce2}', '\0', '\0']), ('\u{2cec}', - ['\u{2ceb}', '\0', '\0']), ('\u{2cee}', ['\u{2ced}', '\0', '\0']), ('\u{2cf3}', ['\u{2cf2}', - '\0', '\0']), ('\u{2d00}', ['\u{10a0}', '\0', '\0']), ('\u{2d01}', ['\u{10a1}', '\0', - '\0']), ('\u{2d02}', ['\u{10a2}', '\0', '\0']), ('\u{2d03}', ['\u{10a3}', '\0', '\0']), - ('\u{2d04}', ['\u{10a4}', '\0', '\0']), ('\u{2d05}', ['\u{10a5}', '\0', '\0']), ('\u{2d06}', - ['\u{10a6}', '\0', '\0']), ('\u{2d07}', ['\u{10a7}', '\0', '\0']), ('\u{2d08}', ['\u{10a8}', - '\0', '\0']), ('\u{2d09}', ['\u{10a9}', '\0', '\0']), ('\u{2d0a}', ['\u{10aa}', '\0', - '\0']), ('\u{2d0b}', ['\u{10ab}', '\0', '\0']), ('\u{2d0c}', ['\u{10ac}', '\0', '\0']), - ('\u{2d0d}', ['\u{10ad}', '\0', '\0']), ('\u{2d0e}', ['\u{10ae}', '\0', '\0']), ('\u{2d0f}', - ['\u{10af}', '\0', '\0']), ('\u{2d10}', ['\u{10b0}', '\0', '\0']), ('\u{2d11}', ['\u{10b1}', - '\0', '\0']), ('\u{2d12}', ['\u{10b2}', '\0', '\0']), ('\u{2d13}', ['\u{10b3}', '\0', - '\0']), ('\u{2d14}', ['\u{10b4}', '\0', '\0']), ('\u{2d15}', ['\u{10b5}', '\0', '\0']), - ('\u{2d16}', ['\u{10b6}', '\0', '\0']), ('\u{2d17}', ['\u{10b7}', '\0', '\0']), ('\u{2d18}', - ['\u{10b8}', '\0', '\0']), ('\u{2d19}', ['\u{10b9}', '\0', '\0']), ('\u{2d1a}', ['\u{10ba}', - '\0', '\0']), ('\u{2d1b}', ['\u{10bb}', '\0', '\0']), ('\u{2d1c}', ['\u{10bc}', '\0', - '\0']), ('\u{2d1d}', ['\u{10bd}', '\0', '\0']), ('\u{2d1e}', ['\u{10be}', '\0', '\0']), - ('\u{2d1f}', ['\u{10bf}', '\0', '\0']), ('\u{2d20}', ['\u{10c0}', '\0', '\0']), ('\u{2d21}', - ['\u{10c1}', '\0', '\0']), ('\u{2d22}', ['\u{10c2}', '\0', '\0']), ('\u{2d23}', ['\u{10c3}', - '\0', '\0']), ('\u{2d24}', ['\u{10c4}', '\0', '\0']), ('\u{2d25}', ['\u{10c5}', '\0', - '\0']), ('\u{2d27}', ['\u{10c7}', '\0', '\0']), ('\u{2d2d}', ['\u{10cd}', '\0', '\0']), - ('\u{a641}', ['\u{a640}', '\0', '\0']), ('\u{a643}', ['\u{a642}', '\0', '\0']), ('\u{a645}', - ['\u{a644}', '\0', '\0']), ('\u{a647}', ['\u{a646}', '\0', '\0']), ('\u{a649}', ['\u{a648}', - '\0', '\0']), ('\u{a64b}', ['\u{a64a}', '\0', '\0']), ('\u{a64d}', ['\u{a64c}', '\0', - '\0']), ('\u{a64f}', ['\u{a64e}', '\0', '\0']), ('\u{a651}', ['\u{a650}', '\0', '\0']), - ('\u{a653}', ['\u{a652}', '\0', '\0']), ('\u{a655}', ['\u{a654}', '\0', '\0']), ('\u{a657}', - ['\u{a656}', '\0', '\0']), ('\u{a659}', ['\u{a658}', '\0', '\0']), ('\u{a65b}', ['\u{a65a}', - '\0', '\0']), ('\u{a65d}', ['\u{a65c}', '\0', '\0']), ('\u{a65f}', ['\u{a65e}', '\0', - '\0']), ('\u{a661}', ['\u{a660}', '\0', '\0']), ('\u{a663}', ['\u{a662}', '\0', '\0']), - ('\u{a665}', ['\u{a664}', '\0', '\0']), ('\u{a667}', ['\u{a666}', '\0', '\0']), ('\u{a669}', - ['\u{a668}', '\0', '\0']), ('\u{a66b}', ['\u{a66a}', '\0', '\0']), ('\u{a66d}', ['\u{a66c}', - '\0', '\0']), ('\u{a681}', ['\u{a680}', '\0', '\0']), ('\u{a683}', ['\u{a682}', '\0', - '\0']), ('\u{a685}', ['\u{a684}', '\0', '\0']), ('\u{a687}', ['\u{a686}', '\0', '\0']), - ('\u{a689}', ['\u{a688}', '\0', '\0']), ('\u{a68b}', ['\u{a68a}', '\0', '\0']), ('\u{a68d}', - ['\u{a68c}', '\0', '\0']), ('\u{a68f}', ['\u{a68e}', '\0', '\0']), ('\u{a691}', ['\u{a690}', - '\0', '\0']), ('\u{a693}', ['\u{a692}', '\0', '\0']), ('\u{a695}', ['\u{a694}', '\0', - '\0']), ('\u{a697}', ['\u{a696}', '\0', '\0']), ('\u{a699}', ['\u{a698}', '\0', '\0']), - ('\u{a69b}', ['\u{a69a}', '\0', '\0']), ('\u{a723}', ['\u{a722}', '\0', '\0']), ('\u{a725}', - ['\u{a724}', '\0', '\0']), ('\u{a727}', ['\u{a726}', '\0', '\0']), ('\u{a729}', ['\u{a728}', - '\0', '\0']), ('\u{a72b}', ['\u{a72a}', '\0', '\0']), ('\u{a72d}', ['\u{a72c}', '\0', - '\0']), ('\u{a72f}', ['\u{a72e}', '\0', '\0']), ('\u{a733}', ['\u{a732}', '\0', '\0']), - ('\u{a735}', ['\u{a734}', '\0', '\0']), ('\u{a737}', ['\u{a736}', '\0', '\0']), ('\u{a739}', - ['\u{a738}', '\0', '\0']), ('\u{a73b}', ['\u{a73a}', '\0', '\0']), ('\u{a73d}', ['\u{a73c}', - '\0', '\0']), ('\u{a73f}', ['\u{a73e}', '\0', '\0']), ('\u{a741}', ['\u{a740}', '\0', - '\0']), ('\u{a743}', ['\u{a742}', '\0', '\0']), ('\u{a745}', ['\u{a744}', '\0', '\0']), - ('\u{a747}', ['\u{a746}', '\0', '\0']), ('\u{a749}', ['\u{a748}', '\0', '\0']), ('\u{a74b}', - ['\u{a74a}', '\0', '\0']), ('\u{a74d}', ['\u{a74c}', '\0', '\0']), ('\u{a74f}', ['\u{a74e}', - '\0', '\0']), ('\u{a751}', ['\u{a750}', '\0', '\0']), ('\u{a753}', ['\u{a752}', '\0', - '\0']), ('\u{a755}', ['\u{a754}', '\0', '\0']), ('\u{a757}', ['\u{a756}', '\0', '\0']), - ('\u{a759}', ['\u{a758}', '\0', '\0']), ('\u{a75b}', ['\u{a75a}', '\0', '\0']), ('\u{a75d}', - ['\u{a75c}', '\0', '\0']), ('\u{a75f}', ['\u{a75e}', '\0', '\0']), ('\u{a761}', ['\u{a760}', - '\0', '\0']), ('\u{a763}', ['\u{a762}', '\0', '\0']), ('\u{a765}', ['\u{a764}', '\0', - '\0']), ('\u{a767}', ['\u{a766}', '\0', '\0']), ('\u{a769}', ['\u{a768}', '\0', '\0']), - ('\u{a76b}', ['\u{a76a}', '\0', '\0']), ('\u{a76d}', ['\u{a76c}', '\0', '\0']), ('\u{a76f}', - ['\u{a76e}', '\0', '\0']), ('\u{a77a}', ['\u{a779}', '\0', '\0']), ('\u{a77c}', ['\u{a77b}', - '\0', '\0']), ('\u{a77f}', ['\u{a77e}', '\0', '\0']), ('\u{a781}', ['\u{a780}', '\0', - '\0']), ('\u{a783}', ['\u{a782}', '\0', '\0']), ('\u{a785}', ['\u{a784}', '\0', '\0']), - ('\u{a787}', ['\u{a786}', '\0', '\0']), ('\u{a78c}', ['\u{a78b}', '\0', '\0']), ('\u{a791}', - ['\u{a790}', '\0', '\0']), ('\u{a793}', ['\u{a792}', '\0', '\0']), ('\u{a797}', ['\u{a796}', - '\0', '\0']), ('\u{a799}', ['\u{a798}', '\0', '\0']), ('\u{a79b}', ['\u{a79a}', '\0', - '\0']), ('\u{a79d}', ['\u{a79c}', '\0', '\0']), ('\u{a79f}', ['\u{a79e}', '\0', '\0']), - ('\u{a7a1}', ['\u{a7a0}', '\0', '\0']), ('\u{a7a3}', ['\u{a7a2}', '\0', '\0']), ('\u{a7a5}', - ['\u{a7a4}', '\0', '\0']), ('\u{a7a7}', ['\u{a7a6}', '\0', '\0']), ('\u{a7a9}', ['\u{a7a8}', - '\0', '\0']), ('\u{a7b5}', ['\u{a7b4}', '\0', '\0']), ('\u{a7b7}', ['\u{a7b6}', '\0', - '\0']), ('\u{ab53}', ['\u{a7b3}', '\0', '\0']), ('\u{ab70}', ['\u{13a0}', '\0', '\0']), - ('\u{ab71}', ['\u{13a1}', '\0', '\0']), ('\u{ab72}', ['\u{13a2}', '\0', '\0']), ('\u{ab73}', - ['\u{13a3}', '\0', '\0']), ('\u{ab74}', ['\u{13a4}', '\0', '\0']), ('\u{ab75}', ['\u{13a5}', - '\0', '\0']), ('\u{ab76}', ['\u{13a6}', '\0', '\0']), ('\u{ab77}', ['\u{13a7}', '\0', - '\0']), ('\u{ab78}', ['\u{13a8}', '\0', '\0']), ('\u{ab79}', ['\u{13a9}', '\0', '\0']), - ('\u{ab7a}', ['\u{13aa}', '\0', '\0']), ('\u{ab7b}', ['\u{13ab}', '\0', '\0']), ('\u{ab7c}', - ['\u{13ac}', '\0', '\0']), ('\u{ab7d}', ['\u{13ad}', '\0', '\0']), ('\u{ab7e}', ['\u{13ae}', - '\0', '\0']), ('\u{ab7f}', ['\u{13af}', '\0', '\0']), ('\u{ab80}', ['\u{13b0}', '\0', - '\0']), ('\u{ab81}', ['\u{13b1}', '\0', '\0']), ('\u{ab82}', ['\u{13b2}', '\0', '\0']), - ('\u{ab83}', ['\u{13b3}', '\0', '\0']), ('\u{ab84}', ['\u{13b4}', '\0', '\0']), ('\u{ab85}', - ['\u{13b5}', '\0', '\0']), ('\u{ab86}', ['\u{13b6}', '\0', '\0']), ('\u{ab87}', ['\u{13b7}', - '\0', '\0']), ('\u{ab88}', ['\u{13b8}', '\0', '\0']), ('\u{ab89}', ['\u{13b9}', '\0', - '\0']), ('\u{ab8a}', ['\u{13ba}', '\0', '\0']), ('\u{ab8b}', ['\u{13bb}', '\0', '\0']), - ('\u{ab8c}', ['\u{13bc}', '\0', '\0']), ('\u{ab8d}', ['\u{13bd}', '\0', '\0']), ('\u{ab8e}', - ['\u{13be}', '\0', '\0']), ('\u{ab8f}', ['\u{13bf}', '\0', '\0']), ('\u{ab90}', ['\u{13c0}', - '\0', '\0']), ('\u{ab91}', ['\u{13c1}', '\0', '\0']), ('\u{ab92}', ['\u{13c2}', '\0', - '\0']), ('\u{ab93}', ['\u{13c3}', '\0', '\0']), ('\u{ab94}', ['\u{13c4}', '\0', '\0']), - ('\u{ab95}', ['\u{13c5}', '\0', '\0']), ('\u{ab96}', ['\u{13c6}', '\0', '\0']), ('\u{ab97}', - ['\u{13c7}', '\0', '\0']), ('\u{ab98}', ['\u{13c8}', '\0', '\0']), ('\u{ab99}', ['\u{13c9}', - '\0', '\0']), ('\u{ab9a}', ['\u{13ca}', '\0', '\0']), ('\u{ab9b}', ['\u{13cb}', '\0', - '\0']), ('\u{ab9c}', ['\u{13cc}', '\0', '\0']), ('\u{ab9d}', ['\u{13cd}', '\0', '\0']), - ('\u{ab9e}', ['\u{13ce}', '\0', '\0']), ('\u{ab9f}', ['\u{13cf}', '\0', '\0']), ('\u{aba0}', - ['\u{13d0}', '\0', '\0']), ('\u{aba1}', ['\u{13d1}', '\0', '\0']), ('\u{aba2}', ['\u{13d2}', - '\0', '\0']), ('\u{aba3}', ['\u{13d3}', '\0', '\0']), ('\u{aba4}', ['\u{13d4}', '\0', - '\0']), ('\u{aba5}', ['\u{13d5}', '\0', '\0']), ('\u{aba6}', ['\u{13d6}', '\0', '\0']), - ('\u{aba7}', ['\u{13d7}', '\0', '\0']), ('\u{aba8}', ['\u{13d8}', '\0', '\0']), ('\u{aba9}', - ['\u{13d9}', '\0', '\0']), ('\u{abaa}', ['\u{13da}', '\0', '\0']), ('\u{abab}', ['\u{13db}', - '\0', '\0']), ('\u{abac}', ['\u{13dc}', '\0', '\0']), ('\u{abad}', ['\u{13dd}', '\0', - '\0']), ('\u{abae}', ['\u{13de}', '\0', '\0']), ('\u{abaf}', ['\u{13df}', '\0', '\0']), - ('\u{abb0}', ['\u{13e0}', '\0', '\0']), ('\u{abb1}', ['\u{13e1}', '\0', '\0']), ('\u{abb2}', - ['\u{13e2}', '\0', '\0']), ('\u{abb3}', ['\u{13e3}', '\0', '\0']), ('\u{abb4}', ['\u{13e4}', - '\0', '\0']), ('\u{abb5}', ['\u{13e5}', '\0', '\0']), ('\u{abb6}', ['\u{13e6}', '\0', - '\0']), ('\u{abb7}', ['\u{13e7}', '\0', '\0']), ('\u{abb8}', ['\u{13e8}', '\0', '\0']), - ('\u{abb9}', ['\u{13e9}', '\0', '\0']), ('\u{abba}', ['\u{13ea}', '\0', '\0']), ('\u{abbb}', - ['\u{13eb}', '\0', '\0']), ('\u{abbc}', ['\u{13ec}', '\0', '\0']), ('\u{abbd}', ['\u{13ed}', - '\0', '\0']), ('\u{abbe}', ['\u{13ee}', '\0', '\0']), ('\u{abbf}', ['\u{13ef}', '\0', - '\0']), ('\u{fb00}', ['\u{46}', '\u{46}', '\0']), ('\u{fb01}', ['\u{46}', '\u{49}', '\0']), - ('\u{fb02}', ['\u{46}', '\u{4c}', '\0']), ('\u{fb03}', ['\u{46}', '\u{46}', '\u{49}']), - ('\u{fb04}', ['\u{46}', '\u{46}', '\u{4c}']), ('\u{fb05}', ['\u{53}', '\u{54}', '\0']), - ('\u{fb06}', ['\u{53}', '\u{54}', '\0']), ('\u{fb13}', ['\u{544}', '\u{546}', '\0']), - ('\u{fb14}', ['\u{544}', '\u{535}', '\0']), ('\u{fb15}', ['\u{544}', '\u{53b}', '\0']), - ('\u{fb16}', ['\u{54e}', '\u{546}', '\0']), ('\u{fb17}', ['\u{544}', '\u{53d}', '\0']), - ('\u{ff41}', ['\u{ff21}', '\0', '\0']), ('\u{ff42}', ['\u{ff22}', '\0', '\0']), ('\u{ff43}', - ['\u{ff23}', '\0', '\0']), ('\u{ff44}', ['\u{ff24}', '\0', '\0']), ('\u{ff45}', ['\u{ff25}', - '\0', '\0']), ('\u{ff46}', ['\u{ff26}', '\0', '\0']), ('\u{ff47}', ['\u{ff27}', '\0', - '\0']), ('\u{ff48}', ['\u{ff28}', '\0', '\0']), ('\u{ff49}', ['\u{ff29}', '\0', '\0']), - ('\u{ff4a}', ['\u{ff2a}', '\0', '\0']), ('\u{ff4b}', ['\u{ff2b}', '\0', '\0']), ('\u{ff4c}', - ['\u{ff2c}', '\0', '\0']), ('\u{ff4d}', ['\u{ff2d}', '\0', '\0']), ('\u{ff4e}', ['\u{ff2e}', - '\0', '\0']), ('\u{ff4f}', ['\u{ff2f}', '\0', '\0']), ('\u{ff50}', ['\u{ff30}', '\0', - '\0']), ('\u{ff51}', ['\u{ff31}', '\0', '\0']), ('\u{ff52}', ['\u{ff32}', '\0', '\0']), - ('\u{ff53}', ['\u{ff33}', '\0', '\0']), ('\u{ff54}', ['\u{ff34}', '\0', '\0']), ('\u{ff55}', - ['\u{ff35}', '\0', '\0']), ('\u{ff56}', ['\u{ff36}', '\0', '\0']), ('\u{ff57}', ['\u{ff37}', - '\0', '\0']), ('\u{ff58}', ['\u{ff38}', '\0', '\0']), ('\u{ff59}', ['\u{ff39}', '\0', - '\0']), ('\u{ff5a}', ['\u{ff3a}', '\0', '\0']), ('\u{10428}', ['\u{10400}', '\0', '\0']), + ['\u{535}', '\u{552}', '\0']), ('\u{10d0}', ['\u{1c90}', '\0', '\0']), ('\u{10d1}', + ['\u{1c91}', '\0', '\0']), ('\u{10d2}', ['\u{1c92}', '\0', '\0']), ('\u{10d3}', ['\u{1c93}', + '\0', '\0']), ('\u{10d4}', ['\u{1c94}', '\0', '\0']), ('\u{10d5}', ['\u{1c95}', '\0', + '\0']), ('\u{10d6}', ['\u{1c96}', '\0', '\0']), ('\u{10d7}', ['\u{1c97}', '\0', '\0']), + ('\u{10d8}', ['\u{1c98}', '\0', '\0']), ('\u{10d9}', ['\u{1c99}', '\0', '\0']), ('\u{10da}', + ['\u{1c9a}', '\0', '\0']), ('\u{10db}', ['\u{1c9b}', '\0', '\0']), ('\u{10dc}', ['\u{1c9c}', + '\0', '\0']), ('\u{10dd}', ['\u{1c9d}', '\0', '\0']), ('\u{10de}', ['\u{1c9e}', '\0', + '\0']), ('\u{10df}', ['\u{1c9f}', '\0', '\0']), ('\u{10e0}', ['\u{1ca0}', '\0', '\0']), + ('\u{10e1}', ['\u{1ca1}', '\0', '\0']), ('\u{10e2}', ['\u{1ca2}', '\0', '\0']), ('\u{10e3}', + ['\u{1ca3}', '\0', '\0']), ('\u{10e4}', ['\u{1ca4}', '\0', '\0']), ('\u{10e5}', ['\u{1ca5}', + '\0', '\0']), ('\u{10e6}', ['\u{1ca6}', '\0', '\0']), ('\u{10e7}', ['\u{1ca7}', '\0', + '\0']), ('\u{10e8}', ['\u{1ca8}', '\0', '\0']), ('\u{10e9}', ['\u{1ca9}', '\0', '\0']), + ('\u{10ea}', ['\u{1caa}', '\0', '\0']), ('\u{10eb}', ['\u{1cab}', '\0', '\0']), ('\u{10ec}', + ['\u{1cac}', '\0', '\0']), ('\u{10ed}', ['\u{1cad}', '\0', '\0']), ('\u{10ee}', ['\u{1cae}', + '\0', '\0']), ('\u{10ef}', ['\u{1caf}', '\0', '\0']), ('\u{10f0}', ['\u{1cb0}', '\0', + '\0']), ('\u{10f1}', ['\u{1cb1}', '\0', '\0']), ('\u{10f2}', ['\u{1cb2}', '\0', '\0']), + ('\u{10f3}', ['\u{1cb3}', '\0', '\0']), ('\u{10f4}', ['\u{1cb4}', '\0', '\0']), ('\u{10f5}', + ['\u{1cb5}', '\0', '\0']), ('\u{10f6}', ['\u{1cb6}', '\0', '\0']), ('\u{10f7}', ['\u{1cb7}', + '\0', '\0']), ('\u{10f8}', ['\u{1cb8}', '\0', '\0']), ('\u{10f9}', ['\u{1cb9}', '\0', + '\0']), ('\u{10fa}', ['\u{1cba}', '\0', '\0']), ('\u{10fd}', ['\u{1cbd}', '\0', '\0']), + ('\u{10fe}', ['\u{1cbe}', '\0', '\0']), ('\u{10ff}', ['\u{1cbf}', '\0', '\0']), ('\u{13f8}', + ['\u{13f0}', '\0', '\0']), ('\u{13f9}', ['\u{13f1}', '\0', '\0']), ('\u{13fa}', ['\u{13f2}', + '\0', '\0']), ('\u{13fb}', ['\u{13f3}', '\0', '\0']), ('\u{13fc}', ['\u{13f4}', '\0', + '\0']), ('\u{13fd}', ['\u{13f5}', '\0', '\0']), ('\u{1c80}', ['\u{412}', '\0', '\0']), + ('\u{1c81}', ['\u{414}', '\0', '\0']), ('\u{1c82}', ['\u{41e}', '\0', '\0']), ('\u{1c83}', + ['\u{421}', '\0', '\0']), ('\u{1c84}', ['\u{422}', '\0', '\0']), ('\u{1c85}', ['\u{422}', + '\0', '\0']), ('\u{1c86}', ['\u{42a}', '\0', '\0']), ('\u{1c87}', ['\u{462}', '\0', '\0']), + ('\u{1c88}', ['\u{a64a}', '\0', '\0']), ('\u{1d79}', ['\u{a77d}', '\0', '\0']), ('\u{1d7d}', + ['\u{2c63}', '\0', '\0']), ('\u{1e01}', ['\u{1e00}', '\0', '\0']), ('\u{1e03}', ['\u{1e02}', + '\0', '\0']), ('\u{1e05}', ['\u{1e04}', '\0', '\0']), ('\u{1e07}', ['\u{1e06}', '\0', + '\0']), ('\u{1e09}', ['\u{1e08}', '\0', '\0']), ('\u{1e0b}', ['\u{1e0a}', '\0', '\0']), + ('\u{1e0d}', ['\u{1e0c}', '\0', '\0']), ('\u{1e0f}', ['\u{1e0e}', '\0', '\0']), ('\u{1e11}', + ['\u{1e10}', '\0', '\0']), ('\u{1e13}', ['\u{1e12}', '\0', '\0']), ('\u{1e15}', ['\u{1e14}', + '\0', '\0']), ('\u{1e17}', ['\u{1e16}', '\0', '\0']), ('\u{1e19}', ['\u{1e18}', '\0', + '\0']), ('\u{1e1b}', ['\u{1e1a}', '\0', '\0']), ('\u{1e1d}', ['\u{1e1c}', '\0', '\0']), + ('\u{1e1f}', ['\u{1e1e}', '\0', '\0']), ('\u{1e21}', ['\u{1e20}', '\0', '\0']), ('\u{1e23}', + ['\u{1e22}', '\0', '\0']), ('\u{1e25}', ['\u{1e24}', '\0', '\0']), ('\u{1e27}', ['\u{1e26}', + '\0', '\0']), ('\u{1e29}', ['\u{1e28}', '\0', '\0']), ('\u{1e2b}', ['\u{1e2a}', '\0', + '\0']), ('\u{1e2d}', ['\u{1e2c}', '\0', '\0']), ('\u{1e2f}', ['\u{1e2e}', '\0', '\0']), + ('\u{1e31}', ['\u{1e30}', '\0', '\0']), ('\u{1e33}', ['\u{1e32}', '\0', '\0']), ('\u{1e35}', + ['\u{1e34}', '\0', '\0']), ('\u{1e37}', ['\u{1e36}', '\0', '\0']), ('\u{1e39}', ['\u{1e38}', + '\0', '\0']), ('\u{1e3b}', ['\u{1e3a}', '\0', '\0']), ('\u{1e3d}', ['\u{1e3c}', '\0', + '\0']), ('\u{1e3f}', ['\u{1e3e}', '\0', '\0']), ('\u{1e41}', ['\u{1e40}', '\0', '\0']), + ('\u{1e43}', ['\u{1e42}', '\0', '\0']), ('\u{1e45}', ['\u{1e44}', '\0', '\0']), ('\u{1e47}', + ['\u{1e46}', '\0', '\0']), ('\u{1e49}', ['\u{1e48}', '\0', '\0']), ('\u{1e4b}', ['\u{1e4a}', + '\0', '\0']), ('\u{1e4d}', ['\u{1e4c}', '\0', '\0']), ('\u{1e4f}', ['\u{1e4e}', '\0', + '\0']), ('\u{1e51}', ['\u{1e50}', '\0', '\0']), ('\u{1e53}', ['\u{1e52}', '\0', '\0']), + ('\u{1e55}', ['\u{1e54}', '\0', '\0']), ('\u{1e57}', ['\u{1e56}', '\0', '\0']), ('\u{1e59}', + ['\u{1e58}', '\0', '\0']), ('\u{1e5b}', ['\u{1e5a}', '\0', '\0']), ('\u{1e5d}', ['\u{1e5c}', + '\0', '\0']), ('\u{1e5f}', ['\u{1e5e}', '\0', '\0']), ('\u{1e61}', ['\u{1e60}', '\0', + '\0']), ('\u{1e63}', ['\u{1e62}', '\0', '\0']), ('\u{1e65}', ['\u{1e64}', '\0', '\0']), + ('\u{1e67}', ['\u{1e66}', '\0', '\0']), ('\u{1e69}', ['\u{1e68}', '\0', '\0']), ('\u{1e6b}', + ['\u{1e6a}', '\0', '\0']), ('\u{1e6d}', ['\u{1e6c}', '\0', '\0']), ('\u{1e6f}', ['\u{1e6e}', + '\0', '\0']), ('\u{1e71}', ['\u{1e70}', '\0', '\0']), ('\u{1e73}', ['\u{1e72}', '\0', + '\0']), ('\u{1e75}', ['\u{1e74}', '\0', '\0']), ('\u{1e77}', ['\u{1e76}', '\0', '\0']), + ('\u{1e79}', ['\u{1e78}', '\0', '\0']), ('\u{1e7b}', ['\u{1e7a}', '\0', '\0']), ('\u{1e7d}', + ['\u{1e7c}', '\0', '\0']), ('\u{1e7f}', ['\u{1e7e}', '\0', '\0']), ('\u{1e81}', ['\u{1e80}', + '\0', '\0']), ('\u{1e83}', ['\u{1e82}', '\0', '\0']), ('\u{1e85}', ['\u{1e84}', '\0', + '\0']), ('\u{1e87}', ['\u{1e86}', '\0', '\0']), ('\u{1e89}', ['\u{1e88}', '\0', '\0']), + ('\u{1e8b}', ['\u{1e8a}', '\0', '\0']), ('\u{1e8d}', ['\u{1e8c}', '\0', '\0']), ('\u{1e8f}', + ['\u{1e8e}', '\0', '\0']), ('\u{1e91}', ['\u{1e90}', '\0', '\0']), ('\u{1e93}', ['\u{1e92}', + '\0', '\0']), ('\u{1e95}', ['\u{1e94}', '\0', '\0']), ('\u{1e96}', ['\u{48}', '\u{331}', + '\0']), ('\u{1e97}', ['\u{54}', '\u{308}', '\0']), ('\u{1e98}', ['\u{57}', '\u{30a}', + '\0']), ('\u{1e99}', ['\u{59}', '\u{30a}', '\0']), ('\u{1e9a}', ['\u{41}', '\u{2be}', + '\0']), ('\u{1e9b}', ['\u{1e60}', '\0', '\0']), ('\u{1ea1}', ['\u{1ea0}', '\0', '\0']), + ('\u{1ea3}', ['\u{1ea2}', '\0', '\0']), ('\u{1ea5}', ['\u{1ea4}', '\0', '\0']), ('\u{1ea7}', + ['\u{1ea6}', '\0', '\0']), ('\u{1ea9}', ['\u{1ea8}', '\0', '\0']), ('\u{1eab}', ['\u{1eaa}', + '\0', '\0']), ('\u{1ead}', ['\u{1eac}', '\0', '\0']), ('\u{1eaf}', ['\u{1eae}', '\0', + '\0']), ('\u{1eb1}', ['\u{1eb0}', '\0', '\0']), ('\u{1eb3}', ['\u{1eb2}', '\0', '\0']), + ('\u{1eb5}', ['\u{1eb4}', '\0', '\0']), ('\u{1eb7}', ['\u{1eb6}', '\0', '\0']), ('\u{1eb9}', + ['\u{1eb8}', '\0', '\0']), ('\u{1ebb}', ['\u{1eba}', '\0', '\0']), ('\u{1ebd}', ['\u{1ebc}', + '\0', '\0']), ('\u{1ebf}', ['\u{1ebe}', '\0', '\0']), ('\u{1ec1}', ['\u{1ec0}', '\0', + '\0']), ('\u{1ec3}', ['\u{1ec2}', '\0', '\0']), ('\u{1ec5}', ['\u{1ec4}', '\0', '\0']), + ('\u{1ec7}', ['\u{1ec6}', '\0', '\0']), ('\u{1ec9}', ['\u{1ec8}', '\0', '\0']), ('\u{1ecb}', + ['\u{1eca}', '\0', '\0']), ('\u{1ecd}', ['\u{1ecc}', '\0', '\0']), ('\u{1ecf}', ['\u{1ece}', + '\0', '\0']), ('\u{1ed1}', ['\u{1ed0}', '\0', '\0']), ('\u{1ed3}', ['\u{1ed2}', '\0', + '\0']), ('\u{1ed5}', ['\u{1ed4}', '\0', '\0']), ('\u{1ed7}', ['\u{1ed6}', '\0', '\0']), + ('\u{1ed9}', ['\u{1ed8}', '\0', '\0']), ('\u{1edb}', ['\u{1eda}', '\0', '\0']), ('\u{1edd}', + ['\u{1edc}', '\0', '\0']), ('\u{1edf}', ['\u{1ede}', '\0', '\0']), ('\u{1ee1}', ['\u{1ee0}', + '\0', '\0']), ('\u{1ee3}', ['\u{1ee2}', '\0', '\0']), ('\u{1ee5}', ['\u{1ee4}', '\0', + '\0']), ('\u{1ee7}', ['\u{1ee6}', '\0', '\0']), ('\u{1ee9}', ['\u{1ee8}', '\0', '\0']), + ('\u{1eeb}', ['\u{1eea}', '\0', '\0']), ('\u{1eed}', ['\u{1eec}', '\0', '\0']), ('\u{1eef}', + ['\u{1eee}', '\0', '\0']), ('\u{1ef1}', ['\u{1ef0}', '\0', '\0']), ('\u{1ef3}', ['\u{1ef2}', + '\0', '\0']), ('\u{1ef5}', ['\u{1ef4}', '\0', '\0']), ('\u{1ef7}', ['\u{1ef6}', '\0', + '\0']), ('\u{1ef9}', ['\u{1ef8}', '\0', '\0']), ('\u{1efb}', ['\u{1efa}', '\0', '\0']), + ('\u{1efd}', ['\u{1efc}', '\0', '\0']), ('\u{1eff}', ['\u{1efe}', '\0', '\0']), ('\u{1f00}', + ['\u{1f08}', '\0', '\0']), ('\u{1f01}', ['\u{1f09}', '\0', '\0']), ('\u{1f02}', ['\u{1f0a}', + '\0', '\0']), ('\u{1f03}', ['\u{1f0b}', '\0', '\0']), ('\u{1f04}', ['\u{1f0c}', '\0', + '\0']), ('\u{1f05}', ['\u{1f0d}', '\0', '\0']), ('\u{1f06}', ['\u{1f0e}', '\0', '\0']), + ('\u{1f07}', ['\u{1f0f}', '\0', '\0']), ('\u{1f10}', ['\u{1f18}', '\0', '\0']), ('\u{1f11}', + ['\u{1f19}', '\0', '\0']), ('\u{1f12}', ['\u{1f1a}', '\0', '\0']), ('\u{1f13}', ['\u{1f1b}', + '\0', '\0']), ('\u{1f14}', ['\u{1f1c}', '\0', '\0']), ('\u{1f15}', ['\u{1f1d}', '\0', + '\0']), ('\u{1f20}', ['\u{1f28}', '\0', '\0']), ('\u{1f21}', ['\u{1f29}', '\0', '\0']), + ('\u{1f22}', ['\u{1f2a}', '\0', '\0']), ('\u{1f23}', ['\u{1f2b}', '\0', '\0']), ('\u{1f24}', + ['\u{1f2c}', '\0', '\0']), ('\u{1f25}', ['\u{1f2d}', '\0', '\0']), ('\u{1f26}', ['\u{1f2e}', + '\0', '\0']), ('\u{1f27}', ['\u{1f2f}', '\0', '\0']), ('\u{1f30}', ['\u{1f38}', '\0', + '\0']), ('\u{1f31}', ['\u{1f39}', '\0', '\0']), ('\u{1f32}', ['\u{1f3a}', '\0', '\0']), + ('\u{1f33}', ['\u{1f3b}', '\0', '\0']), ('\u{1f34}', ['\u{1f3c}', '\0', '\0']), ('\u{1f35}', + ['\u{1f3d}', '\0', '\0']), ('\u{1f36}', ['\u{1f3e}', '\0', '\0']), ('\u{1f37}', ['\u{1f3f}', + '\0', '\0']), ('\u{1f40}', ['\u{1f48}', '\0', '\0']), ('\u{1f41}', ['\u{1f49}', '\0', + '\0']), ('\u{1f42}', ['\u{1f4a}', '\0', '\0']), ('\u{1f43}', ['\u{1f4b}', '\0', '\0']), + ('\u{1f44}', ['\u{1f4c}', '\0', '\0']), ('\u{1f45}', ['\u{1f4d}', '\0', '\0']), ('\u{1f50}', + ['\u{3a5}', '\u{313}', '\0']), ('\u{1f51}', ['\u{1f59}', '\0', '\0']), ('\u{1f52}', + ['\u{3a5}', '\u{313}', '\u{300}']), ('\u{1f53}', ['\u{1f5b}', '\0', '\0']), ('\u{1f54}', + ['\u{3a5}', '\u{313}', '\u{301}']), ('\u{1f55}', ['\u{1f5d}', '\0', '\0']), ('\u{1f56}', + ['\u{3a5}', '\u{313}', '\u{342}']), ('\u{1f57}', ['\u{1f5f}', '\0', '\0']), ('\u{1f60}', + ['\u{1f68}', '\0', '\0']), ('\u{1f61}', ['\u{1f69}', '\0', '\0']), ('\u{1f62}', ['\u{1f6a}', + '\0', '\0']), ('\u{1f63}', ['\u{1f6b}', '\0', '\0']), ('\u{1f64}', ['\u{1f6c}', '\0', + '\0']), ('\u{1f65}', ['\u{1f6d}', '\0', '\0']), ('\u{1f66}', ['\u{1f6e}', '\0', '\0']), + ('\u{1f67}', ['\u{1f6f}', '\0', '\0']), ('\u{1f70}', ['\u{1fba}', '\0', '\0']), ('\u{1f71}', + ['\u{1fbb}', '\0', '\0']), ('\u{1f72}', ['\u{1fc8}', '\0', '\0']), ('\u{1f73}', ['\u{1fc9}', + '\0', '\0']), ('\u{1f74}', ['\u{1fca}', '\0', '\0']), ('\u{1f75}', ['\u{1fcb}', '\0', + '\0']), ('\u{1f76}', ['\u{1fda}', '\0', '\0']), ('\u{1f77}', ['\u{1fdb}', '\0', '\0']), + ('\u{1f78}', ['\u{1ff8}', '\0', '\0']), ('\u{1f79}', ['\u{1ff9}', '\0', '\0']), ('\u{1f7a}', + ['\u{1fea}', '\0', '\0']), ('\u{1f7b}', ['\u{1feb}', '\0', '\0']), ('\u{1f7c}', ['\u{1ffa}', + '\0', '\0']), ('\u{1f7d}', ['\u{1ffb}', '\0', '\0']), ('\u{1f80}', ['\u{1f08}', '\u{399}', + '\0']), ('\u{1f81}', ['\u{1f09}', '\u{399}', '\0']), ('\u{1f82}', ['\u{1f0a}', '\u{399}', + '\0']), ('\u{1f83}', ['\u{1f0b}', '\u{399}', '\0']), ('\u{1f84}', ['\u{1f0c}', '\u{399}', + '\0']), ('\u{1f85}', ['\u{1f0d}', '\u{399}', '\0']), ('\u{1f86}', ['\u{1f0e}', '\u{399}', + '\0']), ('\u{1f87}', ['\u{1f0f}', '\u{399}', '\0']), ('\u{1f88}', ['\u{1f08}', '\u{399}', + '\0']), ('\u{1f89}', ['\u{1f09}', '\u{399}', '\0']), ('\u{1f8a}', ['\u{1f0a}', '\u{399}', + '\0']), ('\u{1f8b}', ['\u{1f0b}', '\u{399}', '\0']), ('\u{1f8c}', ['\u{1f0c}', '\u{399}', + '\0']), ('\u{1f8d}', ['\u{1f0d}', '\u{399}', '\0']), ('\u{1f8e}', ['\u{1f0e}', '\u{399}', + '\0']), ('\u{1f8f}', ['\u{1f0f}', '\u{399}', '\0']), ('\u{1f90}', ['\u{1f28}', '\u{399}', + '\0']), ('\u{1f91}', ['\u{1f29}', '\u{399}', '\0']), ('\u{1f92}', ['\u{1f2a}', '\u{399}', + '\0']), ('\u{1f93}', ['\u{1f2b}', '\u{399}', '\0']), ('\u{1f94}', ['\u{1f2c}', '\u{399}', + '\0']), ('\u{1f95}', ['\u{1f2d}', '\u{399}', '\0']), ('\u{1f96}', ['\u{1f2e}', '\u{399}', + '\0']), ('\u{1f97}', ['\u{1f2f}', '\u{399}', '\0']), ('\u{1f98}', ['\u{1f28}', '\u{399}', + '\0']), ('\u{1f99}', ['\u{1f29}', '\u{399}', '\0']), ('\u{1f9a}', ['\u{1f2a}', '\u{399}', + '\0']), ('\u{1f9b}', ['\u{1f2b}', '\u{399}', '\0']), ('\u{1f9c}', ['\u{1f2c}', '\u{399}', + '\0']), ('\u{1f9d}', ['\u{1f2d}', '\u{399}', '\0']), ('\u{1f9e}', ['\u{1f2e}', '\u{399}', + '\0']), ('\u{1f9f}', ['\u{1f2f}', '\u{399}', '\0']), ('\u{1fa0}', ['\u{1f68}', '\u{399}', + '\0']), ('\u{1fa1}', ['\u{1f69}', '\u{399}', '\0']), ('\u{1fa2}', ['\u{1f6a}', '\u{399}', + '\0']), ('\u{1fa3}', ['\u{1f6b}', '\u{399}', '\0']), ('\u{1fa4}', ['\u{1f6c}', '\u{399}', + '\0']), ('\u{1fa5}', ['\u{1f6d}', '\u{399}', '\0']), ('\u{1fa6}', ['\u{1f6e}', '\u{399}', + '\0']), ('\u{1fa7}', ['\u{1f6f}', '\u{399}', '\0']), ('\u{1fa8}', ['\u{1f68}', '\u{399}', + '\0']), ('\u{1fa9}', ['\u{1f69}', '\u{399}', '\0']), ('\u{1faa}', ['\u{1f6a}', '\u{399}', + '\0']), ('\u{1fab}', ['\u{1f6b}', '\u{399}', '\0']), ('\u{1fac}', ['\u{1f6c}', '\u{399}', + '\0']), ('\u{1fad}', ['\u{1f6d}', '\u{399}', '\0']), ('\u{1fae}', ['\u{1f6e}', '\u{399}', + '\0']), ('\u{1faf}', ['\u{1f6f}', '\u{399}', '\0']), ('\u{1fb0}', ['\u{1fb8}', '\0', '\0']), + ('\u{1fb1}', ['\u{1fb9}', '\0', '\0']), ('\u{1fb2}', ['\u{1fba}', '\u{399}', '\0']), + ('\u{1fb3}', ['\u{391}', '\u{399}', '\0']), ('\u{1fb4}', ['\u{386}', '\u{399}', '\0']), + ('\u{1fb6}', ['\u{391}', '\u{342}', '\0']), ('\u{1fb7}', ['\u{391}', '\u{342}', '\u{399}']), + ('\u{1fbc}', ['\u{391}', '\u{399}', '\0']), ('\u{1fbe}', ['\u{399}', '\0', '\0']), + ('\u{1fc2}', ['\u{1fca}', '\u{399}', '\0']), ('\u{1fc3}', ['\u{397}', '\u{399}', '\0']), + ('\u{1fc4}', ['\u{389}', '\u{399}', '\0']), ('\u{1fc6}', ['\u{397}', '\u{342}', '\0']), + ('\u{1fc7}', ['\u{397}', '\u{342}', '\u{399}']), ('\u{1fcc}', ['\u{397}', '\u{399}', '\0']), + ('\u{1fd0}', ['\u{1fd8}', '\0', '\0']), ('\u{1fd1}', ['\u{1fd9}', '\0', '\0']), ('\u{1fd2}', + ['\u{399}', '\u{308}', '\u{300}']), ('\u{1fd3}', ['\u{399}', '\u{308}', '\u{301}']), + ('\u{1fd6}', ['\u{399}', '\u{342}', '\0']), ('\u{1fd7}', ['\u{399}', '\u{308}', '\u{342}']), + ('\u{1fe0}', ['\u{1fe8}', '\0', '\0']), ('\u{1fe1}', ['\u{1fe9}', '\0', '\0']), ('\u{1fe2}', + ['\u{3a5}', '\u{308}', '\u{300}']), ('\u{1fe3}', ['\u{3a5}', '\u{308}', '\u{301}']), + ('\u{1fe4}', ['\u{3a1}', '\u{313}', '\0']), ('\u{1fe5}', ['\u{1fec}', '\0', '\0']), + ('\u{1fe6}', ['\u{3a5}', '\u{342}', '\0']), ('\u{1fe7}', ['\u{3a5}', '\u{308}', '\u{342}']), + ('\u{1ff2}', ['\u{1ffa}', '\u{399}', '\0']), ('\u{1ff3}', ['\u{3a9}', '\u{399}', '\0']), + ('\u{1ff4}', ['\u{38f}', '\u{399}', '\0']), ('\u{1ff6}', ['\u{3a9}', '\u{342}', '\0']), + ('\u{1ff7}', ['\u{3a9}', '\u{342}', '\u{399}']), ('\u{1ffc}', ['\u{3a9}', '\u{399}', '\0']), + ('\u{214e}', ['\u{2132}', '\0', '\0']), ('\u{2170}', ['\u{2160}', '\0', '\0']), ('\u{2171}', + ['\u{2161}', '\0', '\0']), ('\u{2172}', ['\u{2162}', '\0', '\0']), ('\u{2173}', ['\u{2163}', + '\0', '\0']), ('\u{2174}', ['\u{2164}', '\0', '\0']), ('\u{2175}', ['\u{2165}', '\0', + '\0']), ('\u{2176}', ['\u{2166}', '\0', '\0']), ('\u{2177}', ['\u{2167}', '\0', '\0']), + ('\u{2178}', ['\u{2168}', '\0', '\0']), ('\u{2179}', ['\u{2169}', '\0', '\0']), ('\u{217a}', + ['\u{216a}', '\0', '\0']), ('\u{217b}', ['\u{216b}', '\0', '\0']), ('\u{217c}', ['\u{216c}', + '\0', '\0']), ('\u{217d}', ['\u{216d}', '\0', '\0']), ('\u{217e}', ['\u{216e}', '\0', + '\0']), ('\u{217f}', ['\u{216f}', '\0', '\0']), ('\u{2184}', ['\u{2183}', '\0', '\0']), + ('\u{24d0}', ['\u{24b6}', '\0', '\0']), ('\u{24d1}', ['\u{24b7}', '\0', '\0']), ('\u{24d2}', + ['\u{24b8}', '\0', '\0']), ('\u{24d3}', ['\u{24b9}', '\0', '\0']), ('\u{24d4}', ['\u{24ba}', + '\0', '\0']), ('\u{24d5}', ['\u{24bb}', '\0', '\0']), ('\u{24d6}', ['\u{24bc}', '\0', + '\0']), ('\u{24d7}', ['\u{24bd}', '\0', '\0']), ('\u{24d8}', ['\u{24be}', '\0', '\0']), + ('\u{24d9}', ['\u{24bf}', '\0', '\0']), ('\u{24da}', ['\u{24c0}', '\0', '\0']), ('\u{24db}', + ['\u{24c1}', '\0', '\0']), ('\u{24dc}', ['\u{24c2}', '\0', '\0']), ('\u{24dd}', ['\u{24c3}', + '\0', '\0']), ('\u{24de}', ['\u{24c4}', '\0', '\0']), ('\u{24df}', ['\u{24c5}', '\0', + '\0']), ('\u{24e0}', ['\u{24c6}', '\0', '\0']), ('\u{24e1}', ['\u{24c7}', '\0', '\0']), + ('\u{24e2}', ['\u{24c8}', '\0', '\0']), ('\u{24e3}', ['\u{24c9}', '\0', '\0']), ('\u{24e4}', + ['\u{24ca}', '\0', '\0']), ('\u{24e5}', ['\u{24cb}', '\0', '\0']), ('\u{24e6}', ['\u{24cc}', + '\0', '\0']), ('\u{24e7}', ['\u{24cd}', '\0', '\0']), ('\u{24e8}', ['\u{24ce}', '\0', + '\0']), ('\u{24e9}', ['\u{24cf}', '\0', '\0']), ('\u{2c30}', ['\u{2c00}', '\0', '\0']), + ('\u{2c31}', ['\u{2c01}', '\0', '\0']), ('\u{2c32}', ['\u{2c02}', '\0', '\0']), ('\u{2c33}', + ['\u{2c03}', '\0', '\0']), ('\u{2c34}', ['\u{2c04}', '\0', '\0']), ('\u{2c35}', ['\u{2c05}', + '\0', '\0']), ('\u{2c36}', ['\u{2c06}', '\0', '\0']), ('\u{2c37}', ['\u{2c07}', '\0', + '\0']), ('\u{2c38}', ['\u{2c08}', '\0', '\0']), ('\u{2c39}', ['\u{2c09}', '\0', '\0']), + ('\u{2c3a}', ['\u{2c0a}', '\0', '\0']), ('\u{2c3b}', ['\u{2c0b}', '\0', '\0']), ('\u{2c3c}', + ['\u{2c0c}', '\0', '\0']), ('\u{2c3d}', ['\u{2c0d}', '\0', '\0']), ('\u{2c3e}', ['\u{2c0e}', + '\0', '\0']), ('\u{2c3f}', ['\u{2c0f}', '\0', '\0']), ('\u{2c40}', ['\u{2c10}', '\0', + '\0']), ('\u{2c41}', ['\u{2c11}', '\0', '\0']), ('\u{2c42}', ['\u{2c12}', '\0', '\0']), + ('\u{2c43}', ['\u{2c13}', '\0', '\0']), ('\u{2c44}', ['\u{2c14}', '\0', '\0']), ('\u{2c45}', + ['\u{2c15}', '\0', '\0']), ('\u{2c46}', ['\u{2c16}', '\0', '\0']), ('\u{2c47}', ['\u{2c17}', + '\0', '\0']), ('\u{2c48}', ['\u{2c18}', '\0', '\0']), ('\u{2c49}', ['\u{2c19}', '\0', + '\0']), ('\u{2c4a}', ['\u{2c1a}', '\0', '\0']), ('\u{2c4b}', ['\u{2c1b}', '\0', '\0']), + ('\u{2c4c}', ['\u{2c1c}', '\0', '\0']), ('\u{2c4d}', ['\u{2c1d}', '\0', '\0']), ('\u{2c4e}', + ['\u{2c1e}', '\0', '\0']), ('\u{2c4f}', ['\u{2c1f}', '\0', '\0']), ('\u{2c50}', ['\u{2c20}', + '\0', '\0']), ('\u{2c51}', ['\u{2c21}', '\0', '\0']), ('\u{2c52}', ['\u{2c22}', '\0', + '\0']), ('\u{2c53}', ['\u{2c23}', '\0', '\0']), ('\u{2c54}', ['\u{2c24}', '\0', '\0']), + ('\u{2c55}', ['\u{2c25}', '\0', '\0']), ('\u{2c56}', ['\u{2c26}', '\0', '\0']), ('\u{2c57}', + ['\u{2c27}', '\0', '\0']), ('\u{2c58}', ['\u{2c28}', '\0', '\0']), ('\u{2c59}', ['\u{2c29}', + '\0', '\0']), ('\u{2c5a}', ['\u{2c2a}', '\0', '\0']), ('\u{2c5b}', ['\u{2c2b}', '\0', + '\0']), ('\u{2c5c}', ['\u{2c2c}', '\0', '\0']), ('\u{2c5d}', ['\u{2c2d}', '\0', '\0']), + ('\u{2c5e}', ['\u{2c2e}', '\0', '\0']), ('\u{2c61}', ['\u{2c60}', '\0', '\0']), ('\u{2c65}', + ['\u{23a}', '\0', '\0']), ('\u{2c66}', ['\u{23e}', '\0', '\0']), ('\u{2c68}', ['\u{2c67}', + '\0', '\0']), ('\u{2c6a}', ['\u{2c69}', '\0', '\0']), ('\u{2c6c}', ['\u{2c6b}', '\0', + '\0']), ('\u{2c73}', ['\u{2c72}', '\0', '\0']), ('\u{2c76}', ['\u{2c75}', '\0', '\0']), + ('\u{2c81}', ['\u{2c80}', '\0', '\0']), ('\u{2c83}', ['\u{2c82}', '\0', '\0']), ('\u{2c85}', + ['\u{2c84}', '\0', '\0']), ('\u{2c87}', ['\u{2c86}', '\0', '\0']), ('\u{2c89}', ['\u{2c88}', + '\0', '\0']), ('\u{2c8b}', ['\u{2c8a}', '\0', '\0']), ('\u{2c8d}', ['\u{2c8c}', '\0', + '\0']), ('\u{2c8f}', ['\u{2c8e}', '\0', '\0']), ('\u{2c91}', ['\u{2c90}', '\0', '\0']), + ('\u{2c93}', ['\u{2c92}', '\0', '\0']), ('\u{2c95}', ['\u{2c94}', '\0', '\0']), ('\u{2c97}', + ['\u{2c96}', '\0', '\0']), ('\u{2c99}', ['\u{2c98}', '\0', '\0']), ('\u{2c9b}', ['\u{2c9a}', + '\0', '\0']), ('\u{2c9d}', ['\u{2c9c}', '\0', '\0']), ('\u{2c9f}', ['\u{2c9e}', '\0', + '\0']), ('\u{2ca1}', ['\u{2ca0}', '\0', '\0']), ('\u{2ca3}', ['\u{2ca2}', '\0', '\0']), + ('\u{2ca5}', ['\u{2ca4}', '\0', '\0']), ('\u{2ca7}', ['\u{2ca6}', '\0', '\0']), ('\u{2ca9}', + ['\u{2ca8}', '\0', '\0']), ('\u{2cab}', ['\u{2caa}', '\0', '\0']), ('\u{2cad}', ['\u{2cac}', + '\0', '\0']), ('\u{2caf}', ['\u{2cae}', '\0', '\0']), ('\u{2cb1}', ['\u{2cb0}', '\0', + '\0']), ('\u{2cb3}', ['\u{2cb2}', '\0', '\0']), ('\u{2cb5}', ['\u{2cb4}', '\0', '\0']), + ('\u{2cb7}', ['\u{2cb6}', '\0', '\0']), ('\u{2cb9}', ['\u{2cb8}', '\0', '\0']), ('\u{2cbb}', + ['\u{2cba}', '\0', '\0']), ('\u{2cbd}', ['\u{2cbc}', '\0', '\0']), ('\u{2cbf}', ['\u{2cbe}', + '\0', '\0']), ('\u{2cc1}', ['\u{2cc0}', '\0', '\0']), ('\u{2cc3}', ['\u{2cc2}', '\0', + '\0']), ('\u{2cc5}', ['\u{2cc4}', '\0', '\0']), ('\u{2cc7}', ['\u{2cc6}', '\0', '\0']), + ('\u{2cc9}', ['\u{2cc8}', '\0', '\0']), ('\u{2ccb}', ['\u{2cca}', '\0', '\0']), ('\u{2ccd}', + ['\u{2ccc}', '\0', '\0']), ('\u{2ccf}', ['\u{2cce}', '\0', '\0']), ('\u{2cd1}', ['\u{2cd0}', + '\0', '\0']), ('\u{2cd3}', ['\u{2cd2}', '\0', '\0']), ('\u{2cd5}', ['\u{2cd4}', '\0', + '\0']), ('\u{2cd7}', ['\u{2cd6}', '\0', '\0']), ('\u{2cd9}', ['\u{2cd8}', '\0', '\0']), + ('\u{2cdb}', ['\u{2cda}', '\0', '\0']), ('\u{2cdd}', ['\u{2cdc}', '\0', '\0']), ('\u{2cdf}', + ['\u{2cde}', '\0', '\0']), ('\u{2ce1}', ['\u{2ce0}', '\0', '\0']), ('\u{2ce3}', ['\u{2ce2}', + '\0', '\0']), ('\u{2cec}', ['\u{2ceb}', '\0', '\0']), ('\u{2cee}', ['\u{2ced}', '\0', + '\0']), ('\u{2cf3}', ['\u{2cf2}', '\0', '\0']), ('\u{2d00}', ['\u{10a0}', '\0', '\0']), + ('\u{2d01}', ['\u{10a1}', '\0', '\0']), ('\u{2d02}', ['\u{10a2}', '\0', '\0']), ('\u{2d03}', + ['\u{10a3}', '\0', '\0']), ('\u{2d04}', ['\u{10a4}', '\0', '\0']), ('\u{2d05}', ['\u{10a5}', + '\0', '\0']), ('\u{2d06}', ['\u{10a6}', '\0', '\0']), ('\u{2d07}', ['\u{10a7}', '\0', + '\0']), ('\u{2d08}', ['\u{10a8}', '\0', '\0']), ('\u{2d09}', ['\u{10a9}', '\0', '\0']), + ('\u{2d0a}', ['\u{10aa}', '\0', '\0']), ('\u{2d0b}', ['\u{10ab}', '\0', '\0']), ('\u{2d0c}', + ['\u{10ac}', '\0', '\0']), ('\u{2d0d}', ['\u{10ad}', '\0', '\0']), ('\u{2d0e}', ['\u{10ae}', + '\0', '\0']), ('\u{2d0f}', ['\u{10af}', '\0', '\0']), ('\u{2d10}', ['\u{10b0}', '\0', + '\0']), ('\u{2d11}', ['\u{10b1}', '\0', '\0']), ('\u{2d12}', ['\u{10b2}', '\0', '\0']), + ('\u{2d13}', ['\u{10b3}', '\0', '\0']), ('\u{2d14}', ['\u{10b4}', '\0', '\0']), ('\u{2d15}', + ['\u{10b5}', '\0', '\0']), ('\u{2d16}', ['\u{10b6}', '\0', '\0']), ('\u{2d17}', ['\u{10b7}', + '\0', '\0']), ('\u{2d18}', ['\u{10b8}', '\0', '\0']), ('\u{2d19}', ['\u{10b9}', '\0', + '\0']), ('\u{2d1a}', ['\u{10ba}', '\0', '\0']), ('\u{2d1b}', ['\u{10bb}', '\0', '\0']), + ('\u{2d1c}', ['\u{10bc}', '\0', '\0']), ('\u{2d1d}', ['\u{10bd}', '\0', '\0']), ('\u{2d1e}', + ['\u{10be}', '\0', '\0']), ('\u{2d1f}', ['\u{10bf}', '\0', '\0']), ('\u{2d20}', ['\u{10c0}', + '\0', '\0']), ('\u{2d21}', ['\u{10c1}', '\0', '\0']), ('\u{2d22}', ['\u{10c2}', '\0', + '\0']), ('\u{2d23}', ['\u{10c3}', '\0', '\0']), ('\u{2d24}', ['\u{10c4}', '\0', '\0']), + ('\u{2d25}', ['\u{10c5}', '\0', '\0']), ('\u{2d27}', ['\u{10c7}', '\0', '\0']), ('\u{2d2d}', + ['\u{10cd}', '\0', '\0']), ('\u{a641}', ['\u{a640}', '\0', '\0']), ('\u{a643}', ['\u{a642}', + '\0', '\0']), ('\u{a645}', ['\u{a644}', '\0', '\0']), ('\u{a647}', ['\u{a646}', '\0', + '\0']), ('\u{a649}', ['\u{a648}', '\0', '\0']), ('\u{a64b}', ['\u{a64a}', '\0', '\0']), + ('\u{a64d}', ['\u{a64c}', '\0', '\0']), ('\u{a64f}', ['\u{a64e}', '\0', '\0']), ('\u{a651}', + ['\u{a650}', '\0', '\0']), ('\u{a653}', ['\u{a652}', '\0', '\0']), ('\u{a655}', ['\u{a654}', + '\0', '\0']), ('\u{a657}', ['\u{a656}', '\0', '\0']), ('\u{a659}', ['\u{a658}', '\0', + '\0']), ('\u{a65b}', ['\u{a65a}', '\0', '\0']), ('\u{a65d}', ['\u{a65c}', '\0', '\0']), + ('\u{a65f}', ['\u{a65e}', '\0', '\0']), ('\u{a661}', ['\u{a660}', '\0', '\0']), ('\u{a663}', + ['\u{a662}', '\0', '\0']), ('\u{a665}', ['\u{a664}', '\0', '\0']), ('\u{a667}', ['\u{a666}', + '\0', '\0']), ('\u{a669}', ['\u{a668}', '\0', '\0']), ('\u{a66b}', ['\u{a66a}', '\0', + '\0']), ('\u{a66d}', ['\u{a66c}', '\0', '\0']), ('\u{a681}', ['\u{a680}', '\0', '\0']), + ('\u{a683}', ['\u{a682}', '\0', '\0']), ('\u{a685}', ['\u{a684}', '\0', '\0']), ('\u{a687}', + ['\u{a686}', '\0', '\0']), ('\u{a689}', ['\u{a688}', '\0', '\0']), ('\u{a68b}', ['\u{a68a}', + '\0', '\0']), ('\u{a68d}', ['\u{a68c}', '\0', '\0']), ('\u{a68f}', ['\u{a68e}', '\0', + '\0']), ('\u{a691}', ['\u{a690}', '\0', '\0']), ('\u{a693}', ['\u{a692}', '\0', '\0']), + ('\u{a695}', ['\u{a694}', '\0', '\0']), ('\u{a697}', ['\u{a696}', '\0', '\0']), ('\u{a699}', + ['\u{a698}', '\0', '\0']), ('\u{a69b}', ['\u{a69a}', '\0', '\0']), ('\u{a723}', ['\u{a722}', + '\0', '\0']), ('\u{a725}', ['\u{a724}', '\0', '\0']), ('\u{a727}', ['\u{a726}', '\0', + '\0']), ('\u{a729}', ['\u{a728}', '\0', '\0']), ('\u{a72b}', ['\u{a72a}', '\0', '\0']), + ('\u{a72d}', ['\u{a72c}', '\0', '\0']), ('\u{a72f}', ['\u{a72e}', '\0', '\0']), ('\u{a733}', + ['\u{a732}', '\0', '\0']), ('\u{a735}', ['\u{a734}', '\0', '\0']), ('\u{a737}', ['\u{a736}', + '\0', '\0']), ('\u{a739}', ['\u{a738}', '\0', '\0']), ('\u{a73b}', ['\u{a73a}', '\0', + '\0']), ('\u{a73d}', ['\u{a73c}', '\0', '\0']), ('\u{a73f}', ['\u{a73e}', '\0', '\0']), + ('\u{a741}', ['\u{a740}', '\0', '\0']), ('\u{a743}', ['\u{a742}', '\0', '\0']), ('\u{a745}', + ['\u{a744}', '\0', '\0']), ('\u{a747}', ['\u{a746}', '\0', '\0']), ('\u{a749}', ['\u{a748}', + '\0', '\0']), ('\u{a74b}', ['\u{a74a}', '\0', '\0']), ('\u{a74d}', ['\u{a74c}', '\0', + '\0']), ('\u{a74f}', ['\u{a74e}', '\0', '\0']), ('\u{a751}', ['\u{a750}', '\0', '\0']), + ('\u{a753}', ['\u{a752}', '\0', '\0']), ('\u{a755}', ['\u{a754}', '\0', '\0']), ('\u{a757}', + ['\u{a756}', '\0', '\0']), ('\u{a759}', ['\u{a758}', '\0', '\0']), ('\u{a75b}', ['\u{a75a}', + '\0', '\0']), ('\u{a75d}', ['\u{a75c}', '\0', '\0']), ('\u{a75f}', ['\u{a75e}', '\0', + '\0']), ('\u{a761}', ['\u{a760}', '\0', '\0']), ('\u{a763}', ['\u{a762}', '\0', '\0']), + ('\u{a765}', ['\u{a764}', '\0', '\0']), ('\u{a767}', ['\u{a766}', '\0', '\0']), ('\u{a769}', + ['\u{a768}', '\0', '\0']), ('\u{a76b}', ['\u{a76a}', '\0', '\0']), ('\u{a76d}', ['\u{a76c}', + '\0', '\0']), ('\u{a76f}', ['\u{a76e}', '\0', '\0']), ('\u{a77a}', ['\u{a779}', '\0', + '\0']), ('\u{a77c}', ['\u{a77b}', '\0', '\0']), ('\u{a77f}', ['\u{a77e}', '\0', '\0']), + ('\u{a781}', ['\u{a780}', '\0', '\0']), ('\u{a783}', ['\u{a782}', '\0', '\0']), ('\u{a785}', + ['\u{a784}', '\0', '\0']), ('\u{a787}', ['\u{a786}', '\0', '\0']), ('\u{a78c}', ['\u{a78b}', + '\0', '\0']), ('\u{a791}', ['\u{a790}', '\0', '\0']), ('\u{a793}', ['\u{a792}', '\0', + '\0']), ('\u{a797}', ['\u{a796}', '\0', '\0']), ('\u{a799}', ['\u{a798}', '\0', '\0']), + ('\u{a79b}', ['\u{a79a}', '\0', '\0']), ('\u{a79d}', ['\u{a79c}', '\0', '\0']), ('\u{a79f}', + ['\u{a79e}', '\0', '\0']), ('\u{a7a1}', ['\u{a7a0}', '\0', '\0']), ('\u{a7a3}', ['\u{a7a2}', + '\0', '\0']), ('\u{a7a5}', ['\u{a7a4}', '\0', '\0']), ('\u{a7a7}', ['\u{a7a6}', '\0', + '\0']), ('\u{a7a9}', ['\u{a7a8}', '\0', '\0']), ('\u{a7b5}', ['\u{a7b4}', '\0', '\0']), + ('\u{a7b7}', ['\u{a7b6}', '\0', '\0']), ('\u{a7b9}', ['\u{a7b8}', '\0', '\0']), ('\u{ab53}', + ['\u{a7b3}', '\0', '\0']), ('\u{ab70}', ['\u{13a0}', '\0', '\0']), ('\u{ab71}', ['\u{13a1}', + '\0', '\0']), ('\u{ab72}', ['\u{13a2}', '\0', '\0']), ('\u{ab73}', ['\u{13a3}', '\0', + '\0']), ('\u{ab74}', ['\u{13a4}', '\0', '\0']), ('\u{ab75}', ['\u{13a5}', '\0', '\0']), + ('\u{ab76}', ['\u{13a6}', '\0', '\0']), ('\u{ab77}', ['\u{13a7}', '\0', '\0']), ('\u{ab78}', + ['\u{13a8}', '\0', '\0']), ('\u{ab79}', ['\u{13a9}', '\0', '\0']), ('\u{ab7a}', ['\u{13aa}', + '\0', '\0']), ('\u{ab7b}', ['\u{13ab}', '\0', '\0']), ('\u{ab7c}', ['\u{13ac}', '\0', + '\0']), ('\u{ab7d}', ['\u{13ad}', '\0', '\0']), ('\u{ab7e}', ['\u{13ae}', '\0', '\0']), + ('\u{ab7f}', ['\u{13af}', '\0', '\0']), ('\u{ab80}', ['\u{13b0}', '\0', '\0']), ('\u{ab81}', + ['\u{13b1}', '\0', '\0']), ('\u{ab82}', ['\u{13b2}', '\0', '\0']), ('\u{ab83}', ['\u{13b3}', + '\0', '\0']), ('\u{ab84}', ['\u{13b4}', '\0', '\0']), ('\u{ab85}', ['\u{13b5}', '\0', + '\0']), ('\u{ab86}', ['\u{13b6}', '\0', '\0']), ('\u{ab87}', ['\u{13b7}', '\0', '\0']), + ('\u{ab88}', ['\u{13b8}', '\0', '\0']), ('\u{ab89}', ['\u{13b9}', '\0', '\0']), ('\u{ab8a}', + ['\u{13ba}', '\0', '\0']), ('\u{ab8b}', ['\u{13bb}', '\0', '\0']), ('\u{ab8c}', ['\u{13bc}', + '\0', '\0']), ('\u{ab8d}', ['\u{13bd}', '\0', '\0']), ('\u{ab8e}', ['\u{13be}', '\0', + '\0']), ('\u{ab8f}', ['\u{13bf}', '\0', '\0']), ('\u{ab90}', ['\u{13c0}', '\0', '\0']), + ('\u{ab91}', ['\u{13c1}', '\0', '\0']), ('\u{ab92}', ['\u{13c2}', '\0', '\0']), ('\u{ab93}', + ['\u{13c3}', '\0', '\0']), ('\u{ab94}', ['\u{13c4}', '\0', '\0']), ('\u{ab95}', ['\u{13c5}', + '\0', '\0']), ('\u{ab96}', ['\u{13c6}', '\0', '\0']), ('\u{ab97}', ['\u{13c7}', '\0', + '\0']), ('\u{ab98}', ['\u{13c8}', '\0', '\0']), ('\u{ab99}', ['\u{13c9}', '\0', '\0']), + ('\u{ab9a}', ['\u{13ca}', '\0', '\0']), ('\u{ab9b}', ['\u{13cb}', '\0', '\0']), ('\u{ab9c}', + ['\u{13cc}', '\0', '\0']), ('\u{ab9d}', ['\u{13cd}', '\0', '\0']), ('\u{ab9e}', ['\u{13ce}', + '\0', '\0']), ('\u{ab9f}', ['\u{13cf}', '\0', '\0']), ('\u{aba0}', ['\u{13d0}', '\0', + '\0']), ('\u{aba1}', ['\u{13d1}', '\0', '\0']), ('\u{aba2}', ['\u{13d2}', '\0', '\0']), + ('\u{aba3}', ['\u{13d3}', '\0', '\0']), ('\u{aba4}', ['\u{13d4}', '\0', '\0']), ('\u{aba5}', + ['\u{13d5}', '\0', '\0']), ('\u{aba6}', ['\u{13d6}', '\0', '\0']), ('\u{aba7}', ['\u{13d7}', + '\0', '\0']), ('\u{aba8}', ['\u{13d8}', '\0', '\0']), ('\u{aba9}', ['\u{13d9}', '\0', + '\0']), ('\u{abaa}', ['\u{13da}', '\0', '\0']), ('\u{abab}', ['\u{13db}', '\0', '\0']), + ('\u{abac}', ['\u{13dc}', '\0', '\0']), ('\u{abad}', ['\u{13dd}', '\0', '\0']), ('\u{abae}', + ['\u{13de}', '\0', '\0']), ('\u{abaf}', ['\u{13df}', '\0', '\0']), ('\u{abb0}', ['\u{13e0}', + '\0', '\0']), ('\u{abb1}', ['\u{13e1}', '\0', '\0']), ('\u{abb2}', ['\u{13e2}', '\0', + '\0']), ('\u{abb3}', ['\u{13e3}', '\0', '\0']), ('\u{abb4}', ['\u{13e4}', '\0', '\0']), + ('\u{abb5}', ['\u{13e5}', '\0', '\0']), ('\u{abb6}', ['\u{13e6}', '\0', '\0']), ('\u{abb7}', + ['\u{13e7}', '\0', '\0']), ('\u{abb8}', ['\u{13e8}', '\0', '\0']), ('\u{abb9}', ['\u{13e9}', + '\0', '\0']), ('\u{abba}', ['\u{13ea}', '\0', '\0']), ('\u{abbb}', ['\u{13eb}', '\0', + '\0']), ('\u{abbc}', ['\u{13ec}', '\0', '\0']), ('\u{abbd}', ['\u{13ed}', '\0', '\0']), + ('\u{abbe}', ['\u{13ee}', '\0', '\0']), ('\u{abbf}', ['\u{13ef}', '\0', '\0']), ('\u{fb00}', + ['\u{46}', '\u{46}', '\0']), ('\u{fb01}', ['\u{46}', '\u{49}', '\0']), ('\u{fb02}', + ['\u{46}', '\u{4c}', '\0']), ('\u{fb03}', ['\u{46}', '\u{46}', '\u{49}']), ('\u{fb04}', + ['\u{46}', '\u{46}', '\u{4c}']), ('\u{fb05}', ['\u{53}', '\u{54}', '\0']), ('\u{fb06}', + ['\u{53}', '\u{54}', '\0']), ('\u{fb13}', ['\u{544}', '\u{546}', '\0']), ('\u{fb14}', + ['\u{544}', '\u{535}', '\0']), ('\u{fb15}', ['\u{544}', '\u{53b}', '\0']), ('\u{fb16}', + ['\u{54e}', '\u{546}', '\0']), ('\u{fb17}', ['\u{544}', '\u{53d}', '\0']), ('\u{ff41}', + ['\u{ff21}', '\0', '\0']), ('\u{ff42}', ['\u{ff22}', '\0', '\0']), ('\u{ff43}', ['\u{ff23}', + '\0', '\0']), ('\u{ff44}', ['\u{ff24}', '\0', '\0']), ('\u{ff45}', ['\u{ff25}', '\0', + '\0']), ('\u{ff46}', ['\u{ff26}', '\0', '\0']), ('\u{ff47}', ['\u{ff27}', '\0', '\0']), + ('\u{ff48}', ['\u{ff28}', '\0', '\0']), ('\u{ff49}', ['\u{ff29}', '\0', '\0']), ('\u{ff4a}', + ['\u{ff2a}', '\0', '\0']), ('\u{ff4b}', ['\u{ff2b}', '\0', '\0']), ('\u{ff4c}', ['\u{ff2c}', + '\0', '\0']), ('\u{ff4d}', ['\u{ff2d}', '\0', '\0']), ('\u{ff4e}', ['\u{ff2e}', '\0', + '\0']), ('\u{ff4f}', ['\u{ff2f}', '\0', '\0']), ('\u{ff50}', ['\u{ff30}', '\0', '\0']), + ('\u{ff51}', ['\u{ff31}', '\0', '\0']), ('\u{ff52}', ['\u{ff32}', '\0', '\0']), ('\u{ff53}', + ['\u{ff33}', '\0', '\0']), ('\u{ff54}', ['\u{ff34}', '\0', '\0']), ('\u{ff55}', ['\u{ff35}', + '\0', '\0']), ('\u{ff56}', ['\u{ff36}', '\0', '\0']), ('\u{ff57}', ['\u{ff37}', '\0', + '\0']), ('\u{ff58}', ['\u{ff38}', '\0', '\0']), ('\u{ff59}', ['\u{ff39}', '\0', '\0']), + ('\u{ff5a}', ['\u{ff3a}', '\0', '\0']), ('\u{10428}', ['\u{10400}', '\0', '\0']), ('\u{10429}', ['\u{10401}', '\0', '\0']), ('\u{1042a}', ['\u{10402}', '\0', '\0']), ('\u{1042b}', ['\u{10403}', '\0', '\0']), ('\u{1042c}', ['\u{10404}', '\0', '\0']), ('\u{1042d}', ['\u{10405}', '\0', '\0']), ('\u{1042e}', ['\u{10406}', '\0', '\0']), @@ -2474,6 +2548,22 @@ pub mod conversions { ('\u{118da}', ['\u{118ba}', '\0', '\0']), ('\u{118db}', ['\u{118bb}', '\0', '\0']), ('\u{118dc}', ['\u{118bc}', '\0', '\0']), ('\u{118dd}', ['\u{118bd}', '\0', '\0']), ('\u{118de}', ['\u{118be}', '\0', '\0']), ('\u{118df}', ['\u{118bf}', '\0', '\0']), + ('\u{16e60}', ['\u{16e40}', '\0', '\0']), ('\u{16e61}', ['\u{16e41}', '\0', '\0']), + ('\u{16e62}', ['\u{16e42}', '\0', '\0']), ('\u{16e63}', ['\u{16e43}', '\0', '\0']), + ('\u{16e64}', ['\u{16e44}', '\0', '\0']), ('\u{16e65}', ['\u{16e45}', '\0', '\0']), + ('\u{16e66}', ['\u{16e46}', '\0', '\0']), ('\u{16e67}', ['\u{16e47}', '\0', '\0']), + ('\u{16e68}', ['\u{16e48}', '\0', '\0']), ('\u{16e69}', ['\u{16e49}', '\0', '\0']), + ('\u{16e6a}', ['\u{16e4a}', '\0', '\0']), ('\u{16e6b}', ['\u{16e4b}', '\0', '\0']), + ('\u{16e6c}', ['\u{16e4c}', '\0', '\0']), ('\u{16e6d}', ['\u{16e4d}', '\0', '\0']), + ('\u{16e6e}', ['\u{16e4e}', '\0', '\0']), ('\u{16e6f}', ['\u{16e4f}', '\0', '\0']), + ('\u{16e70}', ['\u{16e50}', '\0', '\0']), ('\u{16e71}', ['\u{16e51}', '\0', '\0']), + ('\u{16e72}', ['\u{16e52}', '\0', '\0']), ('\u{16e73}', ['\u{16e53}', '\0', '\0']), + ('\u{16e74}', ['\u{16e54}', '\0', '\0']), ('\u{16e75}', ['\u{16e55}', '\0', '\0']), + ('\u{16e76}', ['\u{16e56}', '\0', '\0']), ('\u{16e77}', ['\u{16e57}', '\0', '\0']), + ('\u{16e78}', ['\u{16e58}', '\0', '\0']), ('\u{16e79}', ['\u{16e59}', '\0', '\0']), + ('\u{16e7a}', ['\u{16e5a}', '\0', '\0']), ('\u{16e7b}', ['\u{16e5b}', '\0', '\0']), + ('\u{16e7c}', ['\u{16e5c}', '\0', '\0']), ('\u{16e7d}', ['\u{16e5d}', '\0', '\0']), + ('\u{16e7e}', ['\u{16e5e}', '\0', '\0']), ('\u{16e7f}', ['\u{16e5f}', '\0', '\0']), ('\u{1e922}', ['\u{1e900}', '\0', '\0']), ('\u{1e923}', ['\u{1e901}', '\0', '\0']), ('\u{1e924}', ['\u{1e902}', '\0', '\0']), ('\u{1e925}', ['\u{1e903}', '\0', '\0']), ('\u{1e926}', ['\u{1e904}', '\0', '\0']), ('\u{1e927}', ['\u{1e905}', '\0', '\0']), -- cgit 1.4.1-3-g733a5 From f6ab74b8e7efed01c1045773b6693f23f6ebd93c Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Thu, 31 May 2018 15:57:43 +0900 Subject: Remove alloc::Opaque and use *mut u8 as pointer type for GlobalAlloc --- .../src/language-features/global-allocator.md | 6 +- src/liballoc/alloc.rs | 33 ++++---- src/liballoc/arc.rs | 6 +- src/liballoc/btree/node.rs | 10 +-- src/liballoc/heap.rs | 12 +-- src/liballoc/raw_vec.rs | 19 +++-- src/liballoc/rc.rs | 10 +-- src/liballoc_system/lib.rs | 89 +++++++++++----------- src/libcore/alloc.rs | 65 ++++++---------- src/libcore/ptr.rs | 8 -- src/librustc_allocator/expand.rs | 15 +--- src/libstd/alloc.rs | 10 +-- src/libstd/collections/hash/table.rs | 2 +- src/test/run-make-fulldeps/std-core-cycle/bar.rs | 4 +- src/test/run-pass/allocator/auxiliary/custom.rs | 6 +- src/test/run-pass/allocator/custom.rs | 6 +- src/test/run-pass/realloc-16687.rs | 4 +- 17 files changed, 130 insertions(+), 175 deletions(-) (limited to 'src/libcore') diff --git a/src/doc/unstable-book/src/language-features/global-allocator.md b/src/doc/unstable-book/src/language-features/global-allocator.md index 8f1ba22de8c..7dfdc487731 100644 --- a/src/doc/unstable-book/src/language-features/global-allocator.md +++ b/src/doc/unstable-book/src/language-features/global-allocator.md @@ -29,17 +29,17 @@ looks like: ```rust #![feature(global_allocator, allocator_api, heap_api)] -use std::alloc::{GlobalAlloc, System, Layout, Opaque}; +use std::alloc::{GlobalAlloc, System, Layout}; use std::ptr::NonNull; struct MyAllocator; unsafe impl GlobalAlloc for MyAllocator { - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { System.alloc(layout) } - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { System.dealloc(ptr, layout) } } diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 8753c495737..102910f4198 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -51,52 +51,49 @@ pub const Heap: Global = Global; unsafe impl GlobalAlloc for Global { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { - let ptr = __rust_alloc(layout.size(), layout.align()); - ptr as *mut Opaque + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + __rust_alloc(layout.size(), layout.align()) } #[inline] - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { - __rust_dealloc(ptr as *mut u8, layout.size(), layout.align()) + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + __rust_dealloc(ptr, layout.size(), layout.align()) } #[inline] - unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { - let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), new_size); - ptr as *mut Opaque + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + __rust_realloc(ptr, layout.size(), layout.align(), new_size) } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { - let ptr = __rust_alloc_zeroed(layout.size(), layout.align()); - ptr as *mut Opaque + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + __rust_alloc_zeroed(layout.size(), layout.align()) } } unsafe impl Alloc for Global { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) - -> Result, AllocErr> + -> Result, AllocErr> { NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) } } @@ -113,7 +110,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { let layout = Layout::from_size_align_unchecked(size, align); let ptr = Global.alloc(layout); if !ptr.is_null() { - ptr as *mut u8 + ptr } else { oom(layout) } @@ -129,7 +126,7 @@ pub(crate) unsafe fn box_free(ptr: Unique) { // We do not allocate for Box when T is ZST, so deallocation is also not necessary. if size != 0 { let layout = Layout::from_size_align_unchecked(size, align); - Global.dealloc(ptr as *mut Opaque, layout); + Global.dealloc(ptr as *mut u8, layout); } } diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 4026b3ababa..e3369f0a5b5 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -519,7 +519,7 @@ impl Arc { if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); - Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())) + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) } } @@ -639,7 +639,7 @@ impl ArcFromSlice for Arc<[T]> { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Global.dealloc(self.mem.as_opaque(), self.layout.clone()); + Global.dealloc(self.mem.cast(), self.layout.clone()); } } } @@ -1196,7 +1196,7 @@ impl Drop for Weak { if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); unsafe { - Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())) + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) } } } diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs index 431695c32ab..19bdcbc6ad6 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -287,7 +287,7 @@ impl Root { self.as_mut().as_leaf_mut().parent = ptr::null(); unsafe { - Global.dealloc(NonNull::from(top).as_opaque(), Layout::new::>()); + Global.dealloc(NonNull::from(top).cast(), Layout::new::>()); } } } @@ -478,7 +478,7 @@ impl NodeRef { debug_assert!(!self.is_shared_root()); let node = self.node; let ret = self.ascend().ok(); - Global.dealloc(node.as_opaque(), Layout::new::>()); + Global.dealloc(node.cast(), Layout::new::>()); ret } } @@ -499,7 +499,7 @@ impl NodeRef { > { let node = self.node; let ret = self.ascend().ok(); - Global.dealloc(node.as_opaque(), Layout::new::>()); + Global.dealloc(node.cast(), Layout::new::>()); ret } } @@ -1321,12 +1321,12 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: } Global.dealloc( - right_node.node.as_opaque(), + right_node.node.cast(), Layout::new::>(), ); } else { Global.dealloc( - right_node.node.as_opaque(), + right_node.node.cast(), Layout::new::>(), ); } diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 16f0630b911..5ea37ceeb2b 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -10,7 +10,7 @@ #![allow(deprecated)] -pub use alloc::{Layout, AllocErr, CannotReallocInPlace, Opaque}; +pub use alloc::{Layout, AllocErr, CannotReallocInPlace}; use core::alloc::Alloc as CoreAlloc; use core::ptr::NonNull; @@ -54,7 +54,7 @@ unsafe impl Alloc for T where T: CoreAlloc { } unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - let ptr = NonNull::new_unchecked(ptr as *mut Opaque); + let ptr = NonNull::new_unchecked(ptr); CoreAlloc::dealloc(self, ptr, layout) } @@ -70,7 +70,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<*mut u8, AllocErr> { - let ptr = NonNull::new_unchecked(ptr as *mut Opaque); + let ptr = NonNull::new_unchecked(ptr); CoreAlloc::realloc(self, ptr, layout, new_layout.size()).map(|ptr| ptr.cast().as_ptr()) } @@ -87,7 +87,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result { - let ptr = NonNull::new_unchecked(ptr as *mut Opaque); + let ptr = NonNull::new_unchecked(ptr); CoreAlloc::realloc_excess(self, ptr, layout, new_layout.size()) .map(|e| Excess(e.0 .cast().as_ptr(), e.1)) } @@ -96,7 +96,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let ptr = NonNull::new_unchecked(ptr as *mut Opaque); + let ptr = NonNull::new_unchecked(ptr); CoreAlloc::grow_in_place(self, ptr, layout, new_layout.size()) } @@ -104,7 +104,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let ptr = NonNull::new_unchecked(ptr as *mut Opaque); + let ptr = NonNull::new_unchecked(ptr); CoreAlloc::shrink_in_place(self, ptr, layout, new_layout.size()) } } diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 07bb7f1a3eb..c09f21eeb92 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -93,7 +93,7 @@ impl RawVec { // handles ZSTs and `cap = 0` alike let ptr = if alloc_size == 0 { - NonNull::::dangling().as_opaque() + NonNull::::dangling().cast() } else { let align = mem::align_of::(); let layout = Layout::from_size_align(alloc_size, align).unwrap(); @@ -314,7 +314,7 @@ impl RawVec { let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow()); - let ptr_res = self.a.realloc(NonNull::from(self.ptr).as_opaque(), + let ptr_res = self.a.realloc(NonNull::from(self.ptr).cast(), cur, new_size); match ptr_res { @@ -373,7 +373,7 @@ impl RawVec { let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow()); - match self.a.grow_in_place(NonNull::from(self.ptr).as_opaque(), old_layout, new_size) { + match self.a.grow_in_place(NonNull::from(self.ptr).cast(), old_layout, new_size) { Ok(_) => { // We can't directly divide `size`. self.cap = new_cap; @@ -546,7 +546,7 @@ impl RawVec { // FIXME: may crash and burn on over-reserve alloc_guard(new_layout.size()).unwrap_or_else(|_| capacity_overflow()); match self.a.grow_in_place( - NonNull::from(self.ptr).as_opaque(), old_layout, new_layout.size(), + NonNull::from(self.ptr).cast(), old_layout, new_layout.size(), ) { Ok(_) => { self.cap = new_cap; @@ -607,7 +607,7 @@ impl RawVec { let new_size = elem_size * amount; let align = mem::align_of::(); let old_layout = Layout::from_size_align_unchecked(old_size, align); - match self.a.realloc(NonNull::from(self.ptr).as_opaque(), + match self.a.realloc(NonNull::from(self.ptr).cast(), old_layout, new_size) { Ok(p) => self.ptr = p.cast().into(), @@ -667,7 +667,7 @@ impl RawVec { let res = match self.current_layout() { Some(layout) => { debug_assert!(new_layout.align() == layout.align()); - self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size()) + self.a.realloc(NonNull::from(self.ptr).cast(), layout, new_layout.size()) } None => self.a.alloc(new_layout), }; @@ -710,7 +710,7 @@ impl RawVec { let elem_size = mem::size_of::(); if elem_size != 0 { if let Some(layout) = self.current_layout() { - self.a.dealloc(NonNull::from(self.ptr).as_opaque(), layout); + self.a.dealloc(NonNull::from(self.ptr).cast(), layout); } } } @@ -753,7 +753,6 @@ fn capacity_overflow() -> ! { #[cfg(test)] mod tests { use super::*; - use alloc::Opaque; #[test] fn allocator_param() { @@ -773,7 +772,7 @@ mod tests { // before allocation attempts start failing. struct BoundedAlloc { fuel: usize } unsafe impl Alloc for BoundedAlloc { - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); if size > self.fuel { return Err(AllocErr); @@ -783,7 +782,7 @@ mod tests { err @ Err(_) => err, } } - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { Global.dealloc(ptr, layout) } } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 553c8b5ca32..84a6ecf7103 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -259,7 +259,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, NonNull}; use core::convert::From; -use alloc::{Global, Alloc, Layout, Opaque, box_free, oom}; +use alloc::{Global, Alloc, Layout, box_free, oom}; use string::String; use vec::Vec; @@ -732,7 +732,7 @@ impl RcFromSlice for Rc<[T]> { // In the event of a panic, elements that have been written // into the new RcBox will be dropped, then the memory freed. struct Guard { - mem: NonNull, + mem: NonNull, elems: *mut T, layout: Layout, n_elems: usize, @@ -755,7 +755,7 @@ impl RcFromSlice for Rc<[T]> { let v_ptr = v as *const [T]; let ptr = Self::allocate_for_ptr(v_ptr); - let mem = ptr as *mut _ as *mut Opaque; + let mem = ptr as *mut _ as *mut u8; let layout = Layout::for_value(&*ptr); // Pointer to first element @@ -839,7 +839,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { self.dec_weak(); if self.weak() == 0 { - Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())); + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } } @@ -1263,7 +1263,7 @@ impl Drop for Weak { // the weak count starts at 1, and will only go to zero if all // the strong pointers have disappeared. if self.weak() == 0 { - Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())); + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } } diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 9490b54e675..82fda8d639e 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -41,7 +41,7 @@ const MIN_ALIGN: usize = 8; #[allow(dead_code)] const MIN_ALIGN: usize = 16; -use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout, Opaque}; +use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout}; use core::ptr::NonNull; #[unstable(feature = "allocator_api", issue = "32838")] @@ -50,45 +50,45 @@ pub struct System; #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl Alloc for System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, - new_size: usize) -> Result, AllocErr> { + new_size: usize) -> Result, AllocErr> { NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } } #[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))] mod realloc_fallback { - use core::alloc::{GlobalAlloc, Opaque, Layout}; + use core::alloc::{GlobalAlloc, Layout}; use core::cmp; use core::ptr; impl super::System { - pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut Opaque, old_layout: Layout, - new_size: usize) -> *mut Opaque { + pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout, + new_size: usize) -> *mut u8 { // Docs for GlobalAlloc::realloc require this to be valid: let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); let new_ptr = GlobalAlloc::alloc(self, new_layout); if !new_ptr.is_null() { let size = cmp::min(old_layout.size(), new_size); - ptr::copy_nonoverlapping(ptr as *mut u8, new_ptr as *mut u8, size); + ptr::copy_nonoverlapping(ptr, new_ptr, size); GlobalAlloc::dealloc(self, ptr, old_layout); } new_ptr @@ -104,21 +104,19 @@ mod platform { use MIN_ALIGN; use System; - use core::alloc::{GlobalAlloc, Layout, Opaque}; + use core::alloc::{GlobalAlloc, Layout}; #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::malloc(layout.size()) as *mut Opaque + libc::malloc(layout.size()) as *mut u8 } else { #[cfg(target_os = "macos")] { if layout.align() > (1 << 31) { - // FIXME: use Opaque::null_mut - // https://github.com/rust-lang/rust/issues/49659 - return 0 as *mut Opaque + return ptr::null_mut() } } aligned_malloc(&layout) @@ -126,27 +124,27 @@ mod platform { } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::calloc(layout.size(), 1) as *mut Opaque + libc::calloc(layout.size(), 1) as *mut u8 } else { let ptr = self.alloc(layout.clone()); if !ptr.is_null() { - ptr::write_bytes(ptr as *mut u8, 0, layout.size()); + ptr::write_bytes(ptr, 0, layout.size()); } ptr } } #[inline] - unsafe fn dealloc(&self, ptr: *mut Opaque, _layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { libc::free(ptr as *mut libc::c_void) } #[inline] - unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { if layout.align() <= MIN_ALIGN && layout.align() <= new_size { - libc::realloc(ptr as *mut libc::c_void, new_size) as *mut Opaque + libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 } else { self.realloc_fallback(ptr, layout, new_size) } @@ -155,7 +153,7 @@ mod platform { #[cfg(any(target_os = "android", target_os = "redox", target_os = "solaris"))] #[inline] - unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque { + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { // On android we currently target API level 9 which unfortunately // doesn't have the `posix_memalign` API used below. Instead we use // `memalign`, but this unfortunately has the property on some systems @@ -173,19 +171,18 @@ mod platform { // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ // /memory/aligned_memory.cc - libc::memalign(layout.align(), layout.size()) as *mut Opaque + libc::memalign(layout.align(), layout.size()) as *mut u8 } #[cfg(not(any(target_os = "android", target_os = "redox", target_os = "solaris")))] #[inline] - unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque { + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { let mut out = ptr::null_mut(); let ret = libc::posix_memalign(&mut out, layout.align(), layout.size()); if ret != 0 { - // FIXME: use Opaque::null_mut https://github.com/rust-lang/rust/issues/49659 - 0 as *mut Opaque + ptr::null_mut() } else { - out as *mut Opaque + out as *mut u8 } } } @@ -195,7 +192,7 @@ mod platform { mod platform { use MIN_ALIGN; use System; - use core::alloc::{GlobalAlloc, Opaque, Layout}; + use core::alloc::{GlobalAlloc, Layout}; type LPVOID = *mut u8; type HANDLE = LPVOID; @@ -227,7 +224,7 @@ mod platform { } #[inline] - unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut Opaque { + unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 { let ptr = if layout.align() <= MIN_ALIGN { HeapAlloc(GetProcessHeap(), flags, layout.size()) } else { @@ -239,29 +236,29 @@ mod platform { align_ptr(ptr, layout.align()) } }; - ptr as *mut Opaque + ptr as *mut u8 } #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { allocate_with_flags(layout, 0) } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { allocate_with_flags(layout, HEAP_ZERO_MEMORY) } #[inline] - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { if layout.align() <= MIN_ALIGN { let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID); debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); } else { - let header = get_header(ptr as *mut u8); + let header = get_header(ptr); let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID); debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); @@ -269,9 +266,9 @@ mod platform { } #[inline] - unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { if layout.align() <= MIN_ALIGN { - HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut Opaque + HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8 } else { self.realloc_fallback(ptr, layout, new_size) } @@ -300,7 +297,7 @@ mod platform { mod platform { extern crate dlmalloc; - use core::alloc::{GlobalAlloc, Layout, Opaque}; + use core::alloc::{GlobalAlloc, Layout}; use System; // No need for synchronization here as wasm is currently single-threaded @@ -309,23 +306,23 @@ mod platform { #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { - DLMALLOC.malloc(layout.size(), layout.align()) as *mut Opaque + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + DLMALLOC.malloc(layout.size(), layout.align()) } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { - DLMALLOC.calloc(layout.size(), layout.align()) as *mut Opaque + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + DLMALLOC.calloc(layout.size(), layout.align()) } #[inline] - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { - DLMALLOC.free(ptr as *mut u8, layout.size(), layout.align()) + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + DLMALLOC.free(ptr, layout.size(), layout.align()) } #[inline] - unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { - DLMALLOC.realloc(ptr as *mut u8, layout.size(), layout.align(), new_size) as *mut Opaque + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) } } } diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 229758803c8..2815ef6400d 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -22,30 +22,13 @@ use usize; use ptr::{self, NonNull}; use num::NonZeroUsize; -extern { - /// An opaque, unsized type. Used for pointers to allocated memory. - /// - /// This type can only be used behind a pointer like `*mut Opaque` or `ptr::NonNull`. - /// Such pointers are similar to C’s `void*` type. - pub type Opaque; -} - -impl Opaque { - /// Similar to `std::ptr::null`, which requires `T: Sized`. - pub fn null() -> *const Self { - 0 as _ - } - - /// Similar to `std::ptr::null_mut`, which requires `T: Sized`. - pub fn null_mut() -> *mut Self { - 0 as _ - } -} +#[cfg(stage0)] +pub type Opaque = u8; /// Represents the combination of a starting address and /// a total capacity of the returned block. #[derive(Debug)] -pub struct Excess(pub NonNull, pub usize); +pub struct Excess(pub NonNull, pub usize); fn size_align() -> (usize, usize) { (mem::size_of::(), mem::align_of::()) @@ -417,7 +400,7 @@ pub unsafe trait GlobalAlloc { /// # Safety /// /// **FIXME:** what are the exact requirements? - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque; + unsafe fn alloc(&self, layout: Layout) -> *mut u8; /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`. /// @@ -425,13 +408,13 @@ pub unsafe trait GlobalAlloc { /// /// **FIXME:** what are the exact requirements? /// In particular around layout *fit*. (See docs for the `Alloc` trait.) - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout); + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout); - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { let size = layout.size(); let ptr = self.alloc(layout); if !ptr.is_null() { - ptr::write_bytes(ptr as *mut u8, 0, size); + ptr::write_bytes(ptr, 0, size); } ptr } @@ -452,13 +435,13 @@ pub unsafe trait GlobalAlloc { /// /// **FIXME:** what are the exact requirements? /// In particular around layout *fit*. (See docs for the `Alloc` trait.) - unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let new_ptr = self.alloc(new_layout); if !new_ptr.is_null() { ptr::copy_nonoverlapping( - ptr as *const u8, - new_ptr as *mut u8, + ptr, + new_ptr, cmp::min(layout.size(), new_size), ); self.dealloc(ptr, layout); @@ -598,7 +581,7 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; /// Deallocate the memory referenced by `ptr`. /// @@ -615,7 +598,7 @@ pub unsafe trait Alloc { /// * In addition to fitting the block of memory `layout`, the /// alignment of the `layout` must match the alignment used /// to allocate that block of memory. - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS == // usable_size @@ -707,9 +690,9 @@ pub unsafe trait Alloc { /// reallocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, - new_size: usize) -> Result, AllocErr> { + new_size: usize) -> Result, AllocErr> { let old_size = layout.size(); if new_size >= old_size { @@ -726,8 +709,8 @@ pub unsafe trait Alloc { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let result = self.alloc(new_layout); if let Ok(new_ptr) = result { - ptr::copy_nonoverlapping(ptr.as_ptr() as *const u8, - new_ptr.as_ptr() as *mut u8, + ptr::copy_nonoverlapping(ptr.as_ptr(), + new_ptr.as_ptr(), cmp::min(old_size, new_size)); self.dealloc(ptr, layout); } @@ -750,11 +733,11 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); let p = self.alloc(layout); if let Ok(p) = p { - ptr::write_bytes(p.as_ptr() as *mut u8, 0, size); + ptr::write_bytes(p.as_ptr(), 0, size); } p } @@ -799,7 +782,7 @@ pub unsafe trait Alloc { /// reallocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. unsafe fn realloc_excess(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) -> Result { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); @@ -844,7 +827,7 @@ pub unsafe trait Alloc { /// `grow_in_place` failures without aborting, or to fall back on /// another reallocation method before resorting to an abort. unsafe fn grow_in_place(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. @@ -899,7 +882,7 @@ pub unsafe trait Alloc { /// `shrink_in_place` failures without aborting, or to fall back /// on another reallocation method before resorting to an abort. unsafe fn shrink_in_place(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. @@ -978,7 +961,7 @@ pub unsafe trait Alloc { { let k = Layout::new::(); if k.size() > 0 { - self.dealloc(ptr.as_opaque(), k); + self.dealloc(ptr.cast(), k); } } @@ -1066,7 +1049,7 @@ pub unsafe trait Alloc { match (Layout::array::(n_old), Layout::array::(n_new)) { (Ok(ref k_old), Ok(ref k_new)) if k_old.size() > 0 && k_new.size() > 0 => { debug_assert!(k_old.align() == k_new.align()); - self.realloc(ptr.as_opaque(), k_old.clone(), k_new.size()).map(NonNull::cast) + self.realloc(ptr.cast(), k_old.clone(), k_new.size()).map(NonNull::cast) } _ => { Err(AllocErr) @@ -1099,7 +1082,7 @@ pub unsafe trait Alloc { { match Layout::array::(n) { Ok(ref k) if k.size() > 0 => { - Ok(self.dealloc(ptr.as_opaque(), k.clone())) + Ok(self.dealloc(ptr.cast(), k.clone())) } _ => { Err(AllocErr) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 39315d8f0c8..81a8b3ef047 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2922,14 +2922,6 @@ impl NonNull { NonNull::new_unchecked(self.as_ptr() as *mut U) } } - - /// Cast to an `Opaque` pointer - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn as_opaque(self) -> NonNull<::alloc::Opaque> { - unsafe { - NonNull::new_unchecked(self.as_ptr() as _) - } - } } #[stable(feature = "nonnull", since = "1.25.0")] diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 497d5fdcac7..ec0676259ef 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -237,7 +237,7 @@ impl<'a> AllocFnFactory<'a> { let ident = ident(); args.push(self.cx.arg(self.span, ident, self.ptr_u8())); let arg = self.cx.expr_ident(self.span, ident); - self.cx.expr_cast(self.span, arg, self.ptr_opaque()) + self.cx.expr_cast(self.span, arg, self.ptr_u8()) } AllocatorTy::Usize => { @@ -281,17 +281,4 @@ impl<'a> AllocFnFactory<'a> { let ty_u8 = self.cx.ty_path(u8); self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable) } - - fn ptr_opaque(&self) -> P { - let opaque = self.cx.path( - self.span, - vec![ - self.core, - Ident::from_str("alloc"), - Ident::from_str("Opaque"), - ], - ); - let ty_opaque = self.cx.ty_path(opaque); - self.cx.ty_ptr(self.span, ty_opaque, Mutability::Mutable) - } } diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 3b1a3a439e7..ac7da5e9dba 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -74,7 +74,7 @@ pub extern fn rust_oom(layout: Layout) -> ! { #[doc(hidden)] #[allow(unused_attributes)] pub mod __default_lib_allocator { - use super::{System, Layout, GlobalAlloc, Opaque}; + use super::{System, Layout, GlobalAlloc}; // for symbol names src/librustc/middle/allocator.rs // for signatures src/librustc_allocator/lib.rs @@ -85,7 +85,7 @@ pub mod __default_lib_allocator { #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 { let layout = Layout::from_size_align_unchecked(size, align); - System.alloc(layout) as *mut u8 + System.alloc(layout) } #[no_mangle] @@ -93,7 +93,7 @@ pub mod __default_lib_allocator { pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) { - System.dealloc(ptr as *mut Opaque, Layout::from_size_align_unchecked(size, align)) + System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) } #[no_mangle] @@ -103,13 +103,13 @@ pub mod __default_lib_allocator { align: usize, new_size: usize) -> *mut u8 { let old_layout = Layout::from_size_align_unchecked(old_size, align); - System.realloc(ptr as *mut Opaque, old_layout, new_size) as *mut u8 + System.realloc(ptr, old_layout, new_size) } #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 { let layout = Layout::from_size_align_unchecked(size, align); - System.alloc_zeroed(layout) as *mut u8 + System.alloc_zeroed(layout) } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index d997fb28d42..55f9f4f7cfe 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -1124,7 +1124,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { let (layout, _) = calculate_layout::(self.capacity()) .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); unsafe { - Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), layout); + Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).cast(), layout); // Remember how everything was allocated out of one buffer // during initialization? We only need one call to free here. } diff --git a/src/test/run-make-fulldeps/std-core-cycle/bar.rs b/src/test/run-make-fulldeps/std-core-cycle/bar.rs index 62fd2ade1ca..4b885e5e2bb 100644 --- a/src/test/run-make-fulldeps/std-core-cycle/bar.rs +++ b/src/test/run-make-fulldeps/std-core-cycle/bar.rs @@ -16,11 +16,11 @@ use std::alloc::*; pub struct A; unsafe impl GlobalAlloc for A { - unsafe fn alloc(&self, _: Layout) -> *mut Opaque { + unsafe fn alloc(&self, _: Layout) -> *mut u8 { loop {} } - unsafe fn dealloc(&self, _ptr: *mut Opaque, _: Layout) { + unsafe fn dealloc(&self, _ptr: *mut u8, _: Layout) { loop {} } } diff --git a/src/test/run-pass/allocator/auxiliary/custom.rs b/src/test/run-pass/allocator/auxiliary/custom.rs index 91f70aa83e8..02e86fa19f8 100644 --- a/src/test/run-pass/allocator/auxiliary/custom.rs +++ b/src/test/run-pass/allocator/auxiliary/custom.rs @@ -13,18 +13,18 @@ #![feature(heap_api, allocator_api)] #![crate_type = "rlib"] -use std::alloc::{GlobalAlloc, System, Layout, Opaque}; +use std::alloc::{GlobalAlloc, System, Layout}; use std::sync::atomic::{AtomicUsize, Ordering}; pub struct A(pub AtomicUsize); unsafe impl GlobalAlloc for A { - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { self.0.fetch_add(1, Ordering::SeqCst); System.alloc(layout) } - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { self.0.fetch_add(1, Ordering::SeqCst); System.dealloc(ptr, layout) } diff --git a/src/test/run-pass/allocator/custom.rs b/src/test/run-pass/allocator/custom.rs index 415d39a593e..5da13bd4cb9 100644 --- a/src/test/run-pass/allocator/custom.rs +++ b/src/test/run-pass/allocator/custom.rs @@ -15,7 +15,7 @@ extern crate helper; -use std::alloc::{self, Global, Alloc, System, Layout, Opaque}; +use std::alloc::{self, Global, Alloc, System, Layout}; use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; static HITS: AtomicUsize = ATOMIC_USIZE_INIT; @@ -23,12 +23,12 @@ static HITS: AtomicUsize = ATOMIC_USIZE_INIT; struct A; unsafe impl alloc::GlobalAlloc for A { - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { HITS.fetch_add(1, Ordering::SeqCst); System.alloc(layout) } - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { HITS.fetch_add(1, Ordering::SeqCst); System.dealloc(ptr, layout) } diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index febd249d776..355053858cc 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -64,7 +64,7 @@ unsafe fn test_triangle() -> bool { println!("deallocate({:?}, {:?}", ptr, layout); } - Global.dealloc(NonNull::new_unchecked(ptr).as_opaque(), layout); + Global.dealloc(NonNull::new_unchecked(ptr).cast(), layout); } unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 { @@ -72,7 +72,7 @@ unsafe fn test_triangle() -> bool { println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new); } - let ret = Global.realloc(NonNull::new_unchecked(ptr).as_opaque(), old, new.size()) + let ret = Global.realloc(NonNull::new_unchecked(ptr).cast(), old, new.size()) .unwrap_or_else(|_| oom(Layout::from_size_align_unchecked(new.size(), old.align()))); if PRINT { -- cgit 1.4.1-3-g733a5 From 8c30c5168694b8ee740dade3a0145eef8aba66c6 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 30 May 2018 20:46:59 +0200 Subject: Remove deprecated heap modules The heap.rs file was already unused. --- src/liballoc/heap.rs | 110 ------------------------------------------ src/liballoc/lib.rs | 8 --- src/libcore/lib.rs | 7 --- src/libstd/collections/mod.rs | 2 +- src/libstd/error.rs | 2 +- src/libstd/lib.rs | 7 --- 6 files changed, 2 insertions(+), 134 deletions(-) delete mode 100644 src/liballoc/heap.rs (limited to 'src/libcore') diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs deleted file mode 100644 index 5ea37ceeb2b..00000000000 --- a/src/liballoc/heap.rs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(deprecated)] - -pub use alloc::{Layout, AllocErr, CannotReallocInPlace}; -use core::alloc::Alloc as CoreAlloc; -use core::ptr::NonNull; - -#[doc(hidden)] -pub mod __core { - pub use core::*; -} - -#[derive(Debug)] -pub struct Excess(pub *mut u8, pub usize); - -/// Compatibility with older versions of #[global_allocator] during bootstrap -pub unsafe trait Alloc { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); - fn oom(&mut self, err: AllocErr) -> !; - fn usable_size(&self, layout: &Layout) -> (usize, usize); - unsafe fn realloc(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr>; - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; - unsafe fn alloc_excess(&mut self, layout: Layout) -> Result; - unsafe fn realloc_excess(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result; - unsafe fn grow_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace>; - unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace>; -} - -unsafe impl Alloc for T where T: CoreAlloc { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - CoreAlloc::alloc(self, layout).map(|ptr| ptr.cast().as_ptr()) - } - - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - let ptr = NonNull::new_unchecked(ptr); - CoreAlloc::dealloc(self, ptr, layout) - } - - fn oom(&mut self, _: AllocErr) -> ! { - unsafe { ::core::intrinsics::abort() } - } - - fn usable_size(&self, layout: &Layout) -> (usize, usize) { - CoreAlloc::usable_size(self, layout) - } - - unsafe fn realloc(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - let ptr = NonNull::new_unchecked(ptr); - CoreAlloc::realloc(self, ptr, layout, new_layout.size()).map(|ptr| ptr.cast().as_ptr()) - } - - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - CoreAlloc::alloc_zeroed(self, layout).map(|ptr| ptr.cast().as_ptr()) - } - - unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { - CoreAlloc::alloc_excess(self, layout) - .map(|e| Excess(e.0 .cast().as_ptr(), e.1)) - } - - unsafe fn realloc_excess(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result { - let ptr = NonNull::new_unchecked(ptr); - CoreAlloc::realloc_excess(self, ptr, layout, new_layout.size()) - .map(|e| Excess(e.0 .cast().as_ptr(), e.1)) - } - - unsafe fn grow_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let ptr = NonNull::new_unchecked(ptr); - CoreAlloc::grow_in_place(self, ptr, layout, new_layout.size()) - } - - unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let ptr = NonNull::new_unchecked(ptr); - CoreAlloc::shrink_in_place(self, ptr, layout, new_layout.size()) - } -} diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 242c7d2e70f..828461fe8d7 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -150,18 +150,10 @@ pub mod allocator { pub mod alloc; -#[unstable(feature = "allocator_api", issue = "32838")] -#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -/// Use the `alloc` module instead. -pub mod heap { - pub use alloc::*; -} - #[unstable(feature = "futures_api", reason = "futures in libcore are unstable", issue = "50547")] pub mod task; - // Primitive types using the heaps above // Need to conditionally define the mod from `boxed.rs` to avoid diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index a2ee0033872..5ba77edee6e 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -215,13 +215,6 @@ pub mod task; #[allow(missing_docs)] pub mod alloc; -#[unstable(feature = "allocator_api", issue = "32838")] -#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -/// Use the `alloc` module instead. -pub mod heap { - pub use alloc::*; -} - // note: does not need to be public mod iter_private; mod nonzero; diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index d8e79b97970..42113414183 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -438,7 +438,7 @@ pub use self::hash_map::HashMap; pub use self::hash_set::HashSet; #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub use heap::CollectionAllocErr; +pub use alloc::CollectionAllocErr; mod hash; diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 817eea5eaf1..3160485375f 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -23,13 +23,13 @@ // coherence challenge (e.g., specialization, neg impls, etc) we can // reconsider what crate these items belong in. +use alloc::{AllocErr, LayoutErr, CannotReallocInPlace}; use any::TypeId; use borrow::Cow; use cell; use char; use core::array; use fmt::{self, Debug, Display}; -use heap::{AllocErr, LayoutErr, CannotReallocInPlace}; use mem::transmute; use num; use str; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 4bf52224ae6..3972763a051 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -499,13 +499,6 @@ pub mod process; pub mod sync; pub mod time; -#[unstable(feature = "allocator_api", issue = "32838")] -#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -/// Use the `alloc` module instead. -pub mod heap { - pub use alloc::*; -} - // Platform-abstraction modules #[macro_use] mod sys_common; -- cgit 1.4.1-3-g733a5 From e9fd063edb4f6783fbd91a82a0f61626dacf8dad Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 31 May 2018 18:23:42 +0200 Subject: Document memory allocation APIs Add some docs where they were missing, attempt to fix them where they were out of date. --- src/liballoc/alloc.rs | 65 +++++++++++++ src/liballoc_system/lib.rs | 1 + src/libcore/alloc.rs | 227 +++++++++++++++++++++++++++++++++++---------- src/libstd/alloc.rs | 2 +- 4 files changed, 245 insertions(+), 50 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 710da9a475b..c9430a29e4c 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Memory allocation APIs + #![unstable(feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked \ slightly, especially to possibly take into account the \ @@ -37,27 +39,80 @@ extern "Rust" { fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; } +/// The global memory allocator. +/// +/// This type implements the [`Alloc`] trait by forwarding calls +/// to the allocator registered with the `#[global_allocator]` attribute +/// if there is one, or the `std` crate’s default. #[derive(Copy, Clone, Default, Debug)] pub struct Global; +/// Allocate memory with the global allocator. +/// +/// This function forwards calls to the [`GlobalAlloc::alloc`] method +/// of the allocator registered with the `#[global_allocator]` attribute +/// if there is one, or the `std` crate’s default. +/// +/// This function is expected to be deprecated in favor of the `alloc` method +/// of the [`Global`] type when it and the [`Alloc`] trait become stable. +/// +/// # Safety +/// +/// See [`GlobalAlloc::alloc`]. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub unsafe fn alloc(layout: Layout) -> *mut u8 { __rust_alloc(layout.size(), layout.align()) } +/// Deallocate memory with the global allocator. +/// +/// This function forwards calls to the [`GlobalAlloc::dealloc`] method +/// of the allocator registered with the `#[global_allocator]` attribute +/// if there is one, or the `std` crate’s default. +/// +/// This function is expected to be deprecated in favor of the `dealloc` method +/// of the [`Global`] type when it and the [`Alloc`] trait become stable. +/// +/// # Safety +/// +/// See [`GlobalAlloc::dealloc`]. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { __rust_dealloc(ptr, layout.size(), layout.align()) } +/// Reallocate memory with the global allocator. +/// +/// This function forwards calls to the [`GlobalAlloc::realloc`] method +/// of the allocator registered with the `#[global_allocator]` attribute +/// if there is one, or the `std` crate’s default. +/// +/// This function is expected to be deprecated in favor of the `realloc` method +/// of the [`Global`] type when it and the [`Alloc`] trait become stable. +/// +/// # Safety +/// +/// See [`GlobalAlloc::realloc`]. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } +/// Allocate zero-initialized memory with the global allocator. +/// +/// This function forwards calls to the [`GlobalAlloc::alloc_zeroed`] method +/// of the allocator registered with the `#[global_allocator]` attribute +/// if there is one, or the `std` crate’s default. +/// +/// This function is expected to be deprecated in favor of the `alloc_zeroed` method +/// of the [`Global`] type when it and the [`Alloc`] trait become stable. +/// +/// # Safety +/// +/// See [`GlobalAlloc::alloc_zeroed`]. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { @@ -123,6 +178,16 @@ pub(crate) unsafe fn box_free(ptr: Unique) { } } +/// Abort on memory allocation error or failure. +/// +/// Callers of memory allocation APIs wishing to abort computation +/// in response to an allocation error are encouraged to call this function, +/// rather than directly invoking `panic!` or similar. +/// +/// The default behavior of this function is to print a message to standard error +/// and abort the process. +/// It can be replaced with [`std::alloc::set_oom_hook`] +/// and [`std::alloc::take_oom_hook`]. #[rustc_allocator_nounwind] pub fn oom(layout: Layout) -> ! { #[allow(improper_ctypes)] diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 82fda8d639e..85bf43a5429 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -44,6 +44,7 @@ const MIN_ALIGN: usize = 16; use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout}; use core::ptr::NonNull; +/// The default memory allocator provided by the operating system. #[unstable(feature = "allocator_api", issue = "32838")] pub struct System; diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 2815ef6400d..8fcd8555cdc 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Memory allocation APIs + #![unstable(feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked \ slightly, especially to possibly take into account the \ @@ -315,8 +317,9 @@ impl Layout { } } -/// The parameters given to `Layout::from_size_align` do not satisfy -/// its documented constraints. +/// The parameters given to `Layout::from_size_align` +/// or some other `Layout` constructor +/// do not satisfy its documented constraints. #[derive(Clone, PartialEq, Eq, Debug)] pub struct LayoutErr { private: () @@ -329,8 +332,8 @@ impl fmt::Display for LayoutErr { } } -/// The `AllocErr` error specifies whether an allocation failure is -/// specifically due to resource exhaustion or if it is due to +/// The `AllocErr` error indicates an allocation failure +/// that may be due to resource exhaustion or to /// something wrong when combining the given input arguments with this /// allocator. #[derive(Clone, PartialEq, Eq, Debug)] @@ -346,6 +349,7 @@ impl fmt::Display for AllocErr { /// The `CannotReallocInPlace` error is used when `grow_in_place` or /// `shrink_in_place` were unable to reuse the given memory block for /// a requested layout. +// FIXME: should this be in libcore or liballoc? #[derive(Clone, PartialEq, Eq, Debug)] pub struct CannotReallocInPlace; @@ -363,6 +367,7 @@ impl fmt::Display for CannotReallocInPlace { } /// Augments `AllocErr` with a CapacityOverflow variant. +// FIXME: should this be in libcore or liballoc? #[derive(Clone, PartialEq, Eq, Debug)] #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] pub enum CollectionAllocErr { @@ -389,27 +394,125 @@ impl From for CollectionAllocErr { } } -/// A memory allocator that can be registered to be the one backing `std::alloc::Global` +/// A memory allocator that can be registered as the standard library’s default /// though the `#[global_allocator]` attributes. +/// +/// Some of the methods require that a memory block be *currently +/// allocated* via an allocator. This means that: +/// +/// * the starting address for that memory block was previously +/// returned by a previous call to an allocation method +/// such as `alloc`, and +/// +/// * the memory block has not been subsequently deallocated, where +/// blocks are deallocated either by being passed to a deallocation +/// method such as `dealloc` or by being +/// passed to a reallocation method that returns a non-null pointer. +/// +/// +/// # Example +/// +/// ```no_run +/// use std::alloc::{GlobalAlloc, Layout, alloc}; +/// use std::ptr::null_mut; +/// +/// struct MyAllocator; +/// +/// unsafe impl GlobalAlloc for MyAllocator { +/// unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() } +/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} +/// } +/// +/// #[global_allocator] +/// static A: MyAllocator = MyAllocator; +/// +/// fn main() { +/// unsafe { +/// assert!(alloc(Layout::new::()).is_null()) +/// } +/// } +/// ``` +/// +/// # Unsafety +/// +/// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and +/// implementors must ensure that they adhere to these contracts: +/// +/// * Pointers returned from allocation functions must point to valid memory and +/// retain their validity until at least the instance of `GlobalAlloc` is dropped +/// itself. +/// +/// * It's undefined behavior if global allocators unwind. This restriction may +/// be lifted in the future, but currently a panic from any of these +/// functions may lead to memory unsafety. +/// +/// * `Layout` queries and calculations in general must be correct. Callers of +/// this trait are allowed to rely on the contracts defined on each method, +/// and implementors must ensure such contracts remain true. pub unsafe trait GlobalAlloc { /// Allocate memory as described by the given `layout`. /// /// Returns a pointer to newly-allocated memory, - /// or NULL to indicate allocation failure. + /// or null to indicate allocation failure. /// /// # Safety /// - /// **FIXME:** what are the exact requirements? + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure that `layout` has non-zero size. + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// The allocated block of memory may or may not be initialized. + /// + /// # Errors + /// + /// Returning a null pointer indicates that either memory is exhausted + /// or `layout` does not meet allocator's size or alignment constraints. + /// + /// Implementations are encouraged to return null on memory + /// exhaustion rather than aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. unsafe fn alloc(&self, layout: Layout) -> *mut u8; /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`. /// /// # Safety /// - /// **FIXME:** what are the exact requirements? - /// In particular around layout *fit*. (See docs for the `Alloc` trait.) + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must denote a block of memory currently allocated via + /// this allocator, + /// + /// * `layout` must be the same layout that was used + /// to allocated that block of memory, unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout); + /// Behaves like `alloc`, but also ensures that the contents + /// are set to zero before being returned. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `alloc` is. + /// However the allocated block of memory is guaranteed to be initialized. + /// + /// # Errors + /// + /// Returning a null pointer indicates that either memory is exhausted + /// or `layout` does not meet allocator's size or alignment constraints, + /// just as in `alloc`. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { let size = layout.size(); let ptr = self.alloc(layout); @@ -422,19 +525,51 @@ pub unsafe trait GlobalAlloc { /// Shink or grow a block of memory to the given `new_size`. /// The block is described by the given `ptr` pointer and `layout`. /// - /// Return a new pointer (which may or may not be the same as `ptr`), - /// or NULL to indicate reallocation failure. + /// If this returns a non-null pointer, then ownership of the memory block + /// referenced by `ptr` has been transferred to this alloctor. + /// The memory may or may not have been deallocated, + /// and should be considered unusable (unless of course it was + /// transferred back to the caller again via the return value of + /// this method). /// - /// If reallocation is successful, the old `ptr` pointer is considered - /// to have been deallocated. + /// If this method returns null, then ownership of the memory + /// block has not been transferred to this allocator, and the + /// contents of the memory block are unaltered. /// /// # Safety /// - /// `new_size`, when rounded up to the nearest multiple of `old_layout.align()`, - /// must not overflow (i.e. the rounded value must be less than `usize::MAX`). + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must be the same layout that was used + /// to allocated that block of memory, + /// + /// * `new_size` must be greater than zero. + /// + /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, + /// must not overflow (i.e. the rounded value must be less than `usize::MAX`). + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// # Errors + /// + /// Returns null if the new layout does not meet the size + /// and alignment constraints of the allocator, or if reallocation + /// otherwise fails. + /// + /// Implementations are encouraged to return null on memory + /// exhaustion rather than panicking or aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) /// - /// **FIXME:** what are the exact requirements? - /// In particular around layout *fit*. (See docs for the `Alloc` trait.) + /// Clients wishing to abort computation in response to a + /// reallocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let new_ptr = self.alloc(new_layout); @@ -523,27 +658,21 @@ pub unsafe trait GlobalAlloc { /// retain their validity until at least the instance of `Alloc` is dropped /// itself. /// -/// * It's undefined behavior if global allocators unwind. This restriction may -/// be lifted in the future, but currently a panic from any of these -/// functions may lead to memory unsafety. Note that as of the time of this -/// writing allocators *not* intending to be global allocators can still panic -/// in their implementation without violating memory safety. -/// /// * `Layout` queries and calculations in general must be correct. Callers of /// this trait are allowed to rely on the contracts defined on each method, /// and implementors must ensure such contracts remain true. /// /// Note that this list may get tweaked over time as clarifications are made in -/// the future. Additionally global allocators may gain unique requirements for -/// how to safely implement one in the future as well. +/// the future. pub unsafe trait Alloc { - // (Note: existing allocators have unspecified but well-defined + // (Note: some existing allocators have unspecified but well-defined // behavior in response to a zero size allocation request ; // e.g. in C, `malloc` of 0 will either return a null pointer or a // unique pointer, but will not have arbitrary undefined - // behavior. Rust should consider revising the alloc::heap crate - // to reflect this reality.) + // behavior. + // However in jemalloc for example, + // `mallocx(0)` is documented as undefined behavior.) /// Returns a pointer meeting the size and alignment guarantees of /// `layout`. @@ -579,8 +708,8 @@ pub unsafe trait Alloc { /// library that aborts on memory exhaustion.) /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// allocation error are encouraged to call the `oom` function, + /// rather than directly invoking `panic!` or similar. unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; /// Deallocate the memory referenced by `ptr`. @@ -686,9 +815,9 @@ pub unsafe trait Alloc { /// implement this trait atop an underlying native allocation /// library that aborts on memory exhaustion.) /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// Clients wishing to abort computation in response to a + /// reallocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. unsafe fn realloc(&mut self, ptr: NonNull, layout: Layout, @@ -731,8 +860,8 @@ pub unsafe trait Alloc { /// constraints, just as in `alloc`. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// allocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); let p = self.alloc(layout); @@ -757,8 +886,8 @@ pub unsafe trait Alloc { /// constraints, just as in `alloc`. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// allocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { let usable_size = self.usable_size(&layout); self.alloc(layout).map(|p| Excess(p, usable_size.1)) @@ -778,9 +907,9 @@ pub unsafe trait Alloc { /// `layout` does not meet allocator's size or alignment /// constraints, just as in `realloc`. /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// Clients wishing to abort computation in response to a + /// reallocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. unsafe fn realloc_excess(&mut self, ptr: NonNull, layout: Layout, @@ -823,7 +952,7 @@ pub unsafe trait Alloc { /// could fit `layout`. /// /// Note that one cannot pass `CannotReallocInPlace` to the `oom` - /// method; clients are expected either to be able to recover from + /// function; clients are expected either to be able to recover from /// `grow_in_place` failures without aborting, or to fall back on /// another reallocation method before resorting to an abort. unsafe fn grow_in_place(&mut self, @@ -878,7 +1007,7 @@ pub unsafe trait Alloc { /// could fit `layout`. /// /// Note that one cannot pass `CannotReallocInPlace` to the `oom` - /// method; clients are expected either to be able to recover from + /// function; clients are expected either to be able to recover from /// `shrink_in_place` failures without aborting, or to fall back /// on another reallocation method before resorting to an abort. unsafe fn shrink_in_place(&mut self, @@ -926,8 +1055,8 @@ pub unsafe trait Alloc { /// will *not* yield undefined behavior. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// allocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. fn alloc_one(&mut self) -> Result, AllocErr> where Self: Sized { @@ -993,8 +1122,8 @@ pub unsafe trait Alloc { /// Always returns `Err` on arithmetic overflow. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// allocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. fn alloc_array(&mut self, n: usize) -> Result, AllocErr> where Self: Sized { @@ -1037,9 +1166,9 @@ pub unsafe trait Alloc { /// /// Always returns `Err` on arithmetic overflow. /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// Clients wishing to abort computation in response to a + /// reallocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. unsafe fn realloc_array(&mut self, ptr: NonNull, n_old: usize, diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 9904634f1fa..9126155a7c9 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! dox +//! Memory allocation APIs #![unstable(issue = "32838", feature = "allocator_api")] -- cgit 1.4.1-3-g733a5 From 951bc28fd09f5fed793021c6be1645e034394491 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 31 May 2018 18:36:51 +0200 Subject: Stablize the alloc module without changing stability of its contents. --- src/liballoc/alloc.rs | 11 ++++----- src/libcore/alloc.rs | 32 +++++++++++++++++++++----- src/libstd/alloc.rs | 19 ++++++++++----- src/test/compile-fail/lint-stability-fields.rs | 7 ++++++ 4 files changed, 51 insertions(+), 18 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index c9430a29e4c..fc3d0151ec0 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -10,17 +10,13 @@ //! Memory allocation APIs -#![unstable(feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked \ - slightly, especially to possibly take into account the \ - types being stored to make room for a future \ - tracing garbage collector", - issue = "32838")] +#![stable(feature = "alloc_module", since = "1.28.0")] use core::intrinsics::{min_align_of_val, size_of_val}; use core::ptr::{NonNull, Unique}; use core::usize; +#[stable(feature = "alloc_module", since = "1.28.0")] #[doc(inline)] pub use core::alloc::*; @@ -44,6 +40,7 @@ extern "Rust" { /// This type implements the [`Alloc`] trait by forwarding calls /// to the allocator registered with the `#[global_allocator]` attribute /// if there is one, or the `std` crate’s default. +#[unstable(feature = "allocator_api", issue = "32838")] #[derive(Copy, Clone, Default, Debug)] pub struct Global; @@ -119,6 +116,7 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { __rust_alloc_zeroed(layout.size(), layout.align()) } +#[unstable(feature = "allocator_api", issue = "32838")] unsafe impl Alloc for Global { #[inline] unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { @@ -188,6 +186,7 @@ pub(crate) unsafe fn box_free(ptr: Unique) { /// and abort the process. /// It can be replaced with [`std::alloc::set_oom_hook`] /// and [`std::alloc::take_oom_hook`]. +#[unstable(feature = "allocator_api", issue = "32838")] #[rustc_allocator_nounwind] pub fn oom(layout: Layout) -> ! { #[allow(improper_ctypes)] diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 8fcd8555cdc..ae9f77d35cf 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -10,12 +10,7 @@ //! Memory allocation APIs -#![unstable(feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked \ - slightly, especially to possibly take into account the \ - types being stored to make room for a future \ - tracing garbage collector", - issue = "32838")] +#![stable(feature = "alloc_module", since = "1.28.0")] use cmp; use fmt; @@ -24,11 +19,13 @@ use usize; use ptr::{self, NonNull}; use num::NonZeroUsize; +#[unstable(feature = "allocator_api", issue = "32838")] #[cfg(stage0)] pub type Opaque = u8; /// Represents the combination of a starting address and /// a total capacity of the returned block. +#[unstable(feature = "allocator_api", issue = "32838")] #[derive(Debug)] pub struct Excess(pub NonNull, pub usize); @@ -49,6 +46,7 @@ fn size_align() -> (usize, usize) { /// requests have positive size. A caller to the `Alloc::alloc` /// method must either ensure that conditions like this are met, or /// use specific allocators with looser requirements.) +#[unstable(feature = "allocator_api", issue = "32838")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Layout { // size of the requested block of memory, measured in bytes. @@ -74,6 +72,7 @@ impl Layout { /// * `size`, when rounded up to the nearest multiple of `align`, /// must not overflow (i.e. the rounded value must be less than /// `usize::MAX`). + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn from_size_align(size: usize, align: usize) -> Result { if !align.is_power_of_two() { @@ -109,20 +108,24 @@ impl Layout { /// /// This function is unsafe as it does not verify the preconditions from /// [`Layout::from_size_align`](#method.from_size_align). + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) } } /// The minimum size in bytes for a memory block of this layout. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn size(&self) -> usize { self.size_ } /// The minimum byte alignment for a memory block of this layout. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn align(&self) -> usize { self.align_.get() } /// Constructs a `Layout` suitable for holding a value of type `T`. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn new() -> Self { let (size, align) = size_align::(); @@ -139,6 +142,7 @@ impl Layout { /// Produces layout describing a record that could be used to /// allocate backing structure for `T` (which could be a trait /// or other unsized type like a slice). + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn for_value(t: &T) -> Self { let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); @@ -166,6 +170,7 @@ impl Layout { /// Panics if the combination of `self.size()` and the given `align` /// violates the conditions listed in /// [`Layout::from_size_align`](#method.from_size_align). + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn align_to(&self, align: usize) -> Self { Layout::from_size_align(self.size(), cmp::max(self.align(), align)).unwrap() @@ -187,6 +192,7 @@ impl Layout { /// to be less than or equal to the alignment of the starting /// address for the whole allocated block of memory. One way to /// satisfy this constraint is to ensure `align <= self.align()`. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn padding_needed_for(&self, align: usize) -> usize { let len = self.size(); @@ -223,6 +229,7 @@ impl Layout { /// of each element in the array. /// /// On arithmetic overflow, returns `LayoutErr`. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> { let padded_size = self.size().checked_add(self.padding_needed_for(self.align())) @@ -248,6 +255,7 @@ impl Layout { /// (assuming that the record itself starts at offset 0). /// /// On arithmetic overflow, returns `LayoutErr`. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> { let new_align = cmp::max(self.align(), next.align()); @@ -274,6 +282,7 @@ impl Layout { /// aligned. /// /// On arithmetic overflow, returns `LayoutErr`. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn repeat_packed(&self, n: usize) -> Result { let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?; @@ -295,6 +304,7 @@ impl Layout { /// `extend`.) /// /// On arithmetic overflow, returns `LayoutErr`. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn extend_packed(&self, next: Self) -> Result<(Self, usize), LayoutErr> { let new_size = self.size().checked_add(next.size()) @@ -306,6 +316,7 @@ impl Layout { /// Creates a layout describing the record for a `[T; n]`. /// /// On arithmetic overflow, returns `LayoutErr`. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn array(n: usize) -> Result { Layout::new::() @@ -320,12 +331,14 @@ impl Layout { /// The parameters given to `Layout::from_size_align` /// or some other `Layout` constructor /// do not satisfy its documented constraints. +#[unstable(feature = "allocator_api", issue = "32838")] #[derive(Clone, PartialEq, Eq, Debug)] pub struct LayoutErr { private: () } // (we need this for downstream impl of trait Error) +#[unstable(feature = "allocator_api", issue = "32838")] impl fmt::Display for LayoutErr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("invalid parameters to Layout::from_size_align") @@ -336,10 +349,12 @@ impl fmt::Display for LayoutErr { /// that may be due to resource exhaustion or to /// something wrong when combining the given input arguments with this /// allocator. +#[unstable(feature = "allocator_api", issue = "32838")] #[derive(Clone, PartialEq, Eq, Debug)] pub struct AllocErr; // (we need this for downstream impl of trait Error) +#[unstable(feature = "allocator_api", issue = "32838")] impl fmt::Display for AllocErr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("memory allocation failed") @@ -350,9 +365,11 @@ impl fmt::Display for AllocErr { /// `shrink_in_place` were unable to reuse the given memory block for /// a requested layout. // FIXME: should this be in libcore or liballoc? +#[unstable(feature = "allocator_api", issue = "32838")] #[derive(Clone, PartialEq, Eq, Debug)] pub struct CannotReallocInPlace; +#[unstable(feature = "allocator_api", issue = "32838")] impl CannotReallocInPlace { pub fn description(&self) -> &str { "cannot reallocate allocator's memory in place" @@ -360,6 +377,7 @@ impl CannotReallocInPlace { } // (we need this for downstream impl of trait Error) +#[unstable(feature = "allocator_api", issue = "32838")] impl fmt::Display for CannotReallocInPlace { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) @@ -449,6 +467,7 @@ impl From for CollectionAllocErr { /// * `Layout` queries and calculations in general must be correct. Callers of /// this trait are allowed to rely on the contracts defined on each method, /// and implementors must ensure such contracts remain true. +#[unstable(feature = "allocator_api", issue = "32838")] pub unsafe trait GlobalAlloc { /// Allocate memory as described by the given `layout`. /// @@ -664,6 +683,7 @@ pub unsafe trait GlobalAlloc { /// /// Note that this list may get tweaked over time as clarifications are made in /// the future. +#[unstable(feature = "allocator_api", issue = "32838")] pub unsafe trait Alloc { // (Note: some existing allocators have unspecified but well-defined diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 9126155a7c9..1a4869f87c9 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -10,17 +10,20 @@ //! Memory allocation APIs -#![unstable(issue = "32838", feature = "allocator_api")] - -#[doc(inline)] pub use alloc_crate::alloc::{Global, Layout, oom}; -#[doc(inline)] pub use alloc_crate::alloc::{alloc, alloc_zeroed, dealloc, realloc}; -#[doc(inline)] pub use alloc_system::System; -#[doc(inline)] pub use core::alloc::*; +#![stable(feature = "alloc_module", since = "1.28.0")] use core::sync::atomic::{AtomicPtr, Ordering}; use core::{mem, ptr}; use sys_common::util::dumb_print; +#[stable(feature = "alloc_module", since = "1.28.0")] +#[doc(inline)] +pub use alloc_crate::alloc::*; + +#[unstable(feature = "allocator_api", issue = "32838")] +#[doc(inline)] +pub use alloc_system::System; + static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); /// Registers a custom OOM hook, replacing any that was previously registered. @@ -34,6 +37,7 @@ static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); /// about the allocation that failed. /// /// The OOM hook is a global resource. +#[unstable(feature = "allocator_api", issue = "32838")] pub fn set_oom_hook(hook: fn(Layout)) { HOOK.store(hook as *mut (), Ordering::SeqCst); } @@ -43,6 +47,7 @@ pub fn set_oom_hook(hook: fn(Layout)) { /// *See also the function [`set_oom_hook`].* /// /// If no custom hook is registered, the default hook will be returned. +#[unstable(feature = "allocator_api", issue = "32838")] pub fn take_oom_hook() -> fn(Layout) { let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); if hook.is_null() { @@ -59,6 +64,7 @@ fn default_oom_hook(layout: Layout) { #[cfg(not(test))] #[doc(hidden)] #[lang = "oom"] +#[unstable(feature = "allocator_api", issue = "32838")] pub extern fn rust_oom(layout: Layout) -> ! { let hook = HOOK.load(Ordering::SeqCst); let hook: fn(Layout) = if hook.is_null() { @@ -73,6 +79,7 @@ pub extern fn rust_oom(layout: Layout) -> ! { #[cfg(not(test))] #[doc(hidden)] #[allow(unused_attributes)] +#[unstable(feature = "allocator_api", issue = "32838")] pub mod __default_lib_allocator { use super::{System, Layout, GlobalAlloc}; // for symbol names src/librustc/middle/allocator.rs diff --git a/src/test/compile-fail/lint-stability-fields.rs b/src/test/compile-fail/lint-stability-fields.rs index 1b605bdb893..b1b1a9a1fbf 100644 --- a/src/test/compile-fail/lint-stability-fields.rs +++ b/src/test/compile-fail/lint-stability-fields.rs @@ -18,6 +18,11 @@ mod cross_crate { extern crate lint_stability_fields; + mod reexport { + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::lint_stability_fields::*; + } + use self::lint_stability_fields::*; pub fn foo() { @@ -73,6 +78,8 @@ mod cross_crate { // the patterns are all fine: { .. } = x; + // Unstable items are still unstable even when used through a stable "pub use". + let x = reexport::Unstable2(1, 2, 3); //~ ERROR use of unstable let x = Unstable2(1, 2, 3); //~ ERROR use of unstable -- cgit 1.4.1-3-g733a5 From 75e17da87358751becc950b9319f5d4aa82744ce Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 31 May 2018 18:38:39 +0200 Subject: Mark as permanently-unstable some implementation details --- src/libcore/alloc.rs | 2 +- src/libstd/alloc.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index ae9f77d35cf..97ad55304be 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -19,7 +19,7 @@ use usize; use ptr::{self, NonNull}; use num::NonZeroUsize; -#[unstable(feature = "allocator_api", issue = "32838")] +#[unstable(feature = "alloc_internals", issue = "0")] #[cfg(stage0)] pub type Opaque = u8; diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 1a4869f87c9..55325006e74 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -64,7 +64,7 @@ fn default_oom_hook(layout: Layout) { #[cfg(not(test))] #[doc(hidden)] #[lang = "oom"] -#[unstable(feature = "allocator_api", issue = "32838")] +#[unstable(feature = "alloc_internals", issue = "0")] pub extern fn rust_oom(layout: Layout) -> ! { let hook = HOOK.load(Ordering::SeqCst); let hook: fn(Layout) = if hook.is_null() { @@ -79,7 +79,7 @@ pub extern fn rust_oom(layout: Layout) -> ! { #[cfg(not(test))] #[doc(hidden)] #[allow(unused_attributes)] -#[unstable(feature = "allocator_api", issue = "32838")] +#[unstable(feature = "alloc_internals", issue = "0")] pub mod __default_lib_allocator { use super::{System, Layout, GlobalAlloc}; // for symbol names src/librustc/middle/allocator.rs -- cgit 1.4.1-3-g733a5 From 77606f20c92518c16d68bf16c0a117af1e925524 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 31 May 2018 19:10:08 +0200 Subject: Stabilize alloc::Layout (with only some of its methods) --- src/libcore/alloc.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 97ad55304be..a65a06d0c89 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -46,7 +46,7 @@ fn size_align() -> (usize, usize) { /// requests have positive size. A caller to the `Alloc::alloc` /// method must either ensure that conditions like this are met, or /// use specific allocators with looser requirements.) -#[unstable(feature = "allocator_api", issue = "32838")] +#[stable(feature = "alloc_layout", since = "1.28.0")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Layout { // size of the requested block of memory, measured in bytes. @@ -72,7 +72,7 @@ impl Layout { /// * `size`, when rounded up to the nearest multiple of `align`, /// must not overflow (i.e. the rounded value must be less than /// `usize::MAX`). - #[unstable(feature = "allocator_api", issue = "32838")] + #[stable(feature = "alloc_layout", since = "1.28.0")] #[inline] pub fn from_size_align(size: usize, align: usize) -> Result { if !align.is_power_of_two() { @@ -108,24 +108,24 @@ impl Layout { /// /// This function is unsafe as it does not verify the preconditions from /// [`Layout::from_size_align`](#method.from_size_align). - #[unstable(feature = "allocator_api", issue = "32838")] + #[stable(feature = "alloc_layout", since = "1.28.0")] #[inline] pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) } } /// The minimum size in bytes for a memory block of this layout. - #[unstable(feature = "allocator_api", issue = "32838")] + #[stable(feature = "alloc_layout", since = "1.28.0")] #[inline] pub fn size(&self) -> usize { self.size_ } /// The minimum byte alignment for a memory block of this layout. - #[unstable(feature = "allocator_api", issue = "32838")] + #[stable(feature = "alloc_layout", since = "1.28.0")] #[inline] pub fn align(&self) -> usize { self.align_.get() } /// Constructs a `Layout` suitable for holding a value of type `T`. - #[unstable(feature = "allocator_api", issue = "32838")] + #[stable(feature = "alloc_layout", since = "1.28.0")] #[inline] pub fn new() -> Self { let (size, align) = size_align::(); @@ -142,7 +142,7 @@ impl Layout { /// Produces layout describing a record that could be used to /// allocate backing structure for `T` (which could be a trait /// or other unsized type like a slice). - #[unstable(feature = "allocator_api", issue = "32838")] + #[stable(feature = "alloc_layout", since = "1.28.0")] #[inline] pub fn for_value(t: &T) -> Self { let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); @@ -331,14 +331,14 @@ impl Layout { /// The parameters given to `Layout::from_size_align` /// or some other `Layout` constructor /// do not satisfy its documented constraints. -#[unstable(feature = "allocator_api", issue = "32838")] +#[stable(feature = "alloc_layout", since = "1.28.0")] #[derive(Clone, PartialEq, Eq, Debug)] pub struct LayoutErr { private: () } // (we need this for downstream impl of trait Error) -#[unstable(feature = "allocator_api", issue = "32838")] +#[stable(feature = "alloc_layout", since = "1.28.0")] impl fmt::Display for LayoutErr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("invalid parameters to Layout::from_size_align") -- cgit 1.4.1-3-g733a5 From bbaff036e7acef9f5b6bfdcb6339bfc6fa7ecfcf Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 31 May 2018 19:13:18 +0200 Subject: Stablize the GlobalAlloc trait Fixes https://github.com/rust-lang/rust/issues/49668 --- src/libcore/alloc.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index a65a06d0c89..9c324cdb4ed 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -467,7 +467,7 @@ impl From for CollectionAllocErr { /// * `Layout` queries and calculations in general must be correct. Callers of /// this trait are allowed to rely on the contracts defined on each method, /// and implementors must ensure such contracts remain true. -#[unstable(feature = "allocator_api", issue = "32838")] +#[stable(feature = "global_alloc", since = "1.28.0")] pub unsafe trait GlobalAlloc { /// Allocate memory as described by the given `layout`. /// @@ -499,6 +499,7 @@ pub unsafe trait GlobalAlloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the [`oom`] function, /// rather than directly invoking `panic!` or similar. + #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn alloc(&self, layout: Layout) -> *mut u8; /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`. @@ -513,6 +514,7 @@ pub unsafe trait GlobalAlloc { /// /// * `layout` must be the same layout that was used /// to allocated that block of memory, + #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout); /// Behaves like `alloc`, but also ensures that the contents @@ -532,6 +534,7 @@ pub unsafe trait GlobalAlloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the [`oom`] function, /// rather than directly invoking `panic!` or similar. + #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { let size = layout.size(); let ptr = self.alloc(layout); @@ -589,6 +592,7 @@ pub unsafe trait GlobalAlloc { /// Clients wishing to abort computation in response to a /// reallocation error are encouraged to call the [`oom`] function, /// rather than directly invoking `panic!` or similar. + #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let new_ptr = self.alloc(new_layout); -- cgit 1.4.1-3-g733a5 From 9dcb64f34638e8f72fa0ff54b39dfd071d0f8f86 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 1 Jun 2018 02:19:36 +0200 Subject: Alloc docs teaks --- src/libcore/alloc.rs | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 9c324cdb4ed..b0ac43e50f5 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -364,7 +364,6 @@ impl fmt::Display for AllocErr { /// The `CannotReallocInPlace` error is used when `grow_in_place` or /// `shrink_in_place` were unable to reuse the given memory block for /// a requested layout. -// FIXME: should this be in libcore or liballoc? #[unstable(feature = "allocator_api", issue = "32838")] #[derive(Clone, PartialEq, Eq, Debug)] pub struct CannotReallocInPlace; @@ -456,10 +455,6 @@ impl From for CollectionAllocErr { /// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and /// implementors must ensure that they adhere to these contracts: /// -/// * Pointers returned from allocation functions must point to valid memory and -/// retain their validity until at least the instance of `GlobalAlloc` is dropped -/// itself. -/// /// * It's undefined behavior if global allocators unwind. This restriction may /// be lifted in the future, but currently a panic from any of these /// functions may lead to memory unsafety. -- cgit 1.4.1-3-g733a5 From 7f0d54d98842c786ab7a140c17c3ea32aea6aead Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 1 Jun 2018 09:18:25 +0200 Subject: More alloc docs tweaks --- src/liballoc/alloc.rs | 6 ++++-- src/libcore/alloc.rs | 24 +++++++++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index fef668d2365..04c8063ffeb 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -184,8 +184,10 @@ pub(crate) unsafe fn box_free(ptr: Unique) { /// /// The default behavior of this function is to print a message to standard error /// and abort the process. -/// It can be replaced with [`std::alloc::set_oom_hook`] -/// and [`std::alloc::take_oom_hook`]. +/// It can be replaced with [`set_oom_hook`] and [`take_oom_hook`]. +/// +/// [`set_oom_hook`]: ../../std/alloc/fn.set_oom_hook.html +/// [`take_oom_hook`]: ../../std/alloc/fn.take_oom_hook.html #[stable(feature = "global_alloc", since = "1.28.0")] #[rustc_allocator_nounwind] pub fn oom(layout: Layout) -> ! { diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index b0ac43e50f5..353688d1b85 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -494,6 +494,8 @@ pub unsafe trait GlobalAlloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the [`oom`] function, /// rather than directly invoking `panic!` or similar. + /// + /// [`oom`]: ../../alloc/alloc/fn.oom.html #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn alloc(&self, layout: Layout) -> *mut u8; @@ -529,6 +531,8 @@ pub unsafe trait GlobalAlloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the [`oom`] function, /// rather than directly invoking `panic!` or similar. + /// + /// [`oom`]: ../../alloc/alloc/fn.oom.html #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { let size = layout.size(); @@ -587,6 +591,8 @@ pub unsafe trait GlobalAlloc { /// Clients wishing to abort computation in response to a /// reallocation error are encouraged to call the [`oom`] function, /// rather than directly invoking `panic!` or similar. + /// + /// [`oom`]: ../../alloc/alloc/fn.oom.html #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); @@ -727,8 +733,10 @@ pub unsafe trait Alloc { /// library that aborts on memory exhaustion.) /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the `oom` function, + /// allocation error are encouraged to call the [`oom`] function, /// rather than directly invoking `panic!` or similar. + /// + /// [`oom`]: ../../alloc/alloc/fn.oom.html unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; /// Deallocate the memory referenced by `ptr`. @@ -837,6 +845,8 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to a /// reallocation error are encouraged to call the [`oom`] function, /// rather than directly invoking `panic!` or similar. + /// + /// [`oom`]: ../../alloc/alloc/fn.oom.html unsafe fn realloc(&mut self, ptr: NonNull, layout: Layout, @@ -881,6 +891,8 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the [`oom`] function, /// rather than directly invoking `panic!` or similar. + /// + /// [`oom`]: ../../alloc/alloc/fn.oom.html unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); let p = self.alloc(layout); @@ -907,6 +919,8 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the [`oom`] function, /// rather than directly invoking `panic!` or similar. + /// + /// [`oom`]: ../../alloc/alloc/fn.oom.html unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { let usable_size = self.usable_size(&layout); self.alloc(layout).map(|p| Excess(p, usable_size.1)) @@ -929,6 +943,8 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to a /// reallocation error are encouraged to call the [`oom`] function, /// rather than directly invoking `panic!` or similar. + /// + /// [`oom`]: ../../alloc/alloc/fn.oom.html unsafe fn realloc_excess(&mut self, ptr: NonNull, layout: Layout, @@ -1076,6 +1092,8 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the [`oom`] function, /// rather than directly invoking `panic!` or similar. + /// + /// [`oom`]: ../../alloc/alloc/fn.oom.html fn alloc_one(&mut self) -> Result, AllocErr> where Self: Sized { @@ -1143,6 +1161,8 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the [`oom`] function, /// rather than directly invoking `panic!` or similar. + /// + /// [`oom`]: ../../alloc/alloc/fn.oom.html fn alloc_array(&mut self, n: usize) -> Result, AllocErr> where Self: Sized { @@ -1188,6 +1208,8 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to a /// reallocation error are encouraged to call the [`oom`] function, /// rather than directly invoking `panic!` or similar. + /// + /// [`oom`]: ../../alloc/alloc/fn.oom.html unsafe fn realloc_array(&mut self, ptr: NonNull, n_old: usize, -- cgit 1.4.1-3-g733a5 From 85796dd0bad3486f52e3ff9ecb0db6f52d3c460f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 11 Jun 2018 23:10:51 +0200 Subject: stabilize Iterator::flatten in 1.29, fixes #48115. --- src/libcore/iter/iterator.rs | 8 +------- src/libcore/iter/mod.rs | 12 ++++++------ src/libcore/lib.rs | 1 - src/libcore/tests/lib.rs | 1 - 4 files changed, 7 insertions(+), 15 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 1972b009905..102e46dc0f4 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1036,8 +1036,6 @@ pub trait Iterator { /// Basic usage: /// /// ``` - /// #![feature(iterator_flatten)] - /// /// let data = vec![vec![1, 2, 3, 4], vec![5, 6]]; /// let flattened = data.into_iter().flatten().collect::>(); /// assert_eq!(flattened, &[1, 2, 3, 4, 5, 6]); @@ -1046,8 +1044,6 @@ pub trait Iterator { /// Mapping and then flattening: /// /// ``` - /// #![feature(iterator_flatten)] - /// /// let words = ["alpha", "beta", "gamma"]; /// /// // chars() returns an iterator @@ -1074,8 +1070,6 @@ pub trait Iterator { /// Flattening once only removes one level of nesting: /// /// ``` - /// #![feature(iterator_flatten)] - /// /// let d3 = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]; /// /// let d2 = d3.iter().flatten().collect::>(); @@ -1093,7 +1087,7 @@ pub trait Iterator { /// /// [`flat_map()`]: #method.flat_map #[inline] - #[unstable(feature = "iterator_flatten", issue = "48213")] + #[stable(feature = "iterator_flatten", since = "1.29")] fn flatten(self) -> Flatten where Self: Sized, Self::Item: IntoIterator { Flatten { inner: flatten_compat(self) } diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index f152ee73b69..9ab3b786e92 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -2524,13 +2524,13 @@ impl FusedIterator for FlatMap /// [`flatten`]: trait.Iterator.html#method.flatten /// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[unstable(feature = "iterator_flatten", issue = "48213")] +#[stable(feature = "iterator_flatten", since = "1.29")] pub struct Flatten where I::Item: IntoIterator { inner: FlattenCompat::IntoIter>, } -#[unstable(feature = "iterator_flatten", issue = "48213")] +#[stable(feature = "iterator_flatten", since = "1.29")] impl fmt::Debug for Flatten where I: Iterator + fmt::Debug, U: Iterator + fmt::Debug, I::Item: IntoIterator, @@ -2540,7 +2540,7 @@ impl fmt::Debug for Flatten } } -#[unstable(feature = "iterator_flatten", issue = "48213")] +#[stable(feature = "iterator_flatten", since = "1.29")] impl Clone for Flatten where I: Iterator + Clone, U: Iterator + Clone, I::Item: IntoIterator, @@ -2548,7 +2548,7 @@ impl Clone for Flatten fn clone(&self) -> Self { Flatten { inner: self.inner.clone() } } } -#[unstable(feature = "iterator_flatten", issue = "48213")] +#[stable(feature = "iterator_flatten", since = "1.29")] impl Iterator for Flatten where I: Iterator, U: Iterator, I::Item: IntoIterator @@ -2576,7 +2576,7 @@ impl Iterator for Flatten } } -#[unstable(feature = "iterator_flatten", issue = "48213")] +#[stable(feature = "iterator_flatten", since = "1.29")] impl DoubleEndedIterator for Flatten where I: DoubleEndedIterator, U: DoubleEndedIterator, I::Item: IntoIterator @@ -2599,7 +2599,7 @@ impl DoubleEndedIterator for Flatten } } -#[unstable(feature = "iterator_flatten", issue = "48213")] +#[stable(feature = "iterator_flatten", since = "1.29")] impl FusedIterator for Flatten where I: FusedIterator, U: Iterator, I::Item: IntoIterator {} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index a2ee0033872..4edfb06944b 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -89,7 +89,6 @@ #![feature(extern_types)] #![feature(fundamental)] #![feature(intrinsics)] -#![feature(iterator_flatten)] #![feature(lang_items)] #![feature(link_llvm_intrinsics)] #![feature(never_type)] diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 11765e3ef56..4c8f72010a2 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -23,7 +23,6 @@ #![feature(flt2dec)] #![feature(fmt_internals)] #![feature(hashmap_internals)] -#![feature(iterator_flatten)] #![feature(pattern)] #![feature(range_is_empty)] #![feature(raw)] -- cgit 1.4.1-3-g733a5 From e2aef92c19a95d6a0b8e75b473023f77de6150f0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 6 Jun 2018 13:24:16 +0200 Subject: Stabilize #[repr(transparent)] Tracking issue FCP: https://github.com/rust-lang/rust/issues/43036#issuecomment-394094318 Reference PR: https://github.com/rust-lang-nursery/reference/pull/353 --- .../src/language-features/repr-transparent.md | 176 --------------------- src/liballoc/lib.rs | 2 +- src/libcore/lib.rs | 2 +- src/librustc/diagnostics.rs | 8 - src/librustc_typeck/diagnostics.rs | 10 +- src/libsyntax/feature_gate.rs | 10 +- src/test/codegen/repr-transparent-aggregates-1.rs | 1 - src/test/codegen/repr-transparent-aggregates-2.rs | 1 - src/test/codegen/repr-transparent-aggregates-3.rs | 1 - src/test/codegen/repr-transparent-sysv64.rs | 1 - src/test/codegen/repr-transparent.rs | 2 +- .../compile-fail/repr-transparent-other-items.rs | 2 - .../compile-fail/repr-transparent-other-reprs.rs | 2 +- src/test/compile-fail/repr-transparent.rs | 1 - src/test/ui/feature-gate-repr_transparent.rs | 14 -- src/test/ui/feature-gate-repr_transparent.stderr | 11 -- src/test/ui/lint-ctypes.rs | 2 +- 17 files changed, 9 insertions(+), 237 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/repr-transparent.md delete mode 100644 src/test/ui/feature-gate-repr_transparent.rs delete mode 100644 src/test/ui/feature-gate-repr_transparent.stderr (limited to 'src/libcore') diff --git a/src/doc/unstable-book/src/language-features/repr-transparent.md b/src/doc/unstable-book/src/language-features/repr-transparent.md deleted file mode 100644 index 62202dc96fd..00000000000 --- a/src/doc/unstable-book/src/language-features/repr-transparent.md +++ /dev/null @@ -1,176 +0,0 @@ -# `repr_transparent` - -The tracking issue for this feature is: [#43036] - -[#43036]: https://github.com/rust-lang/rust/issues/43036 - ------------------------- - -This feature enables the `repr(transparent)` attribute on structs, which enables -the use of newtypes without the usual ABI implications of wrapping the value in -a struct. - -## Background - -It's sometimes useful to add additional type safety by introducing *newtypes*. -For example, code that handles numeric quantities in different units such as -millimeters, centimeters, grams, kilograms, etc. may want to use the type system -to rule out mistakes such as adding millimeters to grams: - -```rust -use std::ops::Add; - -struct Millimeters(f64); -struct Grams(f64); - -impl Add for Millimeters { - type Output = Millimeters; - - fn add(self, other: Millimeters) -> Millimeters { - Millimeters(self.0 + other.0) - } -} - -// Likewise: impl Add for Grams {} -``` - -Other uses of newtypes include using `PhantomData` to add lifetimes to raw -pointers or to implement the "phantom types" pattern. See the [PhantomData] -documentation and [the Nomicon][nomicon-phantom] for more details. - -The added type safety is especially useful when interacting with C or other -languages. However, in those cases we need to ensure the newtypes we add do not -introduce incompatibilities with the C ABI. - -## Newtypes in FFI - -Luckily, `repr(C)` newtypes are laid out just like the type they wrap on all -platforms which Rust currently supports, and likely on many more. For example, -consider this C declaration: - -```C -struct Object { - double weight; //< in grams - double height; //< in millimeters - // ... -} - -void frobnicate(struct Object *); -``` - -While using this C code from Rust, we could add `repr(C)` to the `Grams` and -`Millimeters` newtypes introduced above and use them to add some type safety -while staying compatible with the memory layout of `Object`: - -```rust,no_run -#[repr(C)] -struct Grams(f64); - -#[repr(C)] -struct Millimeters(f64); - -#[repr(C)] -struct Object { - weight: Grams, - height: Millimeters, - // ... -} - -extern { - fn frobnicate(_: *mut Object); -} -``` - -This works even when adding some `PhantomData` fields, because they are -zero-sized and therefore don't have to affect the memory layout. - -However, there's more to the ABI than just memory layout: there's also the -question of how function call arguments and return values are passed. Many -common ABI treat a struct containing a single field differently from that field -itself, at least when the field is a scalar (e.g., integer or float or pointer). - -To continue the above example, suppose the C library also exposes a function -like this: - -```C -double calculate_weight(double height); -``` - -Using our newtypes on the Rust side like this will cause an ABI mismatch on many -platforms: - -```rust,ignore -extern { - fn calculate_weight(height: Millimeters) -> Grams; -} -``` - -For example, on x86_64 Linux, Rust will pass the argument in an integer -register, while the C function expects the argument to be in a floating-point -register. Likewise, the C function will return the result in a floating-point -register while Rust will expect it in an integer register. - -Note that this problem is not specific to floats: To give another example, -32-bit x86 linux will pass and return `struct Foo(i32);` on the stack while -`i32` is placed in registers. - -## Enter `repr(transparent)` - -So while `repr(C)` happens to do the right thing with respect to memory layout, -it's not quite the right tool for newtypes in FFI. Instead of declaring a C -struct, we need to communicate to the Rust compiler that our newtype is just for -type safety on the Rust side. This is what `repr(transparent)` does. - -The attribute can be applied to a newtype-like structs that contains a single -field. It indicates that the newtype should be represented exactly like that -field's type, i.e., the newtype should be ignored for ABI purpopses: not only is -it laid out the same in memory, it is also passed identically in function calls. - -In the above example, the ABI mismatches can be prevented by making the newtypes -`Grams` and `Millimeters` transparent like this: - -```rust -#![feature(repr_transparent)] - -#[repr(transparent)] -struct Grams(f64); - -#[repr(transparent)] -struct Millimeters(f64); -``` - -In addition to that single field, any number of zero-sized fields are permitted, -including but not limited to `PhantomData`: - -```rust -#![feature(repr_transparent)] - -use std::marker::PhantomData; - -struct Foo { /* ... */ } - -#[repr(transparent)] -struct FooPtrWithLifetime<'a>(*const Foo, PhantomData<&'a Foo>); - -#[repr(transparent)] -struct NumberWithUnit(T, PhantomData); - -struct CustomZst; - -#[repr(transparent)] -struct PtrWithCustomZst<'a> { - ptr: FooPtrWithLifetime<'a>, - some_marker: CustomZst, -} -``` - -Transparent structs can be nested: `PtrWithCustomZst` is also represented -exactly like `*const Foo`. - -Because `repr(transparent)` delegates all representation concerns to another -type, it is incompatible with all other `repr(..)` attributes. It also cannot be -applied to enums, unions, empty structs, structs whose fields are all -zero-sized, or structs with *multiple* non-zero-sized fields. - -[PhantomData]: https://doc.rust-lang.org/std/marker/struct.PhantomData.html -[nomicon-phantom]: https://doc.rust-lang.org/nomicon/phantom-data.html diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 74bbd659246..e25742a4a61 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -105,7 +105,7 @@ #![feature(pin)] #![feature(ptr_internals)] #![feature(ptr_offset_from)] -#![feature(repr_transparent)] +#![cfg_attr(stage0, feature(repr_transparent))] #![feature(rustc_attrs)] #![feature(specialization)] #![feature(staged_api)] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5ba77edee6e..40caee85541 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -100,7 +100,7 @@ #![feature(optin_builtin_traits)] #![feature(prelude_import)] #![feature(repr_simd, platform_intrinsics)] -#![feature(repr_transparent)] +#![cfg_attr(stage0, feature(repr_transparent))] #![feature(rustc_attrs)] #![feature(rustc_const_unstable)] #![feature(simd_ffi)] diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 7415ddd455d..1435957a5c1 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1958,8 +1958,6 @@ representation hints. Erroneous code example: ```compile_fail,E0692 -#![feature(repr_transparent)] - #[repr(transparent, C)] // error: incompatible representation hints struct Grams(f32); ``` @@ -1969,8 +1967,6 @@ another type, so adding more representation hints is contradictory. Remove either the `transparent` hint or the other hints, like this: ``` -#![feature(repr_transparent)] - #[repr(transparent)] struct Grams(f32); ``` @@ -1978,8 +1974,6 @@ struct Grams(f32); Alternatively, move the other attributes to the contained type: ``` -#![feature(repr_transparent)] - #[repr(C)] struct Foo { x: i32, @@ -1994,8 +1988,6 @@ Note that introducing another `struct` just to have a place for the other attributes may have unintended side effects on the representation: ``` -#![feature(repr_transparent)] - #[repr(transparent)] struct Grams(f32); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index e4c73218de5..da54eeabdb9 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4581,8 +4581,6 @@ on fields that were not guaranteed to be zero-sized. Erroneous code example: ```compile_fail,E0690 -#![feature(repr_transparent)] - #[repr(transparent)] struct LengthWithUnit { // error: transparent struct needs exactly one value: f32, // non-zero-sized field, but has 2 @@ -4602,8 +4600,6 @@ To combine `repr(transparent)` with type parameters, `PhantomData` may be useful: ``` -#![feature(repr_transparent)] - use std::marker::PhantomData; #[repr(transparent)] @@ -4621,7 +4617,7 @@ field that requires non-trivial alignment. Erroneous code example: ```compile_fail,E0691 -#![feature(repr_transparent, repr_align, attr_literals)] +#![feature(repr_align, attr_literals)] #[repr(align(32))] struct ForceAlign32; @@ -4640,8 +4636,6 @@ requirement. Consider removing the over-aligned zero-sized field: ``` -#![feature(repr_transparent)] - #[repr(transparent)] struct Wrapper(f32); ``` @@ -4650,7 +4644,7 @@ Alternatively, `PhantomData` has alignment 1 for all `T`, so you can use it if you need to keep the field for some reason: ``` -#![feature(repr_transparent, repr_align, attr_literals)] +#![feature(repr_align, attr_literals)] use std::marker::PhantomData; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1535e649506..9f370672cb2 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -399,9 +399,6 @@ declare_features! ( // `extern` in paths (active, extern_in_paths, "1.23.0", Some(44660), None), - // Allows `#[repr(transparent)]` attribute on newtype structs - (active, repr_transparent, "1.25.0", Some(43036), None), - // Use `?` as the Kleene "at most one" operator (active, macro_at_most_once_rep, "1.25.0", Some(48075), None), @@ -615,6 +612,8 @@ declare_features! ( (accepted, termination_trait_test, "1.27.0", Some(48854), None), // The #[global_allocator] attribute (accepted, global_allocator, "1.28.0", Some(27389), None), + // Allows `#[repr(transparent)]` attribute on newtype structs + (accepted, repr_transparent, "1.28.0", Some(43036), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1595,11 +1594,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, repr_simd, attr.span, "SIMD types are experimental and possibly buggy"); } - if item.check_name("transparent") { - gate_feature_post!(&self, repr_transparent, attr.span, - "the `#[repr(transparent)]` attribute \ - is experimental"); - } if let Some((name, _)) = item.name_value_literal() { if name == "packed" { gate_feature_post!(&self, repr_packed, attr.span, diff --git a/src/test/codegen/repr-transparent-aggregates-1.rs b/src/test/codegen/repr-transparent-aggregates-1.rs index 2eeed2b788c..a1185cc1e2e 100644 --- a/src/test/codegen/repr-transparent-aggregates-1.rs +++ b/src/test/codegen/repr-transparent-aggregates-1.rs @@ -18,7 +18,6 @@ // See repr-transparent.rs #![crate_type="lib"] -#![feature(repr_transparent)] #[repr(C)] diff --git a/src/test/codegen/repr-transparent-aggregates-2.rs b/src/test/codegen/repr-transparent-aggregates-2.rs index 25750a6513f..bc000bd3165 100644 --- a/src/test/codegen/repr-transparent-aggregates-2.rs +++ b/src/test/codegen/repr-transparent-aggregates-2.rs @@ -22,7 +22,6 @@ // See repr-transparent.rs #![crate_type="lib"] -#![feature(repr_transparent)] #[repr(C)] diff --git a/src/test/codegen/repr-transparent-aggregates-3.rs b/src/test/codegen/repr-transparent-aggregates-3.rs index 0c90239c9de..a292f1d70f3 100644 --- a/src/test/codegen/repr-transparent-aggregates-3.rs +++ b/src/test/codegen/repr-transparent-aggregates-3.rs @@ -14,7 +14,6 @@ // See repr-transparent.rs #![crate_type="lib"] -#![feature(repr_transparent)] #[repr(C)] diff --git a/src/test/codegen/repr-transparent-sysv64.rs b/src/test/codegen/repr-transparent-sysv64.rs index 7a30983fdd3..2e4665e22e3 100644 --- a/src/test/codegen/repr-transparent-sysv64.rs +++ b/src/test/codegen/repr-transparent-sysv64.rs @@ -13,7 +13,6 @@ // compile-flags: -C no-prepopulate-passes #![crate_type="lib"] -#![feature(repr_transparent)] #[repr(C)] pub struct Rgb8 { r: u8, g: u8, b: u8 } diff --git a/src/test/codegen/repr-transparent.rs b/src/test/codegen/repr-transparent.rs index 087fa9b16b4..64a62fd7e88 100644 --- a/src/test/codegen/repr-transparent.rs +++ b/src/test/codegen/repr-transparent.rs @@ -11,7 +11,7 @@ // compile-flags: -C no-prepopulate-passes #![crate_type="lib"] -#![feature(repr_transparent, repr_simd)] +#![feature(repr_simd)] use std::marker::PhantomData; diff --git a/src/test/compile-fail/repr-transparent-other-items.rs b/src/test/compile-fail/repr-transparent-other-items.rs index cf0870866c7..685d62dc3a9 100644 --- a/src/test/compile-fail/repr-transparent-other-items.rs +++ b/src/test/compile-fail/repr-transparent-other-items.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(repr_transparent)] - // See also repr-transparent.rs #[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum diff --git a/src/test/compile-fail/repr-transparent-other-reprs.rs b/src/test/compile-fail/repr-transparent-other-reprs.rs index 7b91a6f68e3..a391c0ae1f8 100644 --- a/src/test/compile-fail/repr-transparent-other-reprs.rs +++ b/src/test/compile-fail/repr-transparent-other-reprs.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(repr_transparent, repr_align, attr_literals)] +#![feature(repr_align, attr_literals)] // See also repr-transparent.rs diff --git a/src/test/compile-fail/repr-transparent.rs b/src/test/compile-fail/repr-transparent.rs index b5e6a0fa0b1..4d8ec4cdb40 100644 --- a/src/test/compile-fail/repr-transparent.rs +++ b/src/test/compile-fail/repr-transparent.rs @@ -14,7 +14,6 @@ // - repr-transparent-other-items.rs #![feature(repr_align, attr_literals)] -#![feature(repr_transparent)] use std::marker::PhantomData; diff --git a/src/test/ui/feature-gate-repr_transparent.rs b/src/test/ui/feature-gate-repr_transparent.rs deleted file mode 100644 index deadf2e535d..00000000000 --- a/src/test/ui/feature-gate-repr_transparent.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[repr(transparent)] //~ error: the `#[repr(transparent)]` attribute is experimental -struct Foo(u64); - -fn main() {} diff --git a/src/test/ui/feature-gate-repr_transparent.stderr b/src/test/ui/feature-gate-repr_transparent.stderr deleted file mode 100644 index a4ffaa26690..00000000000 --- a/src/test/ui/feature-gate-repr_transparent.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: the `#[repr(transparent)]` attribute is experimental (see issue #43036) - --> $DIR/feature-gate-repr_transparent.rs:11:1 - | -LL | #[repr(transparent)] //~ error: the `#[repr(transparent)]` attribute is experimental - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(repr_transparent)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/lint-ctypes.rs b/src/test/ui/lint-ctypes.rs index 85957831653..4b20001457f 100644 --- a/src/test/ui/lint-ctypes.rs +++ b/src/test/ui/lint-ctypes.rs @@ -9,7 +9,7 @@ // except according to those terms. #![deny(improper_ctypes)] -#![feature(libc, repr_transparent)] +#![feature(libc)] extern crate libc; -- cgit 1.4.1-3-g733a5 From 8ae188959ba5237f3c40f9d9c15954cce6288aee Mon Sep 17 00:00:00 2001 From: kennytm Date: Mon, 21 May 2018 22:50:25 +0800 Subject: Replace `core::iter::AlwaysOk` by `Result` --- src/libcore/iter/iterator.rs | 4 ++-- src/libcore/iter/mod.rs | 15 --------------- src/libcore/iter/traits.rs | 4 ++-- 3 files changed, 4 insertions(+), 19 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 1972b009905..81150bc0378 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -11,7 +11,7 @@ use cmp::Ordering; use ops::Try; -use super::{AlwaysOk, LoopState}; +use super::LoopState; use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, Fuse}; use super::{Flatten, FlatMap, flatten_compat}; use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev}; @@ -1614,7 +1614,7 @@ pub trait Iterator { fn fold(mut self, init: B, mut f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { - self.try_fold(init, move |acc, x| AlwaysOk(f(acc, x))).0 + self.try_fold(init, move |acc, x| Ok::(f(acc, x))).unwrap() } /// Tests if every element of the iterator matches a predicate. diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index f152ee73b69..840d45ff1cc 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -354,21 +354,6 @@ mod range; mod sources; mod traits; -/// Transparent newtype used to implement foo methods in terms of try_foo. -/// Important until #43278 is fixed; might be better as `Result` later. -struct AlwaysOk(pub T); - -impl Try for AlwaysOk { - type Ok = T; - type Error = !; - #[inline] - fn into_result(self) -> Result { Ok(self.0) } - #[inline] - fn from_error(v: Self::Error) -> Self { v } - #[inline] - fn from_ok(v: Self::Ok) -> Self { AlwaysOk(v) } -} - /// Used to make try_fold closures more like normal loops #[derive(PartialEq)] enum LoopState { diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 1551429557f..3d2ce9e6b10 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -10,7 +10,7 @@ use ops::{Mul, Add, Try}; use num::Wrapping; -use super::{AlwaysOk, LoopState}; +use super::LoopState; /// Conversion from an `Iterator`. /// @@ -524,7 +524,7 @@ pub trait DoubleEndedIterator: Iterator { fn rfold(mut self, accum: B, mut f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { - self.try_rfold(accum, move |acc, x| AlwaysOk(f(acc, x))).0 + self.try_rfold(accum, move |acc, x| Ok::(f(acc, x))).unwrap() } /// Searches for an element of an iterator from the back that satisfies a predicate. -- cgit 1.4.1-3-g733a5 From 2177378e34c5ad431b245e3bd7cd6cd38ab9053a Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Wed, 13 Jun 2018 09:09:57 +0200 Subject: Improve core::task::TaskObj --- src/liballoc/boxed.rs | 8 ++++---- src/libcore/task.rs | 29 +++++++++++++++-------------- 2 files changed, 19 insertions(+), 18 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index c794fb8220a..ea60c7775af 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -66,7 +66,7 @@ use core::marker::{Unpin, Unsize}; use core::mem::{self, PinMut}; use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; use core::ptr::{self, NonNull, Unique}; -use core::task::{Context, Poll, UnsafePoll, TaskObj}; +use core::task::{Context, Poll, UnsafeTask, TaskObj}; use core::convert::From; use raw_vec::RawVec; @@ -933,7 +933,7 @@ impl<'a, F: ?Sized + Future> Future for PinBox { } #[unstable(feature = "futures_api", issue = "50547")] -unsafe impl + Send + 'static> UnsafePoll for PinBox { +unsafe impl + Send + 'static> UnsafeTask for PinBox { fn into_raw(self) -> *mut () { PinBox::into_raw(self) as *mut () } @@ -952,13 +952,13 @@ unsafe impl + Send + 'static> UnsafePoll for PinBox { #[unstable(feature = "futures_api", issue = "50547")] impl + Send + 'static> From> for TaskObj { fn from(boxed: PinBox) -> Self { - TaskObj::from_poll_task(boxed) + TaskObj::new(boxed) } } #[unstable(feature = "futures_api", issue = "50547")] impl + Send + 'static> From> for TaskObj { fn from(boxed: Box) -> Self { - TaskObj::from_poll_task(PinBox::from(boxed)) + TaskObj::new(PinBox::from(boxed)) } } diff --git a/src/libcore/task.rs b/src/libcore/task.rs index bef6d3677d0..1a6018ffb65 100644 --- a/src/libcore/task.rs +++ b/src/libcore/task.rs @@ -16,6 +16,8 @@ use fmt; use ptr::NonNull; +use future::Future; +use mem::PinMut; /// Indicates whether a value is available or if the current task has been /// scheduled to receive a wakeup instead. @@ -455,8 +457,8 @@ pub trait Executor { /// `Box + Send>`. pub struct TaskObj { ptr: *mut (), - poll: unsafe fn(*mut (), &mut Context) -> Poll<()>, - drop: unsafe fn(*mut ()), + poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<()>, + drop_fn: unsafe fn(*mut ()), } impl fmt::Debug for TaskObj { @@ -467,7 +469,6 @@ impl fmt::Debug for TaskObj { } unsafe impl Send for TaskObj {} -unsafe impl Sync for TaskObj {} /// A custom implementation of a task trait object for `TaskObj`, providing /// a hand-rolled vtable. @@ -478,7 +479,7 @@ unsafe impl Sync for TaskObj {} /// The implementor must guarantee that it is safe to call `poll` repeatedly (in /// a non-concurrent fashion) with the result of `into_raw` until `drop` is /// called. -pub unsafe trait UnsafePoll: Send + 'static { +pub unsafe trait UnsafeTask: Send + 'static { /// Convert a owned instance into a (conceptually owned) void pointer. fn into_raw(self) -> *mut (); @@ -504,22 +505,22 @@ pub unsafe trait UnsafePoll: Send + 'static { impl TaskObj { /// Create a `TaskObj` from a custom trait object representation. #[inline] - pub fn from_poll_task(t: T) -> TaskObj { + pub fn new(t: T) -> TaskObj { TaskObj { ptr: t.into_raw(), - poll: T::poll, - drop: T::drop, + poll_fn: T::poll, + drop_fn: T::drop, } } +} + +impl Future for TaskObj { + type Output = (); - /// Poll the task. - /// - /// The semantics here are identical to that for futures, but unlike - /// futures only an `&mut self` reference is needed here. #[inline] - pub fn poll_task(&mut self, cx: &mut Context) -> Poll<()> { + fn poll(self: PinMut, cx: &mut Context) -> Poll<()> { unsafe { - (self.poll)(self.ptr, cx) + (self.poll_fn)(self.ptr, cx) } } } @@ -527,7 +528,7 @@ impl TaskObj { impl Drop for TaskObj { fn drop(&mut self) { unsafe { - (self.drop)(self.ptr) + (self.drop_fn)(self.ptr) } } } -- cgit 1.4.1-3-g733a5 From 2a999b4b525ed8b4f735e233cc065b292d3eeb03 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Sat, 9 Jun 2018 22:32:05 -0700 Subject: Add Ref/RefMut map_split method --- src/libcore/cell.rs | 145 ++++++++++++++++++++++++++++++++++++++++------ src/libcore/tests/cell.rs | 58 +++++++++++++++++++ src/libcore/tests/lib.rs | 1 + 3 files changed, 185 insertions(+), 19 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index d50ad580ed5..dd8fce17cff 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -570,11 +570,20 @@ impl Display for BorrowMutError { } } -// Values [1, MAX-1] represent the number of `Ref` active -// (will not outgrow its range since `usize` is the size of the address space) +// Values [1, MIN_WRITING-1] represent the number of `Ref` active. Values in +// [MIN_WRITING, MAX-1] represent the number of `RefMut` active. Multiple +// `RefMut`s can only be active at a time if they refer to distinct, +// nonoverlapping components of a `RefCell` (e.g., different ranges of a slice). +// +// `Ref` and `RefMut` are both two words in size, and so there will likely never +// be enough `Ref`s or `RefMut`s in existence to overflow half of the `usize` +// range. Thus, a `BorrowFlag` will probably never overflow. However, this is +// not a guarantee, as a pathological program could repeatedly create and then +// mem::forget `Ref`s or `RefMut`s. Thus, all code must explicitly check for +// overflow in order to avoid unsafety. type BorrowFlag = usize; const UNUSED: BorrowFlag = 0; -const WRITING: BorrowFlag = !0; +const MIN_WRITING: BorrowFlag = (!0)/2 + 1; // 0b1000... impl RefCell { /// Creates a new `RefCell` containing `value`. @@ -775,8 +784,9 @@ impl RefCell { /// Mutably borrows the wrapped value. /// - /// The borrow lasts until the returned `RefMut` exits scope. The value - /// cannot be borrowed while this borrow is active. + /// The borrow lasts until the returned `RefMut` or all `RefMut`s derived + /// from it exit scope. The value cannot be borrowed while this borrow is + /// active. /// /// # Panics /// @@ -818,8 +828,9 @@ impl RefCell { /// Mutably borrows the wrapped value, returning an error if the value is currently borrowed. /// - /// The borrow lasts until the returned `RefMut` exits scope. The value cannot be borrowed - /// while this borrow is active. + /// The borrow lasts until the returned `RefMut` or all `RefMut`s derived + /// from it exit scope. The value cannot be borrowed while this borrow is + /// active. /// /// This is the non-panicking variant of [`borrow_mut`](#method.borrow_mut). /// @@ -1010,12 +1021,15 @@ struct BorrowRef<'b> { impl<'b> BorrowRef<'b> { #[inline] fn new(borrow: &'b Cell) -> Option> { - match borrow.get() { - WRITING => None, - b => { - borrow.set(b + 1); - Some(BorrowRef { borrow: borrow }) - }, + let b = borrow.get(); + if b >= MIN_WRITING { + None + } else { + // Prevent the borrow counter from overflowing into + // a writing borrow. + assert!(b < MIN_WRITING - 1); + borrow.set(b + 1); + Some(BorrowRef { borrow }) } } } @@ -1024,7 +1038,7 @@ impl<'b> Drop for BorrowRef<'b> { #[inline] fn drop(&mut self) { let borrow = self.borrow.get(); - debug_assert!(borrow != WRITING && borrow != UNUSED); + debug_assert!(borrow < MIN_WRITING && borrow != UNUSED); self.borrow.set(borrow - 1); } } @@ -1036,8 +1050,9 @@ impl<'b> Clone for BorrowRef<'b> { // is not set to WRITING. let borrow = self.borrow.get(); debug_assert!(borrow != UNUSED); - // Prevent the borrow counter from overflowing. - assert!(borrow != WRITING); + // Prevent the borrow counter from overflowing into + // a writing borrow. + assert!(borrow < MIN_WRITING - 1); self.borrow.set(borrow + 1); BorrowRef { borrow: self.borrow } } @@ -1109,6 +1124,37 @@ impl<'b, T: ?Sized> Ref<'b, T> { borrow: orig.borrow, } } + + /// Split a `Ref` into multiple `Ref`s for different components of the + /// borrowed data. + /// + /// The `RefCell` is already immutably borrowed, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `Ref::map_split(...)`. A method would interfere with methods of the same + /// name on the contents of a `RefCell` used through `Deref`. + /// + /// # Examples + /// + /// ``` + /// #![feature(refcell_map_split)] + /// use std::cell::{Ref, RefCell}; + /// + /// let cell = RefCell::new([1, 2, 3, 4]); + /// let borrow = cell.borrow(); + /// let (begin, end) = Ref::map_split(borrow, |slice| slice.split_at(2)); + /// assert_eq!(*begin, [1, 2]); + /// assert_eq!(*end, [3, 4]); + /// ``` + #[unstable(feature = "refcell_map_split", issue = "51476")] + #[inline] + pub fn map_split(orig: Ref<'b, T>, f: F) -> (Ref<'b, U>, Ref<'b, V>) + where F: FnOnce(&T) -> (&U, &V) + { + let (a, b) = f(orig.value); + let borrow = orig.borrow.clone(); + (Ref { value: a, borrow }, Ref { value: b, borrow: orig.borrow }) + } } #[unstable(feature = "coerce_unsized", issue = "27732")] @@ -1157,6 +1203,44 @@ impl<'b, T: ?Sized> RefMut<'b, T> { borrow: borrow, } } + + /// Split a `RefMut` into multiple `RefMut`s for different components of the + /// borrowed data. + /// + /// The underlying `RefCell` will remain mutably borrowed until both + /// returned `RefMut`s go out of scope. + /// + /// The `RefCell` is already mutably borrowed, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `RefMut::map_split(...)`. A method would interfere with methods of the + /// same name on the contents of a `RefCell` used through `Deref`. + /// + /// # Examples + /// + /// ``` + /// #![feature(refcell_map_split)] + /// use std::cell::{RefCell, RefMut}; + /// + /// let cell = RefCell::new([1, 2, 3, 4]); + /// let borrow = cell.borrow_mut(); + /// let (mut begin, mut end) = RefMut::map_split(borrow, |slice| slice.split_at_mut(2)); + /// assert_eq!(*begin, [1, 2]); + /// assert_eq!(*end, [3, 4]); + /// begin.copy_from_slice(&[4, 3]); + /// end.copy_from_slice(&[2, 1]); + /// ``` + #[unstable(feature = "refcell_map_split", issue = "51476")] + #[inline] + pub fn map_split( + orig: RefMut<'b, T>, f: F + ) -> (RefMut<'b, U>, RefMut<'b, V>) + where F: FnOnce(&mut T) -> (&mut U, &mut V) + { + let (a, b) = f(orig.value); + let borrow = orig.borrow.clone(); + (RefMut { value: a, borrow }, RefMut { value: b, borrow: orig.borrow }) + } } struct BorrowRefMut<'b> { @@ -1167,22 +1251,45 @@ impl<'b> Drop for BorrowRefMut<'b> { #[inline] fn drop(&mut self) { let borrow = self.borrow.get(); - debug_assert!(borrow == WRITING); - self.borrow.set(UNUSED); + debug_assert!(borrow >= MIN_WRITING); + self.borrow.set(if borrow == MIN_WRITING { + UNUSED + } else { + borrow - 1 + }); } } impl<'b> BorrowRefMut<'b> { #[inline] fn new(borrow: &'b Cell) -> Option> { + // NOTE: Unlike BorrowRefMut::clone, new is called to create the initial + // mutable reference, and so there must currently be no existing + // references. Thus, while clone increments the mutable refcount, here + // we simply go directly from UNUSED to MIN_WRITING. match borrow.get() { UNUSED => { - borrow.set(WRITING); + borrow.set(MIN_WRITING); Some(BorrowRefMut { borrow: borrow }) }, _ => None, } } + + // Clone a `BorrowRefMut`. + // + // This is only valid if each `BorrowRefMut` is used to track a mutable + // reference to a distinct, nonoverlapping range of the original object. + // This isn't in a Clone impl so that code doesn't call this implicitly. + #[inline] + fn clone(&self) -> BorrowRefMut<'b> { + let borrow = self.borrow.get(); + debug_assert!(borrow >= MIN_WRITING); + // Prevent the borrow counter from overflowing. + assert!(borrow != !0); + self.borrow.set(borrow + 1); + BorrowRefMut { borrow: self.borrow } + } } /// A wrapper type for a mutably borrowed value from a `RefCell`. diff --git a/src/libcore/tests/cell.rs b/src/libcore/tests/cell.rs index 962fb2f0e02..4b7243b9cfc 100644 --- a/src/libcore/tests/cell.rs +++ b/src/libcore/tests/cell.rs @@ -165,6 +165,64 @@ fn ref_map_does_not_update_flag() { assert!(x.try_borrow_mut().is_ok()); } +#[test] +fn ref_map_split_updates_flag() { + let x = RefCell::new([1, 2]); + { + let b1 = x.borrow(); + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_err()); + { + let (_b2, _b3) = Ref::map_split(b1, |slc| slc.split_at(1)); + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_err()); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_ok()); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_ok()); + + { + let b1 = x.borrow_mut(); + assert!(x.try_borrow().is_err()); + assert!(x.try_borrow_mut().is_err()); + { + let (_b2, _b3) = RefMut::map_split(b1, |slc| slc.split_at_mut(1)); + assert!(x.try_borrow().is_err()); + assert!(x.try_borrow_mut().is_err()); + drop(_b2); + assert!(x.try_borrow().is_err()); + assert!(x.try_borrow_mut().is_err()); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_ok()); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_ok()); +} + +#[test] +fn ref_map_split() { + let x = RefCell::new([1, 2]); + let (b1, b2) = Ref::map_split(x.borrow(), |slc| slc.split_at(1)); + assert_eq!(*b1, [1]); + assert_eq!(*b2, [2]); +} + +#[test] +fn ref_mut_map_split() { + let x = RefCell::new([1, 2]); + { + let (mut b1, mut b2) = RefMut::map_split(x.borrow_mut(), |slc| slc.split_at_mut(1)); + assert_eq!(*b1, [1]); + assert_eq!(*b2, [2]); + b1[0] = 2; + b2[0] = 1; + } + assert_eq!(*x.borrow(), [2, 1]); +} + #[test] fn ref_map_accessor() { struct X(RefCell<(u32, char)>); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 13189d532ab..6d60010cca6 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -29,6 +29,7 @@ #![feature(pattern)] #![feature(range_is_empty)] #![feature(raw)] +#![feature(refcell_map_split)] #![feature(refcell_replace_swap)] #![feature(slice_patterns)] #![feature(slice_rotate)] -- cgit 1.4.1-3-g733a5 From 570590f7271ddd1bcedf14a7bbc38975db720419 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Wed, 6 Jun 2018 19:40:03 -0400 Subject: impl Hash for ! --- src/libcore/hash/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 3e1f21cafe4..e6f8dfffd63 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -603,6 +603,13 @@ mod impls { } } + #[stable(feature = "never_hash", since = "1.29.0")] + impl Hash for ! { + fn hash(&self, _: &mut H) { + *self + } + } + macro_rules! impl_hash_tuple { () => ( #[stable(feature = "rust1", since = "1.0.0")] -- cgit 1.4.1-3-g733a5 From 530d7bc5174e93682a38b22ac7ff4e3569bcd813 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 6 Jun 2018 13:30:35 +0200 Subject: Add #[repr(transparent)] to some libcore types * `UnsafeCell` * `Cell` * `NonZero*` * `NonNull` * `Unique` --- src/libcore/cell.rs | 2 ++ src/libcore/lib.rs | 1 + src/libcore/nonzero.rs | 1 + src/libcore/num/mod.rs | 2 ++ src/libcore/ptr.rs | 2 ++ 5 files changed, 8 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index d50ad580ed5..f922f8f2d93 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -235,6 +235,7 @@ use ptr; /// /// See the [module-level documentation](index.html) for more. #[stable(feature = "rust1", since = "1.0.0")] +#[repr(transparent)] pub struct Cell { value: UnsafeCell, } @@ -1282,6 +1283,7 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// ``` #[lang = "unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] +#[repr(transparent)] pub struct UnsafeCell { value: T, } diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 40caee85541..2d227ebc8c2 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -124,6 +124,7 @@ #![feature(const_slice_len)] #![feature(const_str_as_bytes)] #![feature(const_str_len)] +#![cfg_attr(stage0, feature(repr_transparent))] #[prelude_import] #[allow(unused)] diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index ee5230cef8d..cc36ea7f713 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -16,6 +16,7 @@ use ops::CoerceUnsized; /// NULL or 0 that might allow certain optimizations. #[lang = "non_zero"] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[repr(transparent)] pub(crate) struct NonZero(pub(crate) T); impl, U> CoerceUnsized> for NonZero {} diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 1168126c47c..3aeb1183218 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -48,6 +48,7 @@ macro_rules! nonzero_integers { /// ``` #[stable(feature = "nonzero", since = "1.28.0")] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] + #[repr(transparent)] pub struct $Ty(NonZero<$Int>); impl $Ty { @@ -123,6 +124,7 @@ nonzero_integers! { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] +#[repr(transparent)] pub struct Wrapping(#[stable(feature = "rust1", since = "1.0.0")] pub T); diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 81a8b3ef047..0070defa953 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2692,6 +2692,7 @@ impl PartialOrd for *mut T { reason = "use NonNull instead and consider PhantomData \ (if you also use #[may_dangle]), Send, and/or Sync")] #[doc(hidden)] +#[repr(transparent)] pub struct Unique { pointer: NonZero<*const T>, // NOTE: this marker has no consequences for variance, but is necessary @@ -2840,6 +2841,7 @@ impl<'a, T: ?Sized> From> for Unique { /// such as Box, Rc, Arc, Vec, and LinkedList. This is the case because they /// provide a public API that follows the normal shared XOR mutable rules of Rust. #[stable(feature = "nonnull", since = "1.25.0")] +#[repr(transparent)] pub struct NonNull { pointer: NonZero<*const T>, } -- cgit 1.4.1-3-g733a5 From d22ad76ca83acda1428829173451eee0221f685a Mon Sep 17 00:00:00 2001 From: Pazzaz Date: Sat, 16 Jun 2018 20:19:19 +0200 Subject: Optimize sum of Durations by using custom function --- src/libcore/tests/time.rs | 14 ++++++++++++++ src/libcore/time.rs | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs index df139965753..466f28f0ef0 100644 --- a/src/libcore/tests/time.rs +++ b/src/libcore/tests/time.rs @@ -161,6 +161,20 @@ fn checked_div() { assert_eq!(Duration::new(2, 0).checked_div(0), None); } +#[test] +fn correct_sum() { + let durations = [ + Duration::new(1, 999_999_999), + Duration::new(2, 999_999_999), + Duration::new(0, 999_999_999), + Duration::new(0, 999_999_999), + Duration::new(0, 999_999_999), + Duration::new(5, 0), + ]; + let sum = durations.iter().sum::(); + assert_eq!(sum, Duration::new(1+2+5+4, 1_000_000_000 - 5)); +} + #[test] fn debug_formatting_extreme_values() { assert_eq!( diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 563eea0066d..25721b7fcec 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -524,17 +524,47 @@ impl DivAssign for Duration { } } +macro_rules! sum_durations { + ($iter:expr) => {{ + let mut total_secs: u64 = 0; + let mut total_nanos: u64 = 0; + + for entry in $iter { + total_secs = total_secs + .checked_add(entry.secs) + .expect("overflow in iter::sum over durations"); + total_nanos = match total_nanos.checked_add(entry.nanos as u64) { + Some(n) => n, + None => { + total_secs = total_secs + .checked_add(total_nanos / NANOS_PER_SEC as u64) + .expect("overflow in iter::sum over durations"); + (total_nanos % NANOS_PER_SEC as u64) + entry.nanos as u64 + } + }; + } + total_secs = total_secs + .checked_add(total_nanos / NANOS_PER_SEC as u64) + .expect("overflow in iter::sum over durations"); + total_nanos = total_nanos % NANOS_PER_SEC as u64; + Duration { + secs: total_secs, + nanos: total_nanos as u32, + } + }}; +} + #[stable(feature = "duration_sum", since = "1.16.0")] impl Sum for Duration { fn sum>(iter: I) -> Duration { - iter.fold(Duration::new(0, 0), |a, b| a + b) + sum_durations!(iter) } } #[stable(feature = "duration_sum", since = "1.16.0")] impl<'a> Sum<&'a Duration> for Duration { fn sum>(iter: I) -> Duration { - iter.fold(Duration::new(0, 0), |a, b| a + *b) + sum_durations!(iter) } } -- cgit 1.4.1-3-g733a5 From 5150ff0c729b5af88da8f45f15bef1b95ba70c08 Mon Sep 17 00:00:00 2001 From: David Corbett Date: Sun, 17 Jun 2018 12:58:01 -0400 Subject: Treat gc=No characters as numeric --- src/libcore/char/methods.rs | 8 ++--- src/libcore/tests/char.rs | 3 +- src/libcore/unicode/tables.rs | 72 +++++++++++++++++++++++++----------------- src/libcore/unicode/unicode.py | 2 +- 4 files changed, 50 insertions(+), 35 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index f6b201fe06d..6dc9c796278 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -673,11 +673,11 @@ impl char { /// assert!('٣'.is_alphanumeric()); /// assert!('7'.is_alphanumeric()); /// assert!('৬'.is_alphanumeric()); + /// assert!('¾'.is_alphanumeric()); + /// assert!('①'.is_alphanumeric()); /// assert!('K'.is_alphanumeric()); /// assert!('و'.is_alphanumeric()); /// assert!('藏'.is_alphanumeric()); - /// assert!(!'¾'.is_alphanumeric()); - /// assert!(!'①'.is_alphanumeric()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -727,11 +727,11 @@ impl char { /// assert!('٣'.is_numeric()); /// assert!('7'.is_numeric()); /// assert!('৬'.is_numeric()); + /// assert!('¾'.is_numeric()); + /// assert!('①'.is_numeric()); /// assert!(!'K'.is_numeric()); /// assert!(!'و'.is_numeric()); /// assert!(!'藏'.is_numeric()); - /// assert!(!'¾'.is_numeric()); - /// assert!(!'①'.is_numeric()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] diff --git a/src/libcore/tests/char.rs b/src/libcore/tests/char.rs index d2a9ed75be6..963178c8fc4 100644 --- a/src/libcore/tests/char.rs +++ b/src/libcore/tests/char.rs @@ -148,9 +148,10 @@ fn test_is_control() { } #[test] -fn test_is_digit() { +fn test_is_numeric() { assert!('2'.is_numeric()); assert!('7'.is_numeric()); + assert!('¾'.is_numeric()); assert!(!'c'.is_numeric()); assert!(!'i'.is_numeric()); assert!(!'z'.is_numeric()); diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs index 32668ea93dd..3de855ac943 100644 --- a/src/libcore/unicode/tables.rs +++ b/src/libcore/unicode/tables.rs @@ -40,7 +40,7 @@ pub mod general_category { pub const N_table: &super::BoolTrie = &super::BoolTrie { r1: [ - 0x03ff000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x03ff000000000000, 0x0000000000000000, 0x720c000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, @@ -50,12 +50,14 @@ pub mod general_category { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x00000000000003ff ], r2: [ - 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 3, - 0, 0, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 5, 0, 0, 0, 3, 2, 0, 0, 0, 0, 6, 0, 2, 0, 0, 7, 0, 0, 2, 8, 0, 0, 7, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 2, 0, 1, 0, 1, 0, 3, 0, 4, 0, 5, 0, 1, 0, 6, 0, 1, 0, 7, 0, 7, 8, + 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 11, 0, 0, 0, 12, 7, 0, 0, 0, 0, 13, 0, 14, 0, 0, 15, 0, 0, 7, 16, 0, 0, 15, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 9, 0, 0, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 27, 0, 28, + 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -69,10 +71,10 @@ pub mod general_category { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, + 0, 0, 1, 0, 0, 0, 0, 31, 0, 0, 7, 9, 0, 0, 32, 0, 7, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 2, 4, 0, 0, 12, 0, 2, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -82,18 +84,21 @@ pub mod general_category { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 ], r3: &[ - 0x0000000000000000, 0x0000ffc000000000, 0x0000000003ff0000, 0x000003ff00000000, - 0x00000000000003ff, 0x0001c00000000000, 0x000000000000ffc0, 0x0000000003ff03ff, - 0x03ff000000000000, 0xffffffff00000000, 0x00000000000001e7, 0x070003fe00000080, + 0x0000000000000000, 0x0000ffc000000000, 0x03f0ffc000000000, 0x00fcffc000000000, + 0x0007ffc000000000, 0x7f00ffc000000000, 0x01ffffc07f000000, 0x0000000003ff0000, + 0x000fffff00000000, 0x00000000000003ff, 0x1ffffe0000000000, 0x0001c00000000000, + 0x03ff03ff00000000, 0x000000000000ffc0, 0x0000000007ff0000, 0x0000000003ff03ff, + 0x03ff000000000000, 0x03f1000000000000, 0xffffffffffff0000, 0x00000000000003e7, + 0xffffffff00000000, 0x000000000fffffff, 0xfffffc0000000000, 0xffc0000000000000, + 0x00000000000fffff, 0x2000000000000000, 0x070003fe00000080, 0x00000000003c0000, + 0x000003ff00000000, 0x00000000fffeff00, 0xfffe0000000003ff, 0x003f000000000000, 0x03ff000003ff0000 ], r4: [ - 0, 1, 2, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 5, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 1, 2, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 5, 6, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -104,28 +109,37 @@ pub mod general_category { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ], r5: &[ - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 6, 0, 5, 7, 0, 0, 8, 0, 0, 0, 5, 0, 0, 0, 0, 0, 8, 0, 8, 0, 0, 0, - 0, 0, 8, 0, 9, 5, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, - 0, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, - 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 0, 7, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 10, 11, 12, 0, 13, 14, 0, 15, 16, 17, 0, 18, 19, 0, 0, 0, 0, 20, 21, 0, + 0, 0, 0, 22, 0, 0, 23, 24, 0, 0, 0, 25, 0, 21, 26, 0, 0, 27, 0, 0, 0, 21, 0, 0, 0, 0, 0, + 28, 0, 28, 0, 0, 0, 0, 0, 28, 0, 29, 30, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 32, 0, 0, 0, 28, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 33, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 38, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 28, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], r6: &[ - 0x0000000000000000, 0x001fffffffffffff, 0x0000000000000402, 0x00000000003e0000, - 0x000003ff00000000, 0x03ff000000000000, 0x0000ffc000000000, 0xffc0000000000000, - 0x0000000003ff0000, 0x00000000000003ff, 0xffffffffffffffff, 0x00007fffffffffff, - 0xffffffffffffc000 + 0x0000000000000000, 0x000fffffffffff80, 0x01ffffffffffffff, 0x0000000000000c00, + 0x0ffffffe00000000, 0x0000000f00000000, 0x0000000000000402, 0x00000000003e0000, + 0x000003ff00000000, 0xfe000000ff000000, 0x0000ff8000000000, 0xf800000000000000, + 0x000000000fc00000, 0x3000000000000000, 0xfffffffffffcffff, 0x60000000000001ff, + 0x00000000e0000000, 0x0000f80000000000, 0xff000000ff000000, 0x0000fe0000000000, + 0xfc00000000000000, 0x03ff000000000000, 0x7fffffff00000000, 0x0000007fe0000000, + 0x00000000001e0000, 0x0000fffffffc0000, 0xffc0000000000000, 0x001ffffe03ff0000, + 0x0000000003ff0000, 0x00000000000003ff, 0x0fff000000000000, 0x0007ffff00000000, + 0x00001fffffff0000, 0xffffffffffffffff, 0x00007fffffffffff, 0x00000003fbff0000, + 0x00000000007fffff, 0x000fffff00000000, 0x01ffffff00000000, 0xffffffffffffc000, + 0x000000000000ff80, 0xfffe000000000000, 0x001eefffffffffff, 0x0000000000001fff ], }; diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py index be0970b5444..28a1e01805e 100755 --- a/src/libcore/unicode/unicode.py +++ b/src/libcore/unicode/unicode.py @@ -52,7 +52,7 @@ expanded_categories = { 'Lu': ['LC', 'L'], 'Ll': ['LC', 'L'], 'Lt': ['LC', 'L'], 'Lm': ['L'], 'Lo': ['L'], 'Mn': ['M'], 'Mc': ['M'], 'Me': ['M'], - 'Nd': ['N'], 'Nl': ['N'], 'No': ['No'], + 'Nd': ['N'], 'Nl': ['N'], 'No': ['N'], 'Pc': ['P'], 'Pd': ['P'], 'Ps': ['P'], 'Pe': ['P'], 'Pi': ['P'], 'Pf': ['P'], 'Po': ['P'], 'Sm': ['S'], 'Sc': ['S'], 'Sk': ['S'], 'So': ['S'], -- cgit 1.4.1-3-g733a5 From 2b789bd0570983e82533f9ed30c80312ac334694 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 14 Jun 2018 00:32:30 +0200 Subject: Rename OOM to allocation error The acronym is not descriptive unless one has seen it before. * Rename the `oom` function to `handle_alloc_error`. It was **stabilized in 1.28**, so if we do this at all we need to land it this cycle. * Rename `set_oom_hook` to `set_alloc_error_hook` * Rename `take_oom_hook` to `take_alloc_error_hook` Bikeshed: `alloc` v.s. `allocator`, `error` v.s. `failure` --- src/liballoc/alloc.rs | 14 ++++----- src/liballoc/arc.rs | 4 +-- src/liballoc/raw_vec.rs | 16 +++++++---- src/liballoc/rc.rs | 4 +-- src/libcore/alloc.rs | 48 +++++++++++++++---------------- src/libstd/alloc.rs | 28 +++++++++--------- src/libstd/collections/hash/table.rs | 4 +-- src/test/run-pass/allocator-alloc-one.rs | 6 ++-- src/test/run-pass/realloc-16687.rs | 8 ++++-- src/test/run-pass/regions-mock-codegen.rs | 4 +-- 10 files changed, 72 insertions(+), 64 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 04c8063ffeb..84bd275df34 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -158,7 +158,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { if !ptr.is_null() { ptr } else { - oom(layout) + handle_alloc_error(layout) } } } @@ -184,13 +184,13 @@ pub(crate) unsafe fn box_free(ptr: Unique) { /// /// The default behavior of this function is to print a message to standard error /// and abort the process. -/// It can be replaced with [`set_oom_hook`] and [`take_oom_hook`]. +/// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`]. /// -/// [`set_oom_hook`]: ../../std/alloc/fn.set_oom_hook.html -/// [`take_oom_hook`]: ../../std/alloc/fn.take_oom_hook.html +/// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html +/// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html #[stable(feature = "global_alloc", since = "1.28.0")] #[rustc_allocator_nounwind] -pub fn oom(layout: Layout) -> ! { +pub fn handle_alloc_error(layout: Layout) -> ! { #[allow(improper_ctypes)] extern "Rust" { #[lang = "oom"] @@ -204,14 +204,14 @@ mod tests { extern crate test; use self::test::Bencher; use boxed::Box; - use alloc::{Global, Alloc, Layout, oom}; + use alloc::{Global, Alloc, Layout, handle_alloc_error}; #[test] fn allocate_zeroed() { unsafe { let layout = Layout::from_size_align(1024, 1).unwrap(); let ptr = Global.alloc_zeroed(layout.clone()) - .unwrap_or_else(|_| oom(layout)); + .unwrap_or_else(|_| handle_alloc_error(layout)); let mut i = ptr.cast::().as_ptr(); let end = i.offset(layout.size() as isize); diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index e3369f0a5b5..0fbd1408f64 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -32,7 +32,7 @@ use core::hash::{Hash, Hasher}; use core::{isize, usize}; use core::convert::From; -use alloc::{Global, Alloc, Layout, box_free, oom}; +use alloc::{Global, Alloc, Layout, box_free, handle_alloc_error}; use boxed::Box; use string::String; use vec::Vec; @@ -554,7 +554,7 @@ impl Arc { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|_| oom(layout)); + .unwrap_or_else(|_| handle_alloc_error(layout)); // Initialize the real ArcInner let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner; diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index d1f140e96a3..2369ce648fd 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -14,7 +14,7 @@ use core::ops::Drop; use core::ptr::{self, NonNull, Unique}; use core::slice; -use alloc::{Alloc, Layout, Global, oom}; +use alloc::{Alloc, Layout, Global, handle_alloc_error}; use alloc::CollectionAllocErr; use alloc::CollectionAllocErr::*; use boxed::Box; @@ -104,7 +104,7 @@ impl RawVec { }; match result { Ok(ptr) => ptr.cast(), - Err(_) => oom(layout), + Err(_) => handle_alloc_error(layout), } }; @@ -319,7 +319,9 @@ impl RawVec { new_size); match ptr_res { Ok(ptr) => (new_cap, ptr.cast().into()), - Err(_) => oom(Layout::from_size_align_unchecked(new_size, cur.align())), + Err(_) => handle_alloc_error( + Layout::from_size_align_unchecked(new_size, cur.align()) + ), } } None => { @@ -328,7 +330,7 @@ impl RawVec { let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; match self.a.alloc_array::(new_cap) { Ok(ptr) => (new_cap, ptr.into()), - Err(_) => oom(Layout::array::(new_cap).unwrap()), + Err(_) => handle_alloc_error(Layout::array::(new_cap).unwrap()), } } }; @@ -611,7 +613,9 @@ impl RawVec { old_layout, new_size) { Ok(p) => self.ptr = p.cast().into(), - Err(_) => oom(Layout::from_size_align_unchecked(new_size, align)), + Err(_) => handle_alloc_error( + Layout::from_size_align_unchecked(new_size, align) + ), } } self.cap = amount; @@ -673,7 +677,7 @@ impl RawVec { }; match (&res, fallibility) { - (Err(AllocErr), Infallible) => oom(new_layout), + (Err(AllocErr), Infallible) => handle_alloc_error(new_layout), _ => {} } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 84a6ecf7103..32d624e8fbc 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -259,7 +259,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, NonNull}; use core::convert::From; -use alloc::{Global, Alloc, Layout, box_free, oom}; +use alloc::{Global, Alloc, Layout, box_free, handle_alloc_error}; use string::String; use vec::Vec; @@ -662,7 +662,7 @@ impl Rc { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|_| oom(layout)); + .unwrap_or_else(|_| handle_alloc_error(layout)); // Initialize the real RcBox let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut RcBox; diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 353688d1b85..0c074582281 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -492,10 +492,10 @@ pub unsafe trait GlobalAlloc { /// library that aborts on memory exhaustion.) /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the [`oom`] function, + /// allocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn alloc(&self, layout: Layout) -> *mut u8; @@ -529,10 +529,10 @@ pub unsafe trait GlobalAlloc { /// just as in `alloc`. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the [`oom`] function, + /// allocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { let size = layout.size(); @@ -589,10 +589,10 @@ pub unsafe trait GlobalAlloc { /// library that aborts on memory exhaustion.) /// /// Clients wishing to abort computation in response to a - /// reallocation error are encouraged to call the [`oom`] function, + /// reallocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); @@ -733,10 +733,10 @@ pub unsafe trait Alloc { /// library that aborts on memory exhaustion.) /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the [`oom`] function, + /// allocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; /// Deallocate the memory referenced by `ptr`. @@ -843,10 +843,10 @@ pub unsafe trait Alloc { /// library that aborts on memory exhaustion.) /// /// Clients wishing to abort computation in response to a - /// reallocation error are encouraged to call the [`oom`] function, + /// reallocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn realloc(&mut self, ptr: NonNull, layout: Layout, @@ -889,10 +889,10 @@ pub unsafe trait Alloc { /// constraints, just as in `alloc`. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the [`oom`] function, + /// allocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); let p = self.alloc(layout); @@ -917,10 +917,10 @@ pub unsafe trait Alloc { /// constraints, just as in `alloc`. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the [`oom`] function, + /// allocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { let usable_size = self.usable_size(&layout); self.alloc(layout).map(|p| Excess(p, usable_size.1)) @@ -941,10 +941,10 @@ pub unsafe trait Alloc { /// constraints, just as in `realloc`. /// /// Clients wishing to abort computation in response to a - /// reallocation error are encouraged to call the [`oom`] function, + /// reallocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn realloc_excess(&mut self, ptr: NonNull, layout: Layout, @@ -986,7 +986,7 @@ pub unsafe trait Alloc { /// unable to assert that the memory block referenced by `ptr` /// could fit `layout`. /// - /// Note that one cannot pass `CannotReallocInPlace` to the `oom` + /// Note that one cannot pass `CannotReallocInPlace` to the `handle_alloc_error` /// function; clients are expected either to be able to recover from /// `grow_in_place` failures without aborting, or to fall back on /// another reallocation method before resorting to an abort. @@ -1041,7 +1041,7 @@ pub unsafe trait Alloc { /// unable to assert that the memory block referenced by `ptr` /// could fit `layout`. /// - /// Note that one cannot pass `CannotReallocInPlace` to the `oom` + /// Note that one cannot pass `CannotReallocInPlace` to the `handle_alloc_error` /// function; clients are expected either to be able to recover from /// `shrink_in_place` failures without aborting, or to fall back /// on another reallocation method before resorting to an abort. @@ -1090,10 +1090,10 @@ pub unsafe trait Alloc { /// will *not* yield undefined behavior. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the [`oom`] function, + /// allocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html fn alloc_one(&mut self) -> Result, AllocErr> where Self: Sized { @@ -1159,10 +1159,10 @@ pub unsafe trait Alloc { /// Always returns `Err` on arithmetic overflow. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the [`oom`] function, + /// allocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html fn alloc_array(&mut self, n: usize) -> Result, AllocErr> where Self: Sized { @@ -1206,10 +1206,10 @@ pub unsafe trait Alloc { /// Always returns `Err` on arithmetic overflow. /// /// Clients wishing to abort computation in response to a - /// reallocation error are encouraged to call the [`oom`] function, + /// reallocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn realloc_array(&mut self, ptr: NonNull, n_old: usize, diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index ae74a71dd06..f28e91e19b7 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -88,38 +88,38 @@ pub use alloc_system::System; static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); -/// Registers a custom OOM hook, replacing any that was previously registered. +/// Registers a custom allocation error hook, replacing any that was previously registered. /// -/// The OOM hook is invoked when an infallible memory allocation fails, before +/// The allocation error hook is invoked when an infallible memory allocation fails, before /// the runtime aborts. The default hook prints a message to standard error, -/// but this behavior can be customized with the [`set_oom_hook`] and -/// [`take_oom_hook`] functions. +/// but this behavior can be customized with the [`set_alloc_error_hook`] and +/// [`take_alloc_error_hook`] functions. /// /// The hook is provided with a `Layout` struct which contains information /// about the allocation that failed. /// -/// The OOM hook is a global resource. -#[unstable(feature = "oom_hook", issue = "51245")] -pub fn set_oom_hook(hook: fn(Layout)) { +/// The allocation error hook is a global resource. +#[unstable(feature = "alloc_error_hook", issue = "51245")] +pub fn set_alloc_error_hook(hook: fn(Layout)) { HOOK.store(hook as *mut (), Ordering::SeqCst); } -/// Unregisters the current OOM hook, returning it. +/// Unregisters the current allocation error hook, returning it. /// -/// *See also the function [`set_oom_hook`].* +/// *See also the function [`set_alloc_error_hook`].* /// /// If no custom hook is registered, the default hook will be returned. -#[unstable(feature = "oom_hook", issue = "51245")] -pub fn take_oom_hook() -> fn(Layout) { +#[unstable(feature = "alloc_error_hook", issue = "51245")] +pub fn take_alloc_error_hook() -> fn(Layout) { let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); if hook.is_null() { - default_oom_hook + default_alloc_error_hook } else { unsafe { mem::transmute(hook) } } } -fn default_oom_hook(layout: Layout) { +fn default_alloc_error_hook(layout: Layout) { dumb_print(format_args!("memory allocation of {} bytes failed", layout.size())); } @@ -130,7 +130,7 @@ fn default_oom_hook(layout: Layout) { pub extern fn rust_oom(layout: Layout) -> ! { let hook = HOOK.load(Ordering::SeqCst); let hook: fn(Layout) = if hook.is_null() { - default_oom_hook + default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }; diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 55f9f4f7cfe..d14b754ddb6 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::{Global, Alloc, Layout, LayoutErr, CollectionAllocErr, oom}; +use alloc::{Global, Alloc, Layout, LayoutErr, CollectionAllocErr, handle_alloc_error}; use hash::{BuildHasher, Hash, Hasher}; use marker; use mem::{size_of, needs_drop}; @@ -699,7 +699,7 @@ impl RawTable { // point into it. let (layout, _) = calculate_layout::(capacity)?; let buffer = Global.alloc(layout).map_err(|e| match fallibility { - Infallible => oom(layout), + Infallible => handle_alloc_error(layout), Fallible => e, })?; diff --git a/src/test/run-pass/allocator-alloc-one.rs b/src/test/run-pass/allocator-alloc-one.rs index f1fdbfc702d..f15b013c07b 100644 --- a/src/test/run-pass/allocator-alloc-one.rs +++ b/src/test/run-pass/allocator-alloc-one.rs @@ -10,11 +10,13 @@ #![feature(allocator_api, nonnull)] -use std::alloc::{Alloc, Global, Layout, oom}; +use std::alloc::{Alloc, Global, Layout, handle_alloc_error}; fn main() { unsafe { - let ptr = Global.alloc_one::().unwrap_or_else(|_| oom(Layout::new::())); + let ptr = Global.alloc_one::().unwrap_or_else(|_| { + handle_alloc_error(Layout::new::()) + }); *ptr.as_ptr() = 4; assert_eq!(*ptr.as_ptr(), 4); Global.dealloc_one(ptr); diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index 7152e721eac..3b4b458bb04 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -15,7 +15,7 @@ #![feature(heap_api, allocator_api)] -use std::alloc::{Global, Alloc, Layout, oom}; +use std::alloc::{Global, Alloc, Layout, handle_alloc_error}; use std::ptr::{self, NonNull}; fn main() { @@ -50,7 +50,7 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?})", layout); } - let ret = Global.alloc(layout).unwrap_or_else(|_| oom(layout)); + let ret = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); if PRINT { println!("allocate({:?}) = {:?}", layout, ret); @@ -73,7 +73,9 @@ unsafe fn test_triangle() -> bool { } let ret = Global.realloc(NonNull::new_unchecked(ptr), old, new.size()) - .unwrap_or_else(|_| oom(Layout::from_size_align_unchecked(new.size(), old.align()))); + .unwrap_or_else(|_| handle_alloc_error( + Layout::from_size_align_unchecked(new.size(), old.align()) + )); if PRINT { println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", diff --git a/src/test/run-pass/regions-mock-codegen.rs b/src/test/run-pass/regions-mock-codegen.rs index 745a19dec4d..b58e837f3bd 100644 --- a/src/test/run-pass/regions-mock-codegen.rs +++ b/src/test/run-pass/regions-mock-codegen.rs @@ -12,7 +12,7 @@ #![feature(allocator_api)] -use std::alloc::{Alloc, Global, Layout, oom}; +use std::alloc::{Alloc, Global, Layout, handle_alloc_error}; use std::ptr::NonNull; struct arena(()); @@ -33,7 +33,7 @@ struct Ccx { fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> { unsafe { let layout = Layout::new::(); - let ptr = Global.alloc(layout).unwrap_or_else(|_| oom(layout)); + let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); &*(ptr.as_ptr() as *const _) } } -- cgit 1.4.1-3-g733a5 From 000aff604e3b16ffc3771bd5d93a6e7b425852d2 Mon Sep 17 00:00:00 2001 From: Emerentius Date: Sat, 16 Jun 2018 21:58:28 +0200 Subject: specialize StepBy the originally generated code was highly suboptimal this brings it close to the same code or even exactly the same as a manual while-loop by eliminating a branch and the double stepping of n-1 + 1 steps The intermediate trait lets us circumvent the specialization type inference bugs --- src/libcore/iter/mod.rs | 80 ++++++++++++++++++++++++++++++++++++++++++----- src/libcore/tests/iter.rs | 8 +++++ 2 files changed, 81 insertions(+), 7 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 840d45ff1cc..c4132270d59 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -319,9 +319,10 @@ use cmp; use fmt; use iter_private::TrustedRandomAccess; -use ops::Try; +use ops::{self, Try}; use usize; use intrinsics; +use mem; #[stable(feature = "rust1", since = "1.0.0")] pub use self::iterator::Iterator; @@ -672,12 +673,7 @@ impl Iterator for StepBy where I: Iterator { #[inline] fn next(&mut self) -> Option { - if self.first_take { - self.first_take = false; - self.iter.next() - } else { - self.iter.nth(self.step) - } + ::spec_next(self) } #[inline] @@ -737,6 +733,76 @@ impl Iterator for StepBy where I: Iterator { } } +// hidden trait for specializing iterator methods +// could be generalized but is currently only used for StepBy +trait StepBySpecIterator { + type Item; + fn spec_next(&mut self) -> Option; +} + +impl StepBySpecIterator for StepBy +where + I: Iterator, +{ + type Item = I::Item; + + #[inline] + default fn spec_next(&mut self) -> Option { + if self.first_take { + self.first_take = false; + self.iter.next() + } else { + self.iter.nth(self.step) + } + } +} + +impl StepBySpecIterator for StepBy> +where + T: Step, +{ + #[inline] + fn spec_next(&mut self) -> Option { + self.first_take = false; + if !(self.iter.start < self.iter.end) { + return None; + } + // add 1 to self.step to get original step size back + // it was decremented for the general case on construction + if let Some(n) = self.iter.start.add_usize(self.step+1) { + let next = mem::replace(&mut self.iter.start, n); + Some(next) + } else { + let last = self.iter.start.clone(); + self.iter.start = self.iter.end.clone(); + Some(last) + } + } +} + +impl StepBySpecIterator for StepBy> +where + T: Step, +{ + #[inline] + fn spec_next(&mut self) -> Option { + self.first_take = false; + if !(self.iter.start <= self.iter.end) { + return None; + } + // add 1 to self.step to get original step size back + // it was decremented for the general case on construction + if let Some(n) = self.iter.start.add_usize(self.step+1) { + let next = mem::replace(&mut self.iter.start, n); + Some(next) + } else { + let last = self.iter.start.replace_one(); + self.iter.end.replace_zero(); + Some(last) + } + } +} + // StepBy can only make the iterator shorter, so the len will still fit. #[stable(feature = "iterator_step_by", since = "1.28.0")] impl ExactSizeIterator for StepBy where I: ExactSizeIterator {} diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 9b8d7031f8e..72b115f8b5f 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1618,6 +1618,14 @@ fn test_range_step() { assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), (usize::MAX, Some(usize::MAX))); } +#[test] +fn test_range_inclusive_step() { + assert_eq!((0..=50).step_by(10).collect::>(), [0, 10, 20, 30, 40, 50]); + assert_eq!((0..=5).step_by(1).collect::>(), [0, 1, 2, 3, 4, 5]); + assert_eq!((200..=255u8).step_by(10).collect::>(), [200, 210, 220, 230, 240, 250]); + assert_eq!((250..=255u8).step_by(1).collect::>(), [250, 251, 252, 253, 254, 255]); +} + #[test] fn test_range_last_max() { assert_eq!((0..20).last(), Some(19)); -- cgit 1.4.1-3-g733a5 From 776544f011a6a5beccb7923a261b0dcecdd2396a Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sat, 9 Jun 2018 16:53:36 -0700 Subject: Add message to `rustc_on_unimplemented` attributes in core --- src/liballoc/vec.rs | 10 +- src/libcore/cmp.rs | 10 +- src/libcore/iter/traits.rs | 7 +- src/libcore/marker.rs | 10 +- src/libcore/ops/index.rs | 10 +- src/libstd/panic.rs | 15 ++- src/libsyntax/parse/parser.rs | 8 -- src/test/compile-fail/associated-types-unsized.rs | 2 +- src/test/compile-fail/bad-method-typaram-kind.rs | 2 +- src/test/compile-fail/bad-sized.rs | 4 +- .../builtin-superkinds-double-superkind.rs | 2 +- .../compile-fail/builtin-superkinds-in-metadata.rs | 2 +- src/test/compile-fail/builtin-superkinds-simple.rs | 2 +- .../builtin-superkinds-typaram-not-send.rs | 3 +- ...sure-bounds-cant-promote-superkind-in-struct.rs | 2 +- src/test/compile-fail/dst-bad-assign-2.rs | 2 +- src/test/compile-fail/dst-bad-assign-3.rs | 2 +- src/test/compile-fail/dst-bad-assign.rs | 2 +- src/test/compile-fail/dst-bad-deep-2.rs | 2 +- src/test/compile-fail/dst-bad-deep.rs | 2 +- .../compile-fail/dst-object-from-unsized-type.rs | 8 +- src/test/compile-fail/dst-sized-trait-param.rs | 4 +- .../compile-fail/extern-types-not-sync-send.rs | 2 +- src/test/compile-fail/extern-types-unsized.rs | 8 +- src/test/compile-fail/issue-14366.rs | 2 +- src/test/compile-fail/issue-15756.rs | 2 +- src/test/compile-fail/issue-17651.rs | 2 +- src/test/compile-fail/issue-18107.rs | 2 +- src/test/compile-fail/issue-18919.rs | 2 +- src/test/compile-fail/issue-20005.rs | 2 +- src/test/compile-fail/issue-20433.rs | 2 +- src/test/compile-fail/issue-20605.rs | 2 +- src/test/compile-fail/issue-21763.rs | 2 +- src/test/compile-fail/issue-22874.rs | 2 +- src/test/compile-fail/issue-23281.rs | 2 +- src/test/compile-fail/issue-24446.rs | 2 +- src/test/compile-fail/issue-27060-2.rs | 2 +- src/test/compile-fail/issue-27078.rs | 2 +- src/test/compile-fail/issue-35988.rs | 2 +- src/test/compile-fail/issue-38954.rs | 2 +- src/test/compile-fail/issue-41229-ref-str.rs | 4 +- src/test/compile-fail/issue-42312.rs | 4 +- src/test/compile-fail/issue-5883.rs | 4 +- src/test/compile-fail/issue-7013.rs | 2 +- src/test/compile-fail/kindck-impl-type-params.rs | 8 +- src/test/compile-fail/kindck-nonsendable-1.rs | 2 +- src/test/compile-fail/kindck-send-object.rs | 3 +- src/test/compile-fail/kindck-send-object1.rs | 2 +- src/test/compile-fail/kindck-send-object2.rs | 3 +- src/test/compile-fail/kindck-send-owned.rs | 3 +- src/test/compile-fail/kindck-send-unsafe.rs | 2 +- src/test/compile-fail/no-send-res-ports.rs | 2 +- src/test/compile-fail/no_send-enum.rs | 2 +- src/test/compile-fail/no_send-rc.rs | 2 +- src/test/compile-fail/no_send-struct.rs | 2 +- src/test/compile-fail/not-panic-safe-2.rs | 4 +- src/test/compile-fail/not-panic-safe-3.rs | 4 +- src/test/compile-fail/not-panic-safe-4.rs | 4 +- src/test/compile-fail/not-panic-safe-6.rs | 4 +- src/test/compile-fail/not-panic-safe.rs | 3 +- src/test/compile-fail/range-1.rs | 2 +- src/test/compile-fail/range_traits-1.rs | 24 ++--- src/test/compile-fail/str-idx.rs | 2 +- src/test/compile-fail/str-mut-idx.rs | 6 +- src/test/compile-fail/substs-ppaux.rs | 4 +- .../compile-fail/trait-bounds-not-on-bare-trait.rs | 2 +- src/test/compile-fail/traits-negative-impls.rs | 14 +-- .../typeck-default-trait-impl-negation-send.rs | 2 +- src/test/compile-fail/union/union-unsized.rs | 6 +- src/test/compile-fail/unsized-bare-typaram.rs | 3 +- src/test/compile-fail/unsized-enum.rs | 2 +- .../unsized-inherent-impl-self-type.rs | 3 +- src/test/compile-fail/unsized-struct.rs | 4 +- .../compile-fail/unsized-trait-impl-self-type.rs | 3 +- .../compile-fail/unsized-trait-impl-trait-arg.rs | 2 +- src/test/compile-fail/unsized3.rs | 12 +-- src/test/compile-fail/unsized5.rs | 18 ++-- src/test/compile-fail/unsized6.rs | 39 ++++--- src/test/compile-fail/unsized7.rs | 2 +- src/test/ui/const-unsized.rs | 8 +- src/test/ui/const-unsized.stderr | 8 +- src/test/ui/error-codes/E0277-2.rs | 2 +- src/test/ui/error-codes/E0277-2.stderr | 2 +- src/test/ui/error-codes/E0277.rs | 2 +- src/test/ui/error-codes/E0277.stderr | 2 +- src/test/ui/feature-gate-trivial_bounds.stderr | 6 +- src/test/ui/generator/sized-yield.rs | 6 +- src/test/ui/generator/sized-yield.stderr | 11 +- src/test/ui/impl-trait/auto-trait-leak.rs | 2 +- src/test/ui/impl-trait/auto-trait-leak.stderr | 2 +- src/test/ui/impl-trait/auto-trait-leak2.rs | 4 +- src/test/ui/impl-trait/auto-trait-leak2.stderr | 4 +- .../ui/interior-mutability/interior-mutability.rs | 3 +- .../interior-mutability/interior-mutability.stderr | 6 +- src/test/ui/mismatched_types/binops.rs | 4 +- src/test/ui/mismatched_types/binops.stderr | 12 +-- src/test/ui/mismatched_types/cast-rfc0401.rs | 4 +- src/test/ui/mismatched_types/cast-rfc0401.stderr | 8 +- src/test/ui/partialeq_help.stderr | 4 +- src/test/ui/resolve/issue-5035-2.rs | 3 +- src/test/ui/resolve/issue-5035-2.stderr | 4 +- src/test/ui/suggestions/str-array-assignment.rs | 2 +- .../ui/suggestions/str-array-assignment.stderr | 2 +- src/test/ui/trait-suggest-where-clause.rs | 8 +- src/test/ui/trait-suggest-where-clause.stderr | 8 +- src/test/ui/trivial-bounds-leak.stderr | 2 +- src/test/ui/type-check-defaults.rs | 14 +-- src/test/ui/type-check-defaults.stderr | 8 +- src/test/ui/union/union-sized-field.rs | 9 +- src/test/ui/union/union-sized-field.stderr | 16 +-- src/test/ui/unsized-enum2.rs | 57 +++++++---- src/test/ui/unsized-enum2.stderr | 112 ++++++++++----------- 112 files changed, 394 insertions(+), 318 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index b5739e1a825..752a6c966d5 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1693,7 +1693,10 @@ impl Hash for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] +#[rustc_on_unimplemented( + message="vector indices are of type `usize` or ranges of `usize`", + label="vector indices are of type `usize` or ranges of `usize`", +)] impl Index for Vec where I: ::core::slice::SliceIndex<[T]>, @@ -1707,7 +1710,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] +#[rustc_on_unimplemented( + message="vector indices are of type `usize` or ranges of `usize`", + label="vector indices are of type `usize` or ranges of `usize`", +)] impl IndexMut for Vec where I: ::core::slice::SliceIndex<[T]>, diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 13e838773a5..3626a266ad5 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -108,7 +108,10 @@ use self::Ordering::*; #[stable(feature = "rust1", since = "1.0.0")] #[doc(alias = "==")] #[doc(alias = "!=")] -#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] +#[rustc_on_unimplemented( + message="can't compare `{Self}` with `{Rhs}`", + label="no implementation for `{Self} == {Rhs}`", +)] pub trait PartialEq { /// This method tests for `self` and `other` values to be equal, and is used /// by `==`. @@ -611,7 +614,10 @@ impl PartialOrd for Ordering { #[doc(alias = "<")] #[doc(alias = "<=")] #[doc(alias = ">=")] -#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] +#[rustc_on_unimplemented( + message="can't compare `{Self}` with `{Rhs}`", + label="no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`", +)] pub trait PartialOrd: PartialEq { /// This method returns an ordering between `self` and `other` values if one exists. /// diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 3d2ce9e6b10..4b2c1aa551e 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -104,8 +104,11 @@ use super::LoopState; /// assert_eq!(c.0, vec![0, 1, 2, 3, 4]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented="a collection of type `{Self}` cannot be \ - built from an iterator over elements of type `{A}`"] +#[rustc_on_unimplemented( + message="a collection of type `{Self}` cannot be built from an iterator \ + over elements of type `{A}`", + label="a collection of type `{Self}` cannot be built from `std::iter::Iterator`", +)] pub trait FromIterator: Sized { /// Creates a value from an iterator. /// diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 3d3f63ecf37..d5416e393f4 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -39,7 +39,10 @@ use hash::Hasher; /// [arc]: ../../std/sync/struct.Arc.html /// [ub]: ../../reference/behavior-considered-undefined.html #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"] +#[rustc_on_unimplemented( + message="`{Self}` cannot be sent between threads safely", + label="`{Self}` cannot be sent between threads safely" +)] pub unsafe auto trait Send { // empty. } @@ -88,7 +91,10 @@ impl !Send for *mut T { } /// [trait object]: ../../book/first-edition/trait-objects.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sized"] -#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"] +#[rustc_on_unimplemented( + message="`{Self}` does not have a constant size known at compile-time", + label="`{Self}` does not have a constant size known at compile-time" +)] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable pub trait Sized { // Empty. diff --git a/src/libcore/ops/index.rs b/src/libcore/ops/index.rs index 0a0e92a9180..1ac80ecc96f 100644 --- a/src/libcore/ops/index.rs +++ b/src/libcore/ops/index.rs @@ -60,7 +60,10 @@ /// assert_eq!(nucleotide_count[Nucleotide::T], 12); /// ``` #[lang = "index"] -#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"] +#[rustc_on_unimplemented( + message="the type `{Self}` cannot be indexed by `{Idx}`", + label="`{Self}` cannot be indexed by `{Idx}`", +)] #[stable(feature = "rust1", since = "1.0.0")] #[doc(alias = "]")] #[doc(alias = "[")] @@ -147,7 +150,10 @@ pub trait Index { /// balance[Side::Left] = Weight::Kilogram(3.0); /// ``` #[lang = "index_mut"] -#[rustc_on_unimplemented = "the type `{Self}` cannot be mutably indexed by `{Idx}`"] +#[rustc_on_unimplemented( + message="the type `{Self}` cannot be mutably indexed by `{Idx}`", + label="`{Self}` cannot be mutably indexed by `{Idx}`", +)] #[stable(feature = "rust1", since = "1.0.0")] #[doc(alias = "[")] #[doc(alias = "]")] diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 4b5a063ea73..2c11c262488 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -110,8 +110,10 @@ pub use core::panic::{PanicInfo, Location}; /// /// [`AssertUnwindSafe`]: ./struct.AssertUnwindSafe.html #[stable(feature = "catch_unwind", since = "1.9.0")] -#[rustc_on_unimplemented = "the type {Self} may not be safely transferred \ - across an unwind boundary"] +#[rustc_on_unimplemented( + message="the type `{Self}` may not be safely transferred across an unwind boundary", + label="`{Self}` may not be safely transferred across an unwind boundary", +)] pub auto trait UnwindSafe {} /// A marker trait representing types where a shared reference is considered @@ -126,9 +128,12 @@ pub auto trait UnwindSafe {} /// [`UnsafeCell`]: ../cell/struct.UnsafeCell.html /// [`UnwindSafe`]: ./trait.UnwindSafe.html #[stable(feature = "catch_unwind", since = "1.9.0")] -#[rustc_on_unimplemented = "the type {Self} may contain interior mutability \ - and a reference may not be safely transferrable \ - across a catch_unwind boundary"] +#[rustc_on_unimplemented( + message="the type `{Self}` may contain interior mutability and a reference may not be safely \ + transferrable across a catch_unwind boundary", + label="`{Self}` may contain interior mutability and a reference may not be safely \ + transferrable across a catch_unwind boundary", +)] pub auto trait RefUnwindSafe {} /// A simple wrapper around a type to assert that it is unwind safe. diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index afb0931f950..5d04aa711c1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1204,14 +1204,6 @@ impl<'a> Parser<'a> { fn span_fatal_err>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> { err.span_err(sp, self.diagnostic()) } - fn span_fatal_help>(&self, - sp: S, - m: &str, - help: &str) -> DiagnosticBuilder<'a> { - let mut err = self.sess.span_diagnostic.struct_span_fatal(sp, m); - err.help(help); - err - } fn bug(&self, m: &str) -> ! { self.sess.span_diagnostic.span_bug(self.span, m) } diff --git a/src/test/compile-fail/associated-types-unsized.rs b/src/test/compile-fail/associated-types-unsized.rs index f1827022964..8c0ce26b294 100644 --- a/src/test/compile-fail/associated-types-unsized.rs +++ b/src/test/compile-fail/associated-types-unsized.rs @@ -14,7 +14,7 @@ trait Get { } fn foo(t: T) { - let x = t.get(); //~ ERROR `::Value: std::marker::Sized` is not + let x = t.get(); //~ ERROR `::Value` does not have a constant size known at compile-time } fn main() { diff --git a/src/test/compile-fail/bad-method-typaram-kind.rs b/src/test/compile-fail/bad-method-typaram-kind.rs index 5be90f05018..7cef3f13dfc 100644 --- a/src/test/compile-fail/bad-method-typaram-kind.rs +++ b/src/test/compile-fail/bad-method-typaram-kind.rs @@ -9,7 +9,7 @@ // except according to those terms. fn foo() { - 1.bar::(); //~ ERROR `T: std::marker::Send` is not satisfied + 1.bar::(); //~ ERROR `T` cannot be sent between threads safely } trait bar { diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs index df3da5096bf..55b009aef4f 100644 --- a/src/test/compile-fail/bad-sized.rs +++ b/src/test/compile-fail/bad-sized.rs @@ -13,6 +13,6 @@ trait Trait {} pub fn main() { let x: Vec = Vec::new(); //~^ ERROR only auto traits can be used as additional traits in a trait object - //~| ERROR the trait bound `Trait: std::marker::Sized` is not satisfied - //~| ERROR the trait bound `Trait: std::marker::Sized` is not satisfied + //~| ERROR `Trait` does not have a constant size known at compile-time + //~| ERROR `Trait` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/builtin-superkinds-double-superkind.rs b/src/test/compile-fail/builtin-superkinds-double-superkind.rs index 261881d880b..3f7f2adabdf 100644 --- a/src/test/compile-fail/builtin-superkinds-double-superkind.rs +++ b/src/test/compile-fail/builtin-superkinds-double-superkind.rs @@ -14,7 +14,7 @@ trait Foo : Send+Sync { } impl Foo for (T,) { } -//~^ ERROR the trait bound `T: std::marker::Send` is not satisfied in `(T,)` [E0277] +//~^ ERROR `T` cannot be sent between threads safely [E0277] impl Foo for (T,T) { } //~^ ERROR `T` cannot be shared between threads safely [E0277] diff --git a/src/test/compile-fail/builtin-superkinds-in-metadata.rs b/src/test/compile-fail/builtin-superkinds-in-metadata.rs index de2084c4e81..88b5a3fbb55 100644 --- a/src/test/compile-fail/builtin-superkinds-in-metadata.rs +++ b/src/test/compile-fail/builtin-superkinds-in-metadata.rs @@ -22,6 +22,6 @@ struct X(T); impl RequiresShare for X { } impl RequiresRequiresShareAndSend for X { } -//~^ ERROR `T: std::marker::Send` is not satisfied +//~^ ERROR `T` cannot be sent between threads safely [E0277] fn main() { } diff --git a/src/test/compile-fail/builtin-superkinds-simple.rs b/src/test/compile-fail/builtin-superkinds-simple.rs index 6dc5f39cb30..22dc9598d29 100644 --- a/src/test/compile-fail/builtin-superkinds-simple.rs +++ b/src/test/compile-fail/builtin-superkinds-simple.rs @@ -14,6 +14,6 @@ trait Foo : Send { } impl Foo for std::rc::Rc { } -//~^ ERROR `std::rc::Rc: std::marker::Send` is not satisfied +//~^ ERROR `std::rc::Rc` cannot be sent between threads safely fn main() { } diff --git a/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs b/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs index d4bb8de13d0..e0b2043c110 100644 --- a/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs +++ b/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs @@ -12,6 +12,7 @@ trait Foo : Send { } -impl Foo for T { } //~ ERROR `T: std::marker::Send` is not satisfied +impl Foo for T { } +//~^ ERROR `T` cannot be sent between threads safely fn main() { } diff --git a/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs b/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs index b9224e7be7f..12e9fb30902 100644 --- a/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs +++ b/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs @@ -13,7 +13,7 @@ struct X where F: FnOnce() + 'static + Send { } fn foo(blk: F) -> X where F: FnOnce() + 'static { - //~^ ERROR `F: std::marker::Send` is not satisfied + //~^ ERROR `F` cannot be sent between threads safely return X { field: blk }; } diff --git a/src/test/compile-fail/dst-bad-assign-2.rs b/src/test/compile-fail/dst-bad-assign-2.rs index 10c8f1eed00..c3cbc904842 100644 --- a/src/test/compile-fail/dst-bad-assign-2.rs +++ b/src/test/compile-fail/dst-bad-assign-2.rs @@ -43,5 +43,5 @@ pub fn main() { let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; let z: Box = Box::new(Bar1 {f: 36}); f5.ptr = *z; - //~^ ERROR `ToBar: std::marker::Sized` is not satisfied + //~^ ERROR `ToBar` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/dst-bad-assign-3.rs b/src/test/compile-fail/dst-bad-assign-3.rs index ceaa3716232..1cd5b51fe34 100644 --- a/src/test/compile-fail/dst-bad-assign-3.rs +++ b/src/test/compile-fail/dst-bad-assign-3.rs @@ -45,5 +45,5 @@ pub fn main() { //~| expected type `ToBar` //~| found type `Bar1` //~| expected trait ToBar, found struct `Bar1` - //~| ERROR `ToBar: std::marker::Sized` is not satisfied + //~| ERROR `ToBar` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/dst-bad-assign.rs b/src/test/compile-fail/dst-bad-assign.rs index 4f7d07600ad..dcd78ac044c 100644 --- a/src/test/compile-fail/dst-bad-assign.rs +++ b/src/test/compile-fail/dst-bad-assign.rs @@ -47,5 +47,5 @@ pub fn main() { //~| expected type `ToBar` //~| found type `Bar1` //~| expected trait ToBar, found struct `Bar1` - //~| ERROR `ToBar: std::marker::Sized` is not satisfied + //~| ERROR `ToBar` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/dst-bad-deep-2.rs b/src/test/compile-fail/dst-bad-deep-2.rs index 0c812b1d815..9ed2ec8d98d 100644 --- a/src/test/compile-fail/dst-bad-deep-2.rs +++ b/src/test/compile-fail/dst-bad-deep-2.rs @@ -19,5 +19,5 @@ pub fn main() { let f: ([isize; 3],) = ([5, 6, 7],); let g: &([isize],) = &f; let h: &(([isize],),) = &(*g,); - //~^ ERROR `[isize]: std::marker::Sized` is not satisfied + //~^ ERROR `[isize]` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/dst-bad-deep.rs b/src/test/compile-fail/dst-bad-deep.rs index f508364d751..9b575ae4aad 100644 --- a/src/test/compile-fail/dst-bad-deep.rs +++ b/src/test/compile-fail/dst-bad-deep.rs @@ -21,5 +21,5 @@ pub fn main() { let f: Fat<[isize; 3]> = Fat { ptr: [5, 6, 7] }; let g: &Fat<[isize]> = &f; let h: &Fat> = &Fat { ptr: *g }; - //~^ ERROR `[isize]: std::marker::Sized` is not satisfied + //~^ ERROR `[isize]` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/dst-object-from-unsized-type.rs b/src/test/compile-fail/dst-object-from-unsized-type.rs index 8fafd78d407..678eef76fde 100644 --- a/src/test/compile-fail/dst-object-from-unsized-type.rs +++ b/src/test/compile-fail/dst-object-from-unsized-type.rs @@ -16,22 +16,22 @@ impl Foo for [u8] {} fn test1(t: &T) { let u: &Foo = t; - //~^ ERROR `T: std::marker::Sized` is not satisfied + //~^ ERROR `T` does not have a constant size known at compile-time } fn test2(t: &T) { let v: &Foo = t as &Foo; - //~^ ERROR `T: std::marker::Sized` is not satisfied + //~^ ERROR `T` does not have a constant size known at compile-time } fn test3() { let _: &[&Foo] = &["hi"]; - //~^ ERROR `str: std::marker::Sized` is not satisfied + //~^ ERROR `str` does not have a constant size known at compile-time } fn test4(x: &[u8]) { let _: &Foo = x as &Foo; - //~^ ERROR `[u8]: std::marker::Sized` is not satisfied + //~^ ERROR `[u8]` does not have a constant size known at compile-time } fn main() { } diff --git a/src/test/compile-fail/dst-sized-trait-param.rs b/src/test/compile-fail/dst-sized-trait-param.rs index bd5fd3ee3b7..cafd67809f8 100644 --- a/src/test/compile-fail/dst-sized-trait-param.rs +++ b/src/test/compile-fail/dst-sized-trait-param.rs @@ -15,9 +15,9 @@ trait Foo : Sized { fn take(self, x: &T) { } } // Note: T is sized impl Foo<[isize]> for usize { } -//~^ ERROR `[isize]: std::marker::Sized` is not satisfied +//~^ ERROR `[isize]` does not have a constant size known at compile-time impl Foo for [usize] { } -//~^ ERROR `[usize]: std::marker::Sized` is not satisfied +//~^ ERROR `[usize]` does not have a constant size known at compile-time pub fn main() { } diff --git a/src/test/compile-fail/extern-types-not-sync-send.rs b/src/test/compile-fail/extern-types-not-sync-send.rs index 6a7a515ba5f..10abb80a2f7 100644 --- a/src/test/compile-fail/extern-types-not-sync-send.rs +++ b/src/test/compile-fail/extern-types-not-sync-send.rs @@ -24,5 +24,5 @@ fn main() { //~^ ERROR `A` cannot be shared between threads safely [E0277] assert_send::(); - //~^ ERROR the trait bound `A: std::marker::Send` is not satisfied + //~^ ERROR `A` cannot be sent between threads safely [E0277] } diff --git a/src/test/compile-fail/extern-types-unsized.rs b/src/test/compile-fail/extern-types-unsized.rs index faa27894806..b3e19899a67 100644 --- a/src/test/compile-fail/extern-types-unsized.rs +++ b/src/test/compile-fail/extern-types-unsized.rs @@ -30,14 +30,14 @@ fn assert_sized() { } fn main() { assert_sized::(); - //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied + //~^ ERROR `A` does not have a constant size known at compile-time assert_sized::(); - //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied + //~^ ERROR `A` does not have a constant size known at compile-time assert_sized::>(); - //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied + //~^ ERROR `A` does not have a constant size known at compile-time assert_sized::>>(); - //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied + //~^ ERROR `A` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/issue-14366.rs b/src/test/compile-fail/issue-14366.rs index 84452accc9a..7b4954a2d4e 100644 --- a/src/test/compile-fail/issue-14366.rs +++ b/src/test/compile-fail/issue-14366.rs @@ -10,5 +10,5 @@ fn main() { let _x = "test" as &::std::any::Any; -//~^ ERROR `str: std::marker::Sized` is not satisfied + //~^ ERROR `str` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/issue-15756.rs b/src/test/compile-fail/issue-15756.rs index 41349d7d744..0df82de8338 100644 --- a/src/test/compile-fail/issue-15756.rs +++ b/src/test/compile-fail/issue-15756.rs @@ -15,7 +15,7 @@ fn dft_iter<'a, T>(arg1: Chunks<'a,T>, arg2: ChunksMut<'a,T>) { for &mut something -//~^ ERROR `[T]: std::marker::Sized` is not satisfied + //~^ ERROR `[T]` does not have a constant size known at compile-time in arg2 { } diff --git a/src/test/compile-fail/issue-17651.rs b/src/test/compile-fail/issue-17651.rs index 4996da057dd..13548b06ea1 100644 --- a/src/test/compile-fail/issue-17651.rs +++ b/src/test/compile-fail/issue-17651.rs @@ -13,5 +13,5 @@ fn main() { (|| Box::new(*(&[0][..])))(); - //~^ ERROR `[{integer}]: std::marker::Sized` is not satisfied + //~^ ERROR `[{integer}]` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/issue-18107.rs b/src/test/compile-fail/issue-18107.rs index 33d68c121bf..5faa8885e73 100644 --- a/src/test/compile-fail/issue-18107.rs +++ b/src/test/compile-fail/issue-18107.rs @@ -12,7 +12,7 @@ pub trait AbstractRenderer {} fn _create_render(_: &()) -> AbstractRenderer -//~^ ERROR: `AbstractRenderer + 'static: std::marker::Sized` is not satisfied +//~^ ERROR: `AbstractRenderer + 'static` does not have a constant size known at compile-time { match 0 { _ => unimplemented!() diff --git a/src/test/compile-fail/issue-18919.rs b/src/test/compile-fail/issue-18919.rs index 3e21360721b..14b776cb1ff 100644 --- a/src/test/compile-fail/issue-18919.rs +++ b/src/test/compile-fail/issue-18919.rs @@ -11,7 +11,7 @@ type FuncType<'f> = Fn(&isize) -> isize + 'f; fn ho_func(f: Option) { - //~^ ERROR: `for<'r> std::ops::Fn(&'r isize) -> isize: std::marker::Sized` is not satisfied + //~^ ERROR: `for<'r> std::ops::Fn(&'r isize) -> isize` does not have a constant size known at } fn main() {} diff --git a/src/test/compile-fail/issue-20005.rs b/src/test/compile-fail/issue-20005.rs index b02757fb5a3..ab47f687fc2 100644 --- a/src/test/compile-fail/issue-20005.rs +++ b/src/test/compile-fail/issue-20005.rs @@ -15,7 +15,7 @@ trait From { } trait To { - fn to( //~ ERROR `Self: std::marker::Sized` is not satisfied + fn to( //~ ERROR `Self` does not have a constant size known at compile-time self ) -> >::Result where Dst: From { From::from(self) diff --git a/src/test/compile-fail/issue-20433.rs b/src/test/compile-fail/issue-20433.rs index d1a139e698e..d8ca00d313f 100644 --- a/src/test/compile-fail/issue-20433.rs +++ b/src/test/compile-fail/issue-20433.rs @@ -14,5 +14,5 @@ struct The; impl The { fn iceman(c: Vec<[i32]>) {} - //~^ ERROR the trait bound `[i32]: std::marker::Sized` is not satisfied + //~^ ERROR `[i32]` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/issue-20605.rs b/src/test/compile-fail/issue-20605.rs index 5eb0e4360fc..c5a724bba80 100644 --- a/src/test/compile-fail/issue-20605.rs +++ b/src/test/compile-fail/issue-20605.rs @@ -10,7 +10,7 @@ fn changer<'a>(mut things: Box>) { for item in *things { *item = 0 } -//~^ ERROR the trait bound `std::iter::Iterator: std::marker::Sized` is not satisfied +//~^ ERROR `std::iter::Iterator` does not have a constant size known at compile-time } fn main() {} diff --git a/src/test/compile-fail/issue-21763.rs b/src/test/compile-fail/issue-21763.rs index cb0baee0a87..b4f952c87d4 100644 --- a/src/test/compile-fail/issue-21763.rs +++ b/src/test/compile-fail/issue-21763.rs @@ -17,5 +17,5 @@ fn foo() {} fn main() { foo::, Rc<()>>>(); - //~^ ERROR: `std::rc::Rc<()>: std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely } diff --git a/src/test/compile-fail/issue-22874.rs b/src/test/compile-fail/issue-22874.rs index 0df84a436c0..de176486af7 100644 --- a/src/test/compile-fail/issue-22874.rs +++ b/src/test/compile-fail/issue-22874.rs @@ -10,7 +10,7 @@ struct Table { rows: [[String]], - //~^ ERROR the trait bound `[std::string::String]: std::marker::Sized` is not satisfied [E0277] + //~^ ERROR `[std::string::String]` does not have a constant size known at compile-time } fn f(table: &Table) -> &[String] { diff --git a/src/test/compile-fail/issue-23281.rs b/src/test/compile-fail/issue-23281.rs index 5feeb36b1e4..fdab3b59d1b 100644 --- a/src/test/compile-fail/issue-23281.rs +++ b/src/test/compile-fail/issue-23281.rs @@ -14,7 +14,7 @@ pub struct Struct; impl Struct { pub fn function(funs: Vec ()>) {} - //~^ ERROR the trait bound `std::ops::Fn() + 'static: std::marker::Sized` is not satisfied + //~^ ERROR `std::ops::Fn() + 'static` does not have a constant size known at compile-time } fn main() {} diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index acd50bcf9e1..5f36bbcf5fd 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -11,7 +11,7 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { //~^ ERROR: mismatched types - //~| ERROR: `std::ops::Fn() -> u32 + 'static: std::marker::Sized` is not satisfied + //~| ERROR: `std::ops::Fn() -> u32 + 'static` does not have a constant size known at compile-time 0 }; } diff --git a/src/test/compile-fail/issue-27060-2.rs b/src/test/compile-fail/issue-27060-2.rs index 28180b05c8d..123bbf3358d 100644 --- a/src/test/compile-fail/issue-27060-2.rs +++ b/src/test/compile-fail/issue-27060-2.rs @@ -10,7 +10,7 @@ #[repr(packed)] pub struct Bad { - data: T, //~ ERROR `T: std::marker::Sized` is not satisfied + data: T, //~ ERROR `T` does not have a constant size known at compile-time } fn main() {} diff --git a/src/test/compile-fail/issue-27078.rs b/src/test/compile-fail/issue-27078.rs index f34bef62249..32933fa6176 100644 --- a/src/test/compile-fail/issue-27078.rs +++ b/src/test/compile-fail/issue-27078.rs @@ -13,7 +13,7 @@ trait Foo { const BAR: i32; fn foo(self) -> &'static i32 { - //~^ ERROR the trait bound `Self: std::marker::Sized` is not satisfied + //~^ ERROR `Self` does not have a constant size known at compile-time &::BAR } } diff --git a/src/test/compile-fail/issue-35988.rs b/src/test/compile-fail/issue-35988.rs index c2e6a88a57b..8f5b68986e5 100644 --- a/src/test/compile-fail/issue-35988.rs +++ b/src/test/compile-fail/issue-35988.rs @@ -10,7 +10,7 @@ enum E { V([Box]), - //~^ ERROR the trait bound `[std::boxed::Box]: std::marker::Sized` is not satisfied [E0277] + //~^ ERROR `[std::boxed::Box]` does not have a constant size known at compile-time } fn main() {} diff --git a/src/test/compile-fail/issue-38954.rs b/src/test/compile-fail/issue-38954.rs index 896728b6da0..960099f3193 100644 --- a/src/test/compile-fail/issue-38954.rs +++ b/src/test/compile-fail/issue-38954.rs @@ -9,6 +9,6 @@ // except according to those terms. fn _test(ref _p: str) {} -//~^ ERROR the trait bound `str: std::marker::Sized` is not satisfied [E0277] +//~^ ERROR `str` does not have a constant size known at compile-time fn main() { } diff --git a/src/test/compile-fail/issue-41229-ref-str.rs b/src/test/compile-fail/issue-41229-ref-str.rs index 31bc21c23ba..b1e24c818d8 100644 --- a/src/test/compile-fail/issue-41229-ref-str.rs +++ b/src/test/compile-fail/issue-41229-ref-str.rs @@ -9,8 +9,6 @@ // except according to those terms. pub fn example(ref s: str) {} -//~^ ERROR the trait bound `str: std::marker::Sized` is not satisfied -//~| `str` does not have a constant size known at compile-time -//~| the trait `std::marker::Sized` is not implemented for `str` +//~^ ERROR `str` does not have a constant size known at compile-time fn main() {} diff --git a/src/test/compile-fail/issue-42312.rs b/src/test/compile-fail/issue-42312.rs index 06573b42b59..89eb5c5ebc1 100644 --- a/src/test/compile-fail/issue-42312.rs +++ b/src/test/compile-fail/issue-42312.rs @@ -12,10 +12,10 @@ use std::ops::Deref; pub trait Foo { fn baz(_: Self::Target) where Self: Deref {} - //~^ ERROR `::Target: std::marker::Sized` is not satisfied + //~^ ERROR `::Target` does not have a constant size known at } pub fn f(_: ToString) {} -//~^ ERROR the trait bound `std::string::ToString + 'static: std::marker::Sized` is not satisfied +//~^ ERROR `std::string::ToString + 'static` does not have a constant size known at compile-time fn main() { } diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index e14d9f3a35c..580625f4955 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -15,8 +15,8 @@ struct Struct { } fn new_struct(r: A+'static) - -> Struct { //~^ ERROR `A + 'static: std::marker::Sized` is not satisfied - //~^ ERROR `A + 'static: std::marker::Sized` is not satisfied + -> Struct { //~^ ERROR `A + 'static` does not have a constant size known at compile-time + //~^ ERROR `A + 'static` does not have a constant size known at compile-time Struct { r: r } } diff --git a/src/test/compile-fail/issue-7013.rs b/src/test/compile-fail/issue-7013.rs index 95bbd4eccf4..0c19780bcb4 100644 --- a/src/test/compile-fail/issue-7013.rs +++ b/src/test/compile-fail/issue-7013.rs @@ -34,5 +34,5 @@ struct A { fn main() { let a = A {v: box B{v: None} as Box}; - //~^ ERROR `std::rc::Rc>: std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc>` cannot be sent between threads safely } diff --git a/src/test/compile-fail/kindck-impl-type-params.rs b/src/test/compile-fail/kindck-impl-type-params.rs index 2a86cdef981..3a0e66f58e0 100644 --- a/src/test/compile-fail/kindck-impl-type-params.rs +++ b/src/test/compile-fail/kindck-impl-type-params.rs @@ -26,15 +26,15 @@ impl Gettable for S {} fn f(val: T) { let t: S = S(marker::PhantomData); let a = &t as &Gettable; - //~^ ERROR : std::marker::Send` is not satisfied - //~^^ ERROR : std::marker::Copy` is not satisfied + //~^ ERROR `T` cannot be sent between threads safely + //~| ERROR : std::marker::Copy` is not satisfied } fn g(val: T) { let t: S = S(marker::PhantomData); let a: &Gettable = &t; - //~^ ERROR : std::marker::Send` is not satisfied - //~^^ ERROR : std::marker::Copy` is not satisfied + //~^ ERROR `T` cannot be sent between threads safely + //~| ERROR : std::marker::Copy` is not satisfied } fn foo<'a>() { diff --git a/src/test/compile-fail/kindck-nonsendable-1.rs b/src/test/compile-fail/kindck-nonsendable-1.rs index dd77c2c138f..43c212b2af5 100644 --- a/src/test/compile-fail/kindck-nonsendable-1.rs +++ b/src/test/compile-fail/kindck-nonsendable-1.rs @@ -18,5 +18,5 @@ fn bar(_: F) { } fn main() { let x = Rc::new(3); bar(move|| foo(x)); - //~^ ERROR : std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc` cannot be sent between threads safely } diff --git a/src/test/compile-fail/kindck-send-object.rs b/src/test/compile-fail/kindck-send-object.rs index a84eae0bfda..a3eb47be3ee 100644 --- a/src/test/compile-fail/kindck-send-object.rs +++ b/src/test/compile-fail/kindck-send-object.rs @@ -24,7 +24,8 @@ fn object_ref_with_static_bound_not_ok() { } fn box_object_with_no_bound_not_ok<'a>() { - assert_send::>(); //~ ERROR : std::marker::Send` is not satisfied + assert_send::>(); + //~^ ERROR `Dummy` cannot be sent between threads safely } fn object_with_send_bound_ok() { diff --git a/src/test/compile-fail/kindck-send-object1.rs b/src/test/compile-fail/kindck-send-object1.rs index 66865bbcc7e..673a6abc5f0 100644 --- a/src/test/compile-fail/kindck-send-object1.rs +++ b/src/test/compile-fail/kindck-send-object1.rs @@ -37,7 +37,7 @@ fn test61() { // them not ok fn test_71<'a>() { assert_send::>(); - //~^ ERROR : std::marker::Send` is not satisfied + //~^ ERROR `Dummy + 'a` cannot be sent between threads safely } fn main() { } diff --git a/src/test/compile-fail/kindck-send-object2.rs b/src/test/compile-fail/kindck-send-object2.rs index 51bc587d74f..3a935af2000 100644 --- a/src/test/compile-fail/kindck-send-object2.rs +++ b/src/test/compile-fail/kindck-send-object2.rs @@ -19,7 +19,8 @@ fn test50() { } fn test53() { - assert_send::>(); //~ ERROR : std::marker::Send` is not satisfied + assert_send::>(); + //~^ ERROR `Dummy` cannot be sent between threads safely } // ...unless they are properly bounded diff --git a/src/test/compile-fail/kindck-send-owned.rs b/src/test/compile-fail/kindck-send-owned.rs index 583381a1c28..e48460a8753 100644 --- a/src/test/compile-fail/kindck-send-owned.rs +++ b/src/test/compile-fail/kindck-send-owned.rs @@ -19,7 +19,8 @@ fn test32() { assert_send:: >(); } // but not if they own a bad thing fn test40() { - assert_send::>(); //~ ERROR : std::marker::Send` is not satisfied + assert_send::>(); + //~^ ERROR `*mut u8` cannot be sent between threads safely } fn main() { } diff --git a/src/test/compile-fail/kindck-send-unsafe.rs b/src/test/compile-fail/kindck-send-unsafe.rs index c717d1a72e0..99b995b0906 100644 --- a/src/test/compile-fail/kindck-send-unsafe.rs +++ b/src/test/compile-fail/kindck-send-unsafe.rs @@ -14,7 +14,7 @@ fn assert_send() { } fn test71<'a>() { assert_send::<*mut &'a isize>(); - //~^ ERROR `*mut &'a isize: std::marker::Send` is not satisfied + //~^ ERROR `*mut &'a isize` cannot be sent between threads safely } fn main() { diff --git a/src/test/compile-fail/no-send-res-ports.rs b/src/test/compile-fail/no-send-res-ports.rs index 334952cefa6..6825963c486 100644 --- a/src/test/compile-fail/no-send-res-ports.rs +++ b/src/test/compile-fail/no-send-res-ports.rs @@ -33,7 +33,7 @@ fn main() { let x = foo(Port(Rc::new(()))); thread::spawn(move|| { - //~^ ERROR `std::rc::Rc<()>: std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely let y = x; println!("{:?}", y); }); diff --git a/src/test/compile-fail/no_send-enum.rs b/src/test/compile-fail/no_send-enum.rs index 902710e96e2..83f19ed19ef 100644 --- a/src/test/compile-fail/no_send-enum.rs +++ b/src/test/compile-fail/no_send-enum.rs @@ -24,5 +24,5 @@ fn bar(_: T) {} fn main() { let x = Foo::A(NoSend); bar(x); - //~^ ERROR `NoSend: std::marker::Send` is not satisfied + //~^ ERROR `NoSend` cannot be sent between threads safely } diff --git a/src/test/compile-fail/no_send-rc.rs b/src/test/compile-fail/no_send-rc.rs index f31d3787334..d3616d14422 100644 --- a/src/test/compile-fail/no_send-rc.rs +++ b/src/test/compile-fail/no_send-rc.rs @@ -15,5 +15,5 @@ fn bar(_: T) {} fn main() { let x = Rc::new(5); bar(x); - //~^ ERROR `std::rc::Rc<{integer}>: std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc<{integer}>` cannot be sent between threads safely } diff --git a/src/test/compile-fail/no_send-struct.rs b/src/test/compile-fail/no_send-struct.rs index b2ca4f9f5db..d38d993e7e8 100644 --- a/src/test/compile-fail/no_send-struct.rs +++ b/src/test/compile-fail/no_send-struct.rs @@ -23,5 +23,5 @@ fn bar(_: T) {} fn main() { let x = Foo { a: 5 }; bar(x); - //~^ ERROR `Foo: std::marker::Send` is not satisfied + //~^ ERROR `Foo` cannot be sent between threads safely } diff --git a/src/test/compile-fail/not-panic-safe-2.rs b/src/test/compile-fail/not-panic-safe-2.rs index 7107211fc91..d750851b719 100644 --- a/src/test/compile-fail/not-panic-safe-2.rs +++ b/src/test/compile-fail/not-panic-safe-2.rs @@ -18,6 +18,6 @@ fn assert() {} fn main() { assert::>>(); - //~^ ERROR `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied - //~^^ ERROR `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied + //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a } diff --git a/src/test/compile-fail/not-panic-safe-3.rs b/src/test/compile-fail/not-panic-safe-3.rs index 76c34e4dc0b..cd27b274258 100644 --- a/src/test/compile-fail/not-panic-safe-3.rs +++ b/src/test/compile-fail/not-panic-safe-3.rs @@ -18,6 +18,6 @@ fn assert() {} fn main() { assert::>>(); - //~^ ERROR `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied - //~^^ ERROR `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied + //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a } diff --git a/src/test/compile-fail/not-panic-safe-4.rs b/src/test/compile-fail/not-panic-safe-4.rs index 177a43e2a7f..956eca432c5 100644 --- a/src/test/compile-fail/not-panic-safe-4.rs +++ b/src/test/compile-fail/not-panic-safe-4.rs @@ -17,6 +17,6 @@ fn assert() {} fn main() { assert::<&RefCell>(); - //~^ ERROR `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied - //~^^ ERROR `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied + //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a } diff --git a/src/test/compile-fail/not-panic-safe-6.rs b/src/test/compile-fail/not-panic-safe-6.rs index f03e1d545a8..d0ca1db5212 100644 --- a/src/test/compile-fail/not-panic-safe-6.rs +++ b/src/test/compile-fail/not-panic-safe-6.rs @@ -17,6 +17,6 @@ fn assert() {} fn main() { assert::<*mut RefCell>(); - //~^ ERROR `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied - //~^^ ERROR `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied + //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a } diff --git a/src/test/compile-fail/not-panic-safe.rs b/src/test/compile-fail/not-panic-safe.rs index ece8fa7dc47..0ebf3d3fed7 100644 --- a/src/test/compile-fail/not-panic-safe.rs +++ b/src/test/compile-fail/not-panic-safe.rs @@ -16,5 +16,6 @@ use std::panic::UnwindSafe; fn assert() {} fn main() { - assert::<&mut i32>(); //~ ERROR: UnwindSafe` is not satisfied + assert::<&mut i32>(); + //~^ ERROR the type `&mut i32` may not be safely transferred across an unwind boundary } diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index 58794e3b35d..3fb62b8d869 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -22,5 +22,5 @@ pub fn main() { // Unsized type. let arr: &[_] = &[1, 2, 3]; let range = *arr..; - //~^ ERROR `[{integer}]: std::marker::Sized` is not satisfied + //~^ ERROR `[{integer}]` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/range_traits-1.rs b/src/test/compile-fail/range_traits-1.rs index 32f9b83b6e2..78d3702b449 100644 --- a/src/test/compile-fail/range_traits-1.rs +++ b/src/test/compile-fail/range_traits-1.rs @@ -13,23 +13,23 @@ use std::ops::*; #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] struct AllTheRanges { a: Range, - //~^ ERROR PartialOrd - //~^^ ERROR Ord + //~^ ERROR can't compare + //~| ERROR Ord b: RangeTo, - //~^ ERROR PartialOrd - //~^^ ERROR Ord + //~^ ERROR can't compare + //~| ERROR Ord c: RangeFrom, - //~^ ERROR PartialOrd - //~^^ ERROR Ord + //~^ ERROR can't compare + //~| ERROR Ord d: RangeFull, - //~^ ERROR PartialOrd - //~^^ ERROR Ord + //~^ ERROR can't compare + //~| ERROR Ord e: RangeInclusive, - //~^ ERROR PartialOrd - //~^^ ERROR Ord + //~^ ERROR can't compare + //~| ERROR Ord f: RangeToInclusive, - //~^ ERROR PartialOrd - //~^^ ERROR Ord + //~^ ERROR can't compare + //~| ERROR Ord } fn main() {} diff --git a/src/test/compile-fail/str-idx.rs b/src/test/compile-fail/str-idx.rs index 2b2c23a3ce4..b5f1ffb977e 100644 --- a/src/test/compile-fail/str-idx.rs +++ b/src/test/compile-fail/str-idx.rs @@ -10,5 +10,5 @@ pub fn main() { let s: &str = "hello"; - let c: u8 = s[4]; //~ ERROR `str: std::ops::Index<{integer}>` is not satisfied + let c: u8 = s[4]; //~ ERROR the type `str` cannot be indexed by `{integer}` } diff --git a/src/test/compile-fail/str-mut-idx.rs b/src/test/compile-fail/str-mut-idx.rs index 219fcdfd702..c25d257d5f8 100644 --- a/src/test/compile-fail/str-mut-idx.rs +++ b/src/test/compile-fail/str-mut-idx.rs @@ -12,10 +12,10 @@ fn bot() -> T { loop {} } fn mutate(s: &mut str) { s[1..2] = bot(); - //~^ ERROR `str: std::marker::Sized` is not satisfied - //~| ERROR `str: std::marker::Sized` is not satisfied + //~^ ERROR `str` does not have a constant size known at compile-time + //~| ERROR `str` does not have a constant size known at compile-time s[1usize] = bot(); - //~^ ERROR `str: std::ops::IndexMut` is not satisfied + //~^ ERROR the type `str` cannot be mutably indexed by `usize` } pub fn main() {} diff --git a/src/test/compile-fail/substs-ppaux.rs b/src/test/compile-fail/substs-ppaux.rs index c857790e342..94d2a549a86 100644 --- a/src/test/compile-fail/substs-ppaux.rs +++ b/src/test/compile-fail/substs-ppaux.rs @@ -56,6 +56,6 @@ fn foo<'z>() where &'z (): Sized { //[normal]~| found type `fn() {foo::<'static>}` >::bar; - //[verbose]~^ ERROR `str: std::marker::Sized` is not satisfied - //[normal]~^^ ERROR `str: std::marker::Sized` is not satisfied + //[verbose]~^ ERROR `str` does not have a constant size known at compile-time + //[normal]~^^ ERROR `str` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs index 983c66ec1c4..effee4a70f3 100644 --- a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs +++ b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs @@ -15,7 +15,7 @@ trait Foo { // This should emit the less confusing error, not the more confusing one. fn foo(_x: Foo + Send) { - //~^ ERROR the trait bound `Foo + std::marker::Send + 'static: std::marker::Sized` is not + //~^ ERROR `Foo + std::marker::Send + 'static` does not have a constant size known at compile-time } fn main() { } diff --git a/src/test/compile-fail/traits-negative-impls.rs b/src/test/compile-fail/traits-negative-impls.rs index 8014f92e173..a272686c535 100644 --- a/src/test/compile-fail/traits-negative-impls.rs +++ b/src/test/compile-fail/traits-negative-impls.rs @@ -31,8 +31,8 @@ fn dummy() { impl !Send for TestType {} Outer(TestType); - //~^ ERROR `dummy::TestType: std::marker::Send` is not satisfied - //~| ERROR `dummy::TestType: std::marker::Send` is not satisfied + //~^ ERROR `dummy::TestType` cannot be sent between threads safely + //~| ERROR `dummy::TestType` cannot be sent between threads safely } fn dummy1b() { @@ -40,7 +40,7 @@ fn dummy1b() { impl !Send for TestType {} is_send(TestType); - //~^ ERROR `dummy1b::TestType: std::marker::Send` is not satisfied + //~^ ERROR `dummy1b::TestType` cannot be sent between threads safely } fn dummy1c() { @@ -48,7 +48,7 @@ fn dummy1c() { impl !Send for TestType {} is_send((8, TestType)); - //~^ ERROR `dummy1c::TestType: std::marker::Send` is not satisfied + //~^ ERROR `dummy1c::TestType` cannot be sent between threads safely } fn dummy2() { @@ -56,7 +56,7 @@ fn dummy2() { impl !Send for TestType {} is_send(Box::new(TestType)); - //~^ ERROR `dummy2::TestType: std::marker::Send` is not satisfied + //~^ ERROR `dummy2::TestType` cannot be sent between threads safely } fn dummy3() { @@ -64,7 +64,7 @@ fn dummy3() { impl !Send for TestType {} is_send(Box::new(Outer2(TestType))); - //~^ ERROR `dummy3::TestType: std::marker::Send` is not satisfied + //~^ ERROR `dummy3::TestType` cannot be sent between threads safely } fn main() { @@ -74,5 +74,5 @@ fn main() { // This will complain about a missing Send impl because `Sync` is implement *just* // for T that are `Send`. Look at #20366 and #19950 is_sync(Outer2(TestType)); - //~^ ERROR `main::TestType: std::marker::Send` is not satisfied + //~^ ERROR `main::TestType` cannot be sent between threads safely } diff --git a/src/test/compile-fail/typeck-default-trait-impl-negation-send.rs b/src/test/compile-fail/typeck-default-trait-impl-negation-send.rs index 853718f1e77..65438e5df8e 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-negation-send.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-negation-send.rs @@ -27,5 +27,5 @@ fn is_send() {} fn main() { is_send::(); is_send::(); - //~^ ERROR `MyNotSendable: std::marker::Send` is not satisfied + //~^ ERROR `MyNotSendable` cannot be sent between threads safely } diff --git a/src/test/compile-fail/union/union-unsized.rs b/src/test/compile-fail/union/union-unsized.rs index a238eaf0525..32f22f052c1 100644 --- a/src/test/compile-fail/union/union-unsized.rs +++ b/src/test/compile-fail/union/union-unsized.rs @@ -11,13 +11,15 @@ #![feature(untagged_unions)] union U { - a: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + a: str, + //~^ ERROR `str` does not have a constant size known at compile-time b: u8, } union W { a: u8, - b: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + b: str, + //~^ ERROR `str` does not have a constant size known at compile-time } fn main() {} diff --git a/src/test/compile-fail/unsized-bare-typaram.rs b/src/test/compile-fail/unsized-bare-typaram.rs index 3dcc7d248d7..be1f1dea28c 100644 --- a/src/test/compile-fail/unsized-bare-typaram.rs +++ b/src/test/compile-fail/unsized-bare-typaram.rs @@ -9,5 +9,6 @@ // except according to those terms. fn bar() { } -fn foo() { bar::() } //~ ERROR `T: std::marker::Sized` is not satisfied +fn foo() { bar::() } +//~^ ERROR `T` does not have a constant size known at compile-time fn main() { } diff --git a/src/test/compile-fail/unsized-enum.rs b/src/test/compile-fail/unsized-enum.rs index 5d791215f36..2041c69da54 100644 --- a/src/test/compile-fail/unsized-enum.rs +++ b/src/test/compile-fail/unsized-enum.rs @@ -15,7 +15,7 @@ fn not_sized() { } enum Foo { FooSome(U), FooNone } fn foo1() { not_sized::>() } // Hunky dory. fn foo2() { not_sized::>() } -//~^ ERROR `T: std::marker::Sized` is not satisfied +//~^ ERROR `T` does not have a constant size known at compile-time // // Not OK: `T` is not sized. diff --git a/src/test/compile-fail/unsized-inherent-impl-self-type.rs b/src/test/compile-fail/unsized-inherent-impl-self-type.rs index 4d0774f2ce4..5e5280ff3ea 100644 --- a/src/test/compile-fail/unsized-inherent-impl-self-type.rs +++ b/src/test/compile-fail/unsized-inherent-impl-self-type.rs @@ -14,7 +14,8 @@ struct S5(Y); -impl S5 { //~ ERROR E0277 +impl S5 { + //~^ ERROR `X` does not have a constant size known at compile-time } fn main() { } diff --git a/src/test/compile-fail/unsized-struct.rs b/src/test/compile-fail/unsized-struct.rs index bbefb2fcecd..830ac5d6c20 100644 --- a/src/test/compile-fail/unsized-struct.rs +++ b/src/test/compile-fail/unsized-struct.rs @@ -15,14 +15,14 @@ fn not_sized() { } struct Foo { data: T } fn foo1() { not_sized::>() } // Hunky dory. fn foo2() { not_sized::>() } -//~^ ERROR `T: std::marker::Sized` is not satisfied +//~^ ERROR `T` does not have a constant size known at compile-time // // Not OK: `T` is not sized. struct Bar { data: T } fn bar1() { not_sized::>() } fn bar2() { is_sized::>() } -//~^ ERROR `T: std::marker::Sized` is not satisfied +//~^ ERROR `T` does not have a constant size known at compile-time // // Not OK: `Bar` is not sized, but it should be. diff --git a/src/test/compile-fail/unsized-trait-impl-self-type.rs b/src/test/compile-fail/unsized-trait-impl-self-type.rs index c919bdf924f..9bf4cf7a0bb 100644 --- a/src/test/compile-fail/unsized-trait-impl-self-type.rs +++ b/src/test/compile-fail/unsized-trait-impl-self-type.rs @@ -17,7 +17,8 @@ trait T3 { struct S5(Y); -impl T3 for S5 { //~ ERROR E0277 +impl T3 for S5 { + //~^ ERROR `X` does not have a constant size known at compile-time } fn main() { } diff --git a/src/test/compile-fail/unsized-trait-impl-trait-arg.rs b/src/test/compile-fail/unsized-trait-impl-trait-arg.rs index ad5e4c2daef..b3a848954d1 100644 --- a/src/test/compile-fail/unsized-trait-impl-trait-arg.rs +++ b/src/test/compile-fail/unsized-trait-impl-trait-arg.rs @@ -16,7 +16,7 @@ trait T2 { } struct S4(Box); impl T2 for S4 { - //~^ ERROR `X: std::marker::Sized` is not satisfied + //~^ ERROR `X` does not have a constant size known at compile-time } fn main() { } diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs index e96e0ea3aec..e08cf8280fd 100644 --- a/src/test/compile-fail/unsized3.rs +++ b/src/test/compile-fail/unsized3.rs @@ -15,7 +15,7 @@ use std::marker; // Unbounded. fn f1(x: &X) { f2::(x); - //~^ ERROR `X: std::marker::Sized` is not satisfied + //~^ ERROR `X` does not have a constant size known at compile-time } fn f2(x: &X) { } @@ -26,7 +26,7 @@ trait T { } fn f3(x: &X) { f4::(x); - //~^ ERROR `X: std::marker::Sized` is not satisfied + //~^ ERROR `X` does not have a constant size known at compile-time } fn f4(x: &X) { } @@ -41,20 +41,20 @@ struct S { fn f8(x1: &S, x2: &S) { f5(x1); - //~^ ERROR `X: std::marker::Sized` is not satisfied + //~^ ERROR `X` does not have a constant size known at compile-time f6(x2); // ok } // Test some tuples. fn f9(x1: Box>) { f5(&(*x1, 34)); - //~^ ERROR `X: std::marker::Sized` is not satisfied + //~^ ERROR `X` does not have a constant size known at compile-time } fn f10(x1: Box>) { f5(&(32, *x1)); - //~^ ERROR `X: std::marker::Sized` is not satisfied - //~| ERROR `X: std::marker::Sized` is not satisfied + //~^ ERROR `X` does not have a constant size known at compile-time + //~| ERROR `X` does not have a constant size known at compile-time } pub fn main() { diff --git a/src/test/compile-fail/unsized5.rs b/src/test/compile-fail/unsized5.rs index 3e6c9cc4061..1fb32da5e31 100644 --- a/src/test/compile-fail/unsized5.rs +++ b/src/test/compile-fail/unsized5.rs @@ -11,27 +11,33 @@ // Test `?Sized` types not allowed in fields (except the last one). struct S1 { - f1: X, //~ ERROR `X: std::marker::Sized` is not satisfied + f1: X, + //~^ ERROR `X` does not have a constant size known at compile-time f2: isize, } struct S2 { f: isize, - g: X, //~ ERROR `X: std::marker::Sized` is not satisfied + g: X, + //~^ ERROR `X` does not have a constant size known at compile-time h: isize, } struct S3 { - f: str, //~ ERROR `str: std::marker::Sized` is not satisfied + f: str, + //~^ ERROR `str` does not have a constant size known at compile-time g: [usize] } struct S4 { - f: [u8], //~ ERROR `[u8]: std::marker::Sized` is not satisfied + f: [u8], + //~^ ERROR `[u8]` does not have a constant size known at compile-time g: usize } enum E { - V1(X, isize), //~ERROR `X: std::marker::Sized` is not satisfied + V1(X, isize), + //~^ ERROR `X` does not have a constant size known at compile-time } enum F { - V2{f1: X, f: isize}, //~ERROR `X: std::marker::Sized` is not satisfied + V2{f1: X, f: isize}, + //~^ ERROR `X` does not have a constant size known at compile-time } pub fn main() { diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index dec8699f46e..7ce0e1eb4d8 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -14,28 +14,41 @@ trait T {} fn f1(x: &X) { let _: W; // <-- this is OK, no bindings created, no initializer. - let _: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfie - let y: Y; //~ERROR `Y: std::marker::Sized` is not satisfied - let y: (isize, (Z, usize)); //~ERROR `Z: std::marker::Sized` is not satisfied + let _: (isize, (X, isize)); + //~^ ERROR `X` does not have a constant size known at compile-time + let y: Y; + //~^ ERROR `Y` does not have a constant size known at compile-time + let y: (isize, (Z, usize)); + //~^ ERROR `Z` does not have a constant size known at compile-time } fn f2(x: &X) { - let y: X; //~ERROR `X: std::marker::Sized` is not satisfied - let y: (isize, (Y, isize)); //~ERROR `Y: std::marker::Sized` is not satisfied + let y: X; + //~^ ERROR `X` does not have a constant size known at compile-time + let y: (isize, (Y, isize)); + //~^ ERROR `Y` does not have a constant size known at compile-time } fn f3(x1: Box, x2: Box, x3: Box) { - let y: X = *x1; //~ERROR `X: std::marker::Sized` is not satisfied - let y = *x2; //~ERROR `X: std::marker::Sized` is not satisfied - let (y, z) = (*x3, 4); //~ERROR `X: std::marker::Sized` is not satisfied + let y: X = *x1; + //~^ ERROR `X` does not have a constant size known at compile-time + let y = *x2; + //~^ ERROR `X` does not have a constant size known at compile-time + let (y, z) = (*x3, 4); + //~^ ERROR `X` does not have a constant size known at compile-time } fn f4(x1: Box, x2: Box, x3: Box) { - let y: X = *x1; //~ERROR `X: std::marker::Sized` is not satisfied - let y = *x2; //~ERROR `X: std::marker::Sized` is not satisfied - let (y, z) = (*x3, 4); //~ERROR `X: std::marker::Sized` is not satisfied + let y: X = *x1; + //~^ ERROR `X` does not have a constant size known at compile-time + let y = *x2; + //~^ ERROR `X` does not have a constant size known at compile-time + let (y, z) = (*x3, 4); + //~^ ERROR `X` does not have a constant size known at compile-time } -fn g1(x: X) {} //~ERROR `X: std::marker::Sized` is not satisfied -fn g2(x: X) {} //~ERROR `X: std::marker::Sized` is not satisfied +fn g1(x: X) {} +//~^ ERROR `X` does not have a constant size known at compile-time +fn g2(x: X) {} +//~^ ERROR `X` does not have a constant size known at compile-time pub fn main() { } diff --git a/src/test/compile-fail/unsized7.rs b/src/test/compile-fail/unsized7.rs index 25868c594fe..8a3d78f0827 100644 --- a/src/test/compile-fail/unsized7.rs +++ b/src/test/compile-fail/unsized7.rs @@ -20,7 +20,7 @@ trait T1 { struct S3(Box); impl T1 for S3 { - //~^ ERROR `X: std::marker::Sized` is not satisfied + //~^ ERROR `X` does not have a constant size known at compile-time } fn main() { } diff --git a/src/test/ui/const-unsized.rs b/src/test/ui/const-unsized.rs index c6ce34b60ca..61ee622e21b 100644 --- a/src/test/ui/const-unsized.rs +++ b/src/test/ui/const-unsized.rs @@ -11,16 +11,16 @@ use std::fmt::Debug; const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); -//~^ ERROR `std::fmt::Debug + std::marker::Sync + 'static: std::marker::Sized` is not satisfied +//~^ ERROR `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at const CONST_FOO: str = *"foo"; -//~^ ERROR `str: std::marker::Sized` is not satisfied +//~^ ERROR `str` does not have a constant size known at compile-time static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); -//~^ ERROR `std::fmt::Debug + std::marker::Sync + 'static: std::marker::Sized` is not satisfied +//~^ ERROR `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at static STATIC_BAR: str = *"bar"; -//~^ ERROR `str: std::marker::Sized` is not satisfied +//~^ ERROR `str` does not have a constant size known at compile-time fn main() { println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR); diff --git a/src/test/ui/const-unsized.stderr b/src/test/ui/const-unsized.stderr index 0bbb5debbba..ca434541cc2 100644 --- a/src/test/ui/const-unsized.stderr +++ b/src/test/ui/const-unsized.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `std::fmt::Debug + std::marker::Sync + 'static: std::marker::Sized` is not satisfied +error[E0277]: `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at compile-time --> $DIR/const-unsized.rs:13:29 | LL | const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); @@ -7,7 +7,7 @@ LL | const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); = help: the trait `std::marker::Sized` is not implemented for `std::fmt::Debug + std::marker::Sync + 'static` = note: constant expressions must have a statically known size -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied +error[E0277]: `str` does not have a constant size known at compile-time --> $DIR/const-unsized.rs:16:24 | LL | const CONST_FOO: str = *"foo"; @@ -16,7 +16,7 @@ LL | const CONST_FOO: str = *"foo"; = help: the trait `std::marker::Sized` is not implemented for `str` = note: constant expressions must have a statically known size -error[E0277]: the trait bound `std::fmt::Debug + std::marker::Sync + 'static: std::marker::Sized` is not satisfied +error[E0277]: `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at compile-time --> $DIR/const-unsized.rs:19:31 | LL | static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); @@ -25,7 +25,7 @@ LL | static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); = help: the trait `std::marker::Sized` is not implemented for `std::fmt::Debug + std::marker::Sync + 'static` = note: constant expressions must have a statically known size -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied +error[E0277]: `str` does not have a constant size known at compile-time --> $DIR/const-unsized.rs:22:26 | LL | static STATIC_BAR: str = *"bar"; diff --git a/src/test/ui/error-codes/E0277-2.rs b/src/test/ui/error-codes/E0277-2.rs index 4d1c50002a3..313aa1f706e 100644 --- a/src/test/ui/error-codes/E0277-2.rs +++ b/src/test/ui/error-codes/E0277-2.rs @@ -24,5 +24,5 @@ fn is_send() { } fn main() { is_send::(); - //~^ ERROR the trait bound `*const u8: std::marker::Send` is not satisfied in `Foo` + //~^ ERROR `*const u8` cannot be sent between threads safely } diff --git a/src/test/ui/error-codes/E0277-2.stderr b/src/test/ui/error-codes/E0277-2.stderr index bbe04cfc6e1..32776f028b4 100644 --- a/src/test/ui/error-codes/E0277-2.stderr +++ b/src/test/ui/error-codes/E0277-2.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `*const u8: std::marker::Send` is not satisfied in `Foo` +error[E0277]: `*const u8` cannot be sent between threads safely --> $DIR/E0277-2.rs:26:5 | LL | is_send::(); diff --git a/src/test/ui/error-codes/E0277.rs b/src/test/ui/error-codes/E0277.rs index b29e4357015..9ff2ef4da90 100644 --- a/src/test/ui/error-codes/E0277.rs +++ b/src/test/ui/error-codes/E0277.rs @@ -21,7 +21,7 @@ fn some_func(foo: T) { } fn f(p: Path) { } -//~^ ERROR the trait bound `[u8]: std::marker::Sized` is not satisfied in `std::path::Path` +//~^ ERROR `[u8]` does not have a constant size known at compile-time fn main() { some_func(5i32); diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr index 477128d7d9f..9cfd42b9c19 100644 --- a/src/test/ui/error-codes/E0277.stderr +++ b/src/test/ui/error-codes/E0277.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied in `std::path::Path` +error[E0277]: `[u8]` does not have a constant size known at compile-time --> $DIR/E0277.rs:23:6 | LL | fn f(p: Path) { } diff --git a/src/test/ui/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gate-trivial_bounds.stderr index 9c2c80600b8..3c6d87e059a 100644 --- a/src/test/ui/feature-gate-trivial_bounds.stderr +++ b/src/test/ui/feature-gate-trivial_bounds.stderr @@ -87,7 +87,7 @@ LL | | } = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied +error[E0277]: `str` does not have a constant size known at compile-time --> $DIR/feature-gate-trivial_bounds.rs:62:1 | LL | struct TwoStrs(str, str) where str: Sized; //~ ERROR @@ -97,7 +97,7 @@ LL | struct TwoStrs(str, str) where str: Sized; //~ ERROR = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable -error[E0277]: the trait bound `A + 'static: std::marker::Sized` is not satisfied in `Dst` +error[E0277]: `A + 'static` does not have a constant size known at compile-time --> $DIR/feature-gate-trivial_bounds.rs:65:1 | LL | / fn unsized_local() where Dst: Sized { //~ ERROR @@ -110,7 +110,7 @@ LL | | } = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied +error[E0277]: `str` does not have a constant size known at compile-time --> $DIR/feature-gate-trivial_bounds.rs:69:1 | LL | / fn return_str() -> str where str: Sized { //~ ERROR diff --git a/src/test/ui/generator/sized-yield.rs b/src/test/ui/generator/sized-yield.rs index a1c8ca77e41..165e2702597 100644 --- a/src/test/ui/generator/sized-yield.rs +++ b/src/test/ui/generator/sized-yield.rs @@ -14,8 +14,10 @@ use std::ops::Generator; fn main() { let s = String::from("foo"); - let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + let mut gen = move || { + //~^ ERROR `str` does not have a constant size known at compile-time yield s[..]; }; - unsafe { gen.resume(); } //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + unsafe { gen.resume(); } + //~^ ERROR `str` does not have a constant size known at compile-time } diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr index 957fac172c2..45f06659053 100644 --- a/src/test/ui/generator/sized-yield.stderr +++ b/src/test/ui/generator/sized-yield.stderr @@ -1,8 +1,9 @@ -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied +error[E0277]: `str` does not have a constant size known at compile-time --> $DIR/sized-yield.rs:17:26 | -LL | let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied +LL | let mut gen = move || { | __________________________^ +LL | | //~^ ERROR `str` does not have a constant size known at compile-time LL | | yield s[..]; LL | | }; | |____^ `str` does not have a constant size known at compile-time @@ -10,10 +11,10 @@ LL | | }; = help: the trait `std::marker::Sized` is not implemented for `str` = note: the yield type of a generator must have a statically known size -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied - --> $DIR/sized-yield.rs:20:17 +error[E0277]: `str` does not have a constant size known at compile-time + --> $DIR/sized-yield.rs:21:17 | -LL | unsafe { gen.resume(); } //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied +LL | unsafe { gen.resume(); } | ^^^^^^ `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` diff --git a/src/test/ui/impl-trait/auto-trait-leak.rs b/src/test/ui/impl-trait/auto-trait-leak.rs index abb3682a498..f6b64b394fc 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.rs +++ b/src/test/ui/impl-trait/auto-trait-leak.rs @@ -25,7 +25,7 @@ fn cycle1() -> impl Clone { //~^ ERROR cycle detected //~| ERROR cycle detected send(cycle2().clone()); - //~^ ERROR Send` is not satisfied + //~^ ERROR `std::rc::Rc` cannot be sent between threads safely Rc::new(Cell::new(5)) } diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 4537c96c4ab..b34facd2d39 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -47,7 +47,7 @@ LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires processing `cycle1::{{exist-impl-Trait}}`, completing the cycle -error[E0277]: the trait bound `std::rc::Rc: std::marker::Send` is not satisfied in `impl std::clone::Clone` +error[E0277]: `std::rc::Rc` cannot be sent between threads safely --> $DIR/auto-trait-leak.rs:27:5 | LL | send(cycle2().clone()); diff --git a/src/test/ui/impl-trait/auto-trait-leak2.rs b/src/test/ui/impl-trait/auto-trait-leak2.rs index 16310e67f1b..3c61543a711 100644 --- a/src/test/ui/impl-trait/auto-trait-leak2.rs +++ b/src/test/ui/impl-trait/auto-trait-leak2.rs @@ -23,10 +23,10 @@ fn send(_: T) {} fn main() { send(before()); - //~^ ERROR the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc>` cannot be sent between threads safely send(after()); - //~^ ERROR the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc>` cannot be sent between threads safely } // Deferred path, main has to wait until typeck finishes, diff --git a/src/test/ui/impl-trait/auto-trait-leak2.stderr b/src/test/ui/impl-trait/auto-trait-leak2.stderr index 59623aed3d2..fb00c41f79c 100644 --- a/src/test/ui/impl-trait/auto-trait-leak2.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak2.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied in `impl std::ops::Fn<(i32,)>` +error[E0277]: `std::rc::Rc>` cannot be sent between threads safely --> $DIR/auto-trait-leak2.rs:25:5 | LL | send(before()); @@ -13,7 +13,7 @@ note: required by `send` LL | fn send(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied in `impl std::ops::Fn<(i32,)>` +error[E0277]: `std::rc::Rc>` cannot be sent between threads safely --> $DIR/auto-trait-leak2.rs:28:5 | LL | send(after()); diff --git a/src/test/ui/interior-mutability/interior-mutability.rs b/src/test/ui/interior-mutability/interior-mutability.rs index a772d1f90cc..b0288463e91 100644 --- a/src/test/ui/interior-mutability/interior-mutability.rs +++ b/src/test/ui/interior-mutability/interior-mutability.rs @@ -12,5 +12,6 @@ use std::cell::Cell; use std::panic::catch_unwind; fn main() { let mut x = Cell::new(22); - catch_unwind(|| { x.set(23); }); //~ ERROR the trait bound + catch_unwind(|| { x.set(23); }); + //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a } diff --git a/src/test/ui/interior-mutability/interior-mutability.stderr b/src/test/ui/interior-mutability/interior-mutability.stderr index 4c489c5964b..f2aecc55ccb 100644 --- a/src/test/ui/interior-mutability/interior-mutability.stderr +++ b/src/test/ui/interior-mutability/interior-mutability.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied in `std::cell::Cell` +error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/interior-mutability.rs:15:5 | -LL | catch_unwind(|| { x.set(23); }); //~ ERROR the trait bound - | ^^^^^^^^^^^^ the type std::cell::UnsafeCell may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +LL | catch_unwind(|| { x.set(23); }); + | ^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | = help: within `std::cell::Cell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` = note: required because it appears within the type `std::cell::Cell` diff --git a/src/test/ui/mismatched_types/binops.rs b/src/test/ui/mismatched_types/binops.rs index 3f2cb59b11d..86785f24f36 100644 --- a/src/test/ui/mismatched_types/binops.rs +++ b/src/test/ui/mismatched_types/binops.rs @@ -13,6 +13,6 @@ fn main() { 2 as usize - Some(1); //~ ERROR cannot subtract `std::option::Option<{integer}>` from `usize` 3 * (); //~ ERROR cannot multiply `()` to `{integer}` 4 / ""; //~ ERROR cannot divide `{integer}` by `&str` - 5 < String::new(); //~ ERROR is not satisfied - 6 == Ok(1); //~ ERROR is not satisfied + 5 < String::new(); //~ ERROR can't compare `{integer}` with `std::string::String` + 6 == Ok(1); //~ ERROR can't compare `{integer}` with `std::result::Result<{integer}, _>` } diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr index 9d23b256fd3..4c6d95efadb 100644 --- a/src/test/ui/mismatched_types/binops.stderr +++ b/src/test/ui/mismatched_types/binops.stderr @@ -30,19 +30,19 @@ LL | 4 / ""; //~ ERROR cannot divide `{integer}` by `&str` | = help: the trait `std::ops::Div<&str>` is not implemented for `{integer}` -error[E0277]: the trait bound `{integer}: std::cmp::PartialOrd` is not satisfied +error[E0277]: can't compare `{integer}` with `std::string::String` --> $DIR/binops.rs:16:7 | -LL | 5 < String::new(); //~ ERROR is not satisfied - | ^ can't compare `{integer}` with `std::string::String` +LL | 5 < String::new(); //~ ERROR can't compare `{integer}` with `std::string::String` + | ^ no implementation for `{integer} < std::string::String` and `{integer} > std::string::String` | = help: the trait `std::cmp::PartialOrd` is not implemented for `{integer}` -error[E0277]: the trait bound `{integer}: std::cmp::PartialEq>` is not satisfied +error[E0277]: can't compare `{integer}` with `std::result::Result<{integer}, _>` --> $DIR/binops.rs:17:7 | -LL | 6 == Ok(1); //~ ERROR is not satisfied - | ^^ can't compare `{integer}` with `std::result::Result<{integer}, _>` +LL | 6 == Ok(1); //~ ERROR can't compare `{integer}` with `std::result::Result<{integer}, _>` + | ^^ no implementation for `{integer} == std::result::Result<{integer}, _>` | = help: the trait `std::cmp::PartialEq>` is not implemented for `{integer}` diff --git a/src/test/ui/mismatched_types/cast-rfc0401.rs b/src/test/ui/mismatched_types/cast-rfc0401.rs index 15388b3a764..7ec9593d2de 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.rs +++ b/src/test/ui/mismatched_types/cast-rfc0401.rs @@ -60,7 +60,7 @@ fn main() let _ = 42usize as *const [u8]; //~ ERROR is invalid let _ = v as *const [u8]; //~ ERROR cannot cast - let _ = fat_v as *const Foo; //~ ERROR is not satisfied + let _ = fat_v as *const Foo; //~ ERROR `[u8]` does not have a constant size known at compile-time let _ = foo as *const str; //~ ERROR is invalid let _ = foo as *mut str; //~ ERROR is invalid let _ = main as *mut str; //~ ERROR is invalid @@ -69,7 +69,7 @@ fn main() let _ = fat_sv as usize; //~ ERROR is invalid let a : *const str = "hello"; - let _ = a as *const Foo; //~ ERROR is not satisfied + let _ = a as *const Foo; //~ ERROR `str` does not have a constant size known at compile-time // check no error cascade let _ = main.f as *const u32; //~ ERROR no field diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 7931e7ff07f..2b00c20e201 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -216,19 +216,19 @@ LL | let _ = cf as *const Bar; //~ ERROR is invalid | = note: vtable kinds may not match -error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied +error[E0277]: `[u8]` does not have a constant size known at compile-time --> $DIR/cast-rfc0401.rs:63:13 | -LL | let _ = fat_v as *const Foo; //~ ERROR is not satisfied +LL | let _ = fat_v as *const Foo; //~ ERROR `[u8]` does not have a constant size known at compile-time | ^^^^^ `[u8]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` = note: required for the cast to the object type `Foo` -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied +error[E0277]: `str` does not have a constant size known at compile-time --> $DIR/cast-rfc0401.rs:72:13 | -LL | let _ = a as *const Foo; //~ ERROR is not satisfied +LL | let _ = a as *const Foo; //~ ERROR `str` does not have a constant size known at compile-time | ^ `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` diff --git a/src/test/ui/partialeq_help.stderr b/src/test/ui/partialeq_help.stderr index c813b64d40b..43f13d45684 100644 --- a/src/test/ui/partialeq_help.stderr +++ b/src/test/ui/partialeq_help.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `&T: std::cmp::PartialEq` is not satisfied +error[E0277]: can't compare `&T` with `T` --> $DIR/partialeq_help.rs:12:7 | LL | a == b; //~ ERROR E0277 - | ^^ can't compare `&T` with `T` + | ^^ no implementation for `&T == T` | = help: the trait `std::cmp::PartialEq` is not implemented for `&T` = help: consider adding a `where &T: std::cmp::PartialEq` bound diff --git a/src/test/ui/resolve/issue-5035-2.rs b/src/test/ui/resolve/issue-5035-2.rs index 83ff95cc2ea..f6cdb05394a 100644 --- a/src/test/ui/resolve/issue-5035-2.rs +++ b/src/test/ui/resolve/issue-5035-2.rs @@ -11,6 +11,7 @@ trait I {} type K = I+'static; -fn foo(_x: K) {} //~ ERROR: `I + 'static: std::marker::Sized` is not satisfied +fn foo(_x: K) {} +//~^ ERROR `I + 'static` does not have a constant size known at compile-time fn main() {} diff --git a/src/test/ui/resolve/issue-5035-2.stderr b/src/test/ui/resolve/issue-5035-2.stderr index 92309274e84..554e97a1281 100644 --- a/src/test/ui/resolve/issue-5035-2.stderr +++ b/src/test/ui/resolve/issue-5035-2.stderr @@ -1,7 +1,7 @@ -error[E0277]: the trait bound `I + 'static: std::marker::Sized` is not satisfied +error[E0277]: `I + 'static` does not have a constant size known at compile-time --> $DIR/issue-5035-2.rs:14:8 | -LL | fn foo(_x: K) {} //~ ERROR: `I + 'static: std::marker::Sized` is not satisfied +LL | fn foo(_x: K) {} | ^^ `I + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `I + 'static` diff --git a/src/test/ui/suggestions/str-array-assignment.rs b/src/test/ui/suggestions/str-array-assignment.rs index b70028bd926..f6b75981a66 100644 --- a/src/test/ui/suggestions/str-array-assignment.rs +++ b/src/test/ui/suggestions/str-array-assignment.rs @@ -15,7 +15,7 @@ fn main() { let u: &str = if true { s[..2] } else { s }; //~^ ERROR mismatched types let v = s[..2]; - //~^ ERROR the trait bound `str: std::marker::Sized` is not satisfied + //~^ ERROR `str` does not have a constant size known at compile-time let w: &str = s[..2]; //~^ ERROR mismatched types } diff --git a/src/test/ui/suggestions/str-array-assignment.stderr b/src/test/ui/suggestions/str-array-assignment.stderr index 76db882742a..91e86e344b4 100644 --- a/src/test/ui/suggestions/str-array-assignment.stderr +++ b/src/test/ui/suggestions/str-array-assignment.stderr @@ -19,7 +19,7 @@ LL | let u: &str = if true { s[..2] } else { s }; = note: expected type `&str` found type `str` -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied +error[E0277]: `str` does not have a constant size known at compile-time --> $DIR/str-array-assignment.rs:17:7 | LL | let v = s[..2]; diff --git a/src/test/ui/trait-suggest-where-clause.rs b/src/test/ui/trait-suggest-where-clause.rs index 5dcb4c8a220..7962dbea371 100644 --- a/src/test/ui/trait-suggest-where-clause.rs +++ b/src/test/ui/trait-suggest-where-clause.rs @@ -15,10 +15,10 @@ struct Misc(T); fn check() { // suggest a where-clause, if needed mem::size_of::(); - //~^ ERROR `U: std::marker::Sized` is not satisfied + //~^ ERROR `U` does not have a constant size known at compile-time mem::size_of::>(); - //~^ ERROR `U: std::marker::Sized` is not satisfied + //~^ ERROR `U` does not have a constant size known at compile-time // ... even if T occurs as a type parameter @@ -36,10 +36,10 @@ fn check() { // ... and also not if the error is not related to the type mem::size_of::<[T]>(); - //~^ ERROR `[T]: std::marker::Sized` is not satisfied + //~^ ERROR `[T]` does not have a constant size known at compile-time mem::size_of::<[&U]>(); - //~^ ERROR `[&U]: std::marker::Sized` is not satisfied + //~^ ERROR `[&U]` does not have a constant size known at compile-time } fn main() { diff --git a/src/test/ui/trait-suggest-where-clause.stderr b/src/test/ui/trait-suggest-where-clause.stderr index abd9f5a8b73..d31e9288037 100644 --- a/src/test/ui/trait-suggest-where-clause.stderr +++ b/src/test/ui/trait-suggest-where-clause.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `U: std::marker::Sized` is not satisfied +error[E0277]: `U` does not have a constant size known at compile-time --> $DIR/trait-suggest-where-clause.rs:17:5 | LL | mem::size_of::(); @@ -8,7 +8,7 @@ LL | mem::size_of::(); = help: consider adding a `where U: std::marker::Sized` bound = note: required by `std::mem::size_of` -error[E0277]: the trait bound `U: std::marker::Sized` is not satisfied in `Misc` +error[E0277]: `U` does not have a constant size known at compile-time --> $DIR/trait-suggest-where-clause.rs:20:5 | LL | mem::size_of::>(); @@ -45,7 +45,7 @@ LL | as From>::from; | = note: required by `std::convert::From::from` -error[E0277]: the trait bound `[T]: std::marker::Sized` is not satisfied +error[E0277]: `[T]` does not have a constant size known at compile-time --> $DIR/trait-suggest-where-clause.rs:38:5 | LL | mem::size_of::<[T]>(); @@ -54,7 +54,7 @@ LL | mem::size_of::<[T]>(); = help: the trait `std::marker::Sized` is not implemented for `[T]` = note: required by `std::mem::size_of` -error[E0277]: the trait bound `[&U]: std::marker::Sized` is not satisfied +error[E0277]: `[&U]` does not have a constant size known at compile-time --> $DIR/trait-suggest-where-clause.rs:41:5 | LL | mem::size_of::<[&U]>(); diff --git a/src/test/ui/trivial-bounds-leak.stderr b/src/test/ui/trivial-bounds-leak.stderr index df91ba0dd2a..d54414110b1 100644 --- a/src/test/ui/trivial-bounds-leak.stderr +++ b/src/test/ui/trivial-bounds-leak.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied +error[E0277]: `str` does not have a constant size known at compile-time --> $DIR/trivial-bounds-leak.rs:22:25 | LL | fn cant_return_str() -> str { //~ ERROR diff --git a/src/test/ui/type-check-defaults.rs b/src/test/ui/type-check-defaults.rs index f916df5d32d..92a45db0689 100644 --- a/src/test/ui/type-check-defaults.rs +++ b/src/test/ui/type-check-defaults.rs @@ -14,24 +14,24 @@ use std::ops::Add; struct Foo>(T, U); struct WellFormed>(Z); -//~^ error: the trait bound `i32: std::iter::FromIterator` is not satisfied [E0277] +//~^ ERROR a collection of type `i32` cannot be built from an iterator over elements of type `i32` struct WellFormedNoBounds>(Z); -//~^ error: the trait bound `i32: std::iter::FromIterator` is not satisfied [E0277] +//~^ ERROR a collection of type `i32` cannot be built from an iterator over elements of type `i32` struct Bounds(T); -//~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] +//~^ ERROR the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] struct WhereClause(T) where T: Copy; -//~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] +//~^ ERROR the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] trait TraitBound {} -//~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] +//~^ ERROR the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] trait Super { } trait Base: Super { } -//~^ error: the trait bound `T: std::marker::Copy` is not satisfied [E0277] +//~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied [E0277] trait ProjectionPred> where T::Item : Add {} -//~^ error: cannot add `u8` to `i32` [E0277] +//~^ ERROR cannot add `u8` to `i32` [E0277] fn main() { } diff --git a/src/test/ui/type-check-defaults.stderr b/src/test/ui/type-check-defaults.stderr index a2d6e53df05..aa124110243 100644 --- a/src/test/ui/type-check-defaults.stderr +++ b/src/test/ui/type-check-defaults.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `i32: std::iter::FromIterator` is not satisfied +error[E0277]: a collection of type `i32` cannot be built from an iterator over elements of type `i32` --> $DIR/type-check-defaults.rs:16:19 | LL | struct WellFormed>(Z); - | ^ a collection of type `i32` cannot be built from an iterator over elements of type `i32` + | ^ a collection of type `i32` cannot be built from `std::iter::Iterator` | = help: the trait `std::iter::FromIterator` is not implemented for `i32` note: required by `Foo` @@ -11,11 +11,11 @@ note: required by `Foo` LL | struct Foo>(T, U); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `i32: std::iter::FromIterator` is not satisfied +error[E0277]: a collection of type `i32` cannot be built from an iterator over elements of type `i32` --> $DIR/type-check-defaults.rs:18:27 | LL | struct WellFormedNoBounds>(Z); - | ^ a collection of type `i32` cannot be built from an iterator over elements of type `i32` + | ^ a collection of type `i32` cannot be built from `std::iter::Iterator` | = help: the trait `std::iter::FromIterator` is not implemented for `i32` note: required by `Foo` diff --git a/src/test/ui/union/union-sized-field.rs b/src/test/ui/union/union-sized-field.rs index 8999f1e0930..e40c6d11cb3 100644 --- a/src/test/ui/union/union-sized-field.rs +++ b/src/test/ui/union/union-sized-field.rs @@ -11,16 +11,19 @@ #![feature(untagged_unions)] union Foo { - value: T, //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied + value: T, + //~^ ERROR `T` does not have a constant size known at compile-time } struct Foo2 { - value: T, //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied + value: T, + //~^ ERROR `T` does not have a constant size known at compile-time t: u32, } enum Foo3 { - Value(T), //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied + Value(T), + //~^ ERROR `T` does not have a constant size known at compile-time } fn main() {} diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr index ba80af6c7e0..ce6de86cff9 100644 --- a/src/test/ui/union/union-sized-field.stderr +++ b/src/test/ui/union/union-sized-field.stderr @@ -1,27 +1,27 @@ -error[E0277]: the trait bound `T: std::marker::Sized` is not satisfied +error[E0277]: `T` does not have a constant size known at compile-time --> $DIR/union-sized-field.rs:14:5 | -LL | value: T, //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied +LL | value: T, | ^^^^^^^^ `T` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = help: consider adding a `where T: std::marker::Sized` bound = note: no field of a union may have a dynamically sized type -error[E0277]: the trait bound `T: std::marker::Sized` is not satisfied - --> $DIR/union-sized-field.rs:18:5 +error[E0277]: `T` does not have a constant size known at compile-time + --> $DIR/union-sized-field.rs:19:5 | -LL | value: T, //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied +LL | value: T, | ^^^^^^^^ `T` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = help: consider adding a `where T: std::marker::Sized` bound = note: only the last field of a struct may have a dynamically sized type -error[E0277]: the trait bound `T: std::marker::Sized` is not satisfied - --> $DIR/union-sized-field.rs:23:11 +error[E0277]: `T` does not have a constant size known at compile-time + --> $DIR/union-sized-field.rs:25:11 | -LL | Value(T), //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied +LL | Value(T), | ^ `T` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` diff --git a/src/test/ui/unsized-enum2.rs b/src/test/ui/unsized-enum2.rs index 95fc3243fbe..4e42b92289b 100644 --- a/src/test/ui/unsized-enum2.rs +++ b/src/test/ui/unsized-enum2.rs @@ -30,37 +30,54 @@ struct Path4(PathHelper4); enum E { // parameter - VA(W), //~ ERROR `W: std::marker::Sized` is not satisfied - VB{x: X}, //~ ERROR `X: std::marker::Sized` is not satisfied - VC(isize, Y), //~ ERROR `Y: std::marker::Sized` is not satisfied - VD{u: isize, x: Z}, //~ ERROR `Z: std::marker::Sized` is not satisfied + VA(W), + //~^ ERROR `W` does not have a constant size known at compile-time + VB{x: X}, + //~^ ERROR `X` does not have a constant size known at compile-time + VC(isize, Y), + //~^ ERROR `Y` does not have a constant size known at compile-time + VD{u: isize, x: Z}, + //~^ ERROR `Z` does not have a constant size known at compile-time // slice / str - VE([u8]), //~ ERROR `[u8]: std::marker::Sized` is not satisfied - VF{x: str}, //~ ERROR `str: std::marker::Sized` is not satisfied - VG(isize, [f32]), //~ ERROR `[f32]: std::marker::Sized` is not satisfied - VH{u: isize, x: [u32]}, //~ ERROR `[u32]: std::marker::Sized` is not satisfied + VE([u8]), + //~^ ERROR `[u8]` does not have a constant size known at compile-time + VF{x: str}, + //~^ ERROR `str` does not have a constant size known at compile-time + VG(isize, [f32]), + //~^ ERROR `[f32]` does not have a constant size known at compile-time + VH{u: isize, x: [u32]}, + //~^ ERROR `[u32]` does not have a constant size known at compile-time // unsized struct - VI(Path1), //~ ERROR `PathHelper1 + 'static: std::marker::Sized` is not satisfied - VJ{x: Path2}, //~ ERROR `PathHelper2 + 'static: std::marker::Sized` is not satisfied - VK(isize, Path3), //~ ERROR `PathHelper3 + 'static: std::marker::Sized` is not satisfied - VL{u: isize, x: Path4}, //~ ERROR `PathHelper4 + 'static: std::marker::Sized` is not satisfied + VI(Path1), + //~^ ERROR `PathHelper1 + 'static` does not have a constant size known at compile-time + VJ{x: Path2}, + //~^ ERROR `PathHelper2 + 'static` does not have a constant size known at compile-time + VK(isize, Path3), + //~^ ERROR `PathHelper3 + 'static` does not have a constant size known at compile-time + VL{u: isize, x: Path4}, + //~^ ERROR `PathHelper4 + 'static` does not have a constant size known at compile-time // plain trait - VM(Foo), //~ ERROR `Foo + 'static: std::marker::Sized` is not satisfied - VN{x: Bar}, //~ ERROR `Bar + 'static: std::marker::Sized` is not satisfied - VO(isize, FooBar), //~ ERROR `FooBar + 'static: std::marker::Sized` is not satisfied - VP{u: isize, x: BarFoo}, //~ ERROR `BarFoo + 'static: std::marker::Sized` is not satisfied + VM(Foo), + //~^ ERROR `Foo + 'static` does not have a constant size known at compile-time + VN{x: Bar}, + //~^ ERROR `Bar + 'static` does not have a constant size known at compile-time + VO(isize, FooBar), + //~^ ERROR `FooBar + 'static` does not have a constant size known at compile-time + VP{u: isize, x: BarFoo}, + //~^ ERROR `BarFoo + 'static` does not have a constant size known at compile-time // projected - VQ(<&'static [i8] as Deref>::Target), //~ ERROR `[i8]: std::marker::Sized` is not satisfied + VQ(<&'static [i8] as Deref>::Target), + //~^ ERROR `[i8]` does not have a constant size known at compile-time VR{x: <&'static [char] as Deref>::Target}, - //~^ ERROR `[char]: std::marker::Sized` is not satisfied + //~^ ERROR `[char]` does not have a constant size known at compile-time VS(isize, <&'static [f64] as Deref>::Target), - //~^ ERROR `[f64]: std::marker::Sized` is not satisfied + //~^ ERROR `[f64]` does not have a constant size known at compile-time VT{u: isize, x: <&'static [i32] as Deref>::Target}, - //~^ ERROR `[i32]: std::marker::Sized` is not satisfied + //~^ ERROR `[i32]` does not have a constant size known at compile-time } diff --git a/src/test/ui/unsized-enum2.stderr b/src/test/ui/unsized-enum2.stderr index 0e18efbf9da..2784bf5af1b 100644 --- a/src/test/ui/unsized-enum2.stderr +++ b/src/test/ui/unsized-enum2.stderr @@ -1,126 +1,126 @@ -error[E0277]: the trait bound `W: std::marker::Sized` is not satisfied +error[E0277]: `W` does not have a constant size known at compile-time --> $DIR/unsized-enum2.rs:33:8 | -LL | VA(W), //~ ERROR `W: std::marker::Sized` is not satisfied +LL | VA(W), | ^ `W` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `W` = help: consider adding a `where W: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `X: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:34:8 +error[E0277]: `X` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:35:8 | -LL | VB{x: X}, //~ ERROR `X: std::marker::Sized` is not satisfied +LL | VB{x: X}, | ^^^^ `X` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = help: consider adding a `where X: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `Y: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:35:15 +error[E0277]: `Y` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:37:15 | -LL | VC(isize, Y), //~ ERROR `Y: std::marker::Sized` is not satisfied +LL | VC(isize, Y), | ^ `Y` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Y` = help: consider adding a `where Y: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `Z: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:36:18 +error[E0277]: `Z` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:39:18 | -LL | VD{u: isize, x: Z}, //~ ERROR `Z: std::marker::Sized` is not satisfied +LL | VD{u: isize, x: Z}, | ^^^^ `Z` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Z` = help: consider adding a `where Z: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:39:8 +error[E0277]: `[u8]` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:43:8 | -LL | VE([u8]), //~ ERROR `[u8]: std::marker::Sized` is not satisfied +LL | VE([u8]), | ^^^^ `[u8]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:40:8 +error[E0277]: `str` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:45:8 | -LL | VF{x: str}, //~ ERROR `str: std::marker::Sized` is not satisfied +LL | VF{x: str}, | ^^^^^^ `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `[f32]: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:41:15 +error[E0277]: `[f32]` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:47:15 | -LL | VG(isize, [f32]), //~ ERROR `[f32]: std::marker::Sized` is not satisfied +LL | VG(isize, [f32]), | ^^^^^ `[f32]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[f32]` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `[u32]: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:42:18 +error[E0277]: `[u32]` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:49:18 | -LL | VH{u: isize, x: [u32]}, //~ ERROR `[u32]: std::marker::Sized` is not satisfied +LL | VH{u: isize, x: [u32]}, | ^^^^^^^^ `[u32]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u32]` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `Foo + 'static: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:51:8 +error[E0277]: `Foo + 'static` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:63:8 | -LL | VM(Foo), //~ ERROR `Foo + 'static: std::marker::Sized` is not satisfied +LL | VM(Foo), | ^^^ `Foo + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Foo + 'static` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `Bar + 'static: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:52:8 +error[E0277]: `Bar + 'static` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:65:8 | -LL | VN{x: Bar}, //~ ERROR `Bar + 'static: std::marker::Sized` is not satisfied +LL | VN{x: Bar}, | ^^^^^^ `Bar + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Bar + 'static` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `FooBar + 'static: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:53:15 +error[E0277]: `FooBar + 'static` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:67:15 | -LL | VO(isize, FooBar), //~ ERROR `FooBar + 'static: std::marker::Sized` is not satisfied +LL | VO(isize, FooBar), | ^^^^^^ `FooBar + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `FooBar + 'static` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `BarFoo + 'static: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:54:18 +error[E0277]: `BarFoo + 'static` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:69:18 | -LL | VP{u: isize, x: BarFoo}, //~ ERROR `BarFoo + 'static: std::marker::Sized` is not satisfied +LL | VP{u: isize, x: BarFoo}, | ^^^^^^^^^ `BarFoo + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `BarFoo + 'static` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `[i8]: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:57:8 +error[E0277]: `[i8]` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:73:8 | -LL | VQ(<&'static [i8] as Deref>::Target), //~ ERROR `[i8]: std::marker::Sized` is not satisfied +LL | VQ(<&'static [i8] as Deref>::Target), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[i8]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i8]` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `[char]: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:58:8 +error[E0277]: `[char]` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:75:8 | LL | VR{x: <&'static [char] as Deref>::Target}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[char]` does not have a constant size known at compile-time @@ -128,8 +128,8 @@ LL | VR{x: <&'static [char] as Deref>::Target}, = help: the trait `std::marker::Sized` is not implemented for `[char]` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `[f64]: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:60:15 +error[E0277]: `[f64]` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:77:15 | LL | VS(isize, <&'static [f64] as Deref>::Target), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[f64]` does not have a constant size known at compile-time @@ -137,8 +137,8 @@ LL | VS(isize, <&'static [f64] as Deref>::Target), = help: the trait `std::marker::Sized` is not implemented for `[f64]` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `[i32]: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:62:18 +error[E0277]: `[i32]` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:79:18 | LL | VT{u: isize, x: <&'static [i32] as Deref>::Target}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[i32]` does not have a constant size known at compile-time @@ -146,40 +146,40 @@ LL | VT{u: isize, x: <&'static [i32] as Deref>::Target}, = help: the trait `std::marker::Sized` is not implemented for `[i32]` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `PathHelper1 + 'static: std::marker::Sized` is not satisfied in `Path1` - --> $DIR/unsized-enum2.rs:45:8 +error[E0277]: `PathHelper1 + 'static` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:53:8 | -LL | VI(Path1), //~ ERROR `PathHelper1 + 'static: std::marker::Sized` is not satisfied +LL | VI(Path1), | ^^^^^ `PathHelper1 + 'static` does not have a constant size known at compile-time | = help: within `Path1`, the trait `std::marker::Sized` is not implemented for `PathHelper1 + 'static` = note: required because it appears within the type `Path1` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `PathHelper2 + 'static: std::marker::Sized` is not satisfied in `Path2` - --> $DIR/unsized-enum2.rs:46:8 +error[E0277]: `PathHelper2 + 'static` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:55:8 | -LL | VJ{x: Path2}, //~ ERROR `PathHelper2 + 'static: std::marker::Sized` is not satisfied +LL | VJ{x: Path2}, | ^^^^^^^^ `PathHelper2 + 'static` does not have a constant size known at compile-time | = help: within `Path2`, the trait `std::marker::Sized` is not implemented for `PathHelper2 + 'static` = note: required because it appears within the type `Path2` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `PathHelper3 + 'static: std::marker::Sized` is not satisfied in `Path3` - --> $DIR/unsized-enum2.rs:47:15 +error[E0277]: `PathHelper3 + 'static` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:57:15 | -LL | VK(isize, Path3), //~ ERROR `PathHelper3 + 'static: std::marker::Sized` is not satisfied +LL | VK(isize, Path3), | ^^^^^ `PathHelper3 + 'static` does not have a constant size known at compile-time | = help: within `Path3`, the trait `std::marker::Sized` is not implemented for `PathHelper3 + 'static` = note: required because it appears within the type `Path3` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `PathHelper4 + 'static: std::marker::Sized` is not satisfied in `Path4` - --> $DIR/unsized-enum2.rs:48:18 +error[E0277]: `PathHelper4 + 'static` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:59:18 | -LL | VL{u: isize, x: Path4}, //~ ERROR `PathHelper4 + 'static: std::marker::Sized` is not satisfied +LL | VL{u: isize, x: Path4}, | ^^^^^^^^ `PathHelper4 + 'static` does not have a constant size known at compile-time | = help: within `Path4`, the trait `std::marker::Sized` is not implemented for `PathHelper4 + 'static` -- cgit 1.4.1-3-g733a5 From f1dee43887821e34988f4427db009d19fae69496 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sat, 9 Jun 2018 18:37:52 -0700 Subject: Add link to book for `Sized` errors --- src/libcore/marker.rs | 4 +++- src/test/ui/const-unsized.stderr | 4 ++++ src/test/ui/error-codes/E0277.stderr | 1 + src/test/ui/feature-gate-trivial_bounds.stderr | 3 +++ src/test/ui/generator/sized-yield.stderr | 2 ++ src/test/ui/mismatched_types/cast-rfc0401.stderr | 2 ++ src/test/ui/resolve/issue-5035-2.stderr | 1 + src/test/ui/suggestions/str-array-assignment.stderr | 1 + src/test/ui/trait-suggest-where-clause.stderr | 4 ++++ src/test/ui/union/union-sized-field.stderr | 3 +++ src/test/ui/unsized-enum2.stderr | 20 ++++++++++++++++++++ 11 files changed, 44 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index d5416e393f4..9c0508f1234 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -93,7 +93,9 @@ impl !Send for *mut T { } #[lang = "sized"] #[rustc_on_unimplemented( message="`{Self}` does not have a constant size known at compile-time", - label="`{Self}` does not have a constant size known at compile-time" + label="`{Self}` does not have a constant size known at compile-time", + note="to learn more, visit ", )] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable pub trait Sized { diff --git a/src/test/ui/const-unsized.stderr b/src/test/ui/const-unsized.stderr index ca434541cc2..6baeab90db2 100644 --- a/src/test/ui/const-unsized.stderr +++ b/src/test/ui/const-unsized.stderr @@ -5,6 +5,7 @@ LL | const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); | ^^^^^^^^^^^^^^^^^^^^^^ `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `std::fmt::Debug + std::marker::Sync + 'static` + = note: to learn more, visit = note: constant expressions must have a statically known size error[E0277]: `str` does not have a constant size known at compile-time @@ -14,6 +15,7 @@ LL | const CONST_FOO: str = *"foo"; | ^^^^^^ `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` + = note: to learn more, visit = note: constant expressions must have a statically known size error[E0277]: `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at compile-time @@ -23,6 +25,7 @@ LL | static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); | ^^^^^^^^^^^^^^^^^^^^^^ `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `std::fmt::Debug + std::marker::Sync + 'static` + = note: to learn more, visit = note: constant expressions must have a statically known size error[E0277]: `str` does not have a constant size known at compile-time @@ -32,6 +35,7 @@ LL | static STATIC_BAR: str = *"bar"; | ^^^^^^ `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` + = note: to learn more, visit = note: constant expressions must have a statically known size error: aborting due to 4 previous errors diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr index 9cfd42b9c19..e1c3183104a 100644 --- a/src/test/ui/error-codes/E0277.stderr +++ b/src/test/ui/error-codes/E0277.stderr @@ -5,6 +5,7 @@ LL | fn f(p: Path) { } | ^ `[u8]` does not have a constant size known at compile-time | = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]` + = note: to learn more, visit = note: required because it appears within the type `std::path::Path` = note: all local variables must have a statically known size diff --git a/src/test/ui/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gate-trivial_bounds.stderr index 3c6d87e059a..9344e78c23c 100644 --- a/src/test/ui/feature-gate-trivial_bounds.stderr +++ b/src/test/ui/feature-gate-trivial_bounds.stderr @@ -94,6 +94,7 @@ LL | struct TwoStrs(str, str) where str: Sized; //~ ERROR | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` + = note: to learn more, visit = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable @@ -106,6 +107,7 @@ LL | | } | |_^ `A + 'static` does not have a constant size known at compile-time | = help: within `Dst`, the trait `std::marker::Sized` is not implemented for `A + 'static` + = note: to learn more, visit = note: required because it appears within the type `Dst` = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable @@ -119,6 +121,7 @@ LL | | } | |_^ `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` + = note: to learn more, visit = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr index 45f06659053..7918101850e 100644 --- a/src/test/ui/generator/sized-yield.stderr +++ b/src/test/ui/generator/sized-yield.stderr @@ -9,6 +9,7 @@ LL | | }; | |____^ `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` + = note: to learn more, visit = note: the yield type of a generator must have a statically known size error[E0277]: `str` does not have a constant size known at compile-time @@ -18,6 +19,7 @@ LL | unsafe { gen.resume(); } | ^^^^^^ `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` + = note: to learn more, visit error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 2b00c20e201..70914ded960 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -223,6 +223,7 @@ LL | let _ = fat_v as *const Foo; //~ ERROR `[u8]` does not have a constant | ^^^^^ `[u8]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = note: to learn more, visit = note: required for the cast to the object type `Foo` error[E0277]: `str` does not have a constant size known at compile-time @@ -232,6 +233,7 @@ LL | let _ = a as *const Foo; //~ ERROR `str` does not have a constant size | ^ `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` + = note: to learn more, visit = note: required for the cast to the object type `Foo` error[E0606]: casting `&{float}` as `f32` is invalid diff --git a/src/test/ui/resolve/issue-5035-2.stderr b/src/test/ui/resolve/issue-5035-2.stderr index 554e97a1281..1488f6b9985 100644 --- a/src/test/ui/resolve/issue-5035-2.stderr +++ b/src/test/ui/resolve/issue-5035-2.stderr @@ -5,6 +5,7 @@ LL | fn foo(_x: K) {} | ^^ `I + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `I + 'static` + = note: to learn more, visit = note: all local variables must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/suggestions/str-array-assignment.stderr b/src/test/ui/suggestions/str-array-assignment.stderr index 91e86e344b4..acf51f89fc4 100644 --- a/src/test/ui/suggestions/str-array-assignment.stderr +++ b/src/test/ui/suggestions/str-array-assignment.stderr @@ -28,6 +28,7 @@ LL | let v = s[..2]; | `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` + = note: to learn more, visit = note: all local variables must have a statically known size error[E0308]: mismatched types diff --git a/src/test/ui/trait-suggest-where-clause.stderr b/src/test/ui/trait-suggest-where-clause.stderr index d31e9288037..d87641d8d0f 100644 --- a/src/test/ui/trait-suggest-where-clause.stderr +++ b/src/test/ui/trait-suggest-where-clause.stderr @@ -5,6 +5,7 @@ LL | mem::size_of::(); | ^^^^^^^^^^^^^^^^^ `U` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `U` + = note: to learn more, visit = help: consider adding a `where U: std::marker::Sized` bound = note: required by `std::mem::size_of` @@ -15,6 +16,7 @@ LL | mem::size_of::>(); | ^^^^^^^^^^^^^^^^^^^^^^^ `U` does not have a constant size known at compile-time | = help: within `Misc`, the trait `std::marker::Sized` is not implemented for `U` + = note: to learn more, visit = help: consider adding a `where U: std::marker::Sized` bound = note: required because it appears within the type `Misc` = note: required by `std::mem::size_of` @@ -52,6 +54,7 @@ LL | mem::size_of::<[T]>(); | ^^^^^^^^^^^^^^^^^^^ `[T]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[T]` + = note: to learn more, visit = note: required by `std::mem::size_of` error[E0277]: `[&U]` does not have a constant size known at compile-time @@ -61,6 +64,7 @@ LL | mem::size_of::<[&U]>(); | ^^^^^^^^^^^^^^^^^^^^ `[&U]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[&U]` + = note: to learn more, visit = note: required by `std::mem::size_of` error: aborting due to 7 previous errors diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr index ce6de86cff9..9fdc5af0481 100644 --- a/src/test/ui/union/union-sized-field.stderr +++ b/src/test/ui/union/union-sized-field.stderr @@ -5,6 +5,7 @@ LL | value: T, | ^^^^^^^^ `T` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` + = note: to learn more, visit = help: consider adding a `where T: std::marker::Sized` bound = note: no field of a union may have a dynamically sized type @@ -15,6 +16,7 @@ LL | value: T, | ^^^^^^^^ `T` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` + = note: to learn more, visit = help: consider adding a `where T: std::marker::Sized` bound = note: only the last field of a struct may have a dynamically sized type @@ -25,6 +27,7 @@ LL | Value(T), | ^ `T` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` + = note: to learn more, visit = help: consider adding a `where T: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type diff --git a/src/test/ui/unsized-enum2.stderr b/src/test/ui/unsized-enum2.stderr index 2784bf5af1b..91b8e5def7e 100644 --- a/src/test/ui/unsized-enum2.stderr +++ b/src/test/ui/unsized-enum2.stderr @@ -5,6 +5,7 @@ LL | VA(W), | ^ `W` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `W` + = note: to learn more, visit = help: consider adding a `where W: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type @@ -15,6 +16,7 @@ LL | VB{x: X}, | ^^^^ `X` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` + = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type @@ -25,6 +27,7 @@ LL | VC(isize, Y), | ^ `Y` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Y` + = note: to learn more, visit = help: consider adding a `where Y: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type @@ -35,6 +38,7 @@ LL | VD{u: isize, x: Z}, | ^^^^ `Z` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Z` + = note: to learn more, visit = help: consider adding a `where Z: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type @@ -45,6 +49,7 @@ LL | VE([u8]), | ^^^^ `[u8]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: `str` does not have a constant size known at compile-time @@ -54,6 +59,7 @@ LL | VF{x: str}, | ^^^^^^ `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: `[f32]` does not have a constant size known at compile-time @@ -63,6 +69,7 @@ LL | VG(isize, [f32]), | ^^^^^ `[f32]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[f32]` + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: `[u32]` does not have a constant size known at compile-time @@ -72,6 +79,7 @@ LL | VH{u: isize, x: [u32]}, | ^^^^^^^^ `[u32]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u32]` + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: `Foo + 'static` does not have a constant size known at compile-time @@ -81,6 +89,7 @@ LL | VM(Foo), | ^^^ `Foo + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Foo + 'static` + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: `Bar + 'static` does not have a constant size known at compile-time @@ -90,6 +99,7 @@ LL | VN{x: Bar}, | ^^^^^^ `Bar + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Bar + 'static` + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: `FooBar + 'static` does not have a constant size known at compile-time @@ -99,6 +109,7 @@ LL | VO(isize, FooBar), | ^^^^^^ `FooBar + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `FooBar + 'static` + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: `BarFoo + 'static` does not have a constant size known at compile-time @@ -108,6 +119,7 @@ LL | VP{u: isize, x: BarFoo}, | ^^^^^^^^^ `BarFoo + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `BarFoo + 'static` + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: `[i8]` does not have a constant size known at compile-time @@ -117,6 +129,7 @@ LL | VQ(<&'static [i8] as Deref>::Target), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[i8]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i8]` + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: `[char]` does not have a constant size known at compile-time @@ -126,6 +139,7 @@ LL | VR{x: <&'static [char] as Deref>::Target}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[char]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[char]` + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: `[f64]` does not have a constant size known at compile-time @@ -135,6 +149,7 @@ LL | VS(isize, <&'static [f64] as Deref>::Target), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[f64]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[f64]` + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: `[i32]` does not have a constant size known at compile-time @@ -144,6 +159,7 @@ LL | VT{u: isize, x: <&'static [i32] as Deref>::Target}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[i32]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i32]` + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: `PathHelper1 + 'static` does not have a constant size known at compile-time @@ -153,6 +169,7 @@ LL | VI(Path1), | ^^^^^ `PathHelper1 + 'static` does not have a constant size known at compile-time | = help: within `Path1`, the trait `std::marker::Sized` is not implemented for `PathHelper1 + 'static` + = note: to learn more, visit = note: required because it appears within the type `Path1` = note: no field of an enum variant may have a dynamically sized type @@ -163,6 +180,7 @@ LL | VJ{x: Path2}, | ^^^^^^^^ `PathHelper2 + 'static` does not have a constant size known at compile-time | = help: within `Path2`, the trait `std::marker::Sized` is not implemented for `PathHelper2 + 'static` + = note: to learn more, visit = note: required because it appears within the type `Path2` = note: no field of an enum variant may have a dynamically sized type @@ -173,6 +191,7 @@ LL | VK(isize, Path3), | ^^^^^ `PathHelper3 + 'static` does not have a constant size known at compile-time | = help: within `Path3`, the trait `std::marker::Sized` is not implemented for `PathHelper3 + 'static` + = note: to learn more, visit = note: required because it appears within the type `Path3` = note: no field of an enum variant may have a dynamically sized type @@ -183,6 +202,7 @@ LL | VL{u: isize, x: Path4}, | ^^^^^^^^ `PathHelper4 + 'static` does not have a constant size known at compile-time | = help: within `Path4`, the trait `std::marker::Sized` is not implemented for `PathHelper4 + 'static` + = note: to learn more, visit = note: required because it appears within the type `Path4` = note: no field of an enum variant may have a dynamically sized type -- cgit 1.4.1-3-g733a5 From d4bfae1319b314f9eb0507f62ac16456ee55f0d0 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Tue, 19 Jun 2018 15:53:51 -0700 Subject: Update message for `!Sized` types --- src/libcore/marker.rs | 4 +- src/test/compile-fail/associated-types-unsized.rs | 2 +- src/test/compile-fail/bad-sized.rs | 4 +- src/test/compile-fail/dst-bad-assign-2.rs | 3 +- src/test/compile-fail/dst-bad-assign-3.rs | 2 +- src/test/compile-fail/dst-bad-assign.rs | 2 +- src/test/compile-fail/dst-bad-deep-2.rs | 2 +- src/test/compile-fail/dst-bad-deep.rs | 2 +- .../compile-fail/dst-object-from-unsized-type.rs | 8 +-- src/test/compile-fail/dst-sized-trait-param.rs | 4 +- src/test/compile-fail/extern-types-unsized.rs | 8 +-- src/test/compile-fail/issue-14366.rs | 2 +- src/test/compile-fail/issue-15756.rs | 2 +- src/test/compile-fail/issue-17651.rs | 2 +- src/test/compile-fail/issue-18107.rs | 2 +- src/test/compile-fail/issue-18919.rs | 2 +- src/test/compile-fail/issue-20005.rs | 2 +- src/test/compile-fail/issue-20433.rs | 2 +- src/test/compile-fail/issue-20605.rs | 2 +- src/test/compile-fail/issue-22874.rs | 2 +- src/test/compile-fail/issue-23281.rs | 2 +- src/test/compile-fail/issue-24446.rs | 4 +- src/test/compile-fail/issue-27060-2.rs | 2 +- src/test/compile-fail/issue-27078.rs | 2 +- src/test/compile-fail/issue-35988.rs | 2 +- src/test/compile-fail/issue-38954.rs | 2 +- src/test/compile-fail/issue-41229-ref-str.rs | 2 +- src/test/compile-fail/issue-42312.rs | 4 +- src/test/compile-fail/issue-5883.rs | 4 +- src/test/compile-fail/range-1.rs | 2 +- src/test/compile-fail/str-mut-idx.rs | 4 +- src/test/compile-fail/substs-ppaux.rs | 4 +- .../compile-fail/trait-bounds-not-on-bare-trait.rs | 2 +- src/test/compile-fail/union/union-unsized.rs | 5 +- src/test/compile-fail/unsized-bare-typaram.rs | 2 +- src/test/compile-fail/unsized-enum.rs | 2 +- .../unsized-inherent-impl-self-type.rs | 2 +- src/test/compile-fail/unsized-struct.rs | 4 +- .../compile-fail/unsized-trait-impl-self-type.rs | 2 +- .../compile-fail/unsized-trait-impl-trait-arg.rs | 2 +- src/test/compile-fail/unsized3.rs | 12 ++-- src/test/compile-fail/unsized5.rs | 12 ++-- src/test/compile-fail/unsized6.rs | 26 +++---- src/test/compile-fail/unsized7.rs | 2 +- src/test/ui/const-unsized.rs | 8 +-- src/test/ui/const-unsized.stderr | 16 ++--- src/test/ui/error-codes/E0277.rs | 2 +- src/test/ui/error-codes/E0277.stderr | 4 +- src/test/ui/feature-gate-trivial_bounds.stderr | 12 ++-- src/test/ui/generator/sized-yield.rs | 4 +- src/test/ui/generator/sized-yield.stderr | 10 +-- src/test/ui/mismatched_types/cast-rfc0401.rs | 4 +- src/test/ui/mismatched_types/cast-rfc0401.stderr | 12 ++-- src/test/ui/resolve/issue-5035-2.rs | 2 +- src/test/ui/resolve/issue-5035-2.stderr | 4 +- src/test/ui/suggestions/str-array-assignment.rs | 2 +- .../ui/suggestions/str-array-assignment.stderr | 4 +- src/test/ui/trait-suggest-where-clause.rs | 8 +-- src/test/ui/trait-suggest-where-clause.stderr | 16 ++--- src/test/ui/trivial-bounds-leak.stderr | 4 +- src/test/ui/union/union-sized-field.rs | 6 +- src/test/ui/union/union-sized-field.stderr | 12 ++-- src/test/ui/unsized-enum2.rs | 40 +++++------ src/test/ui/unsized-enum2.stderr | 80 +++++++++++----------- 64 files changed, 209 insertions(+), 207 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 9c0508f1234..5db5d88d4a5 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -92,8 +92,8 @@ impl !Send for *mut T { } #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sized"] #[rustc_on_unimplemented( - message="`{Self}` does not have a constant size known at compile-time", - label="`{Self}` does not have a constant size known at compile-time", + message="the size for value values of type `{Self}` cannot be known at compilation time", + label="doesn't have a size known at compile-time", note="to learn more, visit ", )] diff --git a/src/test/compile-fail/associated-types-unsized.rs b/src/test/compile-fail/associated-types-unsized.rs index 29aa9614745..3bb0382ef03 100644 --- a/src/test/compile-fail/associated-types-unsized.rs +++ b/src/test/compile-fail/associated-types-unsized.rs @@ -14,7 +14,7 @@ trait Get { } fn foo(t: T) { - let x = t.get(); //~ ERROR `::Value` does not have a constant size known at + let x = t.get(); //~ ERROR the size for value values of type } fn main() { diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs index 55b009aef4f..9b87ec4d446 100644 --- a/src/test/compile-fail/bad-sized.rs +++ b/src/test/compile-fail/bad-sized.rs @@ -13,6 +13,6 @@ trait Trait {} pub fn main() { let x: Vec = Vec::new(); //~^ ERROR only auto traits can be used as additional traits in a trait object - //~| ERROR `Trait` does not have a constant size known at compile-time - //~| ERROR `Trait` does not have a constant size known at compile-time + //~| ERROR the size for value values of type + //~| ERROR the size for value values of type } diff --git a/src/test/compile-fail/dst-bad-assign-2.rs b/src/test/compile-fail/dst-bad-assign-2.rs index c3cbc904842..1dbdd42ca36 100644 --- a/src/test/compile-fail/dst-bad-assign-2.rs +++ b/src/test/compile-fail/dst-bad-assign-2.rs @@ -43,5 +43,6 @@ pub fn main() { let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; let z: Box = Box::new(Bar1 {f: 36}); f5.ptr = *z; - //~^ ERROR `ToBar` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type + } diff --git a/src/test/compile-fail/dst-bad-assign-3.rs b/src/test/compile-fail/dst-bad-assign-3.rs index 1cd5b51fe34..5bc6c6cda26 100644 --- a/src/test/compile-fail/dst-bad-assign-3.rs +++ b/src/test/compile-fail/dst-bad-assign-3.rs @@ -45,5 +45,5 @@ pub fn main() { //~| expected type `ToBar` //~| found type `Bar1` //~| expected trait ToBar, found struct `Bar1` - //~| ERROR `ToBar` does not have a constant size known at compile-time + //~| ERROR the size for value values of type } diff --git a/src/test/compile-fail/dst-bad-assign.rs b/src/test/compile-fail/dst-bad-assign.rs index dcd78ac044c..37b6056d1a7 100644 --- a/src/test/compile-fail/dst-bad-assign.rs +++ b/src/test/compile-fail/dst-bad-assign.rs @@ -47,5 +47,5 @@ pub fn main() { //~| expected type `ToBar` //~| found type `Bar1` //~| expected trait ToBar, found struct `Bar1` - //~| ERROR `ToBar` does not have a constant size known at compile-time + //~| ERROR the size for value values of type } diff --git a/src/test/compile-fail/dst-bad-deep-2.rs b/src/test/compile-fail/dst-bad-deep-2.rs index 9ed2ec8d98d..82d81913cd3 100644 --- a/src/test/compile-fail/dst-bad-deep-2.rs +++ b/src/test/compile-fail/dst-bad-deep-2.rs @@ -19,5 +19,5 @@ pub fn main() { let f: ([isize; 3],) = ([5, 6, 7],); let g: &([isize],) = &f; let h: &(([isize],),) = &(*g,); - //~^ ERROR `[isize]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } diff --git a/src/test/compile-fail/dst-bad-deep.rs b/src/test/compile-fail/dst-bad-deep.rs index 9b575ae4aad..b8ca22185bc 100644 --- a/src/test/compile-fail/dst-bad-deep.rs +++ b/src/test/compile-fail/dst-bad-deep.rs @@ -21,5 +21,5 @@ pub fn main() { let f: Fat<[isize; 3]> = Fat { ptr: [5, 6, 7] }; let g: &Fat<[isize]> = &f; let h: &Fat> = &Fat { ptr: *g }; - //~^ ERROR `[isize]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } diff --git a/src/test/compile-fail/dst-object-from-unsized-type.rs b/src/test/compile-fail/dst-object-from-unsized-type.rs index 678eef76fde..4a892753595 100644 --- a/src/test/compile-fail/dst-object-from-unsized-type.rs +++ b/src/test/compile-fail/dst-object-from-unsized-type.rs @@ -16,22 +16,22 @@ impl Foo for [u8] {} fn test1(t: &T) { let u: &Foo = t; - //~^ ERROR `T` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn test2(t: &T) { let v: &Foo = t as &Foo; - //~^ ERROR `T` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn test3() { let _: &[&Foo] = &["hi"]; - //~^ ERROR `str` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn test4(x: &[u8]) { let _: &Foo = x as &Foo; - //~^ ERROR `[u8]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn main() { } diff --git a/src/test/compile-fail/dst-sized-trait-param.rs b/src/test/compile-fail/dst-sized-trait-param.rs index cafd67809f8..06795567432 100644 --- a/src/test/compile-fail/dst-sized-trait-param.rs +++ b/src/test/compile-fail/dst-sized-trait-param.rs @@ -15,9 +15,9 @@ trait Foo : Sized { fn take(self, x: &T) { } } // Note: T is sized impl Foo<[isize]> for usize { } -//~^ ERROR `[isize]` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type impl Foo for [usize] { } -//~^ ERROR `[usize]` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type pub fn main() { } diff --git a/src/test/compile-fail/extern-types-unsized.rs b/src/test/compile-fail/extern-types-unsized.rs index b3e19899a67..135b466161d 100644 --- a/src/test/compile-fail/extern-types-unsized.rs +++ b/src/test/compile-fail/extern-types-unsized.rs @@ -30,14 +30,14 @@ fn assert_sized() { } fn main() { assert_sized::(); - //~^ ERROR `A` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type assert_sized::(); - //~^ ERROR `A` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type assert_sized::>(); - //~^ ERROR `A` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type assert_sized::>>(); - //~^ ERROR `A` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } diff --git a/src/test/compile-fail/issue-14366.rs b/src/test/compile-fail/issue-14366.rs index 7b4954a2d4e..5212cbb004e 100644 --- a/src/test/compile-fail/issue-14366.rs +++ b/src/test/compile-fail/issue-14366.rs @@ -10,5 +10,5 @@ fn main() { let _x = "test" as &::std::any::Any; - //~^ ERROR `str` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } diff --git a/src/test/compile-fail/issue-15756.rs b/src/test/compile-fail/issue-15756.rs index 0df82de8338..4756099ab95 100644 --- a/src/test/compile-fail/issue-15756.rs +++ b/src/test/compile-fail/issue-15756.rs @@ -15,7 +15,7 @@ fn dft_iter<'a, T>(arg1: Chunks<'a,T>, arg2: ChunksMut<'a,T>) { for &mut something - //~^ ERROR `[T]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type in arg2 { } diff --git a/src/test/compile-fail/issue-17651.rs b/src/test/compile-fail/issue-17651.rs index 13548b06ea1..e7019ff7c0d 100644 --- a/src/test/compile-fail/issue-17651.rs +++ b/src/test/compile-fail/issue-17651.rs @@ -13,5 +13,5 @@ fn main() { (|| Box::new(*(&[0][..])))(); - //~^ ERROR `[{integer}]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } diff --git a/src/test/compile-fail/issue-18107.rs b/src/test/compile-fail/issue-18107.rs index 5faa8885e73..9239ceb341f 100644 --- a/src/test/compile-fail/issue-18107.rs +++ b/src/test/compile-fail/issue-18107.rs @@ -12,7 +12,7 @@ pub trait AbstractRenderer {} fn _create_render(_: &()) -> AbstractRenderer -//~^ ERROR: `AbstractRenderer + 'static` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type { match 0 { _ => unimplemented!() diff --git a/src/test/compile-fail/issue-18919.rs b/src/test/compile-fail/issue-18919.rs index 14b776cb1ff..0b717ec6413 100644 --- a/src/test/compile-fail/issue-18919.rs +++ b/src/test/compile-fail/issue-18919.rs @@ -11,7 +11,7 @@ type FuncType<'f> = Fn(&isize) -> isize + 'f; fn ho_func(f: Option) { - //~^ ERROR: `for<'r> std::ops::Fn(&'r isize) -> isize` does not have a constant size known at + //~^ ERROR the size for value values of type } fn main() {} diff --git a/src/test/compile-fail/issue-20005.rs b/src/test/compile-fail/issue-20005.rs index ab47f687fc2..426657ac92e 100644 --- a/src/test/compile-fail/issue-20005.rs +++ b/src/test/compile-fail/issue-20005.rs @@ -15,7 +15,7 @@ trait From { } trait To { - fn to( //~ ERROR `Self` does not have a constant size known at compile-time + fn to( //~ ERROR the size for value values of type self ) -> >::Result where Dst: From { From::from(self) diff --git a/src/test/compile-fail/issue-20433.rs b/src/test/compile-fail/issue-20433.rs index d8ca00d313f..8b7f2d5a458 100644 --- a/src/test/compile-fail/issue-20433.rs +++ b/src/test/compile-fail/issue-20433.rs @@ -14,5 +14,5 @@ struct The; impl The { fn iceman(c: Vec<[i32]>) {} - //~^ ERROR `[i32]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } diff --git a/src/test/compile-fail/issue-20605.rs b/src/test/compile-fail/issue-20605.rs index c5a724bba80..2d8d9c65655 100644 --- a/src/test/compile-fail/issue-20605.rs +++ b/src/test/compile-fail/issue-20605.rs @@ -10,7 +10,7 @@ fn changer<'a>(mut things: Box>) { for item in *things { *item = 0 } -//~^ ERROR `std::iter::Iterator` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type } fn main() {} diff --git a/src/test/compile-fail/issue-22874.rs b/src/test/compile-fail/issue-22874.rs index de176486af7..cb199580b10 100644 --- a/src/test/compile-fail/issue-22874.rs +++ b/src/test/compile-fail/issue-22874.rs @@ -10,7 +10,7 @@ struct Table { rows: [[String]], - //~^ ERROR `[std::string::String]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn f(table: &Table) -> &[String] { diff --git a/src/test/compile-fail/issue-23281.rs b/src/test/compile-fail/issue-23281.rs index fdab3b59d1b..d6b5c329825 100644 --- a/src/test/compile-fail/issue-23281.rs +++ b/src/test/compile-fail/issue-23281.rs @@ -14,7 +14,7 @@ pub struct Struct; impl Struct { pub fn function(funs: Vec ()>) {} - //~^ ERROR `std::ops::Fn() + 'static` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn main() {} diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index cef68dd811b..74c68c50ae3 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -10,8 +10,8 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { - //~^ ERROR: mismatched types - //~| ERROR: `std::ops::Fn() -> u32 + 'static` does not have a constant size known at + //~^ ERROR mismatched types + //~| ERROR the size for value values of type 0 }; } diff --git a/src/test/compile-fail/issue-27060-2.rs b/src/test/compile-fail/issue-27060-2.rs index 123bbf3358d..bc5567e1686 100644 --- a/src/test/compile-fail/issue-27060-2.rs +++ b/src/test/compile-fail/issue-27060-2.rs @@ -10,7 +10,7 @@ #[repr(packed)] pub struct Bad { - data: T, //~ ERROR `T` does not have a constant size known at compile-time + data: T, //~ ERROR the size for value values of type } fn main() {} diff --git a/src/test/compile-fail/issue-27078.rs b/src/test/compile-fail/issue-27078.rs index 32933fa6176..6efc1f10243 100644 --- a/src/test/compile-fail/issue-27078.rs +++ b/src/test/compile-fail/issue-27078.rs @@ -13,7 +13,7 @@ trait Foo { const BAR: i32; fn foo(self) -> &'static i32 { - //~^ ERROR `Self` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type &::BAR } } diff --git a/src/test/compile-fail/issue-35988.rs b/src/test/compile-fail/issue-35988.rs index 8f5b68986e5..805b1a48a03 100644 --- a/src/test/compile-fail/issue-35988.rs +++ b/src/test/compile-fail/issue-35988.rs @@ -10,7 +10,7 @@ enum E { V([Box]), - //~^ ERROR `[std::boxed::Box]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn main() {} diff --git a/src/test/compile-fail/issue-38954.rs b/src/test/compile-fail/issue-38954.rs index 960099f3193..1b64d17bbef 100644 --- a/src/test/compile-fail/issue-38954.rs +++ b/src/test/compile-fail/issue-38954.rs @@ -9,6 +9,6 @@ // except according to those terms. fn _test(ref _p: str) {} -//~^ ERROR `str` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type fn main() { } diff --git a/src/test/compile-fail/issue-41229-ref-str.rs b/src/test/compile-fail/issue-41229-ref-str.rs index b1e24c818d8..6207e669d00 100644 --- a/src/test/compile-fail/issue-41229-ref-str.rs +++ b/src/test/compile-fail/issue-41229-ref-str.rs @@ -9,6 +9,6 @@ // except according to those terms. pub fn example(ref s: str) {} -//~^ ERROR `str` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type fn main() {} diff --git a/src/test/compile-fail/issue-42312.rs b/src/test/compile-fail/issue-42312.rs index 89eb5c5ebc1..2ab44433ede 100644 --- a/src/test/compile-fail/issue-42312.rs +++ b/src/test/compile-fail/issue-42312.rs @@ -12,10 +12,10 @@ use std::ops::Deref; pub trait Foo { fn baz(_: Self::Target) where Self: Deref {} - //~^ ERROR `::Target` does not have a constant size known at + //~^ ERROR the size for value values of type } pub fn f(_: ToString) {} -//~^ ERROR `std::string::ToString + 'static` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type fn main() { } diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index 580625f4955..82d4666ce54 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -15,8 +15,8 @@ struct Struct { } fn new_struct(r: A+'static) - -> Struct { //~^ ERROR `A + 'static` does not have a constant size known at compile-time - //~^ ERROR `A + 'static` does not have a constant size known at compile-time + -> Struct { //~^ ERROR the size for value values of type + //~^ ERROR the size for value values of type Struct { r: r } } diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index 3fb62b8d869..ed26204bbe1 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -22,5 +22,5 @@ pub fn main() { // Unsized type. let arr: &[_] = &[1, 2, 3]; let range = *arr..; - //~^ ERROR `[{integer}]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } diff --git a/src/test/compile-fail/str-mut-idx.rs b/src/test/compile-fail/str-mut-idx.rs index c25d257d5f8..cc5fd7e3f24 100644 --- a/src/test/compile-fail/str-mut-idx.rs +++ b/src/test/compile-fail/str-mut-idx.rs @@ -12,8 +12,8 @@ fn bot() -> T { loop {} } fn mutate(s: &mut str) { s[1..2] = bot(); - //~^ ERROR `str` does not have a constant size known at compile-time - //~| ERROR `str` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type + //~| ERROR the size for value values of type s[1usize] = bot(); //~^ ERROR the type `str` cannot be mutably indexed by `usize` } diff --git a/src/test/compile-fail/substs-ppaux.rs b/src/test/compile-fail/substs-ppaux.rs index 94d2a549a86..b8557cb79e3 100644 --- a/src/test/compile-fail/substs-ppaux.rs +++ b/src/test/compile-fail/substs-ppaux.rs @@ -56,6 +56,6 @@ fn foo<'z>() where &'z (): Sized { //[normal]~| found type `fn() {foo::<'static>}` >::bar; - //[verbose]~^ ERROR `str` does not have a constant size known at compile-time - //[normal]~^^ ERROR `str` does not have a constant size known at compile-time + //[verbose]~^ ERROR the size for value values of type + //[normal]~^^ ERROR the size for value values of type } diff --git a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs index fbf23357393..89fddf1f65f 100644 --- a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs +++ b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs @@ -15,7 +15,7 @@ trait Foo { // This should emit the less confusing error, not the more confusing one. fn foo(_x: Foo + Send) { - //~^ ERROR `Foo + std::marker::Send + 'static` does not have a constant size known at + //~^ ERROR the size for value values of type } fn main() { } diff --git a/src/test/compile-fail/union/union-unsized.rs b/src/test/compile-fail/union/union-unsized.rs index 32f22f052c1..a9a2a3c4c92 100644 --- a/src/test/compile-fail/union/union-unsized.rs +++ b/src/test/compile-fail/union/union-unsized.rs @@ -12,14 +12,15 @@ union U { a: str, - //~^ ERROR `str` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type + b: u8, } union W { a: u8, b: str, - //~^ ERROR `str` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn main() {} diff --git a/src/test/compile-fail/unsized-bare-typaram.rs b/src/test/compile-fail/unsized-bare-typaram.rs index be1f1dea28c..736794ac538 100644 --- a/src/test/compile-fail/unsized-bare-typaram.rs +++ b/src/test/compile-fail/unsized-bare-typaram.rs @@ -10,5 +10,5 @@ fn bar() { } fn foo() { bar::() } -//~^ ERROR `T` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type fn main() { } diff --git a/src/test/compile-fail/unsized-enum.rs b/src/test/compile-fail/unsized-enum.rs index 2041c69da54..f9702e29f1d 100644 --- a/src/test/compile-fail/unsized-enum.rs +++ b/src/test/compile-fail/unsized-enum.rs @@ -15,7 +15,7 @@ fn not_sized() { } enum Foo { FooSome(U), FooNone } fn foo1() { not_sized::>() } // Hunky dory. fn foo2() { not_sized::>() } -//~^ ERROR `T` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type // // Not OK: `T` is not sized. diff --git a/src/test/compile-fail/unsized-inherent-impl-self-type.rs b/src/test/compile-fail/unsized-inherent-impl-self-type.rs index 5e5280ff3ea..03d3d98b59f 100644 --- a/src/test/compile-fail/unsized-inherent-impl-self-type.rs +++ b/src/test/compile-fail/unsized-inherent-impl-self-type.rs @@ -15,7 +15,7 @@ struct S5(Y); impl S5 { - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn main() { } diff --git a/src/test/compile-fail/unsized-struct.rs b/src/test/compile-fail/unsized-struct.rs index 830ac5d6c20..8cb1f760664 100644 --- a/src/test/compile-fail/unsized-struct.rs +++ b/src/test/compile-fail/unsized-struct.rs @@ -15,14 +15,14 @@ fn not_sized() { } struct Foo { data: T } fn foo1() { not_sized::>() } // Hunky dory. fn foo2() { not_sized::>() } -//~^ ERROR `T` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type // // Not OK: `T` is not sized. struct Bar { data: T } fn bar1() { not_sized::>() } fn bar2() { is_sized::>() } -//~^ ERROR `T` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type // // Not OK: `Bar` is not sized, but it should be. diff --git a/src/test/compile-fail/unsized-trait-impl-self-type.rs b/src/test/compile-fail/unsized-trait-impl-self-type.rs index 9bf4cf7a0bb..b3610a4c9b9 100644 --- a/src/test/compile-fail/unsized-trait-impl-self-type.rs +++ b/src/test/compile-fail/unsized-trait-impl-self-type.rs @@ -18,7 +18,7 @@ trait T3 { struct S5(Y); impl T3 for S5 { - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn main() { } diff --git a/src/test/compile-fail/unsized-trait-impl-trait-arg.rs b/src/test/compile-fail/unsized-trait-impl-trait-arg.rs index b3a848954d1..50a058a4338 100644 --- a/src/test/compile-fail/unsized-trait-impl-trait-arg.rs +++ b/src/test/compile-fail/unsized-trait-impl-trait-arg.rs @@ -16,7 +16,7 @@ trait T2 { } struct S4(Box); impl T2 for S4 { - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn main() { } diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs index e08cf8280fd..945f20b2877 100644 --- a/src/test/compile-fail/unsized3.rs +++ b/src/test/compile-fail/unsized3.rs @@ -15,7 +15,7 @@ use std::marker; // Unbounded. fn f1(x: &X) { f2::(x); - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn f2(x: &X) { } @@ -26,7 +26,7 @@ trait T { } fn f3(x: &X) { f4::(x); - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn f4(x: &X) { } @@ -41,20 +41,20 @@ struct S { fn f8(x1: &S, x2: &S) { f5(x1); - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type f6(x2); // ok } // Test some tuples. fn f9(x1: Box>) { f5(&(*x1, 34)); - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn f10(x1: Box>) { f5(&(32, *x1)); - //~^ ERROR `X` does not have a constant size known at compile-time - //~| ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type + //~| ERROR the size for value values of type } pub fn main() { diff --git a/src/test/compile-fail/unsized5.rs b/src/test/compile-fail/unsized5.rs index 1fb32da5e31..e04aa3599e9 100644 --- a/src/test/compile-fail/unsized5.rs +++ b/src/test/compile-fail/unsized5.rs @@ -12,32 +12,32 @@ struct S1 { f1: X, - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type f2: isize, } struct S2 { f: isize, g: X, - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type h: isize, } struct S3 { f: str, - //~^ ERROR `str` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type g: [usize] } struct S4 { f: [u8], - //~^ ERROR `[u8]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type g: usize } enum E { V1(X, isize), - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } enum F { V2{f1: X, f: isize}, - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } pub fn main() { diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index 7ce0e1eb4d8..8ac9fe4c587 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -15,40 +15,40 @@ trait T {} fn f1(x: &X) { let _: W; // <-- this is OK, no bindings created, no initializer. let _: (isize, (X, isize)); - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type let y: Y; - //~^ ERROR `Y` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type let y: (isize, (Z, usize)); - //~^ ERROR `Z` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn f2(x: &X) { let y: X; - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type let y: (isize, (Y, isize)); - //~^ ERROR `Y` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn f3(x1: Box, x2: Box, x3: Box) { let y: X = *x1; - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type let y = *x2; - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type let (y, z) = (*x3, 4); - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn f4(x1: Box, x2: Box, x3: Box) { let y: X = *x1; - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type let y = *x2; - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type let (y, z) = (*x3, 4); - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn g1(x: X) {} -//~^ ERROR `X` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type fn g2(x: X) {} -//~^ ERROR `X` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type pub fn main() { } diff --git a/src/test/compile-fail/unsized7.rs b/src/test/compile-fail/unsized7.rs index 8a3d78f0827..44d7df35680 100644 --- a/src/test/compile-fail/unsized7.rs +++ b/src/test/compile-fail/unsized7.rs @@ -20,7 +20,7 @@ trait T1 { struct S3(Box); impl T1 for S3 { - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn main() { } diff --git a/src/test/ui/const-unsized.rs b/src/test/ui/const-unsized.rs index 61ee622e21b..c0a367604c3 100644 --- a/src/test/ui/const-unsized.rs +++ b/src/test/ui/const-unsized.rs @@ -11,16 +11,16 @@ use std::fmt::Debug; const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); -//~^ ERROR `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at +//~^ ERROR the size for value values of type const CONST_FOO: str = *"foo"; -//~^ ERROR `str` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); -//~^ ERROR `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at +//~^ ERROR the size for value values of type static STATIC_BAR: str = *"bar"; -//~^ ERROR `str` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type fn main() { println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR); diff --git a/src/test/ui/const-unsized.stderr b/src/test/ui/const-unsized.stderr index 6baeab90db2..2cde4aec2b5 100644 --- a/src/test/ui/const-unsized.stderr +++ b/src/test/ui/const-unsized.stderr @@ -1,38 +1,38 @@ -error[E0277]: `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `std::fmt::Debug + std::marker::Sync + 'static` cannot be known at compilation time --> $DIR/const-unsized.rs:13:29 | LL | const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); - | ^^^^^^^^^^^^^^^^^^^^^^ `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `std::fmt::Debug + std::marker::Sync + 'static` = note: to learn more, visit = note: constant expressions must have a statically known size -error[E0277]: `str` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `str` cannot be known at compilation time --> $DIR/const-unsized.rs:16:24 | LL | const CONST_FOO: str = *"foo"; - | ^^^^^^ `str` does not have a constant size known at compile-time + | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit = note: constant expressions must have a statically known size -error[E0277]: `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `std::fmt::Debug + std::marker::Sync + 'static` cannot be known at compilation time --> $DIR/const-unsized.rs:19:31 | LL | static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); - | ^^^^^^^^^^^^^^^^^^^^^^ `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `std::fmt::Debug + std::marker::Sync + 'static` = note: to learn more, visit = note: constant expressions must have a statically known size -error[E0277]: `str` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `str` cannot be known at compilation time --> $DIR/const-unsized.rs:22:26 | LL | static STATIC_BAR: str = *"bar"; - | ^^^^^^ `str` does not have a constant size known at compile-time + | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit diff --git a/src/test/ui/error-codes/E0277.rs b/src/test/ui/error-codes/E0277.rs index 9ff2ef4da90..95f10e7206f 100644 --- a/src/test/ui/error-codes/E0277.rs +++ b/src/test/ui/error-codes/E0277.rs @@ -21,7 +21,7 @@ fn some_func(foo: T) { } fn f(p: Path) { } -//~^ ERROR `[u8]` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type fn main() { some_func(5i32); diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr index e1c3183104a..ca5b0d2b987 100644 --- a/src/test/ui/error-codes/E0277.stderr +++ b/src/test/ui/error-codes/E0277.stderr @@ -1,8 +1,8 @@ -error[E0277]: `[u8]` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `[u8]` cannot be known at compilation time --> $DIR/E0277.rs:23:6 | LL | fn f(p: Path) { } - | ^ `[u8]` does not have a constant size known at compile-time + | ^ doesn't have a size known at compile-time | = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]` = note: to learn more, visit diff --git a/src/test/ui/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gate-trivial_bounds.stderr index 9344e78c23c..db280f2d1f7 100644 --- a/src/test/ui/feature-gate-trivial_bounds.stderr +++ b/src/test/ui/feature-gate-trivial_bounds.stderr @@ -87,24 +87,24 @@ LL | | } = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable -error[E0277]: `str` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `str` cannot be known at compilation time --> $DIR/feature-gate-trivial_bounds.rs:62:1 | LL | struct TwoStrs(str, str) where str: Sized; //~ ERROR - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `str` does not have a constant size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable -error[E0277]: `A + 'static` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `A + 'static` cannot be known at compilation time --> $DIR/feature-gate-trivial_bounds.rs:65:1 | LL | / fn unsized_local() where Dst: Sized { //~ ERROR LL | | let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); LL | | } - | |_^ `A + 'static` does not have a constant size known at compile-time + | |_^ doesn't have a size known at compile-time | = help: within `Dst`, the trait `std::marker::Sized` is not implemented for `A + 'static` = note: to learn more, visit @@ -112,13 +112,13 @@ LL | | } = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable -error[E0277]: `str` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `str` cannot be known at compilation time --> $DIR/feature-gate-trivial_bounds.rs:69:1 | LL | / fn return_str() -> str where str: Sized { //~ ERROR LL | | *"Sized".to_string().into_boxed_str() LL | | } - | |_^ `str` does not have a constant size known at compile-time + | |_^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit diff --git a/src/test/ui/generator/sized-yield.rs b/src/test/ui/generator/sized-yield.rs index 165e2702597..efaee4095c1 100644 --- a/src/test/ui/generator/sized-yield.rs +++ b/src/test/ui/generator/sized-yield.rs @@ -15,9 +15,9 @@ use std::ops::Generator; fn main() { let s = String::from("foo"); let mut gen = move || { - //~^ ERROR `str` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type yield s[..]; }; unsafe { gen.resume(); } - //~^ ERROR `str` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr index 7918101850e..2938268a804 100644 --- a/src/test/ui/generator/sized-yield.stderr +++ b/src/test/ui/generator/sized-yield.stderr @@ -1,22 +1,22 @@ -error[E0277]: `str` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `str` cannot be known at compilation time --> $DIR/sized-yield.rs:17:26 | LL | let mut gen = move || { | __________________________^ -LL | | //~^ ERROR `str` does not have a constant size known at compile-time +LL | | //~^ ERROR the size for value values of type LL | | yield s[..]; LL | | }; - | |____^ `str` does not have a constant size known at compile-time + | |____^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit = note: the yield type of a generator must have a statically known size -error[E0277]: `str` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `str` cannot be known at compilation time --> $DIR/sized-yield.rs:21:17 | LL | unsafe { gen.resume(); } - | ^^^^^^ `str` does not have a constant size known at compile-time + | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit diff --git a/src/test/ui/mismatched_types/cast-rfc0401.rs b/src/test/ui/mismatched_types/cast-rfc0401.rs index 67aa8f89ddf..d76c4a015a2 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.rs +++ b/src/test/ui/mismatched_types/cast-rfc0401.rs @@ -60,7 +60,7 @@ fn main() let _ = 42usize as *const [u8]; //~ ERROR is invalid let _ = v as *const [u8]; //~ ERROR cannot cast - let _ = fat_v as *const Foo; //~ ERROR `[u8]` does not have a constant size known at + let _ = fat_v as *const Foo; //~ ERROR the size for value values of type let _ = foo as *const str; //~ ERROR is invalid let _ = foo as *mut str; //~ ERROR is invalid let _ = main as *mut str; //~ ERROR is invalid @@ -69,7 +69,7 @@ fn main() let _ = fat_sv as usize; //~ ERROR is invalid let a : *const str = "hello"; - let _ = a as *const Foo; //~ ERROR `str` does not have a constant size known at compile-time + let _ = a as *const Foo; //~ ERROR the size for value values of type // check no error cascade let _ = main.f as *const u32; //~ ERROR no field diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index a5992cd6802..feaf492837f 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -216,21 +216,21 @@ LL | let _ = cf as *const Bar; //~ ERROR is invalid | = note: vtable kinds may not match -error[E0277]: `[u8]` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `[u8]` cannot be known at compilation time --> $DIR/cast-rfc0401.rs:63:13 | -LL | let _ = fat_v as *const Foo; //~ ERROR `[u8]` does not have a constant size known at - | ^^^^^ `[u8]` does not have a constant size known at compile-time +LL | let _ = fat_v as *const Foo; //~ ERROR the size for value values of type + | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` = note: to learn more, visit = note: required for the cast to the object type `Foo` -error[E0277]: `str` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `str` cannot be known at compilation time --> $DIR/cast-rfc0401.rs:72:13 | -LL | let _ = a as *const Foo; //~ ERROR `str` does not have a constant size known at compile-time - | ^ `str` does not have a constant size known at compile-time +LL | let _ = a as *const Foo; //~ ERROR the size for value values of type + | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit diff --git a/src/test/ui/resolve/issue-5035-2.rs b/src/test/ui/resolve/issue-5035-2.rs index f6cdb05394a..ca854f9f701 100644 --- a/src/test/ui/resolve/issue-5035-2.rs +++ b/src/test/ui/resolve/issue-5035-2.rs @@ -12,6 +12,6 @@ trait I {} type K = I+'static; fn foo(_x: K) {} -//~^ ERROR `I + 'static` does not have a constant size known at compile-time +//~^ ERROR the size for value values of type fn main() {} diff --git a/src/test/ui/resolve/issue-5035-2.stderr b/src/test/ui/resolve/issue-5035-2.stderr index 1488f6b9985..efcd0b36248 100644 --- a/src/test/ui/resolve/issue-5035-2.stderr +++ b/src/test/ui/resolve/issue-5035-2.stderr @@ -1,8 +1,8 @@ -error[E0277]: `I + 'static` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `I + 'static` cannot be known at compilation time --> $DIR/issue-5035-2.rs:14:8 | LL | fn foo(_x: K) {} - | ^^ `I + 'static` does not have a constant size known at compile-time + | ^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `I + 'static` = note: to learn more, visit diff --git a/src/test/ui/suggestions/str-array-assignment.rs b/src/test/ui/suggestions/str-array-assignment.rs index f6b75981a66..8fbab402232 100644 --- a/src/test/ui/suggestions/str-array-assignment.rs +++ b/src/test/ui/suggestions/str-array-assignment.rs @@ -15,7 +15,7 @@ fn main() { let u: &str = if true { s[..2] } else { s }; //~^ ERROR mismatched types let v = s[..2]; - //~^ ERROR `str` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type let w: &str = s[..2]; //~^ ERROR mismatched types } diff --git a/src/test/ui/suggestions/str-array-assignment.stderr b/src/test/ui/suggestions/str-array-assignment.stderr index acf51f89fc4..12699d8b25f 100644 --- a/src/test/ui/suggestions/str-array-assignment.stderr +++ b/src/test/ui/suggestions/str-array-assignment.stderr @@ -19,13 +19,13 @@ LL | let u: &str = if true { s[..2] } else { s }; = note: expected type `&str` found type `str` -error[E0277]: `str` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `str` cannot be known at compilation time --> $DIR/str-array-assignment.rs:17:7 | LL | let v = s[..2]; | ^ ------ help: consider borrowing here: `&s[..2]` | | - | `str` does not have a constant size known at compile-time + | doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit diff --git a/src/test/ui/trait-suggest-where-clause.rs b/src/test/ui/trait-suggest-where-clause.rs index 7962dbea371..dd74f4f4797 100644 --- a/src/test/ui/trait-suggest-where-clause.rs +++ b/src/test/ui/trait-suggest-where-clause.rs @@ -15,10 +15,10 @@ struct Misc(T); fn check() { // suggest a where-clause, if needed mem::size_of::(); - //~^ ERROR `U` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type mem::size_of::>(); - //~^ ERROR `U` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type // ... even if T occurs as a type parameter @@ -36,10 +36,10 @@ fn check() { // ... and also not if the error is not related to the type mem::size_of::<[T]>(); - //~^ ERROR `[T]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type mem::size_of::<[&U]>(); - //~^ ERROR `[&U]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn main() { diff --git a/src/test/ui/trait-suggest-where-clause.stderr b/src/test/ui/trait-suggest-where-clause.stderr index d87641d8d0f..feb31ae22d8 100644 --- a/src/test/ui/trait-suggest-where-clause.stderr +++ b/src/test/ui/trait-suggest-where-clause.stderr @@ -1,19 +1,19 @@ -error[E0277]: `U` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `U` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:17:5 | LL | mem::size_of::(); - | ^^^^^^^^^^^^^^^^^ `U` does not have a constant size known at compile-time + | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `U` = note: to learn more, visit = help: consider adding a `where U: std::marker::Sized` bound = note: required by `std::mem::size_of` -error[E0277]: `U` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `U` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:20:5 | LL | mem::size_of::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ `U` does not have a constant size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `Misc`, the trait `std::marker::Sized` is not implemented for `U` = note: to learn more, visit @@ -47,21 +47,21 @@ LL | as From>::from; | = note: required by `std::convert::From::from` -error[E0277]: `[T]` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `[T]` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:38:5 | LL | mem::size_of::<[T]>(); - | ^^^^^^^^^^^^^^^^^^^ `[T]` does not have a constant size known at compile-time + | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[T]` = note: to learn more, visit = note: required by `std::mem::size_of` -error[E0277]: `[&U]` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `[&U]` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:41:5 | LL | mem::size_of::<[&U]>(); - | ^^^^^^^^^^^^^^^^^^^^ `[&U]` does not have a constant size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[&U]` = note: to learn more, visit diff --git a/src/test/ui/trivial-bounds-leak.stderr b/src/test/ui/trivial-bounds-leak.stderr index 6f1f885a506..d08574c3d87 100644 --- a/src/test/ui/trivial-bounds-leak.stderr +++ b/src/test/ui/trivial-bounds-leak.stderr @@ -1,8 +1,8 @@ -error[E0277]: `str` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `str` cannot be known at compilation time --> $DIR/trivial-bounds-leak.rs:22:25 | LL | fn cant_return_str() -> str { //~ ERROR - | ^^^ `str` does not have a constant size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit diff --git a/src/test/ui/union/union-sized-field.rs b/src/test/ui/union/union-sized-field.rs index e40c6d11cb3..15822ae4299 100644 --- a/src/test/ui/union/union-sized-field.rs +++ b/src/test/ui/union/union-sized-field.rs @@ -12,18 +12,18 @@ union Foo { value: T, - //~^ ERROR `T` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } struct Foo2 { value: T, - //~^ ERROR `T` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type t: u32, } enum Foo3 { Value(T), - //~^ ERROR `T` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } fn main() {} diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr index 9fdc5af0481..c6b7cf4e078 100644 --- a/src/test/ui/union/union-sized-field.stderr +++ b/src/test/ui/union/union-sized-field.stderr @@ -1,30 +1,30 @@ -error[E0277]: `T` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `T` cannot be known at compilation time --> $DIR/union-sized-field.rs:14:5 | LL | value: T, - | ^^^^^^^^ `T` does not have a constant size known at compile-time + | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit = help: consider adding a `where T: std::marker::Sized` bound = note: no field of a union may have a dynamically sized type -error[E0277]: `T` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `T` cannot be known at compilation time --> $DIR/union-sized-field.rs:19:5 | LL | value: T, - | ^^^^^^^^ `T` does not have a constant size known at compile-time + | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit = help: consider adding a `where T: std::marker::Sized` bound = note: only the last field of a struct may have a dynamically sized type -error[E0277]: `T` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `T` cannot be known at compilation time --> $DIR/union-sized-field.rs:25:11 | LL | Value(T), - | ^ `T` does not have a constant size known at compile-time + | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit diff --git a/src/test/ui/unsized-enum2.rs b/src/test/ui/unsized-enum2.rs index 4e42b92289b..9082ea4abdd 100644 --- a/src/test/ui/unsized-enum2.rs +++ b/src/test/ui/unsized-enum2.rs @@ -31,53 +31,53 @@ struct Path4(PathHelper4); enum E { // parameter VA(W), - //~^ ERROR `W` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type VB{x: X}, - //~^ ERROR `X` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type VC(isize, Y), - //~^ ERROR `Y` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type VD{u: isize, x: Z}, - //~^ ERROR `Z` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type // slice / str VE([u8]), - //~^ ERROR `[u8]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type VF{x: str}, - //~^ ERROR `str` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type VG(isize, [f32]), - //~^ ERROR `[f32]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type VH{u: isize, x: [u32]}, - //~^ ERROR `[u32]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type // unsized struct VI(Path1), - //~^ ERROR `PathHelper1 + 'static` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type VJ{x: Path2}, - //~^ ERROR `PathHelper2 + 'static` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type VK(isize, Path3), - //~^ ERROR `PathHelper3 + 'static` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type VL{u: isize, x: Path4}, - //~^ ERROR `PathHelper4 + 'static` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type // plain trait VM(Foo), - //~^ ERROR `Foo + 'static` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type VN{x: Bar}, - //~^ ERROR `Bar + 'static` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type VO(isize, FooBar), - //~^ ERROR `FooBar + 'static` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type VP{u: isize, x: BarFoo}, - //~^ ERROR `BarFoo + 'static` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type // projected VQ(<&'static [i8] as Deref>::Target), - //~^ ERROR `[i8]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type VR{x: <&'static [char] as Deref>::Target}, - //~^ ERROR `[char]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type VS(isize, <&'static [f64] as Deref>::Target), - //~^ ERROR `[f64]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type VT{u: isize, x: <&'static [i32] as Deref>::Target}, - //~^ ERROR `[i32]` does not have a constant size known at compile-time + //~^ ERROR the size for value values of type } diff --git a/src/test/ui/unsized-enum2.stderr b/src/test/ui/unsized-enum2.stderr index 91b8e5def7e..ff2aa1d1ef9 100644 --- a/src/test/ui/unsized-enum2.stderr +++ b/src/test/ui/unsized-enum2.stderr @@ -1,205 +1,205 @@ -error[E0277]: `W` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `W` cannot be known at compilation time --> $DIR/unsized-enum2.rs:33:8 | LL | VA(W), - | ^ `W` does not have a constant size known at compile-time + | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `W` = note: to learn more, visit = help: consider adding a `where W: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `X` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `X` cannot be known at compilation time --> $DIR/unsized-enum2.rs:35:8 | LL | VB{x: X}, - | ^^^^ `X` does not have a constant size known at compile-time + | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `Y` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `Y` cannot be known at compilation time --> $DIR/unsized-enum2.rs:37:15 | LL | VC(isize, Y), - | ^ `Y` does not have a constant size known at compile-time + | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Y` = note: to learn more, visit = help: consider adding a `where Y: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `Z` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `Z` cannot be known at compilation time --> $DIR/unsized-enum2.rs:39:18 | LL | VD{u: isize, x: Z}, - | ^^^^ `Z` does not have a constant size known at compile-time + | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Z` = note: to learn more, visit = help: consider adding a `where Z: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `[u8]` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `[u8]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:43:8 | LL | VE([u8]), - | ^^^^ `[u8]` does not have a constant size known at compile-time + | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `str` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `str` cannot be known at compilation time --> $DIR/unsized-enum2.rs:45:8 | LL | VF{x: str}, - | ^^^^^^ `str` does not have a constant size known at compile-time + | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `[f32]` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `[f32]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:47:15 | LL | VG(isize, [f32]), - | ^^^^^ `[f32]` does not have a constant size known at compile-time + | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[f32]` = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `[u32]` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `[u32]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:49:18 | LL | VH{u: isize, x: [u32]}, - | ^^^^^^^^ `[u32]` does not have a constant size known at compile-time + | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u32]` = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `Foo + 'static` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `Foo + 'static` cannot be known at compilation time --> $DIR/unsized-enum2.rs:63:8 | LL | VM(Foo), - | ^^^ `Foo + 'static` does not have a constant size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Foo + 'static` = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `Bar + 'static` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `Bar + 'static` cannot be known at compilation time --> $DIR/unsized-enum2.rs:65:8 | LL | VN{x: Bar}, - | ^^^^^^ `Bar + 'static` does not have a constant size known at compile-time + | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Bar + 'static` = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `FooBar + 'static` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `FooBar + 'static` cannot be known at compilation time --> $DIR/unsized-enum2.rs:67:15 | LL | VO(isize, FooBar), - | ^^^^^^ `FooBar + 'static` does not have a constant size known at compile-time + | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `FooBar + 'static` = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `BarFoo + 'static` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `BarFoo + 'static` cannot be known at compilation time --> $DIR/unsized-enum2.rs:69:18 | LL | VP{u: isize, x: BarFoo}, - | ^^^^^^^^^ `BarFoo + 'static` does not have a constant size known at compile-time + | ^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `BarFoo + 'static` = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `[i8]` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `[i8]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:73:8 | LL | VQ(<&'static [i8] as Deref>::Target), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[i8]` does not have a constant size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i8]` = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `[char]` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `[char]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:75:8 | LL | VR{x: <&'static [char] as Deref>::Target}, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[char]` does not have a constant size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[char]` = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `[f64]` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `[f64]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:77:15 | LL | VS(isize, <&'static [f64] as Deref>::Target), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[f64]` does not have a constant size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[f64]` = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `[i32]` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `[i32]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:79:18 | LL | VT{u: isize, x: <&'static [i32] as Deref>::Target}, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[i32]` does not have a constant size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i32]` = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `PathHelper1 + 'static` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `PathHelper1 + 'static` cannot be known at compilation time --> $DIR/unsized-enum2.rs:53:8 | LL | VI(Path1), - | ^^^^^ `PathHelper1 + 'static` does not have a constant size known at compile-time + | ^^^^^ doesn't have a size known at compile-time | = help: within `Path1`, the trait `std::marker::Sized` is not implemented for `PathHelper1 + 'static` = note: to learn more, visit = note: required because it appears within the type `Path1` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `PathHelper2 + 'static` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `PathHelper2 + 'static` cannot be known at compilation time --> $DIR/unsized-enum2.rs:55:8 | LL | VJ{x: Path2}, - | ^^^^^^^^ `PathHelper2 + 'static` does not have a constant size known at compile-time + | ^^^^^^^^ doesn't have a size known at compile-time | = help: within `Path2`, the trait `std::marker::Sized` is not implemented for `PathHelper2 + 'static` = note: to learn more, visit = note: required because it appears within the type `Path2` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `PathHelper3 + 'static` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `PathHelper3 + 'static` cannot be known at compilation time --> $DIR/unsized-enum2.rs:57:15 | LL | VK(isize, Path3), - | ^^^^^ `PathHelper3 + 'static` does not have a constant size known at compile-time + | ^^^^^ doesn't have a size known at compile-time | = help: within `Path3`, the trait `std::marker::Sized` is not implemented for `PathHelper3 + 'static` = note: to learn more, visit = note: required because it appears within the type `Path3` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: `PathHelper4 + 'static` does not have a constant size known at compile-time +error[E0277]: the size for value values of type `PathHelper4 + 'static` cannot be known at compilation time --> $DIR/unsized-enum2.rs:59:18 | LL | VL{u: isize, x: Path4}, - | ^^^^^^^^ `PathHelper4 + 'static` does not have a constant size known at compile-time + | ^^^^^^^^ doesn't have a size known at compile-time | = help: within `Path4`, the trait `std::marker::Sized` is not implemented for `PathHelper4 + 'static` = note: to learn more, visit -- cgit 1.4.1-3-g733a5 From 11341e2b069d70710cc0625c4bd3be6f851e04c7 Mon Sep 17 00:00:00 2001 From: Martin Glagla Date: Wed, 20 Jun 2018 10:08:11 +0200 Subject: Replace unreachable! with unreachable_unchecked --- src/libcore/option.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 1e615042a6d..e633d80a63c 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -146,7 +146,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use iter::{FromIterator, FusedIterator, TrustedLen}; -use {mem, ops}; +use {hint, mem, ops}; use mem::PinMut; // Note that this is not a lang item per se, but it has a hidden dependency on @@ -784,7 +784,7 @@ impl Option { match *self { Some(ref mut v) => v, - _ => unreachable!(), + None => unsafe { hint::unreachable_unchecked() }, } } @@ -817,7 +817,7 @@ impl Option { match *self { Some(ref mut v) => v, - _ => unreachable!(), + None => unsafe { hint::unreachable_unchecked() }, } } -- cgit 1.4.1-3-g733a5 From 4eca24700be4cf9f1fad3e7674e4849f4de234a1 Mon Sep 17 00:00:00 2001 From: Anirudh Balaji Date: Fri, 22 Jun 2018 00:20:51 -0700 Subject: Add explanation for (copy, clone)_from_slice It elaborates over why we have to slice the 4-size src to 2-size (same as dst). --- src/libcore/slice/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 6f4c130d8f3..01db55a00f6 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1541,6 +1541,10 @@ impl [T] { /// let src = [1, 2, 3, 4]; /// let mut dst = [0, 0]; /// + /// // Note: the slices must be the same length, so + /// // you can slice the source to be the same size. + /// // Here we slice the source, four elements, to two, the same size + /// // as the destination slice. It *will* panic if we don't do this. /// dst.clone_from_slice(&src[2..]); /// /// assert_eq!(src, [1, 2, 3, 4]); @@ -1607,6 +1611,10 @@ impl [T] { /// let src = [1, 2, 3, 4]; /// let mut dst = [0, 0]; /// + /// // Note: the slices must be the same length, so + /// // you can slice the source to be the same size. + /// // Here we slice the source, four elements, to two, the same size + /// // as the destination slice. It *will* panic if we don't do this. /// dst.copy_from_slice(&src[2..]); /// /// assert_eq!(src, [1, 2, 3, 4]); -- cgit 1.4.1-3-g733a5 From 3bcb85ee658e7a5362f5e381c337f07381f916dc Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Sat, 23 Jun 2018 13:32:53 +0200 Subject: `PinMut`: Add safe `get_mut` and rename unsafe fns to `get_mut_unchecked` and `map_unchecked` --- src/libcore/mem.rs | 14 ++++++++++---- src/libcore/option.rs | 2 +- src/libstd/future.rs | 2 +- src/libstd/panic.rs | 11 +++-------- 4 files changed, 15 insertions(+), 14 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 31635ffa53c..08bd9289ab4 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1119,6 +1119,12 @@ impl<'a, T: ?Sized + Unpin> PinMut<'a, T> { pub fn new(reference: &'a mut T) -> PinMut<'a, T> { PinMut { inner: reference } } + + /// Get a mutable reference to the data inside of this `PinMut`. + #[unstable(feature = "pin", issue = "49150")] + pub fn get_mut(this: PinMut<'a, T>) -> &'a mut T { + this.inner + } } @@ -1150,21 +1156,21 @@ impl<'a, T: ?Sized> PinMut<'a, T> { /// the data out of the mutable reference you receive when you call this /// function. #[unstable(feature = "pin", issue = "49150")] - pub unsafe fn get_mut(this: PinMut<'a, T>) -> &'a mut T { + pub unsafe fn get_mut_unchecked(this: PinMut<'a, T>) -> &'a mut T { this.inner } /// Construct a new pin by mapping the interior value. /// - /// For example, if you wanted to get a `PinMut` of a field of something, you - /// could use this to get access to that field in one line of code. + /// For example, if you wanted to get a `PinMut` of a field of something, + /// you could use this to get access to that field in one line of code. /// /// This function is unsafe. You must guarantee that the data you return /// will not move so long as the argument value does not move (for example, /// because it is one of the fields of that value), and also that you do /// not move out of the argument you receive to the interior function. #[unstable(feature = "pin", issue = "49150")] - pub unsafe fn map(this: PinMut<'a, T>, f: F) -> PinMut<'a, U> where + pub unsafe fn map_unchecked(this: PinMut<'a, T>, f: F) -> PinMut<'a, U> where F: FnOnce(&mut T) -> &mut U { PinMut { inner: f(this.inner) } diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 1e615042a6d..70979f631cd 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -275,7 +275,7 @@ impl Option { #[unstable(feature = "pin", issue = "49150")] pub fn as_pin_mut<'a>(self: PinMut<'a, Self>) -> Option> { unsafe { - PinMut::get_mut(self).as_mut().map(|x| PinMut::new_unchecked(x)) + PinMut::get_mut_unchecked(self).as_mut().map(|x| PinMut::new_unchecked(x)) } } diff --git a/src/libstd/future.rs b/src/libstd/future.rs index 2da775fdc94..c1cc36f3b41 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -43,7 +43,7 @@ impl> !Unpin for GenFuture {} impl> Future for GenFuture { type Output = T::Return; fn poll(self: PinMut, cx: &mut task::Context) -> Poll { - set_task_cx(cx, || match unsafe { PinMut::get_mut(self).0.resume() } { + set_task_cx(cx, || match unsafe { PinMut::get_mut_unchecked(self).0.resume() } { GeneratorState::Yielded(()) => Poll::Pending, GeneratorState::Complete(x) => Poll::Ready(x), }) diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 2c11c262488..451420ae88a 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -327,14 +327,9 @@ impl fmt::Debug for AssertUnwindSafe { impl<'a, F: Future> Future for AssertUnwindSafe { type Output = F::Output; - fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { - unsafe { - let pinned_field = PinMut::new_unchecked( - &mut PinMut::get_mut(self.reborrow()).0 - ); - - pinned_field.poll(cx) - } + fn poll(self: PinMut, cx: &mut task::Context) -> Poll { + let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) }; + pinned_field.poll(cx) } } -- cgit 1.4.1-3-g733a5 From 6b0c2fd1d6caf3317da930912b9dc85ed92747f7 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 24 Jun 2018 20:11:56 +0200 Subject: Use assert_eq! in copy_from_slice This will print both lengths when the assertion fails instead of just saying that they're different. --- src/libcore/slice/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 6f4c130d8f3..e4ed5f61d1c 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1642,8 +1642,8 @@ impl [T] { /// [`split_at_mut`]: #method.split_at_mut #[stable(feature = "copy_from_slice", since = "1.9.0")] pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy { - assert!(self.len() == src.len(), - "destination and source slices have different lengths"); + assert_eq!(self.len(), src.len(), + "destination and source slices have different lengths"); unsafe { ptr::copy_nonoverlapping( src.as_ptr(), self.as_mut_ptr(), self.len()); -- cgit 1.4.1-3-g733a5 From 57f7f22fe46a08c197e4cd1d2e78df9de4c00798 Mon Sep 17 00:00:00 2001 From: Anirudh Balaji Date: Sun, 24 Jun 2018 15:31:03 -0700 Subject: Make line-breaking more consistent. --- src/libcore/slice/mod.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 01db55a00f6..a6d95b11825 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1541,10 +1541,9 @@ impl [T] { /// let src = [1, 2, 3, 4]; /// let mut dst = [0, 0]; /// - /// // Note: the slices must be the same length, so - /// // you can slice the source to be the same size. - /// // Here we slice the source, four elements, to two, the same size - /// // as the destination slice. It *will* panic if we don't do this. + /// // Note: the slices must be the same length, so you can slice the + /// // source to be the same size. Here we slice the source, four elements, + /// // to two, the same size as the destination slice. It *will* panic if we don't do this. /// dst.clone_from_slice(&src[2..]); /// /// assert_eq!(src, [1, 2, 3, 4]); @@ -1611,10 +1610,9 @@ impl [T] { /// let src = [1, 2, 3, 4]; /// let mut dst = [0, 0]; /// - /// // Note: the slices must be the same length, so - /// // you can slice the source to be the same size. - /// // Here we slice the source, four elements, to two, the same size - /// // as the destination slice. It *will* panic if we don't do this. + /// // Note: the slices must be the same length, so you can slice the + /// // source to be the same size. Here we slice the source, four elements, + /// // to two, the same size as the destination slice. It *will* panic if we don't do this. /// dst.copy_from_slice(&src[2..]); /// /// assert_eq!(src, [1, 2, 3, 4]); -- cgit 1.4.1-3-g733a5 From 7c316090ebf216308b36ba1651bc6286b113ebd7 Mon Sep 17 00:00:00 2001 From: newpavlov Date: Tue, 26 Jun 2018 13:34:42 +0300 Subject: Deprecation of str::slice_uncheked(_mut) --- src/liballoc/str.rs | 8 ++++---- src/liballoc/string.rs | 2 +- src/libcore/str/mod.rs | 28 +++++++++++++++------------- src/libcore/str/pattern.rs | 2 +- 4 files changed, 21 insertions(+), 19 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 32ca8d1fa5e..2184a84ac7d 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -266,11 +266,11 @@ impl str { let mut result = String::new(); let mut last_end = 0; for (start, part) in self.match_indices(from) { - result.push_str(unsafe { self.slice_unchecked(last_end, start) }); + result.push_str(unsafe { self.get_unchecked(last_end..start) }); result.push_str(to); last_end = start + part.len(); } - result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) }); + result.push_str(unsafe { self.get_unchecked(last_end..self.len()) }); result } @@ -307,11 +307,11 @@ impl str { let mut result = String::with_capacity(32); let mut last_end = 0; for (start, part) in self.match_indices(pat).take(count) { - result.push_str(unsafe { self.slice_unchecked(last_end, start) }); + result.push_str(unsafe { self.get_unchecked(last_end..start) }); result.push_str(to); last_end = start + part.len(); } - result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) }); + result.push_str(unsafe { self.get_unchecked(last_end..self.len()) }); result } diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index a988b6a26d9..7dbd86c0038 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1222,7 +1222,7 @@ impl String { while idx < len { let ch = unsafe { - self.slice_unchecked(idx, len).chars().next().unwrap() + self.get_unchecked(idx..len).chars().next().unwrap() }; let ch_len = ch.len_utf8(); diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 5e1a9c25a21..210fc5fd5a6 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1055,7 +1055,7 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) { self.finished = true; unsafe { - let string = self.matcher.haystack().slice_unchecked(self.start, self.end); + let string = self.matcher.haystack().get_unchecked(self.start..self.end); Some(string) } } else { @@ -1070,7 +1070,7 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { let haystack = self.matcher.haystack(); match self.matcher.next_match() { Some((a, b)) => unsafe { - let elt = haystack.slice_unchecked(self.start, a); + let elt = haystack.get_unchecked(self.start..a); self.start = b; Some(elt) }, @@ -1095,13 +1095,13 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { let haystack = self.matcher.haystack(); match self.matcher.next_match_back() { Some((a, b)) => unsafe { - let elt = haystack.slice_unchecked(b, self.end); + let elt = haystack.get_unchecked(b..self.end); self.end = a; Some(elt) }, None => unsafe { self.finished = true; - Some(haystack.slice_unchecked(self.start, self.end)) + Some(haystack.get_unchecked(self.start..self.end)) }, } } @@ -1222,7 +1222,7 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { #[inline] fn next(&mut self) -> Option<(usize, &'a str)> { self.0.next_match().map(|(start, end)| unsafe { - (start, self.0.haystack().slice_unchecked(start, end)) + (start, self.0.haystack().get_unchecked(start..end)) }) } @@ -1231,7 +1231,7 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { where P::Searcher: ReverseSearcher<'a> { self.0.next_match_back().map(|(start, end)| unsafe { - (start, self.0.haystack().slice_unchecked(start, end)) + (start, self.0.haystack().get_unchecked(start..end)) }) } } @@ -1274,7 +1274,7 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { fn next(&mut self) -> Option<&'a str> { self.0.next_match().map(|(a, b)| unsafe { // Indices are known to be on utf8 boundaries - self.0.haystack().slice_unchecked(a, b) + self.0.haystack().get_unchecked(a..b) }) } @@ -1284,7 +1284,7 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { { self.0.next_match_back().map(|(a, b)| unsafe { // Indices are known to be on utf8 boundaries - self.0.haystack().slice_unchecked(a, b) + self.0.haystack().get_unchecked(a..b) }) } } @@ -2453,6 +2453,7 @@ impl str { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated(since = "1.28.0", reason = "duplicates `get_unchecked`")] #[inline] pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { (begin..end).get_unchecked(self) @@ -2483,6 +2484,7 @@ impl str { /// * `begin` and `end` must be byte positions within the string slice. /// * `begin` and `end` must lie on UTF-8 sequence boundaries. #[stable(feature = "str_slice_mut", since = "1.5.0")] + #[rustc_deprecated(since = "1.28.0", reason = "duplicates `get_unchecked`")] #[inline] pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { (begin..end).get_unchecked_mut(self) @@ -2524,8 +2526,8 @@ impl str { // is_char_boundary checks that the index is in [0, .len()] if self.is_char_boundary(mid) { unsafe { - (self.slice_unchecked(0, mid), - self.slice_unchecked(mid, self.len())) + (self.get_unchecked(0..mid), + self.get_unchecked(mid..self.len())) } } else { slice_error_fail(self, 0, mid) @@ -3652,7 +3654,7 @@ impl str { } unsafe { // Searcher is known to return valid indices - self.slice_unchecked(i, j) + self.get_unchecked(i..j) } } @@ -3691,7 +3693,7 @@ impl str { } unsafe { // Searcher is known to return valid indices - self.slice_unchecked(i, self.len()) + self.get_unchecked(i..self.len()) } } @@ -3738,7 +3740,7 @@ impl str { } unsafe { // Searcher is known to return valid indices - self.slice_unchecked(0, j) + self.get_unchecked(0..j) } } diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 464d57a2702..5e63fa9ff35 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -354,7 +354,7 @@ unsafe impl<'a> ReverseSearcher<'a> for CharSearcher<'a> { #[inline] fn next_back(&mut self) -> SearchStep { let old_finger = self.finger_back; - let slice = unsafe { self.haystack.slice_unchecked(self.finger, old_finger) }; + let slice = unsafe { self.haystack.get_unchecked(self.finger..old_finger) }; let mut iter = slice.chars(); let old_len = iter.iter.len(); if let Some(ch) = iter.next_back() { -- cgit 1.4.1-3-g733a5 From bd853a6469fb71b4719d05c20535a70e75d1aa78 Mon Sep 17 00:00:00 2001 From: Fabian Kössel Date: Mon, 28 May 2018 16:40:57 +0200 Subject: Add unit tests for `.mod_euc()` and `.div_euc()` --- src/libcore/tests/num/mod.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index b5e6a019a22..24fe96a2b82 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -574,6 +574,25 @@ macro_rules! test_float { assert_eq!((-9.0 as $fty).max($nan), -9.0); assert!(($nan as $fty).max($nan).is_nan()); } + #[test] + fn mod_euc() { + let a: $fty = 42.0; + assert!($inf.mod_euc(a).is_nan()); + assert_eq!(a.mod_euc($inf), a); + assert!(a.mod_euc($nan).is_nan()); + assert!($inf.mod_euc($inf).is_nan()); + assert!($inf.mod_euc($nan).is_nan()); + assert!($nan.mod_euc($inf).is_nan()); + } + #[test] + fn div_euc() { + let a: $fty = 42.0; + assert_eq!(a.div_euc($inf), 0.0); + assert!(a.div_euc($nan).is_nan()); + assert!($inf.div_euc($inf).is_nan()); + assert!($inf.div_euc($nan).is_nan()); + assert!($nan.div_euc($inf).is_nan()); + } } } } -- cgit 1.4.1-3-g733a5 From 1f9aa1332fc9f0194bac1761ef04e54564e26fc8 Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Tue, 26 Jun 2018 16:40:42 +0200 Subject: Split libcore/task.rs into submodules --- src/libcore/task.rs | 569 ---------------------------------------- src/libcore/task/context.rs | 92 +++++++ src/libcore/task/executor.rs | 44 ++++ src/libcore/task/mod.rs | 33 +++ src/libcore/task/poll.rs | 83 ++++++ src/libcore/task/spawn_error.rs | 51 ++++ src/libcore/task/task.rs | 98 +++++++ src/libcore/task/wake.rs | 275 +++++++++++++++++++ 8 files changed, 676 insertions(+), 569 deletions(-) delete mode 100644 src/libcore/task.rs create mode 100644 src/libcore/task/context.rs create mode 100644 src/libcore/task/executor.rs create mode 100644 src/libcore/task/mod.rs create mode 100644 src/libcore/task/poll.rs create mode 100644 src/libcore/task/spawn_error.rs create mode 100644 src/libcore/task/task.rs create mode 100644 src/libcore/task/wake.rs (limited to 'src/libcore') diff --git a/src/libcore/task.rs b/src/libcore/task.rs deleted file mode 100644 index 1a6018ffb65..00000000000 --- a/src/libcore/task.rs +++ /dev/null @@ -1,569 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] - -//! Types and Traits for working with asynchronous tasks. - -use fmt; -use ptr::NonNull; -use future::Future; -use mem::PinMut; - -/// Indicates whether a value is available or if the current task has been -/// scheduled to receive a wakeup instead. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub enum Poll { - /// Represents that a value is immediately ready. - Ready(T), - - /// Represents that a value is not ready yet. - /// - /// When a function returns `Pending`, the function *must* also - /// ensure that the current task is scheduled to be awoken when - /// progress can be made. - Pending, -} - -impl Poll { - /// Change the ready value of this `Poll` with the closure provided - pub fn map(self, f: F) -> Poll - where F: FnOnce(T) -> U - { - match self { - Poll::Ready(t) => Poll::Ready(f(t)), - Poll::Pending => Poll::Pending, - } - } - - /// Returns whether this is `Poll::Ready` - pub fn is_ready(&self) -> bool { - match *self { - Poll::Ready(_) => true, - Poll::Pending => false, - } - } - - /// Returns whether this is `Poll::Pending` - pub fn is_pending(&self) -> bool { - !self.is_ready() - } -} - -impl Poll> { - /// Change the success value of this `Poll` with the closure provided - pub fn map_ok(self, f: F) -> Poll> - where F: FnOnce(T) -> U - { - match self { - Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))), - Poll::Ready(Err(e)) => Poll::Ready(Err(e)), - Poll::Pending => Poll::Pending, - } - } - - /// Change the error value of this `Poll` with the closure provided - pub fn map_err(self, f: F) -> Poll> - where F: FnOnce(E) -> U - { - match self { - Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)), - Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))), - Poll::Pending => Poll::Pending, - } - } -} - -impl From for Poll { - fn from(t: T) -> Poll { - Poll::Ready(t) - } -} - -/// A `Waker` is a handle for waking up a task by notifying its executor that it -/// is ready to be run. -/// -/// This handle contains a trait object pointing to an instance of the `UnsafeWake` -/// trait, allowing notifications to get routed through it. -#[repr(transparent)] -pub struct Waker { - inner: NonNull, -} - -unsafe impl Send for Waker {} -unsafe impl Sync for Waker {} - -impl Waker { - /// Constructs a new `Waker` directly. - /// - /// Note that most code will not need to call this. Implementers of the - /// `UnsafeWake` trait will typically provide a wrapper that calls this - /// but you otherwise shouldn't call it directly. - /// - /// If you're working with the standard library then it's recommended to - /// use the `Waker::from` function instead which works with the safe - /// `Arc` type and the safe `Wake` trait. - #[inline] - pub unsafe fn new(inner: NonNull) -> Self { - Waker { inner: inner } - } - - /// Wake up the task associated with this `Waker`. - #[inline] - pub fn wake(&self) { - unsafe { self.inner.as_ref().wake() } - } - - /// Returns whether or not this `Waker` and `other` awaken the same task. - /// - /// This function works on a best-effort basis, and may return false even - /// when the `Waker`s would awaken the same task. However, if this function - /// returns true, it is guaranteed that the `Waker`s will awaken the same - /// task. - /// - /// This function is primarily used for optimization purposes. - #[inline] - pub fn will_wake(&self, other: &Waker) -> bool { - self.inner == other.inner - } -} - -impl Clone for Waker { - #[inline] - fn clone(&self) -> Self { - unsafe { - self.inner.as_ref().clone_raw() - } - } -} - -impl fmt::Debug for Waker { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Waker") - .finish() - } -} - -impl Drop for Waker { - #[inline] - fn drop(&mut self) { - unsafe { - self.inner.as_ref().drop_raw() - } - } -} - -/// A `LocalWaker` is a handle for waking up a task by notifying its executor that it -/// is ready to be run. -/// -/// This is similar to the `Waker` type, but cannot be sent across threads. -/// Task executors can use this type to implement more optimized singlethreaded wakeup -/// behavior. -#[repr(transparent)] -pub struct LocalWaker { - inner: NonNull, -} - -impl !Send for LocalWaker {} -impl !Sync for LocalWaker {} - -impl LocalWaker { - /// Constructs a new `LocalWaker` directly. - /// - /// Note that most code will not need to call this. Implementers of the - /// `UnsafeWake` trait will typically provide a wrapper that calls this - /// but you otherwise shouldn't call it directly. - /// - /// If you're working with the standard library then it's recommended to - /// use the `LocalWaker::from` function instead which works with the safe - /// `Rc` type and the safe `LocalWake` trait. - /// - /// For this function to be used safely, it must be sound to call `inner.wake_local()` - /// on the current thread. - #[inline] - pub unsafe fn new(inner: NonNull) -> Self { - LocalWaker { inner: inner } - } - - /// Wake up the task associated with this `LocalWaker`. - #[inline] - pub fn wake(&self) { - unsafe { self.inner.as_ref().wake_local() } - } - - /// Returns whether or not this `LocalWaker` and `other` `LocalWaker` awaken the same task. - /// - /// This function works on a best-effort basis, and may return false even - /// when the `LocalWaker`s would awaken the same task. However, if this function - /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same - /// task. - /// - /// This function is primarily used for optimization purposes. - #[inline] - pub fn will_wake(&self, other: &LocalWaker) -> bool { - self.inner == other.inner - } - - /// Returns whether or not this `LocalWaker` and `other` `Waker` awaken the same task. - /// - /// This function works on a best-effort basis, and may return false even - /// when the `Waker`s would awaken the same task. However, if this function - /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same - /// task. - /// - /// This function is primarily used for optimization purposes. - #[inline] - pub fn will_wake_nonlocal(&self, other: &Waker) -> bool { - self.inner == other.inner - } -} - -impl From for Waker { - #[inline] - fn from(local_waker: LocalWaker) -> Self { - Waker { inner: local_waker.inner } - } -} - -impl Clone for LocalWaker { - #[inline] - fn clone(&self) -> Self { - unsafe { - LocalWaker { inner: self.inner.as_ref().clone_raw().inner } - } - } -} - -impl fmt::Debug for LocalWaker { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Waker") - .finish() - } -} - -impl Drop for LocalWaker { - #[inline] - fn drop(&mut self) { - unsafe { - self.inner.as_ref().drop_raw() - } - } -} - -/// An unsafe trait for implementing custom memory management for a `Waker` or `LocalWaker`. -/// -/// A `Waker` conceptually is a cloneable trait object for `Wake`, and is -/// most often essentially just `Arc`. However, in some contexts -/// (particularly `no_std`), it's desirable to avoid `Arc` in favor of some -/// custom memory management strategy. This trait is designed to allow for such -/// customization. -/// -/// When using `std`, a default implementation of the `UnsafeWake` trait is provided for -/// `Arc` where `T: Wake` and `Rc` where `T: LocalWake`. -/// -/// Although the methods on `UnsafeWake` take pointers rather than references, -pub unsafe trait UnsafeWake: Send + Sync { - /// Creates a clone of this `UnsafeWake` and stores it behind a `Waker`. - /// - /// This function will create a new uniquely owned handle that under the - /// hood references the same notification instance. In other words calls - /// to `wake` on the returned handle should be equivalent to calls to - /// `wake` on this handle. - /// - /// # Unsafety - /// - /// This function is unsafe to call because it's asserting the `UnsafeWake` - /// value is in a consistent state, i.e. hasn't been dropped. - unsafe fn clone_raw(&self) -> Waker; - - /// Drops this instance of `UnsafeWake`, deallocating resources - /// associated with it. - /// - /// FIXME(cramertj) - /// This method is intended to have a signature such as: - /// - /// ```ignore (not-a-doctest) - /// fn drop_raw(self: *mut Self); - /// ``` - /// - /// Unfortunately in Rust today that signature is not object safe. - /// Nevertheless it's recommended to implement this function *as if* that - /// were its signature. As such it is not safe to call on an invalid - /// pointer, nor is the validity of the pointer guaranteed after this - /// function returns. - /// - /// # Unsafety - /// - /// This function is unsafe to call because it's asserting the `UnsafeWake` - /// value is in a consistent state, i.e. hasn't been dropped. - unsafe fn drop_raw(&self); - - /// Indicates that the associated task is ready to make progress and should - /// be `poll`ed. - /// - /// Executors generally maintain a queue of "ready" tasks; `wake` should place - /// the associated task onto this queue. - /// - /// # Panics - /// - /// Implementations should avoid panicking, but clients should also be prepared - /// for panics. - /// - /// # Unsafety - /// - /// This function is unsafe to call because it's asserting the `UnsafeWake` - /// value is in a consistent state, i.e. hasn't been dropped. - unsafe fn wake(&self); - - /// Indicates that the associated task is ready to make progress and should - /// be `poll`ed. This function is the same as `wake`, but can only be called - /// from the thread that this `UnsafeWake` is "local" to. This allows for - /// implementors to provide specialized wakeup behavior specific to the current - /// thread. This function is called by `LocalWaker::wake`. - /// - /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place - /// the associated task onto this queue. - /// - /// # Panics - /// - /// Implementations should avoid panicking, but clients should also be prepared - /// for panics. - /// - /// # Unsafety - /// - /// This function is unsafe to call because it's asserting the `UnsafeWake` - /// value is in a consistent state, i.e. hasn't been dropped, and that the - /// `UnsafeWake` hasn't moved from the thread on which it was created. - unsafe fn wake_local(&self) { - self.wake() - } -} - -/// Information about the currently-running task. -/// -/// Contexts are always tied to the stack, since they are set up specifically -/// when performing a single `poll` step on a task. -pub struct Context<'a> { - local_waker: &'a LocalWaker, - executor: &'a mut Executor, -} - -impl<'a> fmt::Debug for Context<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Context") - .finish() - } -} - -impl<'a> Context<'a> { - /// Create a new task `Context` with the provided `local_waker`, `waker`, and `executor`. - #[inline] - pub fn new(local_waker: &'a LocalWaker, executor: &'a mut Executor) -> Context<'a> { - Context { - local_waker, - executor, - } - } - - /// Get the `LocalWaker` associated with the current task. - #[inline] - pub fn local_waker(&self) -> &'a LocalWaker { - self.local_waker - } - - /// Get the `Waker` associated with the current task. - #[inline] - pub fn waker(&self) -> &'a Waker { - unsafe { &*(self.local_waker as *const LocalWaker as *const Waker) } - } - - /// Get the default executor associated with this task. - /// - /// This method is useful primarily if you want to explicitly handle - /// spawn failures. - #[inline] - pub fn executor(&mut self) -> &mut Executor { - self.executor - } - - /// Produce a context like the current one, but using the given waker instead. - /// - /// This advanced method is primarily used when building "internal - /// schedulers" within a task, where you want to provide some customized - /// wakeup logic. - #[inline] - pub fn with_waker<'b>(&'b mut self, local_waker: &'b LocalWaker) -> Context<'b> { - Context { - local_waker, - executor: self.executor, - } - } - - /// Produce a context like the current one, but using the given executor - /// instead. - /// - /// This advanced method is primarily used when building "internal - /// schedulers" within a task. - #[inline] - pub fn with_executor<'b, E>(&'b mut self, executor: &'b mut E) -> Context<'b> - where E: Executor - { - Context { - local_waker: self.local_waker, - executor: executor, - } - } -} - -/// A task executor. -/// -/// A *task* is a `()`-producing async value that runs at the top level, and will -/// be `poll`ed until completion. It's also the unit at which wake-up -/// notifications occur. Executors, such as thread pools, allow tasks to be -/// spawned and are responsible for putting tasks onto ready queues when -/// they are woken up, and polling them when they are ready. -pub trait Executor { - /// Spawn the given task, polling it until completion. - /// - /// # Errors - /// - /// The executor may be unable to spawn tasks, either because it has - /// been shut down or is resource-constrained. - fn spawn_obj(&mut self, task: TaskObj) -> Result<(), SpawnObjError>; - - /// Determine whether the executor is able to spawn new tasks. - /// - /// # Returns - /// - /// An `Ok` return means the executor is *likely* (but not guaranteed) - /// to accept a subsequent spawn attempt. Likewise, an `Err` return - /// means that `spawn` is likely, but not guaranteed, to yield an error. - #[inline] - fn status(&self) -> Result<(), SpawnErrorKind> { - Ok(()) - } -} - -/// A custom trait object for polling tasks, roughly akin to -/// `Box + Send>`. -pub struct TaskObj { - ptr: *mut (), - poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<()>, - drop_fn: unsafe fn(*mut ()), -} - -impl fmt::Debug for TaskObj { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("TaskObj") - .finish() - } -} - -unsafe impl Send for TaskObj {} - -/// A custom implementation of a task trait object for `TaskObj`, providing -/// a hand-rolled vtable. -/// -/// This custom representation is typically used only in `no_std` contexts, -/// where the default `Box`-based implementation is not available. -/// -/// The implementor must guarantee that it is safe to call `poll` repeatedly (in -/// a non-concurrent fashion) with the result of `into_raw` until `drop` is -/// called. -pub unsafe trait UnsafeTask: Send + 'static { - /// Convert a owned instance into a (conceptually owned) void pointer. - fn into_raw(self) -> *mut (); - - /// Poll the task represented by the given void pointer. - /// - /// # Safety - /// - /// The trait implementor must guarantee that it is safe to repeatedly call - /// `poll` with the result of `into_raw` until `drop` is called; such calls - /// are not, however, allowed to race with each other or with calls to `drop`. - unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()>; - - /// Drops the task represented by the given void pointer. - /// - /// # Safety - /// - /// The trait implementor must guarantee that it is safe to call this - /// function once per `into_raw` invocation; that call cannot race with - /// other calls to `drop` or `poll`. - unsafe fn drop(task: *mut ()); -} - -impl TaskObj { - /// Create a `TaskObj` from a custom trait object representation. - #[inline] - pub fn new(t: T) -> TaskObj { - TaskObj { - ptr: t.into_raw(), - poll_fn: T::poll, - drop_fn: T::drop, - } - } -} - -impl Future for TaskObj { - type Output = (); - - #[inline] - fn poll(self: PinMut, cx: &mut Context) -> Poll<()> { - unsafe { - (self.poll_fn)(self.ptr, cx) - } - } -} - -impl Drop for TaskObj { - fn drop(&mut self) { - unsafe { - (self.drop_fn)(self.ptr) - } - } -} - -/// Provides the reason that an executor was unable to spawn. -pub struct SpawnErrorKind { - _hidden: (), -} - -impl fmt::Debug for SpawnErrorKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("SpawnErrorKind") - .field(&"shutdown") - .finish() - } -} - -impl SpawnErrorKind { - /// Spawning is failing because the executor has been shut down. - pub fn shutdown() -> SpawnErrorKind { - SpawnErrorKind { _hidden: () } - } - - /// Check whether this error is the `shutdown` error. - pub fn is_shutdown(&self) -> bool { - true - } -} - -/// The result of a failed spawn -#[derive(Debug)] -pub struct SpawnObjError { - /// The kind of error - pub kind: SpawnErrorKind, - - /// The task for which spawning was attempted - pub task: TaskObj, -} diff --git a/src/libcore/task/context.rs b/src/libcore/task/context.rs new file mode 100644 index 00000000000..c69d45248a5 --- /dev/null +++ b/src/libcore/task/context.rs @@ -0,0 +1,92 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use fmt; +use super::{Executor, Waker, LocalWaker}; + +/// Information about the currently-running task. +/// +/// Contexts are always tied to the stack, since they are set up specifically +/// when performing a single `poll` step on a task. +pub struct Context<'a> { + local_waker: &'a LocalWaker, + executor: &'a mut Executor, +} + +impl<'a> fmt::Debug for Context<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Context") + .finish() + } +} + +impl<'a> Context<'a> { + /// Create a new task `Context` with the provided `local_waker`, `waker`, and `executor`. + #[inline] + pub fn new(local_waker: &'a LocalWaker, executor: &'a mut Executor) -> Context<'a> { + Context { + local_waker, + executor, + } + } + + /// Get the `LocalWaker` associated with the current task. + #[inline] + pub fn local_waker(&self) -> &'a LocalWaker { + self.local_waker + } + + /// Get the `Waker` associated with the current task. + #[inline] + pub fn waker(&self) -> &'a Waker { + unsafe { &*(self.local_waker as *const LocalWaker as *const Waker) } + } + + /// Get the default executor associated with this task. + /// + /// This method is useful primarily if you want to explicitly handle + /// spawn failures. + #[inline] + pub fn executor(&mut self) -> &mut Executor { + self.executor + } + + /// Produce a context like the current one, but using the given waker instead. + /// + /// This advanced method is primarily used when building "internal + /// schedulers" within a task, where you want to provide some customized + /// wakeup logic. + #[inline] + pub fn with_waker<'b>(&'b mut self, local_waker: &'b LocalWaker) -> Context<'b> { + Context { + local_waker, + executor: self.executor, + } + } + + /// Produce a context like the current one, but using the given executor + /// instead. + /// + /// This advanced method is primarily used when building "internal + /// schedulers" within a task. + #[inline] + pub fn with_executor<'b, E>(&'b mut self, executor: &'b mut E) -> Context<'b> + where E: Executor + { + Context { + local_waker: self.local_waker, + executor: executor, + } + } +} diff --git a/src/libcore/task/executor.rs b/src/libcore/task/executor.rs new file mode 100644 index 00000000000..fcef6d5ffc8 --- /dev/null +++ b/src/libcore/task/executor.rs @@ -0,0 +1,44 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use super::{TaskObj, SpawnObjError, SpawnErrorKind}; + +/// A task executor. +/// +/// A *task* is a `()`-producing async value that runs at the top level, and will +/// be `poll`ed until completion. It's also the unit at which wake-up +/// notifications occur. Executors, such as thread pools, allow tasks to be +/// spawned and are responsible for putting tasks onto ready queues when +/// they are woken up, and polling them when they are ready. +pub trait Executor { + /// Spawn the given task, polling it until completion. + /// + /// # Errors + /// + /// The executor may be unable to spawn tasks, either because it has + /// been shut down or is resource-constrained. + fn spawn_obj(&mut self, task: TaskObj) -> Result<(), SpawnObjError>; + + /// Determine whether the executor is able to spawn new tasks. + /// + /// # Returns + /// + /// An `Ok` return means the executor is *likely* (but not guaranteed) + /// to accept a subsequent spawn attempt. Likewise, an `Err` return + /// means that `spawn` is likely, but not guaranteed, to yield an error. + #[inline] + fn status(&self) -> Result<(), SpawnErrorKind> { + Ok(()) + } +} diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs new file mode 100644 index 00000000000..66ab21d177d --- /dev/null +++ b/src/libcore/task/mod.rs @@ -0,0 +1,33 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +//! Types and Traits for working with asynchronous tasks. + +mod context; +pub use self::context::Context; + +mod executor; +pub use self::executor::Executor; + +mod poll; +pub use self::poll::Poll; + +mod spawn_error; +pub use self::spawn_error::{SpawnErrorKind, SpawnObjError}; + +mod task; +pub use self::task::{TaskObj, UnsafeTask}; + +mod wake; +pub use self::wake::{Waker, LocalWaker, UnsafeWake}; diff --git a/src/libcore/task/poll.rs b/src/libcore/task/poll.rs new file mode 100644 index 00000000000..10c954f0e80 --- /dev/null +++ b/src/libcore/task/poll.rs @@ -0,0 +1,83 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +/// Indicates whether a value is available or if the current task has been +/// scheduled to receive a wakeup instead. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum Poll { + /// Represents that a value is immediately ready. + Ready(T), + + /// Represents that a value is not ready yet. + /// + /// When a function returns `Pending`, the function *must* also + /// ensure that the current task is scheduled to be awoken when + /// progress can be made. + Pending, +} + +impl Poll { + /// Change the ready value of this `Poll` with the closure provided + pub fn map(self, f: F) -> Poll + where F: FnOnce(T) -> U + { + match self { + Poll::Ready(t) => Poll::Ready(f(t)), + Poll::Pending => Poll::Pending, + } + } + + /// Returns whether this is `Poll::Ready` + pub fn is_ready(&self) -> bool { + match *self { + Poll::Ready(_) => true, + Poll::Pending => false, + } + } + + /// Returns whether this is `Poll::Pending` + pub fn is_pending(&self) -> bool { + !self.is_ready() + } +} + +impl Poll> { + /// Change the success value of this `Poll` with the closure provided + pub fn map_ok(self, f: F) -> Poll> + where F: FnOnce(T) -> U + { + match self { + Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))), + Poll::Ready(Err(e)) => Poll::Ready(Err(e)), + Poll::Pending => Poll::Pending, + } + } + + /// Change the error value of this `Poll` with the closure provided + pub fn map_err(self, f: F) -> Poll> + where F: FnOnce(E) -> U + { + match self { + Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)), + Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))), + Poll::Pending => Poll::Pending, + } + } +} + +impl From for Poll { + fn from(t: T) -> Poll { + Poll::Ready(t) + } +} diff --git a/src/libcore/task/spawn_error.rs b/src/libcore/task/spawn_error.rs new file mode 100644 index 00000000000..5dd9c5be689 --- /dev/null +++ b/src/libcore/task/spawn_error.rs @@ -0,0 +1,51 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use fmt; +use super::TaskObj; + +/// Provides the reason that an executor was unable to spawn. +pub struct SpawnErrorKind { + _hidden: (), +} + +impl fmt::Debug for SpawnErrorKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("SpawnErrorKind") + .field(&"shutdown") + .finish() + } +} + +impl SpawnErrorKind { + /// Spawning is failing because the executor has been shut down. + pub fn shutdown() -> SpawnErrorKind { + SpawnErrorKind { _hidden: () } + } + + /// Check whether this error is the `shutdown` error. + pub fn is_shutdown(&self) -> bool { + true + } +} + +/// The result of a failed spawn +#[derive(Debug)] +pub struct SpawnObjError { + /// The kind of error + pub kind: SpawnErrorKind, + + /// The task for which spawning was attempted + pub task: TaskObj, +} diff --git a/src/libcore/task/task.rs b/src/libcore/task/task.rs new file mode 100644 index 00000000000..dc4ff314e5b --- /dev/null +++ b/src/libcore/task/task.rs @@ -0,0 +1,98 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use fmt; +use future::Future; +use mem::PinMut; +use super::{Context, Poll}; + +/// A custom trait object for polling tasks, roughly akin to +/// `Box + Send>`. +pub struct TaskObj { + ptr: *mut (), + poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<()>, + drop_fn: unsafe fn(*mut ()), +} + +unsafe impl Send for TaskObj {} + +impl TaskObj { + /// Create a `TaskObj` from a custom trait object representation. + #[inline] + pub fn new(t: T) -> TaskObj { + TaskObj { + ptr: t.into_raw(), + poll_fn: T::poll, + drop_fn: T::drop, + } + } +} + +impl fmt::Debug for TaskObj { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("TaskObj") + .finish() + } +} + +impl Future for TaskObj { + type Output = (); + + #[inline] + fn poll(self: PinMut, cx: &mut Context) -> Poll<()> { + unsafe { + (self.poll_fn)(self.ptr, cx) + } + } +} + +impl Drop for TaskObj { + fn drop(&mut self) { + unsafe { + (self.drop_fn)(self.ptr) + } + } +} + +/// A custom implementation of a task trait object for `TaskObj`, providing +/// a hand-rolled vtable. +/// +/// This custom representation is typically used only in `no_std` contexts, +/// where the default `Box`-based implementation is not available. +/// +/// The implementor must guarantee that it is safe to call `poll` repeatedly (in +/// a non-concurrent fashion) with the result of `into_raw` until `drop` is +/// called. +pub unsafe trait UnsafeTask: Send + 'static { + /// Convert a owned instance into a (conceptually owned) void pointer. + fn into_raw(self) -> *mut (); + + /// Poll the task represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to repeatedly call + /// `poll` with the result of `into_raw` until `drop` is called; such calls + /// are not, however, allowed to race with each other or with calls to `drop`. + unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()>; + + /// Drops the task represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to call this + /// function once per `into_raw` invocation; that call cannot race with + /// other calls to `drop` or `poll`. + unsafe fn drop(task: *mut ()); +} diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs new file mode 100644 index 00000000000..4fd45be56fb --- /dev/null +++ b/src/libcore/task/wake.rs @@ -0,0 +1,275 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use fmt; +use ptr::NonNull; + +/// A `Waker` is a handle for waking up a task by notifying its executor that it +/// is ready to be run. +/// +/// This handle contains a trait object pointing to an instance of the `UnsafeWake` +/// trait, allowing notifications to get routed through it. +#[repr(transparent)] +pub struct Waker { + inner: NonNull, +} + +unsafe impl Send for Waker {} +unsafe impl Sync for Waker {} + +impl Waker { + /// Constructs a new `Waker` directly. + /// + /// Note that most code will not need to call this. Implementers of the + /// `UnsafeWake` trait will typically provide a wrapper that calls this + /// but you otherwise shouldn't call it directly. + /// + /// If you're working with the standard library then it's recommended to + /// use the `Waker::from` function instead which works with the safe + /// `Arc` type and the safe `Wake` trait. + #[inline] + pub unsafe fn new(inner: NonNull) -> Self { + Waker { inner: inner } + } + + /// Wake up the task associated with this `Waker`. + #[inline] + pub fn wake(&self) { + unsafe { self.inner.as_ref().wake() } + } + + /// Returns whether or not this `Waker` and `other` awaken the same task. + /// + /// This function works on a best-effort basis, and may return false even + /// when the `Waker`s would awaken the same task. However, if this function + /// returns true, it is guaranteed that the `Waker`s will awaken the same + /// task. + /// + /// This function is primarily used for optimization purposes. + #[inline] + pub fn will_wake(&self, other: &Waker) -> bool { + self.inner == other.inner + } +} + +impl Clone for Waker { + #[inline] + fn clone(&self) -> Self { + unsafe { + self.inner.as_ref().clone_raw() + } + } +} + +impl fmt::Debug for Waker { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Waker") + .finish() + } +} + +impl Drop for Waker { + #[inline] + fn drop(&mut self) { + unsafe { + self.inner.as_ref().drop_raw() + } + } +} + +/// A `LocalWaker` is a handle for waking up a task by notifying its executor that it +/// is ready to be run. +/// +/// This is similar to the `Waker` type, but cannot be sent across threads. +/// Task executors can use this type to implement more optimized singlethreaded wakeup +/// behavior. +#[repr(transparent)] +pub struct LocalWaker { + inner: NonNull, +} + +impl !Send for LocalWaker {} +impl !Sync for LocalWaker {} + +impl LocalWaker { + /// Constructs a new `LocalWaker` directly. + /// + /// Note that most code will not need to call this. Implementers of the + /// `UnsafeWake` trait will typically provide a wrapper that calls this + /// but you otherwise shouldn't call it directly. + /// + /// If you're working with the standard library then it's recommended to + /// use the `LocalWaker::from` function instead which works with the safe + /// `Rc` type and the safe `LocalWake` trait. + /// + /// For this function to be used safely, it must be sound to call `inner.wake_local()` + /// on the current thread. + #[inline] + pub unsafe fn new(inner: NonNull) -> Self { + LocalWaker { inner: inner } + } + + /// Wake up the task associated with this `LocalWaker`. + #[inline] + pub fn wake(&self) { + unsafe { self.inner.as_ref().wake_local() } + } + + /// Returns whether or not this `LocalWaker` and `other` `LocalWaker` awaken the same task. + /// + /// This function works on a best-effort basis, and may return false even + /// when the `LocalWaker`s would awaken the same task. However, if this function + /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same + /// task. + /// + /// This function is primarily used for optimization purposes. + #[inline] + pub fn will_wake(&self, other: &LocalWaker) -> bool { + self.inner == other.inner + } + + /// Returns whether or not this `LocalWaker` and `other` `Waker` awaken the same task. + /// + /// This function works on a best-effort basis, and may return false even + /// when the `Waker`s would awaken the same task. However, if this function + /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same + /// task. + /// + /// This function is primarily used for optimization purposes. + #[inline] + pub fn will_wake_nonlocal(&self, other: &Waker) -> bool { + self.inner == other.inner + } +} + +impl From for Waker { + #[inline] + fn from(local_waker: LocalWaker) -> Self { + Waker { inner: local_waker.inner } + } +} + +impl Clone for LocalWaker { + #[inline] + fn clone(&self) -> Self { + unsafe { + LocalWaker { inner: self.inner.as_ref().clone_raw().inner } + } + } +} + +impl fmt::Debug for LocalWaker { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Waker") + .finish() + } +} + +impl Drop for LocalWaker { + #[inline] + fn drop(&mut self) { + unsafe { + self.inner.as_ref().drop_raw() + } + } +} + +/// An unsafe trait for implementing custom memory management for a `Waker` or `LocalWaker`. +/// +/// A `Waker` conceptually is a cloneable trait object for `Wake`, and is +/// most often essentially just `Arc`. However, in some contexts +/// (particularly `no_std`), it's desirable to avoid `Arc` in favor of some +/// custom memory management strategy. This trait is designed to allow for such +/// customization. +/// +/// When using `std`, a default implementation of the `UnsafeWake` trait is provided for +/// `Arc` where `T: Wake` and `Rc` where `T: LocalWake`. +/// +/// Although the methods on `UnsafeWake` take pointers rather than references, +pub unsafe trait UnsafeWake: Send + Sync { + /// Creates a clone of this `UnsafeWake` and stores it behind a `Waker`. + /// + /// This function will create a new uniquely owned handle that under the + /// hood references the same notification instance. In other words calls + /// to `wake` on the returned handle should be equivalent to calls to + /// `wake` on this handle. + /// + /// # Unsafety + /// + /// This function is unsafe to call because it's asserting the `UnsafeWake` + /// value is in a consistent state, i.e. hasn't been dropped. + unsafe fn clone_raw(&self) -> Waker; + + /// Drops this instance of `UnsafeWake`, deallocating resources + /// associated with it. + /// + /// FIXME(cramertj) + /// This method is intended to have a signature such as: + /// + /// ```ignore (not-a-doctest) + /// fn drop_raw(self: *mut Self); + /// ``` + /// + /// Unfortunately in Rust today that signature is not object safe. + /// Nevertheless it's recommended to implement this function *as if* that + /// were its signature. As such it is not safe to call on an invalid + /// pointer, nor is the validity of the pointer guaranteed after this + /// function returns. + /// + /// # Unsafety + /// + /// This function is unsafe to call because it's asserting the `UnsafeWake` + /// value is in a consistent state, i.e. hasn't been dropped. + unsafe fn drop_raw(&self); + + /// Indicates that the associated task is ready to make progress and should + /// be `poll`ed. + /// + /// Executors generally maintain a queue of "ready" tasks; `wake` should place + /// the associated task onto this queue. + /// + /// # Panics + /// + /// Implementations should avoid panicking, but clients should also be prepared + /// for panics. + /// + /// # Unsafety + /// + /// This function is unsafe to call because it's asserting the `UnsafeWake` + /// value is in a consistent state, i.e. hasn't been dropped. + unsafe fn wake(&self); + + /// Indicates that the associated task is ready to make progress and should + /// be `poll`ed. This function is the same as `wake`, but can only be called + /// from the thread that this `UnsafeWake` is "local" to. This allows for + /// implementors to provide specialized wakeup behavior specific to the current + /// thread. This function is called by `LocalWaker::wake`. + /// + /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place + /// the associated task onto this queue. + /// + /// # Panics + /// + /// Implementations should avoid panicking, but clients should also be prepared + /// for panics. + /// + /// # Unsafety + /// + /// This function is unsafe to call because it's asserting the `UnsafeWake` + /// value is in a consistent state, i.e. hasn't been dropped, and that the + /// `UnsafeWake` hasn't moved from the thread on which it was created. + unsafe fn wake_local(&self) { + self.wake() + } +} -- cgit 1.4.1-3-g733a5 From 057715557b51af125847da6d19b2e016283c5ae7 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Mon, 28 May 2018 19:42:11 -0700 Subject: migrate codebase to `..=` inclusive range patterns These were stabilized in March 2018's #47813, and are the Preferred Way to Do It going forward (q.v. #51043). --- src/libcore/ascii.rs | 4 +- src/libcore/char/decode.rs | 18 ++++---- src/libcore/char/methods.rs | 18 ++++---- src/libcore/fmt/num.rs | 14 +++--- src/libcore/slice/mod.rs | 6 +-- src/libcore/str/lossy.rs | 14 +++--- src/libcore/str/mod.rs | 14 +++--- src/libcore/tests/slice.rs | 4 +- src/librustc_apfloat/ieee.rs | 4 +- src/librustc_codegen_utils/symbol_names.rs | 2 +- src/librustc_mir/diagnostics.rs | 4 +- src/librustc_mir/hair/pattern/check_match.rs | 2 +- src/librustc_target/abi/call/mod.rs | 10 ++--- src/librustc_target/abi/mod.rs | 16 +++---- src/librustc_typeck/diagnostics.rs | 6 +-- src/libserialize/hex.rs | 6 +-- src/libserialize/json.rs | 22 ++++----- src/libstd/sys_common/backtrace.rs | 2 +- src/libstd/sys_common/wtf8.rs | 12 ++--- src/libsyntax/ast.rs | 4 +- src/libsyntax/parse/lexer/mod.rs | 4 +- src/libsyntax_ext/format_foreign.rs | 14 +++--- src/libsyntax_pos/lib.rs | 4 +- src/libterm/terminfo/parm.rs | 10 ++--- src/test/compile-fail/associated-path-shl.rs | 2 +- src/test/compile-fail/issue-27895.rs | 2 +- src/test/compile-fail/issue-41255.rs | 2 +- src/test/compile-fail/match-range-fail-2.rs | 4 +- src/test/compile-fail/match-range-fail.rs | 6 +-- .../compile-fail/non-constant-in-const-path.rs | 2 +- src/test/compile-fail/patkind-litrange-no-expr.rs | 3 +- src/test/compile-fail/qualified-path-params.rs | 2 +- src/test/compile-fail/refutable-pattern-errors.rs | 4 +- src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs | 8 ++-- src/test/run-pass/byte-literals.rs | 2 +- .../run-pass/inferred-suffix-in-pattern-range.rs | 6 +-- src/test/run-pass/issue-12582.rs | 4 +- src/test/run-pass/issue-13027.rs | 52 +++++++++++----------- src/test/run-pass/issue-13867.rs | 14 +++--- src/test/run-pass/issue-18060.rs | 6 +-- src/test/run-pass/issue-18464.rs | 2 +- src/test/run-pass/issue-21475.rs | 6 +-- src/test/run-pass/issue-26251.rs | 4 +- src/test/run-pass/issue-35423.rs | 2 +- src/test/run-pass/issue-7222.rs | 2 +- src/test/run-pass/macro-literal.rs | 20 ++++----- src/test/run-pass/match-range-infer.rs | 6 +-- src/test/run-pass/match-range-static.rs | 2 +- src/test/run-pass/match-range.rs | 14 +++--- .../rfc-2005-default-binding-mode/range.rs | 4 +- src/test/ui/check_match/issue-43253.rs | 8 ++-- src/test/ui/check_match/issue-43253.stderr | 4 +- src/test/ui/const-eval/const_signed_pat.rs | 2 +- src/test/ui/const-eval/ref_to_int_match.rs | 4 +- src/test/ui/const-eval/ref_to_int_match.stderr | 2 +- src/test/ui/error-codes/E0029-teach.rs | 2 +- src/test/ui/error-codes/E0029-teach.stderr | 2 +- src/test/ui/error-codes/E0029.rs | 2 +- src/test/ui/error-codes/E0029.stderr | 2 +- src/test/ui/error-codes/E0030-teach.rs | 2 +- src/test/ui/error-codes/E0030-teach.stderr | 2 +- src/test/ui/error-codes/E0030.rs | 2 +- src/test/ui/error-codes/E0030.stderr | 2 +- src/test/ui/error-codes/E0308-4.rs | 2 +- src/test/ui/error-codes/E0308-4.stderr | 2 +- 65 files changed, 217 insertions(+), 218 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index e6b0569281f..6ee91e0b22f 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -108,7 +108,7 @@ pub fn escape_default(c: u8) -> EscapeDefault { b'\\' => ([b'\\', b'\\', 0, 0], 2), b'\'' => ([b'\\', b'\'', 0, 0], 2), b'"' => ([b'\\', b'"', 0, 0], 2), - b'\x20' ... b'\x7e' => ([c, 0, 0, 0], 1), + b'\x20' ..= b'\x7e' => ([c, 0, 0, 0], 1), _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4), }; @@ -116,7 +116,7 @@ pub fn escape_default(c: u8) -> EscapeDefault { fn hexify(b: u8) -> u8 { match b { - 0 ... 9 => b'0' + b, + 0 ..= 9 => b'0' + b, _ => b'a' + b - 10, } } diff --git a/src/libcore/char/decode.rs b/src/libcore/char/decode.rs index 45a73191db2..0b8dce19dff 100644 --- a/src/libcore/char/decode.rs +++ b/src/libcore/char/decode.rs @@ -64,7 +64,7 @@ impl> Iterator for DecodeUtf8 { } } macro_rules! continuation_byte { - () => { continuation_byte!(0x80...0xBF) }; + () => { continuation_byte!(0x80..=0xBF) }; ($range: pat) => { match self.0.peek() { Some(&byte @ $range) => { @@ -77,35 +77,35 @@ impl> Iterator for DecodeUtf8 { } match first_byte { - 0x00...0x7F => { + 0x00..=0x7F => { first_byte!(0b1111_1111); } - 0xC2...0xDF => { + 0xC2..=0xDF => { first_byte!(0b0001_1111); continuation_byte!(); } 0xE0 => { first_byte!(0b0000_1111); - continuation_byte!(0xA0...0xBF); // 0x80...0x9F here are overlong + continuation_byte!(0xA0..=0xBF); // 0x80..=0x9F here are overlong continuation_byte!(); } - 0xE1...0xEC | 0xEE...0xEF => { + 0xE1..=0xEC | 0xEE..=0xEF => { first_byte!(0b0000_1111); continuation_byte!(); continuation_byte!(); } 0xED => { first_byte!(0b0000_1111); - continuation_byte!(0x80...0x9F); // 0xA0..0xBF here are surrogates + continuation_byte!(0x80..=0x9F); // 0xA0..0xBF here are surrogates continuation_byte!(); } 0xF0 => { first_byte!(0b0000_0111); - continuation_byte!(0x90...0xBF); // 0x80..0x8F here are overlong + continuation_byte!(0x90..=0xBF); // 0x80..0x8F here are overlong continuation_byte!(); continuation_byte!(); } - 0xF1...0xF3 => { + 0xF1..=0xF3 => { first_byte!(0b0000_0111); continuation_byte!(); continuation_byte!(); @@ -113,7 +113,7 @@ impl> Iterator for DecodeUtf8 { } 0xF4 => { first_byte!(0b0000_0111); - continuation_byte!(0x80...0x8F); // 0x90..0xBF here are beyond char::MAX + continuation_byte!(0x80..=0x8F); // 0x90..0xBF here are beyond char::MAX continuation_byte!(); continuation_byte!(); } diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index f6b201fe06d..eee78de9036 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -125,9 +125,9 @@ impl char { panic!("to_digit: radix is too high (maximum 36)"); } let val = match self { - '0' ... '9' => self as u32 - '0' as u32, - 'a' ... 'z' => self as u32 - 'a' as u32 + 10, - 'A' ... 'Z' => self as u32 - 'A' as u32 + 10, + '0' ..= '9' => self as u32 - '0' as u32, + 'a' ..= 'z' => self as u32 - 'a' as u32 + 10, + 'A' ..= 'Z' => self as u32 - 'A' as u32 + 10, _ => return None, }; if val < radix { Some(val) } @@ -305,7 +305,7 @@ impl char { '\r' => EscapeDefaultState::Backslash('r'), '\n' => EscapeDefaultState::Backslash('n'), '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), - '\x20' ... '\x7e' => EscapeDefaultState::Char(self), + '\x20' ..= '\x7e' => EscapeDefaultState::Char(self), _ => EscapeDefaultState::Unicode(self.escape_unicode()) }; EscapeDefault { state: init_state } @@ -543,7 +543,7 @@ impl char { #[inline] pub fn is_alphabetic(self) -> bool { match self { - 'a'...'z' | 'A'...'Z' => true, + 'a'..='z' | 'A'..='Z' => true, c if c > '\x7f' => derived_property::Alphabetic(c), _ => false, } @@ -599,7 +599,7 @@ impl char { #[inline] pub fn is_lowercase(self) -> bool { match self { - 'a'...'z' => true, + 'a'..='z' => true, c if c > '\x7f' => derived_property::Lowercase(c), _ => false, } @@ -627,7 +627,7 @@ impl char { #[inline] pub fn is_uppercase(self) -> bool { match self { - 'A'...'Z' => true, + 'A'..='Z' => true, c if c > '\x7f' => derived_property::Uppercase(c), _ => false, } @@ -654,7 +654,7 @@ impl char { #[inline] pub fn is_whitespace(self) -> bool { match self { - ' ' | '\x09'...'\x0d' => true, + ' ' | '\x09'..='\x0d' => true, c if c > '\x7f' => property::White_Space(c), _ => false, } @@ -737,7 +737,7 @@ impl char { #[inline] pub fn is_numeric(self) -> bool { match self { - '0'...'9' => true, + '0'..='9' => true, c if c > '\x7f' => general_category::N(c), _ => false, } diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index 4451ab445cc..51391fa50d5 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -121,19 +121,19 @@ macro_rules! radix { fn digit(x: u8) -> u8 { match x { $($x => $conv,)+ - x => panic!("number not in the range 0..{}: {}", Self::BASE - 1, x), + x => panic!("number not in the range 0..={}: {}", Self::BASE - 1, x), } } } } } -radix! { Binary, 2, "0b", x @ 0 ... 1 => b'0' + x } -radix! { Octal, 8, "0o", x @ 0 ... 7 => b'0' + x } -radix! { LowerHex, 16, "0x", x @ 0 ... 9 => b'0' + x, - x @ 10 ... 15 => b'a' + (x - 10) } -radix! { UpperHex, 16, "0x", x @ 0 ... 9 => b'0' + x, - x @ 10 ... 15 => b'A' + (x - 10) } +radix! { Binary, 2, "0b", x @ 0 ..= 1 => b'0' + x } +radix! { Octal, 8, "0o", x @ 0 ..= 7 => b'0' + x } +radix! { LowerHex, 16, "0x", x @ 0 ..= 9 => b'0' + x, + x @ 10 ..= 15 => b'a' + (x - 10) } +radix! { UpperHex, 16, "0x", x @ 0 ..= 9 => b'0' + x, + x @ 10 ..= 15 => b'A' + (x - 10) } macro_rules! int_base { ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => { diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 6f4c130d8f3..e74e527927d 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1230,7 +1230,7 @@ impl [T] { /// assert_eq!(s.binary_search(&4), Err(7)); /// assert_eq!(s.binary_search(&100), Err(13)); /// let r = s.binary_search(&1); - /// assert!(match r { Ok(1...4) => true, _ => false, }); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn binary_search(&self, x: &T) -> Result @@ -1268,7 +1268,7 @@ impl [T] { /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13)); /// let seek = 1; /// let r = s.binary_search_by(|probe| probe.cmp(&seek)); - /// assert!(match r { Ok(1...4) => true, _ => false, }); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1325,7 +1325,7 @@ impl [T] { /// assert_eq!(s.binary_search_by_key(&4, |&(a,b)| b), Err(7)); /// assert_eq!(s.binary_search_by_key(&100, |&(a,b)| b), Err(13)); /// let r = s.binary_search_by_key(&1, |&(a,b)| b); - /// assert!(match r { Ok(1...4) => true, _ => false, }); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); /// ``` #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] #[inline] diff --git a/src/libcore/str/lossy.rs b/src/libcore/str/lossy.rs index 30b7267da7c..5cfb36d3b19 100644 --- a/src/libcore/str/lossy.rs +++ b/src/libcore/str/lossy.rs @@ -101,10 +101,10 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> { } 3 => { match (byte, safe_get(self.source, i)) { - (0xE0, 0xA0 ... 0xBF) => (), - (0xE1 ... 0xEC, 0x80 ... 0xBF) => (), - (0xED, 0x80 ... 0x9F) => (), - (0xEE ... 0xEF, 0x80 ... 0xBF) => (), + (0xE0, 0xA0 ..= 0xBF) => (), + (0xE1 ..= 0xEC, 0x80 ..= 0xBF) => (), + (0xED, 0x80 ..= 0x9F) => (), + (0xEE ..= 0xEF, 0x80 ..= 0xBF) => (), _ => { error!(); } @@ -117,9 +117,9 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> { } 4 => { match (byte, safe_get(self.source, i)) { - (0xF0, 0x90 ... 0xBF) => (), - (0xF1 ... 0xF3, 0x80 ... 0xBF) => (), - (0xF4, 0x80 ... 0x8F) => (), + (0xF0, 0x90 ..= 0xBF) => (), + (0xF1 ..= 0xF3, 0x80 ..= 0xBF) => (), + (0xF4, 0x80 ..= 0x8F) => (), _ => { error!(); } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 5e1a9c25a21..42fb1bc238b 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1484,10 +1484,10 @@ fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { }, 3 => { match (first, next!()) { - (0xE0 , 0xA0 ... 0xBF) | - (0xE1 ... 0xEC, 0x80 ... 0xBF) | - (0xED , 0x80 ... 0x9F) | - (0xEE ... 0xEF, 0x80 ... 0xBF) => {} + (0xE0 , 0xA0 ..= 0xBF) | + (0xE1 ..= 0xEC, 0x80 ..= 0xBF) | + (0xED , 0x80 ..= 0x9F) | + (0xEE ..= 0xEF, 0x80 ..= 0xBF) => {} _ => err!(Some(1)) } if next!() & !CONT_MASK != TAG_CONT_U8 { @@ -1496,9 +1496,9 @@ fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { } 4 => { match (first, next!()) { - (0xF0 , 0x90 ... 0xBF) | - (0xF1 ... 0xF3, 0x80 ... 0xBF) | - (0xF4 , 0x80 ... 0x8F) => {} + (0xF0 , 0x90 ..= 0xBF) | + (0xF1 ..= 0xF3, 0x80 ..= 0xBF) | + (0xF4 , 0x80 ..= 0x8F) => {} _ => err!(Some(1)) } if next!() & !CONT_MASK != TAG_CONT_U8 { diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index fcd79222e16..7981567067d 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -60,8 +60,8 @@ fn test_binary_search() { assert_eq!(b.binary_search(&0), Err(0)); assert_eq!(b.binary_search(&1), Ok(0)); assert_eq!(b.binary_search(&2), Err(1)); - assert!(match b.binary_search(&3) { Ok(1...3) => true, _ => false }); - assert!(match b.binary_search(&3) { Ok(1...3) => true, _ => false }); + assert!(match b.binary_search(&3) { Ok(1..=3) => true, _ => false }); + assert!(match b.binary_search(&3) { Ok(1..=3) => true, _ => false }); assert_eq!(b.binary_search(&4), Err(4)); assert_eq!(b.binary_search(&5), Err(4)); assert_eq!(b.binary_search(&6), Err(4)); diff --git a/src/librustc_apfloat/ieee.rs b/src/librustc_apfloat/ieee.rs index 7abd02b6656..b21448df582 100644 --- a/src/librustc_apfloat/ieee.rs +++ b/src/librustc_apfloat/ieee.rs @@ -1753,9 +1753,9 @@ impl IeeeFloat { } else { loss = Some(match hex_value { 0 => Loss::ExactlyZero, - 1...7 => Loss::LessThanHalf, + 1..=7 => Loss::LessThanHalf, 8 => Loss::ExactlyHalf, - 9...15 => Loss::MoreThanHalf, + 9..=15 => Loss::MoreThanHalf, _ => unreachable!(), }); } diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index dcb82e5c424..ac71ecff964 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -424,7 +424,7 @@ pub fn sanitize(result: &mut String, s: &str) -> bool { '-' | ':' => result.push('.'), // These are legal symbols - 'a'...'z' | 'A'...'Z' | '0'...'9' | '_' | '.' | '$' => result.push(c), + 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => result.push(c), _ => { result.push('$'); diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index f195775bf86..c2da1bee395 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -306,9 +306,9 @@ For example: ```compile_fail match 5u32 { // This range is ok, albeit pointless. - 1 ... 1 => {} + 1 ..= 1 => {} // This range is empty, and the compiler can tell. - 1000 ... 5 => {} + 1000 ..= 5 => {} } ``` "##, diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 4ac896d84ff..24301e970f5 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -481,7 +481,7 @@ fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, let joined_patterns = match witnesses.len() { 0 => bug!(), 1 => format!("`{}`", witnesses[0]), - 2...LIMIT => { + 2..=LIMIT => { let (tail, head) = witnesses.split_last().unwrap(); let head: Vec<_> = head.iter().map(|w| w.to_string()).collect(); format!("`{}` and `{}`", head.join("`, `"), tail) diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index fcae9ea22bb..3195823eb09 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -139,11 +139,11 @@ impl Reg { RegKind::Integer => { match self.size.bits() { 1 => dl.i1_align, - 2...8 => dl.i8_align, - 9...16 => dl.i16_align, - 17...32 => dl.i32_align, - 33...64 => dl.i64_align, - 65...128 => dl.i128_align, + 2..=8 => dl.i8_align, + 9..=16 => dl.i16_align, + 17..=32 => dl.i32_align, + 33..=64 => dl.i64_align, + 65..=128 => dl.i128_align, _ => panic!("unsupported integer: {:?}", self) } } diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 7ff04df6233..9003e30357c 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -441,10 +441,10 @@ impl Integer { /// Find the smallest Integer type which can represent the signed value. pub fn fit_signed(x: i128) -> Integer { match x { - -0x0000_0000_0000_0080...0x0000_0000_0000_007f => I8, - -0x0000_0000_0000_8000...0x0000_0000_0000_7fff => I16, - -0x0000_0000_8000_0000...0x0000_0000_7fff_ffff => I32, - -0x8000_0000_0000_0000...0x7fff_ffff_ffff_ffff => I64, + -0x0000_0000_0000_0080..=0x0000_0000_0000_007f => I8, + -0x0000_0000_0000_8000..=0x0000_0000_0000_7fff => I16, + -0x0000_0000_8000_0000..=0x0000_0000_7fff_ffff => I32, + -0x8000_0000_0000_0000..=0x7fff_ffff_ffff_ffff => I64, _ => I128 } } @@ -452,10 +452,10 @@ impl Integer { /// Find the smallest Integer type which can represent the unsigned value. pub fn fit_unsigned(x: u128) -> Integer { match x { - 0...0x0000_0000_0000_00ff => I8, - 0...0x0000_0000_0000_ffff => I16, - 0...0x0000_0000_ffff_ffff => I32, - 0...0xffff_ffff_ffff_ffff => I64, + 0..=0x0000_0000_0000_00ff => I8, + 0..=0x0000_0000_0000_ffff => I16, + 0..=0x0000_0000_ffff_ffff => I32, + 0..=0xffff_ffff_ffff_ffff => I64, _ => I128, } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index b0b72256edc..dd09bf96da5 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -207,7 +207,7 @@ let string = "salutations !"; // The ordering relation for strings can't be evaluated at compile time, // so this doesn't work: match string { - "hello" ... "world" => {} + "hello" ..= "world" => {} _ => {} } @@ -2146,7 +2146,7 @@ fn main() -> i32 { 0 } let x = 1u8; match x { - 0u8...3i8 => (), + 0u8..=3i8 => (), // error: mismatched types in range: expected u8, found i8 _ => () } @@ -2189,7 +2189,7 @@ as the type you're matching on. Example: let x = 1u8; match x { - 0u8...3u8 => (), // ok! + 0u8..=3u8 => (), // ok! _ => () } ``` diff --git a/src/libserialize/hex.rs b/src/libserialize/hex.rs index b5b344e8d5f..4c306d9b2d3 100644 --- a/src/libserialize/hex.rs +++ b/src/libserialize/hex.rs @@ -125,9 +125,9 @@ impl FromHex for str { buf <<= 4; match byte { - b'A'...b'F' => buf |= byte - b'A' + 10, - b'a'...b'f' => buf |= byte - b'a' + 10, - b'0'...b'9' => buf |= byte - b'0', + b'A'..=b'F' => buf |= byte - b'A' + 10, + b'a'..=b'f' => buf |= byte - b'a' + 10, + b'0'..=b'9' => buf |= byte - b'0', b' '|b'\r'|b'\n'|b'\t' => { buf >>= 4; continue diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index efdad7d801a..9959d5ce40d 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -1557,14 +1557,14 @@ impl> Parser { self.bump(); // A leading '0' must be the only digit before the decimal point. - if let '0' ... '9' = self.ch_or_null() { + if let '0' ..= '9' = self.ch_or_null() { return self.error(InvalidNumber) } }, - '1' ... '9' => { + '1' ..= '9' => { while !self.eof() { match self.ch_or_null() { - c @ '0' ... '9' => { + c @ '0' ..= '9' => { accum = accum.wrapping_mul(10); accum = accum.wrapping_add((c as u64) - ('0' as u64)); @@ -1588,14 +1588,14 @@ impl> Parser { // Make sure a digit follows the decimal place. match self.ch_or_null() { - '0' ... '9' => (), + '0' ..= '9' => (), _ => return self.error(InvalidNumber) } let mut dec = 1.0; while !self.eof() { match self.ch_or_null() { - c @ '0' ... '9' => { + c @ '0' ..= '9' => { dec /= 10.0; res += (((c as isize) - ('0' as isize)) as f64) * dec; self.bump(); @@ -1622,12 +1622,12 @@ impl> Parser { // Make sure a digit follows the exponent place. match self.ch_or_null() { - '0' ... '9' => (), + '0' ..= '9' => (), _ => return self.error(InvalidNumber) } while !self.eof() { match self.ch_or_null() { - c @ '0' ... '9' => { + c @ '0' ..= '9' => { exp *= 10; exp += (c as usize) - ('0' as usize); @@ -1653,7 +1653,7 @@ impl> Parser { while i < 4 && !self.eof() { self.bump(); n = match self.ch_or_null() { - c @ '0' ... '9' => n * 16 + ((c as u16) - ('0' as u16)), + c @ '0' ..= '9' => n * 16 + ((c as u16) - ('0' as u16)), 'a' | 'A' => n * 16 + 10, 'b' | 'B' => n * 16 + 11, 'c' | 'C' => n * 16 + 12, @@ -1695,13 +1695,13 @@ impl> Parser { 'r' => res.push('\r'), 't' => res.push('\t'), 'u' => match self.decode_hex_escape()? { - 0xDC00 ... 0xDFFF => { + 0xDC00 ..= 0xDFFF => { return self.error(LoneLeadingSurrogateInHexEscape) } // Non-BMP characters are encoded as a sequence of // two hex escapes, representing UTF-16 surrogates. - n1 @ 0xD800 ... 0xDBFF => { + n1 @ 0xD800 ..= 0xDBFF => { match (self.next_char(), self.next_char()) { (Some('\\'), Some('u')) => (), _ => return self.error(UnexpectedEndOfHexEscape), @@ -1928,7 +1928,7 @@ impl> Parser { 'n' => { self.parse_ident("ull", NullValue) } 't' => { self.parse_ident("rue", BooleanValue(true)) } 'f' => { self.parse_ident("alse", BooleanValue(false)) } - '0' ... '9' | '-' => self.parse_number(), + '0' ..= '9' | '-' => self.parse_number(), '"' => match self.parse_str() { Ok(s) => StringValue(s), Err(e) => Error(e), diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 20109d2d0d5..61d7ed463dd 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -263,7 +263,7 @@ pub fn demangle(writer: &mut Write, mut s: &str, format: PrintFormat) -> io::Res let candidate = &s[i + llvm.len()..]; let all_hex = candidate.chars().all(|c| { match c { - 'A' ... 'F' | '0' ... '9' => true, + 'A' ..= 'F' | '0' ..= '9' => true, _ => false, } }); diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 14a2555adf9..bbb5980bd9d 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -76,7 +76,7 @@ impl CodePoint { #[inline] pub fn from_u32(value: u32) -> Option { match value { - 0 ... 0x10FFFF => Some(CodePoint { value: value }), + 0 ..= 0x10FFFF => Some(CodePoint { value: value }), _ => None } } @@ -101,7 +101,7 @@ impl CodePoint { #[inline] pub fn to_char(&self) -> Option { match self.value { - 0xD800 ... 0xDFFF => None, + 0xD800 ..= 0xDFFF => None, _ => Some(unsafe { char::from_u32_unchecked(self.value) }) } } @@ -305,7 +305,7 @@ impl Wtf8Buf { /// like concatenating ill-formed UTF-16 strings effectively would. #[inline] pub fn push(&mut self, code_point: CodePoint) { - if let trail @ 0xDC00...0xDFFF = code_point.to_u32() { + if let trail @ 0xDC00..=0xDFFF = code_point.to_u32() { if let Some(lead) = (&*self).final_lead_surrogate() { let len_without_lead_surrogate = self.len() - 3; self.bytes.truncate(len_without_lead_surrogate); @@ -525,7 +525,7 @@ impl Wtf8 { #[inline] pub fn ascii_byte_at(&self, position: usize) -> u8 { match self.bytes[position] { - ascii_byte @ 0x00 ... 0x7F => ascii_byte, + ascii_byte @ 0x00 ..= 0x7F => ascii_byte, _ => 0xFF } } @@ -630,7 +630,7 @@ impl Wtf8 { return None } match &self.bytes[(len - 3)..] { - &[0xED, b2 @ 0xA0...0xAF, b3] => Some(decode_surrogate(b2, b3)), + &[0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)), _ => None } } @@ -642,7 +642,7 @@ impl Wtf8 { return None } match &self.bytes[..3] { - &[0xED, b2 @ 0xB0...0xBF, b3] => Some(decode_surrogate(b2, b3)), + &[0xED, b2 @ 0xB0..=0xBF, b3] => Some(decode_surrogate(b2, b3)), _ => None } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a57a9b95e5f..a09055e6c4a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -843,11 +843,11 @@ pub struct Local { /// An arm of a 'match'. /// -/// E.g. `0...10 => { println!("match!") }` as in +/// E.g. `0..=10 => { println!("match!") }` as in /// /// ``` /// match 123 { -/// 0...10 => { println!("match!") }, +/// 0..=10 => { println!("match!") }, /// _ => { println!("no match!") }, /// } /// ``` diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 5353ff9a1e1..c09cfd910d2 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -266,7 +266,7 @@ impl<'a> StringReader<'a> { /// Pushes a character to a message string for error reporting fn push_escaped_char_for_msg(m: &mut String, c: char) { match c { - '\u{20}'...'\u{7e}' => { + '\u{20}'..='\u{7e}' => { // Don't escape \, ' or " for user-facing messages m.push(c); } @@ -779,7 +779,7 @@ impl<'a> StringReader<'a> { base = 16; num_digits = self.scan_digits(16, 16); } - '0'...'9' | '_' | '.' | 'e' | 'E' => { + '0'..='9' | '_' | '.' | 'e' | 'E' => { num_digits = self.scan_digits(10, 10) + 1; } _ => { diff --git a/src/libsyntax_ext/format_foreign.rs b/src/libsyntax_ext/format_foreign.rs index 0dd8f0c55d8..2393af76c34 100644 --- a/src/libsyntax_ext/format_foreign.rs +++ b/src/libsyntax_ext/format_foreign.rs @@ -374,7 +374,7 @@ pub mod printf { if let Start = state { match c { - '1'...'9' => { + '1'..='9' => { let end = at_next_cp_while(next, is_digit); match end.next_cp() { // Yes, this *is* the parameter. @@ -416,7 +416,7 @@ pub mod printf { state = WidthArg; move_to!(next); }, - '1' ... '9' => { + '1' ..= '9' => { let end = at_next_cp_while(next, is_digit); state = Prec; width = Some(Num::from_str(at.slice_between(end).unwrap(), None)); @@ -477,7 +477,7 @@ pub mod printf { } } }, - '0' ... '9' => { + '0' ..= '9' => { let end = at_next_cp_while(next, is_digit); state = Length; precision = Some(Num::from_str(at.slice_between(end).unwrap(), None)); @@ -570,7 +570,7 @@ pub mod printf { fn is_digit(c: char) -> bool { match c { - '0' ... '9' => true, + '0' ..= '9' => true, _ => false } } @@ -799,7 +799,7 @@ pub mod shell { let start = s.find('$')?; match s[start+1..].chars().next()? { '$' => return Some((Substitution::Escape, &s[start+2..])), - c @ '0' ... '9' => { + c @ '0' ..= '9' => { let n = (c as u8) - b'0'; return Some((Substitution::Ordinal(n), &s[start+2..])); }, @@ -836,14 +836,14 @@ pub mod shell { fn is_ident_head(c: char) -> bool { match c { - 'a' ... 'z' | 'A' ... 'Z' | '_' => true, + 'a' ..= 'z' | 'A' ..= 'Z' | '_' => true, _ => false } } fn is_ident_tail(c: char) -> bool { match c { - '0' ... '9' => true, + '0' ..= '9' => true, c => is_ident_head(c) } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index a4fb9571ecb..756e0c059a7 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -818,8 +818,8 @@ impl Encodable for FileMap { }; let bytes_per_diff: u8 = match max_line_length { - 0 ... 0xFF => 1, - 0x100 ... 0xFFFF => 2, + 0 ..= 0xFF => 1, + 0x100 ..= 0xFFFF => 2, _ => 4 }; diff --git a/src/libterm/terminfo/parm.rs b/src/libterm/terminfo/parm.rs index bd5ab92e8b0..b720d55594f 100644 --- a/src/libterm/terminfo/parm.rs +++ b/src/libterm/terminfo/parm.rs @@ -215,7 +215,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result { + ':' | '#' | ' ' | '.' | '0'..='9' => { let mut flags = Flags::new(); let mut fstate = FormatStateFlags; match cur { @@ -223,7 +223,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result flags.alternate = true, ' ' => flags.space = true, '.' => fstate = FormatStatePrecision, - '0'...'9' => { + '0'..='9' => { flags.width = cur as usize - '0' as usize; fstate = FormatStateWidth; } @@ -337,14 +337,14 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result { flags.space = true; } - (FormatStateFlags, '0'...'9') => { + (FormatStateFlags, '0'..='9') => { flags.width = cur as usize - '0' as usize; *fstate = FormatStateWidth; } (FormatStateFlags, '.') => { *fstate = FormatStatePrecision; } - (FormatStateWidth, '0'...'9') => { + (FormatStateWidth, '0'..='9') => { let old = flags.width; flags.width = flags.width * 10 + (cur as usize - '0' as usize); if flags.width < old { @@ -354,7 +354,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result { *fstate = FormatStatePrecision; } - (FormatStatePrecision, '0'...'9') => { + (FormatStatePrecision, '0'..='9') => { let old = flags.precision; flags.precision = flags.precision * 10 + (cur as usize - '0' as usize); if flags.precision < old { diff --git a/src/test/compile-fail/associated-path-shl.rs b/src/test/compile-fail/associated-path-shl.rs index 64afd702f5d..7daf0d3c4e2 100644 --- a/src/test/compile-fail/associated-path-shl.rs +++ b/src/test/compile-fail/associated-path-shl.rs @@ -14,7 +14,7 @@ fn main() { let _: <::B>::C; //~ ERROR cannot find type `A` in this scope let _ = <::B>::C; //~ ERROR cannot find type `A` in this scope let <::B>::C; //~ ERROR cannot find type `A` in this scope - let 0 ... <::B>::C; //~ ERROR cannot find type `A` in this scope + let 0 ..= <::B>::C; //~ ERROR cannot find type `A` in this scope //~^ ERROR only char and numeric types are allowed in range patterns <::B>::C; //~ ERROR cannot find type `A` in this scope } diff --git a/src/test/compile-fail/issue-27895.rs b/src/test/compile-fail/issue-27895.rs index be76796c5c4..6063755c04f 100644 --- a/src/test/compile-fail/issue-27895.rs +++ b/src/test/compile-fail/issue-27895.rs @@ -13,7 +13,7 @@ fn main() { let index = 6; match i { - 0...index => println!("winner"), + 0..=index => println!("winner"), //~^ ERROR runtime values cannot be referenced in patterns _ => println!("hello"), } diff --git a/src/test/compile-fail/issue-41255.rs b/src/test/compile-fail/issue-41255.rs index bdd502d4420..29912de37eb 100644 --- a/src/test/compile-fail/issue-41255.rs +++ b/src/test/compile-fail/issue-41255.rs @@ -27,7 +27,7 @@ fn main() { //~| WARNING hard error //~| ERROR floating-point types cannot be used in patterns //~| WARNING hard error - 39.0 ... 70.0 => {}, //~ ERROR floating-point types cannot be used in patterns + 39.0 ..= 70.0 => {}, //~ ERROR floating-point types cannot be used in patterns //~| WARNING hard error //~| ERROR floating-point types cannot be used in patterns //~| WARNING hard error diff --git a/src/test/compile-fail/match-range-fail-2.rs b/src/test/compile-fail/match-range-fail-2.rs index 91ad2b3507a..b42e2ff919a 100644 --- a/src/test/compile-fail/match-range-fail-2.rs +++ b/src/test/compile-fail/match-range-fail-2.rs @@ -12,7 +12,7 @@ fn main() { match 5 { - 6 ... 1 => { } + 6 ..= 1 => { } _ => { } }; //~^^^ ERROR lower range bound must be less than or equal to upper @@ -24,7 +24,7 @@ fn main() { //~^^^ ERROR lower range bound must be less than upper match 5u64 { - 0xFFFF_FFFF_FFFF_FFFF ... 1 => { } + 0xFFFF_FFFF_FFFF_FFFF ..= 1 => { } _ => { } }; //~^^^ ERROR lower range bound must be less than or equal to upper diff --git a/src/test/compile-fail/match-range-fail.rs b/src/test/compile-fail/match-range-fail.rs index f89b3e39390..ca99b0c7b89 100644 --- a/src/test/compile-fail/match-range-fail.rs +++ b/src/test/compile-fail/match-range-fail.rs @@ -10,21 +10,21 @@ fn main() { match "wow" { - "bar" ... "foo" => { } + "bar" ..= "foo" => { } }; //~^^ ERROR only char and numeric types are allowed in range //~| start type: &'static str //~| end type: &'static str match "wow" { - 10 ... "what" => () + 10 ..= "what" => () }; //~^^ ERROR only char and numeric types are allowed in range //~| start type: {integer} //~| end type: &'static str match 5 { - 'c' ... 100 => { } + 'c' ..= 100 => { } _ => { } }; //~^^^ ERROR mismatched types diff --git a/src/test/compile-fail/non-constant-in-const-path.rs b/src/test/compile-fail/non-constant-in-const-path.rs index fe88ab4e117..1aae25105a8 100644 --- a/src/test/compile-fail/non-constant-in-const-path.rs +++ b/src/test/compile-fail/non-constant-in-const-path.rs @@ -11,7 +11,7 @@ fn main() { let x = 0; match 1 { - 0 ... x => {} + 0 ..= x => {} //~^ ERROR runtime values cannot be referenced in patterns }; } diff --git a/src/test/compile-fail/patkind-litrange-no-expr.rs b/src/test/compile-fail/patkind-litrange-no-expr.rs index d57a23f26c4..8fef98f815f 100644 --- a/src/test/compile-fail/patkind-litrange-no-expr.rs +++ b/src/test/compile-fail/patkind-litrange-no-expr.rs @@ -17,7 +17,7 @@ macro_rules! enum_number { fn foo(value: i32) -> Option<$name> { match value { $( $value => Some($name::$variant), )* // PatKind::Lit - $( $value ... 42 => Some($name::$variant), )* // PatKind::Range + $( $value ..= 42 => Some($name::$variant), )* // PatKind::Range _ => None } } @@ -32,4 +32,3 @@ enum_number!(Change { }); fn main() {} - diff --git a/src/test/compile-fail/qualified-path-params.rs b/src/test/compile-fail/qualified-path-params.rs index a7bc27e1749..018a3b2ae32 100644 --- a/src/test/compile-fail/qualified-path-params.rs +++ b/src/test/compile-fail/qualified-path-params.rs @@ -29,6 +29,6 @@ fn main() { match 10 { ::A::f:: => {} //~^ ERROR expected unit struct/variant or constant, found method `<::A>::f` - 0 ... ::A::f:: => {} //~ ERROR only char and numeric types are allowed in range + 0 ..= ::A::f:: => {} //~ ERROR only char and numeric types are allowed in range } } diff --git a/src/test/compile-fail/refutable-pattern-errors.rs b/src/test/compile-fail/refutable-pattern-errors.rs index ce93e1875ae..7b4009481ab 100644 --- a/src/test/compile-fail/refutable-pattern-errors.rs +++ b/src/test/compile-fail/refutable-pattern-errors.rs @@ -9,10 +9,10 @@ // except according to those terms. -fn func((1, (Some(1), 2...3)): (isize, (Option, isize))) { } +fn func((1, (Some(1), 2..=3)): (isize, (Option, isize))) { } //~^ ERROR refutable pattern in function argument: `(_, _)` not covered fn main() { - let (1, (Some(1), 2...3)) = (1, (None, 2)); + let (1, (Some(1), 2..=3)) = (1, (None, 2)); //~^ ERROR refutable pattern in local binding: `(_, _)` not covered } diff --git a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs index 62cb870c7bb..f9d1ce34535 100644 --- a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs +++ b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs @@ -286,16 +286,16 @@ fn run() { // would require parens in patterns to allow disambiguation... reject_expr_parse("match 0 { - 0...#[attr] 10 => () + 0..=#[attr] 10 => () }"); reject_expr_parse("match 0 { - 0...#[attr] -10 => () + 0..=#[attr] -10 => () }"); reject_expr_parse("match 0 { - 0...-#[attr] 10 => () + 0..=-#[attr] 10 => () }"); reject_expr_parse("match 0 { - 0...#[attr] FOO => () + 0..=#[attr] FOO => () }"); // make sure we don't catch this bug again... diff --git a/src/test/run-pass/byte-literals.rs b/src/test/run-pass/byte-literals.rs index ad779d26f9e..f5acb72429a 100644 --- a/src/test/run-pass/byte-literals.rs +++ b/src/test/run-pass/byte-literals.rs @@ -36,7 +36,7 @@ pub fn main() { } match 100 { - b'a' ... b'z' => {}, + b'a' ..= b'z' => {}, _ => panic!() } diff --git a/src/test/run-pass/inferred-suffix-in-pattern-range.rs b/src/test/run-pass/inferred-suffix-in-pattern-range.rs index 22369c77ed3..89d26aade2e 100644 --- a/src/test/run-pass/inferred-suffix-in-pattern-range.rs +++ b/src/test/run-pass/inferred-suffix-in-pattern-range.rs @@ -12,21 +12,21 @@ pub fn main() { let x = 2; let x_message = match x { - 0 ... 1 => { "not many".to_string() } + 0 ..= 1 => { "not many".to_string() } _ => { "lots".to_string() } }; assert_eq!(x_message, "lots".to_string()); let y = 2; let y_message = match y { - 0 ... 1 => { "not many".to_string() } + 0 ..= 1 => { "not many".to_string() } _ => { "lots".to_string() } }; assert_eq!(y_message, "lots".to_string()); let z = 1u64; let z_message = match z { - 0 ... 1 => { "not many".to_string() } + 0 ..= 1 => { "not many".to_string() } _ => { "lots".to_string() } }; assert_eq!(z_message, "not many".to_string()); diff --git a/src/test/run-pass/issue-12582.rs b/src/test/run-pass/issue-12582.rs index 7bab2ddfed0..b89964d968e 100644 --- a/src/test/run-pass/issue-12582.rs +++ b/src/test/run-pass/issue-12582.rs @@ -16,7 +16,7 @@ pub fn main() { assert_eq!(3, match (x, y) { (1, 1) => 1, (2, 2) => 2, - (1...2, 2) => 3, + (1..=2, 2) => 3, _ => 4, }); @@ -24,7 +24,7 @@ pub fn main() { assert_eq!(3, match ((x, y),) { ((1, 1),) => 1, ((2, 2),) => 2, - ((1...2, 2),) => 3, + ((1..=2, 2),) => 3, _ => 4, }); } diff --git a/src/test/run-pass/issue-13027.rs b/src/test/run-pass/issue-13027.rs index d28ea94ec1a..2c460900ef6 100644 --- a/src/test/run-pass/issue-13027.rs +++ b/src/test/run-pass/issue-13027.rs @@ -30,7 +30,7 @@ pub fn main() { fn lit_shadow_range() { assert_eq!(2, match 1 { 1 if false => 1, - 1...2 => 2, + 1..=2 => 2, _ => 3 }); @@ -38,34 +38,34 @@ fn lit_shadow_range() { assert_eq!(2, match x+1 { 0 => 0, 1 if false => 1, - 1...2 => 2, + 1..=2 => 2, _ => 3 }); assert_eq!(2, match val() { 1 if false => 1, - 1...2 => 2, + 1..=2 => 2, _ => 3 }); assert_eq!(2, match CONST { 0 => 0, 1 if false => 1, - 1...2 => 2, + 1..=2 => 2, _ => 3 }); // value is out of the range of second arm, should match wildcard pattern assert_eq!(3, match 3 { 1 if false => 1, - 1...2 => 2, + 1..=2 => 2, _ => 3 }); } fn range_shadow_lit() { assert_eq!(2, match 1 { - 1...2 if false => 1, + 1..=2 if false => 1, 1 => 2, _ => 3 }); @@ -73,27 +73,27 @@ fn range_shadow_lit() { let x = 0; assert_eq!(2, match x+1 { 0 => 0, - 1...2 if false => 1, + 1..=2 if false => 1, 1 => 2, _ => 3 }); assert_eq!(2, match val() { - 1...2 if false => 1, + 1..=2 if false => 1, 1 => 2, _ => 3 }); assert_eq!(2, match CONST { 0 => 0, - 1...2 if false => 1, + 1..=2 if false => 1, 1 => 2, _ => 3 }); // ditto assert_eq!(3, match 3 { - 1...2 if false => 1, + 1..=2 if false => 1, 1 => 2, _ => 3 }); @@ -101,36 +101,36 @@ fn range_shadow_lit() { fn range_shadow_range() { assert_eq!(2, match 1 { - 0...2 if false => 1, - 1...3 => 2, + 0..=2 if false => 1, + 1..=3 => 2, _ => 3, }); let x = 0; assert_eq!(2, match x+1 { 100 => 0, - 0...2 if false => 1, - 1...3 => 2, + 0..=2 if false => 1, + 1..=3 => 2, _ => 3, }); assert_eq!(2, match val() { - 0...2 if false => 1, - 1...3 => 2, + 0..=2 if false => 1, + 1..=3 => 2, _ => 3, }); assert_eq!(2, match CONST { 100 => 0, - 0...2 if false => 1, - 1...3 => 2, + 0..=2 if false => 1, + 1..=3 => 2, _ => 3, }); // ditto assert_eq!(3, match 5 { - 0...2 if false => 1, - 1...3 => 2, + 0..=2 if false => 1, + 1..=3 => 2, _ => 3, }); } @@ -138,7 +138,7 @@ fn range_shadow_range() { fn multi_pats_shadow_lit() { assert_eq!(2, match 1 { 100 => 0, - 0 | 1...10 if false => 1, + 0 | 1..=10 if false => 1, 1 => 2, _ => 3, }); @@ -147,8 +147,8 @@ fn multi_pats_shadow_lit() { fn multi_pats_shadow_range() { assert_eq!(2, match 1 { 100 => 0, - 0 | 1...10 if false => 1, - 1...3 => 2, + 0 | 1..=10 if false => 1, + 1..=3 => 2, _ => 3, }); } @@ -157,7 +157,7 @@ fn lit_shadow_multi_pats() { assert_eq!(2, match 1 { 100 => 0, 1 if false => 1, - 0 | 1...10 => 2, + 0 | 1..=10 => 2, _ => 3, }); } @@ -165,8 +165,8 @@ fn lit_shadow_multi_pats() { fn range_shadow_multi_pats() { assert_eq!(2, match 1 { 100 => 0, - 1...3 if false => 1, - 0 | 1...10 => 2, + 1..=3 if false => 1, + 0 | 1..=10 => 2, _ => 3, }); } diff --git a/src/test/run-pass/issue-13867.rs b/src/test/run-pass/issue-13867.rs index e21070e2eaf..bc28dc54de6 100644 --- a/src/test/run-pass/issue-13867.rs +++ b/src/test/run-pass/issue-13867.rs @@ -19,14 +19,14 @@ enum Foo { fn main() { let r = match (Foo::FooNullary, 'a') { - (Foo::FooUint(..), 'a'...'z') => 1, + (Foo::FooUint(..), 'a'..='z') => 1, (Foo::FooNullary, 'x') => 2, _ => 0 }; assert_eq!(r, 0); let r = match (Foo::FooUint(0), 'a') { - (Foo::FooUint(1), 'a'...'z') => 1, + (Foo::FooUint(1), 'a'..='z') => 1, (Foo::FooUint(..), 'x') => 2, (Foo::FooNullary, 'a') => 3, _ => 0 @@ -34,7 +34,7 @@ fn main() { assert_eq!(r, 0); let r = match ('a', Foo::FooUint(0)) { - ('a'...'z', Foo::FooUint(1)) => 1, + ('a'..='z', Foo::FooUint(1)) => 1, ('x', Foo::FooUint(..)) => 2, ('a', Foo::FooNullary) => 3, _ => 0 @@ -42,15 +42,15 @@ fn main() { assert_eq!(r, 0); let r = match ('a', 'a') { - ('a'...'z', 'b') => 1, - ('x', 'a'...'z') => 2, + ('a'..='z', 'b') => 1, + ('x', 'a'..='z') => 2, _ => 0 }; assert_eq!(r, 0); let r = match ('a', 'a') { - ('a'...'z', 'b') => 1, - ('x', 'a'...'z') => 2, + ('a'..='z', 'b') => 1, + ('x', 'a'..='z') => 2, ('a', 'a') => 3, _ => 0 }; diff --git a/src/test/run-pass/issue-18060.rs b/src/test/run-pass/issue-18060.rs index d6c9a92ca02..322a3d8c9bb 100644 --- a/src/test/run-pass/issue-18060.rs +++ b/src/test/run-pass/issue-18060.rs @@ -11,7 +11,7 @@ // Regression test for #18060: match arms were matching in the wrong order. fn main() { - assert_eq!(2, match (1, 3) { (0, 2...5) => 1, (1, 3) => 2, (_, 2...5) => 3, (_, _) => 4 }); - assert_eq!(2, match (1, 3) { (1, 3) => 2, (_, 2...5) => 3, (_, _) => 4 }); - assert_eq!(2, match (1, 7) { (0, 2...5) => 1, (1, 7) => 2, (_, 2...5) => 3, (_, _) => 4 }); + assert_eq!(2, match (1, 3) { (0, 2..=5) => 1, (1, 3) => 2, (_, 2..=5) => 3, (_, _) => 4 }); + assert_eq!(2, match (1, 3) { (1, 3) => 2, (_, 2..=5) => 3, (_, _) => 4 }); + assert_eq!(2, match (1, 7) { (0, 2..=5) => 1, (1, 7) => 2, (_, 2..=5) => 3, (_, _) => 4 }); } diff --git a/src/test/run-pass/issue-18464.rs b/src/test/run-pass/issue-18464.rs index dff86bc1b45..f4faab5e468 100644 --- a/src/test/run-pass/issue-18464.rs +++ b/src/test/run-pass/issue-18464.rs @@ -15,7 +15,7 @@ const HIGH_RANGE: char = '9'; fn main() { match '5' { - LOW_RANGE...HIGH_RANGE => (), + LOW_RANGE..=HIGH_RANGE => (), _ => () }; } diff --git a/src/test/run-pass/issue-21475.rs b/src/test/run-pass/issue-21475.rs index 0666a1f133f..99839b56506 100644 --- a/src/test/run-pass/issue-21475.rs +++ b/src/test/run-pass/issue-21475.rs @@ -14,9 +14,9 @@ use m::{START, END}; fn main() { match 42 { - m::START...m::END => {}, - 0...m::END => {}, - m::START...59 => {}, + m::START..=m::END => {}, + 0..=m::END => {}, + m::START..=59 => {}, _ => {}, } } diff --git a/src/test/run-pass/issue-26251.rs b/src/test/run-pass/issue-26251.rs index 1e77d54fbf9..3735d36147d 100644 --- a/src/test/run-pass/issue-26251.rs +++ b/src/test/run-pass/issue-26251.rs @@ -12,9 +12,9 @@ fn main() { let x = 'a'; let y = match x { - 'a'...'b' if false => "one", + 'a'..='b' if false => "one", 'a' => "two", - 'a'...'b' => "three", + 'a'..='b' => "three", _ => panic!("what?"), }; diff --git a/src/test/run-pass/issue-35423.rs b/src/test/run-pass/issue-35423.rs index 35d0c305ed8..34cb2930db0 100644 --- a/src/test/run-pass/issue-35423.rs +++ b/src/test/run-pass/issue-35423.rs @@ -12,7 +12,7 @@ fn main () { let x = 4; match x { ref r if *r < 0 => println!("got negative num {} < 0", r), - e @ 1 ... 100 => println!("got number within range [1,100] {}", e), + e @ 1 ..= 100 => println!("got number within range [1,100] {}", e), _ => println!("no"), } } diff --git a/src/test/run-pass/issue-7222.rs b/src/test/run-pass/issue-7222.rs index 1bf343e23f0..3eb39ad6aad 100644 --- a/src/test/run-pass/issue-7222.rs +++ b/src/test/run-pass/issue-7222.rs @@ -14,7 +14,7 @@ pub fn main() { const FOO: f64 = 10.0; match 0.0 { - 0.0 ... FOO => (), + 0.0 ..= FOO => (), _ => () } } diff --git a/src/test/run-pass/macro-literal.rs b/src/test/run-pass/macro-literal.rs index 0bcda7bc144..6d5e8bc97c0 100644 --- a/src/test/run-pass/macro-literal.rs +++ b/src/test/run-pass/macro-literal.rs @@ -41,18 +41,18 @@ macro_rules! mtester_dbg { } macro_rules! catch_range { - ($s:literal ... $e:literal) => { - &format!("macro caught literal: {} ... {}", $s, $e) + ($s:literal ..= $e:literal) => { + &format!("macro caught literal: {} ..= {}", $s, $e) }; - (($s:expr) ... ($e:expr)) => { // Must use ')' before '...' - &format!("macro caught expr: {} ... {}", $s, $e) + (($s:expr) ..= ($e:expr)) => { // Must use ')' before '..=' + &format!("macro caught expr: {} ..= {}", $s, $e) }; } macro_rules! pat_match { - ($s:literal ... $e:literal) => { + ($s:literal ..= $e:literal) => { match 3 { - $s ... $e => "literal, in range", + $s ..= $e => "literal, in range", _ => "literal, other", } }; @@ -115,22 +115,22 @@ pub fn main() { assert_eq!(mtester!('c'), "macro caught literal: c"); assert_eq!(mtester!(-1.2), "macro caught literal: -1.2"); assert_eq!(two_negative_literals!(-2 -3), "macro caught literals: -2, -3"); - assert_eq!(catch_range!(2 ... 3), "macro caught literal: 2 ... 3"); + assert_eq!(catch_range!(2 ..= 3), "macro caught literal: 2 ..= 3"); assert_eq!(match_attr!(#[attr] 1), "attr matched literal"); assert_eq!(test_user!(10, 20), "literal"); assert_eq!(mtester!(false), "macro caught literal: false"); assert_eq!(mtester!(true), "macro caught literal: true"); match_produced_attr!("a"); let _a = LiteralProduced; - assert_eq!(pat_match!(1 ... 3), "literal, in range"); - assert_eq!(pat_match!(4 ... 6), "literal, other"); + assert_eq!(pat_match!(1 ..= 3), "literal, in range"); + assert_eq!(pat_match!(4 ..= 6), "literal, other"); // Cases where 'expr' catches assert_eq!(mtester!((-1.2)), "macro caught expr: -1.2"); assert_eq!(only_expr!(-1.2), "macro caught expr: -1.2"); assert_eq!(mtester!((1 + 3)), "macro caught expr: 4"); assert_eq!(mtester_dbg!(()), "macro caught expr: ()"); - assert_eq!(catch_range!((1 + 1) ... (2 + 2)), "macro caught expr: 2 ... 4"); + assert_eq!(catch_range!((1 + 1) ..= (2 + 2)), "macro caught expr: 2 ..= 4"); assert_eq!(match_attr!(#[attr] (1 + 2)), "attr matched expr"); assert_eq!(test_user!(10, (20 + 2)), "expr"); diff --git a/src/test/run-pass/match-range-infer.rs b/src/test/run-pass/match-range-infer.rs index 74f513ef081..cf07345d343 100644 --- a/src/test/run-pass/match-range-infer.rs +++ b/src/test/run-pass/match-range-infer.rs @@ -12,15 +12,15 @@ pub fn main() { match 1 { - 1 ... 3 => {} + 1 ..= 3 => {} _ => panic!("should match range") } match 1 { - 1 ... 3u16 => {} + 1 ..= 3u16 => {} _ => panic!("should match range with inferred start type") } match 1 { - 1u16 ... 3 => {} + 1u16 ..= 3 => {} _ => panic!("should match range with inferred end type") } } diff --git a/src/test/run-pass/match-range-static.rs b/src/test/run-pass/match-range-static.rs index 9aafcda1b02..b63ca7defd6 100644 --- a/src/test/run-pass/match-range-static.rs +++ b/src/test/run-pass/match-range-static.rs @@ -15,7 +15,7 @@ const e: isize = 42; pub fn main() { match 7 { - s...e => (), + s..=e => (), _ => (), } } diff --git a/src/test/run-pass/match-range.rs b/src/test/run-pass/match-range.rs index cf695a77ce1..859edb80a07 100644 --- a/src/test/run-pass/match-range.rs +++ b/src/test/run-pass/match-range.rs @@ -12,7 +12,7 @@ pub fn main() { match 5_usize { - 1_usize...5_usize => {} + 1_usize..=5_usize => {} _ => panic!("should match range"), } match 1_usize { @@ -20,7 +20,7 @@ pub fn main() { _ => panic!("should match range start"), } match 5_usize { - 6_usize...7_usize => panic!("shouldn't match range"), + 6_usize..=7_usize => panic!("shouldn't match range"), _ => {} } match 7_usize { @@ -29,23 +29,23 @@ pub fn main() { } match 5_usize { 1_usize => panic!("should match non-first range"), - 2_usize...6_usize => {} + 2_usize..=6_usize => {} _ => panic!("math is broken") } match 'c' { - 'a'...'z' => {} + 'a'..='z' => {} _ => panic!("should suppport char ranges") } match -3 { - -7...5 => {} + -7..=5 => {} _ => panic!("should match signed range") } match 3.0f64 { - 1.0...5.0 => {} + 1.0..=5.0 => {} _ => panic!("should match float range") } match -1.5f64 { - -3.6...3.6 => {} + -3.6..=3.6 => {} _ => panic!("should match negative float range") } match 3.5 { diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/range.rs b/src/test/run-pass/rfc-2005-default-binding-mode/range.rs index 2292d97eaf4..f38bd2de869 100644 --- a/src/test/run-pass/rfc-2005-default-binding-mode/range.rs +++ b/src/test/run-pass/rfc-2005-default-binding-mode/range.rs @@ -11,8 +11,8 @@ pub fn main() { let i = 5; match &&&&i { - 1 ... 3 => panic!(), - 3 ... 8 => {}, + 1 ..= 3 => panic!(), + 3 ..= 8 => {}, _ => panic!(), } } diff --git a/src/test/ui/check_match/issue-43253.rs b/src/test/ui/check_match/issue-43253.rs index a01ebb768b4..aace8c0c02b 100644 --- a/src/test/ui/check_match/issue-43253.rs +++ b/src/test/ui/check_match/issue-43253.rs @@ -23,13 +23,13 @@ fn main() { match 10 { 1..10 => {}, - 9...10 => {}, + 9..=10 => {}, _ => {}, } match 10 { 1..10 => {}, - 10...10 => {}, + 10..=10 => {}, _ => {}, } @@ -42,13 +42,13 @@ fn main() { match 10 { 1..10 => {}, - 8...9 => {}, + 8..=9 => {}, _ => {}, } match 10 { 1..10 => {}, - 9...9 => {}, + 9..=9 => {}, _ => {}, } } diff --git a/src/test/ui/check_match/issue-43253.stderr b/src/test/ui/check_match/issue-43253.stderr index 111f4e44ee9..2af6a2a6368 100644 --- a/src/test/ui/check_match/issue-43253.stderr +++ b/src/test/ui/check_match/issue-43253.stderr @@ -13,12 +13,12 @@ LL | #![warn(unreachable_patterns)] warning: unreachable pattern --> $DIR/issue-43253.rs:45:9 | -LL | 8...9 => {}, +LL | 8..=9 => {}, | ^^^^^ warning: unreachable pattern --> $DIR/issue-43253.rs:51:9 | -LL | 9...9 => {}, +LL | 9..=9 => {}, | ^^^^^ diff --git a/src/test/ui/const-eval/const_signed_pat.rs b/src/test/ui/const-eval/const_signed_pat.rs index f53d6f3fa0a..008ebf13c63 100644 --- a/src/test/ui/const-eval/const_signed_pat.rs +++ b/src/test/ui/const-eval/const_signed_pat.rs @@ -13,7 +13,7 @@ fn main() { const MIN: i8 = -5; match 5i8 { - MIN...-1 => {}, + MIN..=-1 => {}, _ => {}, } } diff --git a/src/test/ui/const-eval/ref_to_int_match.rs b/src/test/ui/const-eval/ref_to_int_match.rs index 4c5fc6c3797..8ad7f11f0ce 100644 --- a/src/test/ui/const-eval/ref_to_int_match.rs +++ b/src/test/ui/const-eval/ref_to_int_match.rs @@ -11,8 +11,8 @@ fn main() { let n: Int = 40; match n { - 0...10 => {}, - 10...BAR => {}, //~ ERROR lower range bound must be less than or equal to upper + 0..=10 => {}, + 10..=BAR => {}, //~ ERROR lower range bound must be less than or equal to upper _ => {}, } } diff --git a/src/test/ui/const-eval/ref_to_int_match.stderr b/src/test/ui/const-eval/ref_to_int_match.stderr index eef7b6df252..64ea57702d7 100644 --- a/src/test/ui/const-eval/ref_to_int_match.stderr +++ b/src/test/ui/const-eval/ref_to_int_match.stderr @@ -1,7 +1,7 @@ error[E0030]: lower range bound must be less than or equal to upper --> $DIR/ref_to_int_match.rs:15:9 | -LL | 10...BAR => {}, //~ ERROR lower range bound must be less than or equal to upper +LL | 10..=BAR => {}, //~ ERROR lower range bound must be less than or equal to upper | ^^ lower bound larger than upper bound error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0029-teach.rs b/src/test/ui/error-codes/E0029-teach.rs index 1bc2c2d58b1..328c46311af 100644 --- a/src/test/ui/error-codes/E0029-teach.rs +++ b/src/test/ui/error-codes/E0029-teach.rs @@ -14,7 +14,7 @@ fn main() { let s = "hoho"; match s { - "hello" ... "world" => {} + "hello" ..= "world" => {} //~^ ERROR only char and numeric types are allowed in range patterns _ => {} } diff --git a/src/test/ui/error-codes/E0029-teach.stderr b/src/test/ui/error-codes/E0029-teach.stderr index 4bb71f68a98..bb4fac9a4cb 100644 --- a/src/test/ui/error-codes/E0029-teach.stderr +++ b/src/test/ui/error-codes/E0029-teach.stderr @@ -1,7 +1,7 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/E0029-teach.rs:17:9 | -LL | "hello" ... "world" => {} +LL | "hello" ..= "world" => {} | ^^^^^^^^^^^^^^^^^^^ ranges require char or numeric types | = note: start type: &'static str diff --git a/src/test/ui/error-codes/E0029.rs b/src/test/ui/error-codes/E0029.rs index 29b6fe44113..c89b4f5b377 100644 --- a/src/test/ui/error-codes/E0029.rs +++ b/src/test/ui/error-codes/E0029.rs @@ -12,7 +12,7 @@ fn main() { let s = "hoho"; match s { - "hello" ... "world" => {} + "hello" ..= "world" => {} //~^ ERROR only char and numeric types are allowed in range patterns _ => {} } diff --git a/src/test/ui/error-codes/E0029.stderr b/src/test/ui/error-codes/E0029.stderr index bcdfa387111..d25666f9cf8 100644 --- a/src/test/ui/error-codes/E0029.stderr +++ b/src/test/ui/error-codes/E0029.stderr @@ -1,7 +1,7 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/E0029.rs:15:9 | -LL | "hello" ... "world" => {} +LL | "hello" ..= "world" => {} | ^^^^^^^^^^^^^^^^^^^ ranges require char or numeric types | = note: start type: &'static str diff --git a/src/test/ui/error-codes/E0030-teach.rs b/src/test/ui/error-codes/E0030-teach.rs index 2af32eda62b..cf860cea24c 100644 --- a/src/test/ui/error-codes/E0030-teach.rs +++ b/src/test/ui/error-codes/E0030-teach.rs @@ -12,7 +12,7 @@ fn main() { match 5u32 { - 1000 ... 5 => {} + 1000 ..= 5 => {} //~^ ERROR lower range bound must be less than or equal to upper } } diff --git a/src/test/ui/error-codes/E0030-teach.stderr b/src/test/ui/error-codes/E0030-teach.stderr index 8b262d5b296..2a7243a9569 100644 --- a/src/test/ui/error-codes/E0030-teach.stderr +++ b/src/test/ui/error-codes/E0030-teach.stderr @@ -1,7 +1,7 @@ error[E0030]: lower range bound must be less than or equal to upper --> $DIR/E0030-teach.rs:15:9 | -LL | 1000 ... 5 => {} +LL | 1000 ..= 5 => {} | ^^^^ lower bound larger than upper bound | = note: When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range. diff --git a/src/test/ui/error-codes/E0030.rs b/src/test/ui/error-codes/E0030.rs index ef3bded4bef..e147dd932b0 100644 --- a/src/test/ui/error-codes/E0030.rs +++ b/src/test/ui/error-codes/E0030.rs @@ -11,7 +11,7 @@ fn main() { match 5u32 { - 1000 ... 5 => {} + 1000 ..= 5 => {} //~^ ERROR lower range bound must be less than or equal to upper } } diff --git a/src/test/ui/error-codes/E0030.stderr b/src/test/ui/error-codes/E0030.stderr index 0949cfb50b6..020655ee45b 100644 --- a/src/test/ui/error-codes/E0030.stderr +++ b/src/test/ui/error-codes/E0030.stderr @@ -1,7 +1,7 @@ error[E0030]: lower range bound must be less than or equal to upper --> $DIR/E0030.rs:14:9 | -LL | 1000 ... 5 => {} +LL | 1000 ..= 5 => {} | ^^^^ lower bound larger than upper bound error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0308-4.rs b/src/test/ui/error-codes/E0308-4.rs index bb4cd143416..106c55817c1 100644 --- a/src/test/ui/error-codes/E0308-4.rs +++ b/src/test/ui/error-codes/E0308-4.rs @@ -11,7 +11,7 @@ fn main() { let x = 1u8; match x { - 0u8...3i8 => (), //~ ERROR E0308 + 0u8..=3i8 => (), //~ ERROR E0308 _ => () } } diff --git a/src/test/ui/error-codes/E0308-4.stderr b/src/test/ui/error-codes/E0308-4.stderr index 31875349bac..8943c7332e9 100644 --- a/src/test/ui/error-codes/E0308-4.stderr +++ b/src/test/ui/error-codes/E0308-4.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/E0308-4.rs:14:9 | -LL | 0u8...3i8 => (), //~ ERROR E0308 +LL | 0u8..=3i8 => (), //~ ERROR E0308 | ^^^^^^^^^ expected u8, found i8 error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 433e6b31a75eea5ce45493acc63eae462d740338 Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Tue, 26 Jun 2018 17:06:20 +0200 Subject: Add `LocalTaskObj` --- src/liballoc/boxed.rs | 18 +++++++++-- src/libcore/task/mod.rs | 4 +-- src/libcore/task/spawn_error.rs | 33 ++++++++++++++++++- src/libcore/task/task.rs | 71 +++++++++++++++++++++++++++++++++++++++-- 4 files changed, 118 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index ea60c7775af..6a05ef68088 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -66,7 +66,7 @@ use core::marker::{Unpin, Unsize}; use core::mem::{self, PinMut}; use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; use core::ptr::{self, NonNull, Unique}; -use core::task::{Context, Poll, UnsafeTask, TaskObj}; +use core::task::{Context, Poll, UnsafeTask, TaskObj, LocalTaskObj}; use core::convert::From; use raw_vec::RawVec; @@ -933,7 +933,7 @@ impl<'a, F: ?Sized + Future> Future for PinBox { } #[unstable(feature = "futures_api", issue = "50547")] -unsafe impl + Send + 'static> UnsafeTask for PinBox { +unsafe impl + 'static> UnsafeTask for PinBox { fn into_raw(self) -> *mut () { PinBox::into_raw(self) as *mut () } @@ -962,3 +962,17 @@ impl + Send + 'static> From> for TaskObj { TaskObj::new(PinBox::from(boxed)) } } + +#[unstable(feature = "futures_api", issue = "50547")] +impl + 'static> From> for LocalTaskObj { + fn from(boxed: PinBox) -> Self { + LocalTaskObj::new(boxed) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +impl + 'static> From> for LocalTaskObj { + fn from(boxed: Box) -> Self { + LocalTaskObj::new(PinBox::from(boxed)) + } +} diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index 66ab21d177d..36370b6b37c 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -24,10 +24,10 @@ mod poll; pub use self::poll::Poll; mod spawn_error; -pub use self::spawn_error::{SpawnErrorKind, SpawnObjError}; +pub use self::spawn_error::{SpawnErrorKind, SpawnObjError, SpawnLocalObjError}; mod task; -pub use self::task::{TaskObj, UnsafeTask}; +pub use self::task::{TaskObj, LocalTaskObj, UnsafeTask}; mod wake; pub use self::wake::{Waker, LocalWaker, UnsafeWake}; diff --git a/src/libcore/task/spawn_error.rs b/src/libcore/task/spawn_error.rs index 5dd9c5be689..57bb9ebeb30 100644 --- a/src/libcore/task/spawn_error.rs +++ b/src/libcore/task/spawn_error.rs @@ -13,7 +13,8 @@ issue = "50547")] use fmt; -use super::TaskObj; +use mem; +use super::{TaskObj, LocalTaskObj}; /// Provides the reason that an executor was unable to spawn. pub struct SpawnErrorKind { @@ -49,3 +50,33 @@ pub struct SpawnObjError { /// The task for which spawning was attempted pub task: TaskObj, } + +/// The result of a failed spawn +#[derive(Debug)] +pub struct SpawnLocalObjError { + /// The kind of error + pub kind: SpawnErrorKind, + + /// The task for which spawning was attempted + pub task: LocalTaskObj, +} + +impl SpawnLocalObjError { + /// Converts the `SpawnLocalObjError` into a `SpawnObjError` + /// To make this operation safe one has to ensure that the `UnsafeTask` + /// instance from which the `LocalTaskObj` stored inside was created + /// actually implements `Send`. + pub unsafe fn as_spawn_obj_error(self) -> SpawnObjError { + // Safety: Both structs have the same memory layout + mem::transmute::(self) + } +} + +impl From for SpawnLocalObjError { + fn from(error: SpawnObjError) -> SpawnLocalObjError { + unsafe { + // Safety: Both structs have the same memory layout + mem::transmute::(error) + } + } +} diff --git a/src/libcore/task/task.rs b/src/libcore/task/task.rs index dc4ff314e5b..9896d7f5ff2 100644 --- a/src/libcore/task/task.rs +++ b/src/libcore/task/task.rs @@ -14,7 +14,7 @@ use fmt; use future::Future; -use mem::PinMut; +use mem::{self, PinMut}; use super::{Context, Poll}; /// A custom trait object for polling tasks, roughly akin to @@ -30,7 +30,7 @@ unsafe impl Send for TaskObj {} impl TaskObj { /// Create a `TaskObj` from a custom trait object representation. #[inline] - pub fn new(t: T) -> TaskObj { + pub fn new(t: T) -> TaskObj { TaskObj { ptr: t.into_raw(), poll_fn: T::poll, @@ -65,6 +65,71 @@ impl Drop for TaskObj { } } +/// A custom trait object for polling tasks, roughly akin to +/// `Box>`. +/// Contrary to `TaskObj`, `LocalTaskObj` does not have a `Send` bound. +pub struct LocalTaskObj { + ptr: *mut (), + poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<()>, + drop_fn: unsafe fn(*mut ()), +} + +impl LocalTaskObj { + /// Create a `LocalTaskObj` from a custom trait object representation. + #[inline] + pub fn new(t: T) -> LocalTaskObj { + LocalTaskObj { + ptr: t.into_raw(), + poll_fn: T::poll, + drop_fn: T::drop, + } + } + + /// Converts the `LocalTaskObj` into a `TaskObj` + /// To make this operation safe one has to ensure that the `UnsafeTask` + /// instance from which this `LocalTaskObj` was created actually implements + /// `Send`. + pub unsafe fn as_task_obj(self) -> TaskObj { + // Safety: Both structs have the same memory layout + mem::transmute::(self) + } +} + +impl fmt::Debug for LocalTaskObj { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("LocalTaskObj") + .finish() + } +} + +impl From for LocalTaskObj { + fn from(task: TaskObj) -> LocalTaskObj { + unsafe { + // Safety: Both structs have the same memory layout + mem::transmute::(task) + } + } +} + +impl Future for LocalTaskObj { + type Output = (); + + #[inline] + fn poll(self: PinMut, cx: &mut Context) -> Poll<()> { + unsafe { + (self.poll_fn)(self.ptr, cx) + } + } +} + +impl Drop for LocalTaskObj { + fn drop(&mut self) { + unsafe { + (self.drop_fn)(self.ptr) + } + } +} + /// A custom implementation of a task trait object for `TaskObj`, providing /// a hand-rolled vtable. /// @@ -74,7 +139,7 @@ impl Drop for TaskObj { /// The implementor must guarantee that it is safe to call `poll` repeatedly (in /// a non-concurrent fashion) with the result of `into_raw` until `drop` is /// called. -pub unsafe trait UnsafeTask: Send + 'static { +pub unsafe trait UnsafeTask: 'static { /// Convert a owned instance into a (conceptually owned) void pointer. fn into_raw(self) -> *mut (); -- cgit 1.4.1-3-g733a5 From f1cc8b2854d5c4342efc295dd7eddeed9343b556 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Tue, 26 Jun 2018 21:24:05 +0300 Subject: review fix --- src/libcore/str/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 210fc5fd5a6..e7bebc891d9 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2453,7 +2453,7 @@ impl str { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.28.0", reason = "duplicates `get_unchecked`")] + #[rustc_deprecated(since = "1.29.0", reason = "duplicates `get_unchecked`")] #[inline] pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { (begin..end).get_unchecked(self) @@ -2484,7 +2484,7 @@ impl str { /// * `begin` and `end` must be byte positions within the string slice. /// * `begin` and `end` must lie on UTF-8 sequence boundaries. #[stable(feature = "str_slice_mut", since = "1.5.0")] - #[rustc_deprecated(since = "1.28.0", reason = "duplicates `get_unchecked`")] + #[rustc_deprecated(since = "1.29.0", reason = "duplicates `get_unchecked_mut`")] #[inline] pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { (begin..end).get_unchecked_mut(self) -- cgit 1.4.1-3-g733a5 From c055fef0104f017b9f6aaa25ba0fc69ccb34ae8e Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Tue, 26 Jun 2018 21:06:20 +0200 Subject: Nested `LocalTaskObj` in `TaskObj`, remove `SpawnErrorObj` conversions --- src/libcore/task/spawn_error.rs | 20 --------- src/libcore/task/task.rs | 89 ++++++++++++++++------------------------- 2 files changed, 34 insertions(+), 75 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/task/spawn_error.rs b/src/libcore/task/spawn_error.rs index 57bb9ebeb30..42d37efbe19 100644 --- a/src/libcore/task/spawn_error.rs +++ b/src/libcore/task/spawn_error.rs @@ -60,23 +60,3 @@ pub struct SpawnLocalObjError { /// The task for which spawning was attempted pub task: LocalTaskObj, } - -impl SpawnLocalObjError { - /// Converts the `SpawnLocalObjError` into a `SpawnObjError` - /// To make this operation safe one has to ensure that the `UnsafeTask` - /// instance from which the `LocalTaskObj` stored inside was created - /// actually implements `Send`. - pub unsafe fn as_spawn_obj_error(self) -> SpawnObjError { - // Safety: Both structs have the same memory layout - mem::transmute::(self) - } -} - -impl From for SpawnLocalObjError { - fn from(error: SpawnObjError) -> SpawnLocalObjError { - unsafe { - // Safety: Both structs have the same memory layout - mem::transmute::(error) - } - } -} diff --git a/src/libcore/task/task.rs b/src/libcore/task/task.rs index 9896d7f5ff2..c5a41873db4 100644 --- a/src/libcore/task/task.rs +++ b/src/libcore/task/task.rs @@ -14,57 +14,9 @@ use fmt; use future::Future; -use mem::{self, PinMut}; +use mem::PinMut; use super::{Context, Poll}; -/// A custom trait object for polling tasks, roughly akin to -/// `Box + Send>`. -pub struct TaskObj { - ptr: *mut (), - poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<()>, - drop_fn: unsafe fn(*mut ()), -} - -unsafe impl Send for TaskObj {} - -impl TaskObj { - /// Create a `TaskObj` from a custom trait object representation. - #[inline] - pub fn new(t: T) -> TaskObj { - TaskObj { - ptr: t.into_raw(), - poll_fn: T::poll, - drop_fn: T::drop, - } - } -} - -impl fmt::Debug for TaskObj { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("TaskObj") - .finish() - } -} - -impl Future for TaskObj { - type Output = (); - - #[inline] - fn poll(self: PinMut, cx: &mut Context) -> Poll<()> { - unsafe { - (self.poll_fn)(self.ptr, cx) - } - } -} - -impl Drop for TaskObj { - fn drop(&mut self) { - unsafe { - (self.drop_fn)(self.ptr) - } - } -} - /// A custom trait object for polling tasks, roughly akin to /// `Box>`. /// Contrary to `TaskObj`, `LocalTaskObj` does not have a `Send` bound. @@ -90,8 +42,7 @@ impl LocalTaskObj { /// instance from which this `LocalTaskObj` was created actually implements /// `Send`. pub unsafe fn as_task_obj(self) -> TaskObj { - // Safety: Both structs have the same memory layout - mem::transmute::(self) + TaskObj(self) } } @@ -104,10 +55,7 @@ impl fmt::Debug for LocalTaskObj { impl From for LocalTaskObj { fn from(task: TaskObj) -> LocalTaskObj { - unsafe { - // Safety: Both structs have the same memory layout - mem::transmute::(task) - } + task.0 } } @@ -130,6 +78,37 @@ impl Drop for LocalTaskObj { } } +/// A custom trait object for polling tasks, roughly akin to +/// `Box + Send>`. +pub struct TaskObj(LocalTaskObj); + +unsafe impl Send for TaskObj {} + +impl TaskObj { + /// Create a `TaskObj` from a custom trait object representation. + #[inline] + pub fn new(t: T) -> TaskObj { + TaskObj(LocalTaskObj::new(t)) + } +} + +impl fmt::Debug for TaskObj { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("TaskObj") + .finish() + } +} + +impl Future for TaskObj { + type Output = (); + + #[inline] + fn poll(self: PinMut, cx: &mut Context) -> Poll<()> { + let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) }; + pinned_field.poll(cx) + } +} + /// A custom implementation of a task trait object for `TaskObj`, providing /// a hand-rolled vtable. /// -- cgit 1.4.1-3-g733a5 From b39ea1d18f19f9cee3ad271a802b3157f9827f51 Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Tue, 26 Jun 2018 21:13:36 +0200 Subject: Move spawn errors into executor.rs --- src/libcore/task/executor.rs | 48 ++++++++++++++++++++++++++++++- src/libcore/task/mod.rs | 7 ++--- src/libcore/task/spawn_error.rs | 62 ----------------------------------------- 3 files changed, 50 insertions(+), 67 deletions(-) delete mode 100644 src/libcore/task/spawn_error.rs (limited to 'src/libcore') diff --git a/src/libcore/task/executor.rs b/src/libcore/task/executor.rs index fcef6d5ffc8..73bf80d2f99 100644 --- a/src/libcore/task/executor.rs +++ b/src/libcore/task/executor.rs @@ -12,7 +12,8 @@ reason = "futures in libcore are unstable", issue = "50547")] -use super::{TaskObj, SpawnObjError, SpawnErrorKind}; +use fmt; +use super::{TaskObj, LocalTaskObj}; /// A task executor. /// @@ -42,3 +43,48 @@ pub trait Executor { Ok(()) } } + +/// Provides the reason that an executor was unable to spawn. +pub struct SpawnErrorKind { + _hidden: (), +} + +impl fmt::Debug for SpawnErrorKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("SpawnErrorKind") + .field(&"shutdown") + .finish() + } +} + +impl SpawnErrorKind { + /// Spawning is failing because the executor has been shut down. + pub fn shutdown() -> SpawnErrorKind { + SpawnErrorKind { _hidden: () } + } + + /// Check whether this error is the `shutdown` error. + pub fn is_shutdown(&self) -> bool { + true + } +} + +/// The result of a failed spawn +#[derive(Debug)] +pub struct SpawnObjError { + /// The kind of error + pub kind: SpawnErrorKind, + + /// The task for which spawning was attempted + pub task: TaskObj, +} + +/// The result of a failed spawn +#[derive(Debug)] +pub struct SpawnLocalObjError { + /// The kind of error + pub kind: SpawnErrorKind, + + /// The task for which spawning was attempted + pub task: LocalTaskObj, +} diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index 36370b6b37c..d167a374105 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -18,14 +18,13 @@ mod context; pub use self::context::Context; mod executor; -pub use self::executor::Executor; +pub use self::executor::{ + Executor, SpawnErrorKind, SpawnObjError, SpawnLocalObjError +}; mod poll; pub use self::poll::Poll; -mod spawn_error; -pub use self::spawn_error::{SpawnErrorKind, SpawnObjError, SpawnLocalObjError}; - mod task; pub use self::task::{TaskObj, LocalTaskObj, UnsafeTask}; diff --git a/src/libcore/task/spawn_error.rs b/src/libcore/task/spawn_error.rs deleted file mode 100644 index 42d37efbe19..00000000000 --- a/src/libcore/task/spawn_error.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] - -use fmt; -use mem; -use super::{TaskObj, LocalTaskObj}; - -/// Provides the reason that an executor was unable to spawn. -pub struct SpawnErrorKind { - _hidden: (), -} - -impl fmt::Debug for SpawnErrorKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("SpawnErrorKind") - .field(&"shutdown") - .finish() - } -} - -impl SpawnErrorKind { - /// Spawning is failing because the executor has been shut down. - pub fn shutdown() -> SpawnErrorKind { - SpawnErrorKind { _hidden: () } - } - - /// Check whether this error is the `shutdown` error. - pub fn is_shutdown(&self) -> bool { - true - } -} - -/// The result of a failed spawn -#[derive(Debug)] -pub struct SpawnObjError { - /// The kind of error - pub kind: SpawnErrorKind, - - /// The task for which spawning was attempted - pub task: TaskObj, -} - -/// The result of a failed spawn -#[derive(Debug)] -pub struct SpawnLocalObjError { - /// The kind of error - pub kind: SpawnErrorKind, - - /// The task for which spawning was attempted - pub task: LocalTaskObj, -} -- cgit 1.4.1-3-g733a5 From c8f9b84b393915a48253e3edc862c15a9b7152a7 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Tue, 26 Jun 2018 23:17:56 -0600 Subject: Stabilize to_bytes and from_bytes for integers. Fixes #49792 --- src/libcore/num/mod.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 1168126c47c..7e2dd304d7f 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1996,12 +1996,10 @@ $EndFeature, " /// # Examples /// /// ``` - /// #![feature(int_to_from_bytes)] - /// /// let bytes = i32::min_value().to_be().to_bytes(); /// assert_eq!(bytes, [0x80, 0, 0, 0]); /// ``` - #[unstable(feature = "int_to_from_bytes", issue = "49792")] + #[stable(feature = "int_to_from_bytes", since = "1.29.0")] #[inline] pub fn to_bytes(self) -> [u8; mem::size_of::()] { unsafe { mem::transmute(self) } @@ -2018,12 +2016,10 @@ $EndFeature, " /// # Examples /// /// ``` - /// #![feature(int_to_from_bytes)] - /// /// let int = i32::from_be(i32::from_bytes([0x80, 0, 0, 0])); /// assert_eq!(int, i32::min_value()); /// ``` - #[unstable(feature = "int_to_from_bytes", issue = "49792")] + #[stable(feature = "int_to_from_bytes", since = "1.29.0")] #[inline] pub fn from_bytes(bytes: [u8; mem::size_of::()]) -> Self { unsafe { mem::transmute(bytes) } @@ -3702,12 +3698,10 @@ $EndFeature, " /// # Examples /// /// ``` - /// #![feature(int_to_from_bytes)] - /// /// let bytes = 0x1234_5678_u32.to_be().to_bytes(); /// assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]); /// ``` - #[unstable(feature = "int_to_from_bytes", issue = "49792")] + #[stable(feature = "int_to_from_bytes", since = "1.29.0")] #[inline] pub fn to_bytes(self) -> [u8; mem::size_of::()] { unsafe { mem::transmute(self) } @@ -3724,12 +3718,10 @@ $EndFeature, " /// # Examples /// /// ``` - /// #![feature(int_to_from_bytes)] - /// /// let int = u32::from_be(u32::from_bytes([0x12, 0x34, 0x56, 0x78])); /// assert_eq!(int, 0x1234_5678_u32); /// ``` - #[unstable(feature = "int_to_from_bytes", issue = "49792")] + #[stable(feature = "int_to_from_bytes", since = "1.29.0")] #[inline] pub fn from_bytes(bytes: [u8; mem::size_of::()]) -> Self { unsafe { mem::transmute(bytes) } -- cgit 1.4.1-3-g733a5 From 851cc39503a53b38ecbdd03bd391289e095bd7ca Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Wed, 27 Jun 2018 00:07:18 -0700 Subject: Optimize RefCell refcount tracking --- src/libcore/cell.rs | 66 +++++++++++++++++-------------- src/test/compile-fail/not-panic-safe-2.rs | 2 +- src/test/compile-fail/not-panic-safe-3.rs | 2 +- src/test/compile-fail/not-panic-safe-4.rs | 2 +- src/test/compile-fail/not-panic-safe-6.rs | 2 +- 5 files changed, 40 insertions(+), 34 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index dd8fce17cff..21edc6dfee4 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -570,20 +570,31 @@ impl Display for BorrowMutError { } } -// Values [1, MIN_WRITING-1] represent the number of `Ref` active. Values in -// [MIN_WRITING, MAX-1] represent the number of `RefMut` active. Multiple -// `RefMut`s can only be active at a time if they refer to distinct, -// nonoverlapping components of a `RefCell` (e.g., different ranges of a slice). +// Positive values represent the number of `Ref` active. Negative values +// represent the number of `RefMut` active. Multiple `RefMut`s can only be +// active at a time if they refer to distinct, nonoverlapping components of a +// `RefCell` (e.g., different ranges of a slice). // // `Ref` and `RefMut` are both two words in size, and so there will likely never // be enough `Ref`s or `RefMut`s in existence to overflow half of the `usize` -// range. Thus, a `BorrowFlag` will probably never overflow. However, this is -// not a guarantee, as a pathological program could repeatedly create and then -// mem::forget `Ref`s or `RefMut`s. Thus, all code must explicitly check for -// overflow in order to avoid unsafety. -type BorrowFlag = usize; +// range. Thus, a `BorrowFlag` will probably never overflow or underflow. +// However, this is not a guarantee, as a pathological program could repeatedly +// create and then mem::forget `Ref`s or `RefMut`s. Thus, all code must +// explicitly check for overflow and underflow in order to avoid unsafety, or at +// least behave correctly in the event that overflow or underflow happens (e.g., +// see BorrowRef::new). +type BorrowFlag = isize; const UNUSED: BorrowFlag = 0; -const MIN_WRITING: BorrowFlag = (!0)/2 + 1; // 0b1000... + +#[inline(always)] +fn is_writing(x: BorrowFlag) -> bool { + x < UNUSED +} + +#[inline(always)] +fn is_reading(x: BorrowFlag) -> bool { + x > UNUSED +} impl RefCell { /// Creates a new `RefCell` containing `value`. @@ -1022,12 +1033,11 @@ impl<'b> BorrowRef<'b> { #[inline] fn new(borrow: &'b Cell) -> Option> { let b = borrow.get(); - if b >= MIN_WRITING { + if is_writing(b) || b == isize::max_value() { + // If there's currently a writing borrow, or if incrementing the + // refcount would overflow into a writing borrow. None } else { - // Prevent the borrow counter from overflowing into - // a writing borrow. - assert!(b < MIN_WRITING - 1); borrow.set(b + 1); Some(BorrowRef { borrow }) } @@ -1038,7 +1048,7 @@ impl<'b> Drop for BorrowRef<'b> { #[inline] fn drop(&mut self) { let borrow = self.borrow.get(); - debug_assert!(borrow < MIN_WRITING && borrow != UNUSED); + debug_assert!(is_reading(borrow)); self.borrow.set(borrow - 1); } } @@ -1047,12 +1057,12 @@ impl<'b> Clone for BorrowRef<'b> { #[inline] fn clone(&self) -> BorrowRef<'b> { // Since this Ref exists, we know the borrow flag - // is not set to WRITING. + // is a reading borrow. let borrow = self.borrow.get(); - debug_assert!(borrow != UNUSED); + debug_assert!(is_reading(borrow)); // Prevent the borrow counter from overflowing into // a writing borrow. - assert!(borrow < MIN_WRITING - 1); + assert!(borrow != isize::max_value()); self.borrow.set(borrow + 1); BorrowRef { borrow: self.borrow } } @@ -1251,12 +1261,8 @@ impl<'b> Drop for BorrowRefMut<'b> { #[inline] fn drop(&mut self) { let borrow = self.borrow.get(); - debug_assert!(borrow >= MIN_WRITING); - self.borrow.set(if borrow == MIN_WRITING { - UNUSED - } else { - borrow - 1 - }); + debug_assert!(is_writing(borrow)); + self.borrow.set(borrow + 1); } } @@ -1266,10 +1272,10 @@ impl<'b> BorrowRefMut<'b> { // NOTE: Unlike BorrowRefMut::clone, new is called to create the initial // mutable reference, and so there must currently be no existing // references. Thus, while clone increments the mutable refcount, here - // we simply go directly from UNUSED to MIN_WRITING. + // we explicitly only allow going from UNUSED to UNUSED - 1. match borrow.get() { UNUSED => { - borrow.set(MIN_WRITING); + borrow.set(UNUSED - 1); Some(BorrowRefMut { borrow: borrow }) }, _ => None, @@ -1284,10 +1290,10 @@ impl<'b> BorrowRefMut<'b> { #[inline] fn clone(&self) -> BorrowRefMut<'b> { let borrow = self.borrow.get(); - debug_assert!(borrow >= MIN_WRITING); - // Prevent the borrow counter from overflowing. - assert!(borrow != !0); - self.borrow.set(borrow + 1); + debug_assert!(is_writing(borrow)); + // Prevent the borrow counter from underflowing. + assert!(borrow != isize::min_value()); + self.borrow.set(borrow - 1); BorrowRefMut { borrow: self.borrow } } } diff --git a/src/test/compile-fail/not-panic-safe-2.rs b/src/test/compile-fail/not-panic-safe-2.rs index d750851b719..5490acf4bd6 100644 --- a/src/test/compile-fail/not-panic-safe-2.rs +++ b/src/test/compile-fail/not-panic-safe-2.rs @@ -19,5 +19,5 @@ fn assert() {} fn main() { assert::>>(); //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a - //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a } diff --git a/src/test/compile-fail/not-panic-safe-3.rs b/src/test/compile-fail/not-panic-safe-3.rs index cd27b274258..0fac395a115 100644 --- a/src/test/compile-fail/not-panic-safe-3.rs +++ b/src/test/compile-fail/not-panic-safe-3.rs @@ -19,5 +19,5 @@ fn assert() {} fn main() { assert::>>(); //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a - //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a } diff --git a/src/test/compile-fail/not-panic-safe-4.rs b/src/test/compile-fail/not-panic-safe-4.rs index 956eca432c5..bf0392018b5 100644 --- a/src/test/compile-fail/not-panic-safe-4.rs +++ b/src/test/compile-fail/not-panic-safe-4.rs @@ -18,5 +18,5 @@ fn assert() {} fn main() { assert::<&RefCell>(); //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a - //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a } diff --git a/src/test/compile-fail/not-panic-safe-6.rs b/src/test/compile-fail/not-panic-safe-6.rs index d0ca1db5212..950f0a0b53a 100644 --- a/src/test/compile-fail/not-panic-safe-6.rs +++ b/src/test/compile-fail/not-panic-safe-6.rs @@ -18,5 +18,5 @@ fn assert() {} fn main() { assert::<*mut RefCell>(); //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a - //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a } -- cgit 1.4.1-3-g733a5 From 1565fc21205cf6f589c89732babc6991a7baaee8 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 27 Jun 2018 15:04:49 +0200 Subject: Document that Layout::from_size_align does not allow align=0 This was already implied since zero is not a power of two, but maybe worth pointing out. --- src/libcore/alloc.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 0c074582281..91447e01ad4 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -67,6 +67,8 @@ impl Layout { /// or returns `LayoutErr` if either of the following conditions /// are not met: /// + /// * `align` must not be zero, + /// /// * `align` must be a power of two, /// /// * `size`, when rounded up to the nearest multiple of `align`, -- cgit 1.4.1-3-g733a5 From 30d825ce72c6e56a3c82f338897a437eaa8cd882 Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Wed, 27 Jun 2018 20:15:24 +0200 Subject: Fix doc links --- src/libcore/future.rs | 14 +++++++++----- src/libstd/error.rs | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/future.rs b/src/libcore/future.rs index a8c8f69411e..153cd6c0724 100644 --- a/src/libcore/future.rs +++ b/src/libcore/future.rs @@ -45,18 +45,18 @@ pub trait Future { /// /// This function returns: /// - /// - `Poll::Pending` if the future is not ready yet - /// - `Poll::Ready(val)` with the result `val` of this future if it finished - /// successfully. + /// - [`Poll::Pending`] if the future is not ready yet + /// - [`Poll::Ready(val)`] with the result `val` of this future if it + /// finished successfully. /// /// Once a future has finished, clients should not `poll` it again. /// /// When a future is not ready yet, `poll` returns - /// [`Poll::Pending`](::task::Poll). The future will *also* register the + /// `Poll::Pending`. The future will *also* register the /// interest of the current task in the value being produced. For example, /// if the future represents the availability of data on a socket, then the /// task is recorded so that when data arrives, it is woken up (via - /// [`cx.waker()`](::task::Context::waker)). Once a task has been woken up, + /// [`cx.waker()`]). Once a task has been woken up, /// it should attempt to `poll` the future again, which may or may not /// produce a final value. /// @@ -90,6 +90,10 @@ pub trait Future { /// then any future calls to `poll` may panic, block forever, or otherwise /// cause bad behavior. The `Future` trait itself provides no guarantees /// about the behavior of `poll` after a future has completed. + /// + /// [`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending + /// [`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready + /// [`cx.waker()`]: ../task/struct.Context.html#method.waker fn poll(self: PinMut, cx: &mut task::Context) -> Poll; } diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 3160485375f..1958915602f 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -49,6 +49,7 @@ use string; /// /// [`Result`]: ../result/enum.Result.html /// [`Display`]: ../fmt/trait.Display.html +/// [`Debug`]: ../fmt/trait.Debug.html /// [`cause`]: trait.Error.html#method.cause #[stable(feature = "rust1", since = "1.0.0")] pub trait Error: Debug + Display { -- cgit 1.4.1-3-g733a5 From c95fba7b5b7cc3a923707df414f4bc8258400d52 Mon Sep 17 00:00:00 2001 From: Anirudh Balaji Date: Wed, 27 Jun 2018 13:49:50 -0700 Subject: Nit: Remove leading whitespace --- src/libcore/slice/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index a6d95b11825..0ee4c0bdbe7 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1541,7 +1541,7 @@ impl [T] { /// let src = [1, 2, 3, 4]; /// let mut dst = [0, 0]; /// - /// // Note: the slices must be the same length, so you can slice the + /// // Note: the slices must be the same length, so you can slice the /// // source to be the same size. Here we slice the source, four elements, /// // to two, the same size as the destination slice. It *will* panic if we don't do this. /// dst.clone_from_slice(&src[2..]); @@ -1610,7 +1610,7 @@ impl [T] { /// let src = [1, 2, 3, 4]; /// let mut dst = [0, 0]; /// - /// // Note: the slices must be the same length, so you can slice the + /// // Note: the slices must be the same length, so you can slice the /// // source to be the same size. Here we slice the source, four elements, /// // to two, the same size as the destination slice. It *will* panic if we don't do this. /// dst.copy_from_slice(&src[2..]); -- cgit 1.4.1-3-g733a5 From b5cee029a55cd35fcdad52acb294a04ebff1f341 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Sat, 5 May 2018 00:33:20 -0400 Subject: Add str::split_ascii_whitespace. --- src/liballoc/lib.rs | 1 + src/liballoc/str.rs | 2 + src/libcore/str/mod.rs | 159 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 158 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index e25742a4a61..ec9b5eba561 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -108,6 +108,7 @@ #![cfg_attr(stage0, feature(repr_transparent))] #![feature(rustc_attrs)] #![feature(specialization)] +#![feature(split_ascii_whitespace)] #![feature(staged_api)] #![feature(str_internals)] #![feature(trusted_len)] diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 32ca8d1fa5e..ec9c39c916c 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -78,6 +78,8 @@ pub use core::str::SplitWhitespace; pub use core::str::pattern; #[stable(feature = "encode_utf16", since = "1.8.0")] pub use core::str::EncodeUtf16; +#[unstable(feature = "split_ascii_whitespace", issue = "48656")] +pub use core::str::SplitAsciiWhitespace; #[unstable(feature = "slice_concat_ext", reason = "trait should not have to exist", diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 42fb1bc238b..5ae2f6349e5 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -21,7 +21,7 @@ use char; use fmt; use iter::{Map, Cloned, FusedIterator, TrustedLen, Filter}; use iter_private::TrustedRandomAccess; -use slice::{self, SliceIndex}; +use slice::{self, SliceIndex, Split as SliceSplit}; use mem; pub mod pattern; @@ -2722,7 +2722,10 @@ impl str { /// the original string slice, separated by any amount of whitespace. /// /// 'Whitespace' is defined according to the terms of the Unicode Derived - /// Core Property `White_Space`. + /// Core Property `White_Space`. If you only want to split on ASCII whitespace + /// instead, use [`split_ascii_whitespace`]. + /// + /// [`split_ascii_whitespace`]: #method.split_ascii_whitespace /// /// # Examples /// @@ -2756,6 +2759,53 @@ impl str { SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } } + /// Split a string slice by ASCII whitespace. + /// + /// The iterator returned will return string slices that are sub-slices of + /// the original string slice, separated by any amount of ASCII whitespace. + /// + /// To split by Unicode `Whitespace` instead, use [`split_whitespace`]. + /// + /// [`split_whitespace`]: #method.split_whitespace + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(split_ascii_whitespace)] + /// let mut iter = "A few words".split_ascii_whitespace(); + /// + /// assert_eq!(Some("A"), iter.next()); + /// assert_eq!(Some("few"), iter.next()); + /// assert_eq!(Some("words"), iter.next()); + /// + /// assert_eq!(None, iter.next()); + /// ``` + /// + /// All kinds of ASCII whitespace are considered: + /// + /// ``` + /// let mut iter = " Mary had\ta little \n\t lamb".split_whitespace(); + /// assert_eq!(Some("Mary"), iter.next()); + /// assert_eq!(Some("had"), iter.next()); + /// assert_eq!(Some("a"), iter.next()); + /// assert_eq!(Some("little"), iter.next()); + /// assert_eq!(Some("lamb"), iter.next()); + /// + /// assert_eq!(None, iter.next()); + /// ``` + #[unstable(feature = "split_ascii_whitespace", issue = "48656")] + #[inline] + pub fn split_ascii_whitespace(&self) -> SplitAsciiWhitespace { + let inner = self + .as_bytes() + .split(IsAsciiWhitespace) + .filter(IsNotEmpty) + .map(UnsafeBytesToStr); + SplitAsciiWhitespace { inner } + } + /// An iterator over the lines of a string, as string slices. /// /// Lines are ended with either a newline (`\n`) or a carriage return with @@ -3895,6 +3945,20 @@ pub struct SplitWhitespace<'a> { inner: Filter, IsNotEmpty>, } +/// An iterator over the non-ASCII-whitespace substrings of a string, +/// separated by any amount of ASCII whitespace. +/// +/// This struct is created by the [`split_ascii_whitespace`] method on [`str`]. +/// See its documentation for more. +/// +/// [`split_ascii_whitespace`]: ../../std/primitive.str.html#method.split_ascii_whitespace +/// [`str`]: ../../std/primitive.str.html +#[unstable(feature = "split_ascii_whitespace", issue = "48656")] +#[derive(Clone, Debug)] +pub struct SplitAsciiWhitespace<'a> { + inner: Map, IsNotEmpty>, UnsafeBytesToStr>, +} + #[derive(Clone)] struct IsWhitespace; @@ -3914,6 +3978,25 @@ impl FnMut<(char, )> for IsWhitespace { } } +#[derive(Clone)] +struct IsAsciiWhitespace; + +impl<'a> FnOnce<(&'a u8, )> for IsAsciiWhitespace { + type Output = bool; + + #[inline] + extern "rust-call" fn call_once(mut self, arg: (&u8, )) -> bool { + self.call_mut(arg) + } +} + +impl<'a> FnMut<(&'a u8, )> for IsAsciiWhitespace { + #[inline] + extern "rust-call" fn call_mut(&mut self, arg: (&u8, )) -> bool { + arg.0.is_ascii_whitespace() + } +} + #[derive(Clone)] struct IsNotEmpty; @@ -3921,30 +4004,72 @@ impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty { type Output = bool; #[inline] - extern "rust-call" fn call_once(mut self, arg: (&&str, )) -> bool { + extern "rust-call" fn call_once(mut self, arg: (&'a &'b str, )) -> bool { self.call_mut(arg) } } impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty { #[inline] - extern "rust-call" fn call_mut(&mut self, arg: (&&str, )) -> bool { + extern "rust-call" fn call_mut(&mut self, arg: (&'a &'b str, )) -> bool { + !arg.0.is_empty() + } +} + +impl<'a, 'b> FnOnce<(&'a &'b [u8], )> for IsNotEmpty { + type Output = bool; + + #[inline] + extern "rust-call" fn call_once(mut self, arg: (&'a &'b [u8], )) -> bool { + self.call_mut(arg) + } +} + +impl<'a, 'b> FnMut<(&'a &'b [u8], )> for IsNotEmpty { + #[inline] + extern "rust-call" fn call_mut(&mut self, arg: (&'a &'b [u8], )) -> bool { !arg.0.is_empty() } } +#[derive(Clone)] +struct UnsafeBytesToStr; + +impl<'a> FnOnce<(&'a [u8], )> for UnsafeBytesToStr { + type Output = &'a str; + + #[inline] + extern "rust-call" fn call_once(mut self, arg: (&'a [u8], )) -> &'a str { + self.call_mut(arg) + } +} + +impl<'a> FnMut<(&'a [u8], )> for UnsafeBytesToStr { + #[inline] + extern "rust-call" fn call_mut(&mut self, arg: (&'a [u8], )) -> &'a str { + unsafe { from_utf8_unchecked(arg.0) } + } +} + #[stable(feature = "split_whitespace", since = "1.1.0")] impl<'a> Iterator for SplitWhitespace<'a> { type Item = &'a str; + #[inline] fn next(&mut self) -> Option<&'a str> { self.inner.next() } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } } #[stable(feature = "split_whitespace", since = "1.1.0")] impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { + #[inline] fn next_back(&mut self) -> Option<&'a str> { self.inner.next_back() } @@ -3953,6 +4078,32 @@ impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { #[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for SplitWhitespace<'a> {} +#[unstable(feature = "split_ascii_whitespace", issue = "48656")] +impl<'a> Iterator for SplitAsciiWhitespace<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + self.inner.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[unstable(feature = "split_ascii_whitespace", issue = "48656")] +impl<'a> DoubleEndedIterator for SplitAsciiWhitespace<'a> { + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + self.inner.next_back() + } +} + +#[unstable(feature = "split_ascii_whitespace", issue = "48656")] +impl<'a> FusedIterator for SplitAsciiWhitespace<'a> {} + /// An iterator of [`u16`] over the string encoded as UTF-16. /// /// [`u16`]: ../../std/primitive.u16.html -- cgit 1.4.1-3-g733a5 From b0547cea0ae50f49619ded26f43d0d55a1674b14 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 15 Jun 2018 03:56:35 +0200 Subject: Move core::alloc::CollectionAllocErr to alloc::collections --- src/liballoc/collections/mod.rs | 29 +++++++++++++++++++++++++++++ src/liballoc/collections/vec_deque.rs | 2 +- src/liballoc/raw_vec.rs | 4 ++-- src/liballoc/string.rs | 2 +- src/liballoc/vec.rs | 2 +- src/libcore/alloc.rs | 28 ---------------------------- src/libstd/collections/hash/map.rs | 2 +- src/libstd/collections/hash/table.rs | 3 ++- src/libstd/collections/mod.rs | 2 +- 9 files changed, 38 insertions(+), 36 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/collections/mod.rs b/src/liballoc/collections/mod.rs index 35c816a1ceb..96e0eb633b2 100644 --- a/src/liballoc/collections/mod.rs +++ b/src/liballoc/collections/mod.rs @@ -51,6 +51,35 @@ pub use self::linked_list::LinkedList; #[doc(no_inline)] pub use self::vec_deque::VecDeque; +use alloc::{AllocErr, LayoutErr}; + +/// Augments `AllocErr` with a CapacityOverflow variant. +#[derive(Clone, PartialEq, Eq, Debug)] +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +pub enum CollectionAllocErr { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + /// Error due to the allocator (see the `AllocErr` type's docs). + AllocErr, +} + +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +impl From for CollectionAllocErr { + #[inline] + fn from(AllocErr: AllocErr) -> Self { + CollectionAllocErr::AllocErr + } +} + +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +impl From for CollectionAllocErr { + #[inline] + fn from(_: LayoutErr) -> Self { + CollectionAllocErr::CapacityOverflow + } +} + /// An intermediate trait for specialization of `Extend`. #[doc(hidden)] trait SpecExtend { diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 4753d36415c..ba92b886138 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -30,7 +30,7 @@ use core::slice; use core::hash::{Hash, Hasher}; use core::cmp; -use alloc::CollectionAllocErr; +use collections::CollectionAllocErr; use raw_vec::RawVec; use vec::Vec; diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 5095bbe96cc..4f2686abf45 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -18,8 +18,8 @@ use core::ptr::{self, NonNull, Unique}; use core::slice; use alloc::{Alloc, Layout, Global, handle_alloc_error}; -use alloc::CollectionAllocErr; -use alloc::CollectionAllocErr::*; +use collections::CollectionAllocErr; +use collections::CollectionAllocErr::*; use boxed::Box; /// A low-level utility for more ergonomically allocating, reallocating, and deallocating diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index a988b6a26d9..6b28687a060 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -66,7 +66,7 @@ use core::ptr; use core::str::pattern::Pattern; use core::str::lossy; -use alloc::CollectionAllocErr; +use collections::CollectionAllocErr; use borrow::{Cow, ToOwned}; use boxed::Box; use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 752a6c966d5..fbbaced540e 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -80,7 +80,7 @@ use core::ptr; use core::ptr::NonNull; use core::slice; -use alloc::CollectionAllocErr; +use collections::CollectionAllocErr; use borrow::ToOwned; use borrow::Cow; use boxed::Box; diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 91447e01ad4..01221aecb62 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -385,34 +385,6 @@ impl fmt::Display for CannotReallocInPlace { } } -/// Augments `AllocErr` with a CapacityOverflow variant. -// FIXME: should this be in libcore or liballoc? -#[derive(Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub enum CollectionAllocErr { - /// Error due to the computed capacity exceeding the collection's maximum - /// (usually `isize::MAX` bytes). - CapacityOverflow, - /// Error due to the allocator (see the `AllocErr` type's docs). - AllocErr, -} - -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -impl From for CollectionAllocErr { - #[inline] - fn from(AllocErr: AllocErr) -> Self { - CollectionAllocErr::AllocErr - } -} - -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -impl From for CollectionAllocErr { - #[inline] - fn from(_: LayoutErr) -> Self { - CollectionAllocErr::CapacityOverflow - } -} - /// A memory allocator that can be registered as the standard library’s default /// though the `#[global_allocator]` attributes. /// diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index ee8c1dc81ad..91912e5f241 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -11,7 +11,7 @@ use self::Entry::*; use self::VacantEntryState::*; -use alloc::CollectionAllocErr; +use collections::CollectionAllocErr; use cell::Cell; use borrow::Borrow; use cmp::max; diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index d14b754ddb6..2b319186a8d 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::{Global, Alloc, Layout, LayoutErr, CollectionAllocErr, handle_alloc_error}; +use alloc::{Global, Alloc, Layout, LayoutErr, handle_alloc_error}; +use collections::CollectionAllocErr; use hash::{BuildHasher, Hash, Hasher}; use marker; use mem::{size_of, needs_drop}; diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 643426c377b..8d2c82bc0aa 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -438,7 +438,7 @@ pub use self::hash_map::HashMap; pub use self::hash_set::HashSet; #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub use alloc::CollectionAllocErr; +pub use alloc_crate::collections::CollectionAllocErr; mod hash; -- cgit 1.4.1-3-g733a5 From 2ce61c0aedb54c146c03608757b4e9a25d844025 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Fri, 29 Jun 2018 19:30:06 -0700 Subject: Implement Unpin for references These don'town the backing storage for their data, so projecting `PinMut` into their fields is already unsound. --- src/libcore/marker.rs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 5db5d88d4a5..4a54ebce0a3 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -625,6 +625,12 @@ pub struct Pinned; #[unstable(feature = "pin", issue = "49150")] impl !Unpin for Pinned {} +#[unstable(feature = "pin", issue = "49150")] +impl<'a, T: ?Sized + 'a> Unpin for &'a T {} + +#[unstable(feature = "pin", issue = "49150")] +impl<'a, T: ?Sized + 'a> Unpin for &'a mut T {} + /// Implementations of `Copy` for primitive types. /// /// Implementations that cannot be described in Rust -- cgit 1.4.1-3-g733a5 From a2b21e58192134c5ec7d92000460b500f88003e8 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Fri, 29 Jun 2018 19:33:16 -0700 Subject: Make Waker and LocalWaker Unpin These types never project pinned-ness into their contents, so it is safe for them to be `Unpin`. --- src/libcore/task/wake.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs index 4fd45be56fb..418d5af006f 100644 --- a/src/libcore/task/wake.rs +++ b/src/libcore/task/wake.rs @@ -13,6 +13,7 @@ issue = "50547")] use fmt; +use marker::Unpin; use ptr::NonNull; /// A `Waker` is a handle for waking up a task by notifying its executor that it @@ -25,6 +26,7 @@ pub struct Waker { inner: NonNull, } +impl Unpin for Waker {} unsafe impl Send for Waker {} unsafe impl Sync for Waker {} @@ -99,6 +101,7 @@ pub struct LocalWaker { inner: NonNull, } +impl Unpin for LocalWaker {} impl !Send for LocalWaker {} impl !Sync for LocalWaker {} -- cgit 1.4.1-3-g733a5 From ad97f8b491422d947c1c97d8e9f1bfecdb7f47ba Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Fri, 22 Jun 2018 09:48:43 -0600 Subject: Bootstrap from 1.28.0-beta.3 --- src/Cargo.lock | 29 +++--- src/bootstrap/channel.rs | 2 +- src/liballoc/lib.rs | 1 - src/libcore/intrinsics.rs | 4 - src/libcore/lib.rs | 1 - src/libcore/num/mod.rs | 192 -------------------------------------- src/libcore/num/wrapping.rs | 1 - src/libcore/panic.rs | 2 +- src/libcore/panicking.rs | 15 --- src/libcore/ptr.rs | 27 ------ src/libcore/slice/mod.rs | 3 - src/librustc/lib.rs | 1 - src/librustc_asan/lib.rs | 1 - src/librustc_lsan/lib.rs | 1 - src/librustc_metadata/lib.rs | 1 - src/librustc_msan/lib.rs | 1 - src/librustc_save_analysis/lib.rs | 1 - src/librustc_tsan/lib.rs | 1 - src/libstd/lib.rs | 5 +- src/libstd/panicking.rs | 100 +++++++------------- src/stage0.txt | 2 +- src/tools/cargo | 2 +- src/tools/rust-installer | 2 +- 23 files changed, 53 insertions(+), 342 deletions(-) (limited to 'src/libcore') diff --git a/src/Cargo.lock b/src/Cargo.lock index a9339055264..5d09507c41b 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -191,13 +191,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cargo" -version = "0.29.0" +version = "0.30.0" dependencies = [ "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crates-io 0.17.0", + "crates-io 0.18.0", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -232,6 +232,7 @@ dependencies = [ "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -299,7 +300,7 @@ dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -472,7 +473,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crates-io" -version = "0.17.0" +version = "0.18.0" dependencies = [ "curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1683,7 +1684,7 @@ dependencies = [ name = "rls" version = "0.128.0" dependencies = [ - "cargo 0.29.0", + "cargo 0.30.0", "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "clippy_lints 0.0.205 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1882,7 +1883,7 @@ dependencies = [ "rustc-ap-serialize 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-syntax_pos 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1895,7 +1896,7 @@ dependencies = [ "rustc-ap-serialize 164.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-syntax_pos 164.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1969,7 +1970,7 @@ dependencies = [ "rustc-ap-rustc_data_structures 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-serialize 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1981,7 +1982,7 @@ dependencies = [ "rustc-ap-rustc_data_structures 164.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-serialize 164.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2192,7 +2193,7 @@ dependencies = [ "serialize 0.0.0", "syntax_pos 0.0.0", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2783,7 +2784,7 @@ dependencies = [ "rustc_data_structures 0.0.0", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2908,7 +2909,7 @@ name = "textwrap" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2984,7 +2985,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-width" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -3388,7 +3389,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946" -"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" +"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index a2495f68c1f..04d576df955 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -24,7 +24,7 @@ use Build; use config::Config; // The version number -pub const CFG_RELEASE_NUM: &str = "1.28.0"; +pub const CFG_RELEASE_NUM: &str = "1.29.0"; pub struct GitInfo { inner: Option, diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index ec9b5eba561..42fc716bae2 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -105,7 +105,6 @@ #![feature(pin)] #![feature(ptr_internals)] #![feature(ptr_offset_from)] -#![cfg_attr(stage0, feature(repr_transparent))] #![feature(rustc_attrs)] #![feature(specialization)] #![feature(split_ascii_whitespace)] diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 95f13daf841..89fe2d941a3 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1364,10 +1364,6 @@ extern "rust-intrinsic" { /// source as well as std's catch implementation. pub fn try(f: fn(*mut u8), data: *mut u8, local_ptr: *mut u8) -> i32; - #[cfg(stage0)] - /// docs my friends, its friday! - pub fn align_offset(ptr: *const (), align: usize) -> usize; - /// Emits a `!nontemporal` store according to LLVM (see their docs). /// Probably will never become stable. pub fn nontemporal_store(ptr: *mut T, val: T); diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 40caee85541..cef126f36e8 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -100,7 +100,6 @@ #![feature(optin_builtin_traits)] #![feature(prelude_import)] #![feature(repr_simd, platform_intrinsics)] -#![cfg_attr(stage0, feature(repr_transparent))] #![feature(rustc_attrs)] #![feature(rustc_const_unstable)] #![feature(simd_ffi)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 7e2dd304d7f..e0d267a6ce0 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -267,20 +267,11 @@ $EndFeature, " ``` "), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } - } - doc_comment! { concat!("Returns the number of zeros in the binary representation of `self`. @@ -292,7 +283,6 @@ Basic usage: ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 1);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn count_zeros(self) -> u32 { @@ -300,16 +290,6 @@ Basic usage: } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentatio"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn count_zeros(self) -> u32 { - (!self).count_ones() - } - } - doc_comment! { concat!("Returns the number of leading zeros in the binary representation of `self`. @@ -324,7 +304,6 @@ assert_eq!(n.leading_zeros(), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn leading_zeros(self) -> u32 { @@ -332,16 +311,6 @@ $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn leading_zeros(self) -> u32 { - (self as $UnsignedT).leading_zeros() - } - } - doc_comment! { concat!("Returns the number of trailing zeros in the binary representation of `self`. @@ -356,7 +325,6 @@ assert_eq!(n.trailing_zeros(), 2);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn trailing_zeros(self) -> u32 { @@ -364,16 +332,6 @@ $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn trailing_zeros(self) -> u32 { - (self as $UnsignedT).trailing_zeros() - } - } - /// Shifts the bits to the left by a specified amount, `n`, /// wrapping the truncated bits to the end of the resulting integer. /// @@ -442,21 +400,12 @@ $EndFeature, " /// assert_eq!(m, 21760); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn swap_bytes(self) -> Self { (self as $UnsignedT).swap_bytes() as Self } - /// Dummy docs. See !stage0 documentation. - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn swap_bytes(self) -> Self { - (self as $UnsignedT).swap_bytes() as Self - } - /// Reverses the bit pattern of the integer. /// /// # Examples @@ -503,7 +452,6 @@ if cfg!(target_endian = \"big\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn from_be(x: Self) -> Self { @@ -518,16 +466,6 @@ $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn from_be(x: Self) -> Self { - if cfg!(target_endian = "big") { x } else { x.swap_bytes() } - } - } - doc_comment! { concat!("Converts an integer from little endian to the target's endianness. @@ -548,7 +486,6 @@ if cfg!(target_endian = \"little\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn from_le(x: Self) -> Self { @@ -563,16 +500,6 @@ $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn from_le(x: Self) -> Self { - if cfg!(target_endian = "little") { x } else { x.swap_bytes() } - } - } - doc_comment! { concat!("Converts `self` to big endian from the target's endianness. @@ -593,7 +520,6 @@ if cfg!(target_endian = \"big\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn to_be(self) -> Self { // or not to be? @@ -608,16 +534,6 @@ $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn to_be(self) -> Self { // or not to be? - if cfg!(target_endian = "big") { self } else { self.swap_bytes() } - } - } - doc_comment! { concat!("Converts `self` to little endian from the target's endianness. @@ -638,7 +554,6 @@ if cfg!(target_endian = \"little\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn to_le(self) -> Self { @@ -653,16 +568,6 @@ $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn to_le(self) -> Self { - if cfg!(target_endian = "little") { self } else { self.swap_bytes() } - } - } - doc_comment! { concat!("Checked integer addition. Computes `self + rhs`, returning `None` if overflow occurred. @@ -2161,7 +2066,6 @@ Basic usage: assert_eq!(n.count_ones(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn count_ones(self) -> u32 { @@ -2169,16 +2073,6 @@ assert_eq!(n.count_ones(), 3);", $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn count_ones(self) -> u32 { - unsafe { intrinsics::ctpop(self as $ActualT) as u32 } - } - } - doc_comment! { concat!("Returns the number of zeros in the binary representation of `self`. @@ -2190,7 +2084,6 @@ Basic usage: ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn count_zeros(self) -> u32 { @@ -2198,16 +2091,6 @@ Basic usage: } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn count_zeros(self) -> u32 { - (!self).count_ones() - } - } - doc_comment! { concat!("Returns the number of leading zeros in the binary representation of `self`. @@ -2221,7 +2104,6 @@ Basic usage: assert_eq!(n.leading_zeros(), 2);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn leading_zeros(self) -> u32 { @@ -2229,16 +2111,6 @@ assert_eq!(n.leading_zeros(), 2);", $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn leading_zeros(self) -> u32 { - unsafe { intrinsics::ctlz(self as $ActualT) as u32 } - } - } - doc_comment! { concat!("Returns the number of trailing zeros in the binary representation of `self`. @@ -2253,7 +2125,6 @@ Basic usage: assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn trailing_zeros(self) -> u32 { @@ -2261,16 +2132,6 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn trailing_zeros(self) -> u32 { - unsafe { uint_cttz_call!(self, $BITS) as u32 } - } - } - /// Shifts the bits to the left by a specified amount, `n`, /// wrapping the truncated bits to the end of the resulting integer. /// @@ -2343,21 +2204,12 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " /// assert_eq!(m, 21760); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn swap_bytes(self) -> Self { unsafe { intrinsics::bswap(self as $ActualT) as Self } } - /// Dummy docs. See !stage0 documentation. - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn swap_bytes(self) -> Self { - unsafe { intrinsics::bswap(self as $ActualT) as Self } - } - /// Reverses the bit pattern of the integer. /// /// # Examples @@ -2404,7 +2256,6 @@ if cfg!(target_endian = \"big\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn from_be(x: Self) -> Self { @@ -2419,16 +2270,6 @@ if cfg!(target_endian = \"big\") { } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn from_be(x: Self) -> Self { - if cfg!(target_endian = "big") { x } else { x.swap_bytes() } - } - } - doc_comment! { concat!("Converts an integer from little endian to the target's endianness. @@ -2449,7 +2290,6 @@ if cfg!(target_endian = \"little\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn from_le(x: Self) -> Self { @@ -2464,16 +2304,6 @@ if cfg!(target_endian = \"little\") { } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn from_le(x: Self) -> Self { - if cfg!(target_endian = "little") { x } else { x.swap_bytes() } - } - } - doc_comment! { concat!("Converts `self` to big endian from the target's endianness. @@ -2494,7 +2324,6 @@ if cfg!(target_endian = \"big\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn to_be(self) -> Self { // or not to be? @@ -2509,16 +2338,6 @@ if cfg!(target_endian = \"big\") { } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn to_be(self) -> Self { // or not to be? - if cfg!(target_endian = "big") { self } else { self.swap_bytes() } - } - } - doc_comment! { concat!("Converts `self` to little endian from the target's endianness. @@ -2539,7 +2358,6 @@ if cfg!(target_endian = \"little\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn to_le(self) -> Self { @@ -2554,16 +2372,6 @@ if cfg!(target_endian = \"little\") { } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn to_le(self) -> Self { - if cfg!(target_endian = "little") { self } else { self.swap_bytes() } - } - } - doc_comment! { concat!("Checked integer addition. Computes `self + rhs`, returning `None` if overflow occurred. diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index d7f87d37f5b..1c826c2fa76 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -531,7 +531,6 @@ assert_eq!(n.trailing_zeros(), 3); /// assert_eq!(m, Wrapping(-22016)); /// ``` #[unstable(feature = "reverse_bits", issue = "48763")] - #[cfg(not(stage0))] #[inline] pub fn reverse_bits(self) -> Self { Wrapping(self.0.reverse_bits()) diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 37ae05309af..1b4129b99fc 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -35,7 +35,7 @@ use fmt; /// /// panic!("Normal panic"); /// ``` -#[cfg_attr(not(stage0), lang = "panic_info")] +#[lang = "panic_info"] #[stable(feature = "panic_hooks", since = "1.10.0")] #[derive(Debug)] pub struct PanicInfo<'a> { diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 0d4f8d1141e..58407de9566 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -37,7 +37,6 @@ issue = "0")] use fmt; -#[cfg(not(stage0))] use panic::{Location, PanicInfo}; #[cold] #[inline(never)] // this is the slow path, always @@ -61,20 +60,6 @@ fn panic_bounds_check(file_line_col: &(&'static str, u32, u32), len, index), file_line_col) } -#[cfg(stage0)] -#[cold] #[inline(never)] -pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { - #[allow(improper_ctypes)] - extern { - #[lang = "panic_fmt"] - #[unwind(allowed)] - fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32, col: u32) -> !; - } - let (file, line, col) = *file_line_col; - unsafe { panic_impl(fmt, file, line, col) } -} - -#[cfg(not(stage0))] #[cold] #[inline(never)] pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 81a8b3ef047..164b29d3515 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -1243,7 +1243,6 @@ impl *const T { /// # } } /// ``` #[unstable(feature = "align_offset", issue = "44488")] - #[cfg(not(stage0))] pub fn align_offset(self, align: usize) -> usize where T: Sized { if !align.is_power_of_two() { panic!("align_offset: align is not a power-of-two"); @@ -1252,18 +1251,6 @@ impl *const T { align_offset(self, align) } } - - /// definitely docs. - #[unstable(feature = "align_offset", issue = "44488")] - #[cfg(stage0)] - pub fn align_offset(self, align: usize) -> usize where T: Sized { - if !align.is_power_of_two() { - panic!("align_offset: align is not a power-of-two"); - } - unsafe { - intrinsics::align_offset(self as *const (), align) - } - } } @@ -2308,7 +2295,6 @@ impl *mut T { /// # } } /// ``` #[unstable(feature = "align_offset", issue = "44488")] - #[cfg(not(stage0))] pub fn align_offset(self, align: usize) -> usize where T: Sized { if !align.is_power_of_two() { panic!("align_offset: align is not a power-of-two"); @@ -2317,18 +2303,6 @@ impl *mut T { align_offset(self, align) } } - - /// definitely docs. - #[unstable(feature = "align_offset", issue = "44488")] - #[cfg(stage0)] - pub fn align_offset(self, align: usize) -> usize where T: Sized { - if !align.is_power_of_two() { - panic!("align_offset: align is not a power-of-two"); - } - unsafe { - intrinsics::align_offset(self as *const (), align) - } - } } /// Align pointer `p`. @@ -2346,7 +2320,6 @@ impl *mut T { /// /// Any questions go to @nagisa. #[lang="align_offset"] -#[cfg(not(stage0))] pub(crate) unsafe fn align_offset(p: *const T, a: usize) -> usize { /// Calculate multiplicative modular inverse of `x` modulo `m`. /// diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index e74e527927d..bcac9322ae8 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1708,7 +1708,6 @@ impl [T] { } /// Function to calculate lenghts of the middle and trailing slice for `align_to{,_mut}`. - #[cfg(not(stage0))] fn align_to_offsets(&self) -> (usize, usize) { // What we gonna do about `rest` is figure out what multiple of `U`s we can put in a // lowest number of `T`s. And how many `T`s we need for each such "multiple". @@ -1798,7 +1797,6 @@ impl [T] { /// } /// ``` #[unstable(feature = "slice_align_to", issue = "44488")] - #[cfg(not(stage0))] pub unsafe fn align_to(&self) -> (&[T], &[U], &[T]) { // Note that most of this function will be constant-evaluated, if ::mem::size_of::() == 0 || ::mem::size_of::() == 0 { @@ -1851,7 +1849,6 @@ impl [T] { /// } /// ``` #[unstable(feature = "slice_align_to", issue = "44488")] - #[cfg(not(stage0))] pub unsafe fn align_to_mut(&mut self) -> (&mut [T], &mut [U], &mut [T]) { // Note that most of this function will be constant-evaluated, if ::mem::size_of::() == 0 || ::mem::size_of::() == 0 { diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 102efe2bef3..95e2d0e2edb 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -49,7 +49,6 @@ #![feature(fs_read_write)] #![feature(iterator_find_map)] #![cfg_attr(windows, feature(libc))] -#![cfg_attr(stage0, feature(macro_lifetime_matcher))] #![feature(macro_vis_matcher)] #![feature(never_type)] #![feature(exhaustive_patterns)] diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs index a7aeed76309..0c78fd74a23 100644 --- a/src/librustc_asan/lib.rs +++ b/src/librustc_asan/lib.rs @@ -10,7 +10,6 @@ #![sanitizer_runtime] #![feature(alloc_system)] -#![cfg_attr(stage0, feature(global_allocator))] #![feature(sanitizer_runtime)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_lsan/lib.rs b/src/librustc_lsan/lib.rs index a7aeed76309..0c78fd74a23 100644 --- a/src/librustc_lsan/lib.rs +++ b/src/librustc_lsan/lib.rs @@ -10,7 +10,6 @@ #![sanitizer_runtime] #![feature(alloc_system)] -#![cfg_attr(stage0, feature(global_allocator))] #![feature(sanitizer_runtime)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 0fbedcaff6e..dad1030cb61 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -16,7 +16,6 @@ #![feature(fs_read_write)] #![feature(libc)] #![feature(macro_at_most_once_rep)] -#![cfg_attr(stage0, feature(macro_lifetime_matcher))] #![feature(proc_macro_internals)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_msan/lib.rs b/src/librustc_msan/lib.rs index a7aeed76309..0c78fd74a23 100644 --- a/src/librustc_msan/lib.rs +++ b/src/librustc_msan/lib.rs @@ -10,7 +10,6 @@ #![sanitizer_runtime] #![feature(alloc_system)] -#![cfg_attr(stage0, feature(global_allocator))] #![feature(sanitizer_runtime)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 89d30fd666a..4c9cdc1e6d3 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -12,7 +12,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(custom_attribute)] -#![cfg_attr(stage0, feature(macro_lifetime_matcher))] #![allow(unused_attributes)] #![recursion_limit="256"] diff --git a/src/librustc_tsan/lib.rs b/src/librustc_tsan/lib.rs index a7aeed76309..0c78fd74a23 100644 --- a/src/librustc_tsan/lib.rs +++ b/src/librustc_tsan/lib.rs @@ -10,7 +10,6 @@ #![sanitizer_runtime] #![feature(alloc_system)] -#![cfg_attr(stage0, feature(global_allocator))] #![feature(sanitizer_runtime)] #![feature(staged_api)] #![no_std] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index caad924ea5b..d73cb1f8349 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -322,7 +322,7 @@ #![feature(doc_keyword)] #![feature(float_internals)] #![feature(panic_info_message)] -#![cfg_attr(not(stage0), feature(panic_implementation))] +#![feature(panic_implementation)] #![default_lib_allocator] @@ -332,9 +332,6 @@ // `force_alloc_system` is *only* intended as a workaround for local rebuilds // with a rustc without jemalloc. // FIXME(#44236) shouldn't need MSVC logic -#![cfg_attr(all(not(target_env = "msvc"), - any(all(stage0, not(test)), feature = "force_alloc_system")), - feature(global_allocator))] #[cfg(all(not(target_env = "msvc"), any(all(stage0, not(test)), feature = "force_alloc_system")))] #[global_allocator] diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 0808efa2ece..46b6cf60705 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -319,18 +319,6 @@ pub fn panicking() -> bool { /// Entry point of panic from the libcore crate. #[cfg(not(test))] -#[cfg(stage0)] -#[lang = "panic_fmt"] -pub extern fn rust_begin_panic(msg: fmt::Arguments, - file: &'static str, - line: u32, - col: u32) -> ! { - begin_panic_fmt(&msg, &(file, line, col)) -} - -/// Entry point of panic from the libcore crate. -#[cfg(not(test))] -#[cfg(not(stage0))] #[panic_implementation] #[unwind(allowed)] pub fn rust_begin_panic(info: &PanicInfo) -> ! { @@ -343,78 +331,54 @@ pub fn rust_begin_panic(info: &PanicInfo) -> ! { /// site as much as possible (so that `panic!()` has as low an impact /// on (e.g.) the inlining of other functions as possible), by moving /// the actual formatting into this shared place. -#[cfg(stage0)] #[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "0")] #[inline(never)] #[cold] pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { - // We do two allocations here, unfortunately. But (a) they're - // required with the current scheme, and (b) we don't handle - // panic + OOM properly anyway (see comment in begin_panic - // below). - - rust_panic_with_hook(&mut PanicPayload::new(msg), Some(msg), file_line_col); -} - -// NOTE(stage0) move into `continue_panic_fmt` on next stage0 update -struct PanicPayload<'a> { - inner: &'a fmt::Arguments<'a>, - string: Option, + let (file, line, col) = *file_line_col; + let info = PanicInfo::internal_constructor( + Some(msg), + Location::internal_constructor(file, line, col), + ); + continue_panic_fmt(&info) } -impl<'a> PanicPayload<'a> { - fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> { - PanicPayload { inner, string: None } +fn continue_panic_fmt(info: &PanicInfo) -> ! { + struct PanicPayload<'a> { + inner: &'a fmt::Arguments<'a>, + string: Option, } - fn fill(&mut self) -> &mut String { - use fmt::Write; + impl<'a> PanicPayload<'a> { + fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> { + PanicPayload { inner, string: None } + } - let inner = self.inner; - self.string.get_or_insert_with(|| { - let mut s = String::new(); - drop(s.write_fmt(*inner)); - s - }) - } -} + fn fill(&mut self) -> &mut String { + use fmt::Write; -unsafe impl<'a> BoxMeUp for PanicPayload<'a> { - fn box_me_up(&mut self) -> *mut (Any + Send) { - let contents = mem::replace(self.fill(), String::new()); - Box::into_raw(Box::new(contents)) + let inner = self.inner; + self.string.get_or_insert_with(|| { + let mut s = String::new(); + drop(s.write_fmt(*inner)); + s + }) + } } - fn get(&mut self) -> &(Any + Send) { - self.fill() - } -} + unsafe impl<'a> BoxMeUp for PanicPayload<'a> { + fn box_me_up(&mut self) -> *mut (Any + Send) { + let contents = mem::replace(self.fill(), String::new()); + Box::into_raw(Box::new(contents)) + } -/// The entry point for panicking with a formatted message. -/// -/// This is designed to reduce the amount of code required at the call -/// site as much as possible (so that `panic!()` has as low an impact -/// on (e.g.) the inlining of other functions as possible), by moving -/// the actual formatting into this shared place. -#[cfg(not(stage0))] -#[unstable(feature = "libstd_sys_internals", - reason = "used by the panic! macro", - issue = "0")] -#[inline(never)] #[cold] -pub fn begin_panic_fmt(msg: &fmt::Arguments, - file_line_col: &(&'static str, u32, u32)) -> ! { - let (file, line, col) = *file_line_col; - let info = PanicInfo::internal_constructor( - Some(msg), - Location::internal_constructor(file, line, col), - ); - continue_panic_fmt(&info) -} + fn get(&mut self) -> &(Any + Send) { + self.fill() + } + } -#[cfg(not(stage0))] -fn continue_panic_fmt(info: &PanicInfo) -> ! { // We do two allocations here, unfortunately. But (a) they're // required with the current scheme, and (b) we don't handle // panic + OOM properly anyway (see comment in begin_panic diff --git a/src/stage0.txt b/src/stage0.txt index 435cfd2f6db..538f3a85176 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.x.0` for Cargo where they were released on `date`. -date: 2018-05-10 +date: 2018-06-30 rustc: beta cargo: beta diff --git a/src/tools/cargo b/src/tools/cargo index e2348c2db29..5699afe508d 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit e2348c2db296ce33428933c3ab8786d5f3c54a2e +Subproject commit 5699afe508d62924f6b38b19dc98296ad33d1659 diff --git a/src/tools/rust-installer b/src/tools/rust-installer index 118e078c5ba..89414e44dc9 160000 --- a/src/tools/rust-installer +++ b/src/tools/rust-installer @@ -1 +1 @@ -Subproject commit 118e078c5badd520d18b92813fd88789c8d341ab +Subproject commit 89414e44dc94844888e59c08bc31dcccb1792800 -- cgit 1.4.1-3-g733a5 From 3d43f828f5f1261b88f00582074f6cd021f31614 Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Sat, 30 Jun 2018 17:26:38 +0200 Subject: Make custom trait object for `Future` generic --- src/liballoc/boxed.rs | 30 ++++---- src/libcore/task/executor.rs | 8 +-- src/libcore/task/future_obj.rs | 147 +++++++++++++++++++++++++++++++++++++++ src/libcore/task/mod.rs | 4 +- src/libcore/task/task.rs | 142 ------------------------------------- src/test/run-pass/async-await.rs | 4 +- src/test/run-pass/futures-api.rs | 4 +- 7 files changed, 172 insertions(+), 167 deletions(-) create mode 100644 src/libcore/task/future_obj.rs delete mode 100644 src/libcore/task/task.rs (limited to 'src/libcore') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 6a05ef68088..c1778ef101a 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -66,7 +66,7 @@ use core::marker::{Unpin, Unsize}; use core::mem::{self, PinMut}; use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; use core::ptr::{self, NonNull, Unique}; -use core::task::{Context, Poll, UnsafeTask, TaskObj, LocalTaskObj}; +use core::task::{Context, Poll, UnsafeFutureObj, FutureObj, LocalFutureObj}; use core::convert::From; use raw_vec::RawVec; @@ -933,12 +933,12 @@ impl<'a, F: ?Sized + Future> Future for PinBox { } #[unstable(feature = "futures_api", issue = "50547")] -unsafe impl + 'static> UnsafeTask for PinBox { +unsafe impl + 'static> UnsafeFutureObj for PinBox { fn into_raw(self) -> *mut () { PinBox::into_raw(self) as *mut () } - unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()> { + unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll { let ptr = task as *mut F; let pin: PinMut = PinMut::new_unchecked(&mut *ptr); pin.poll(cx) @@ -950,29 +950,29 @@ unsafe impl + 'static> UnsafeTask for PinBox { } #[unstable(feature = "futures_api", issue = "50547")] -impl + Send + 'static> From> for TaskObj { - fn from(boxed: PinBox) -> Self { - TaskObj::new(boxed) +impl + Send + 'static> Into> for PinBox { + fn into(self) -> FutureObj { + FutureObj::new(self) } } #[unstable(feature = "futures_api", issue = "50547")] -impl + Send + 'static> From> for TaskObj { - fn from(boxed: Box) -> Self { - TaskObj::new(PinBox::from(boxed)) +impl + Send + 'static> Into> for Box { + fn into(self) -> FutureObj { + FutureObj::new(PinBox::from(self)) } } #[unstable(feature = "futures_api", issue = "50547")] -impl + 'static> From> for LocalTaskObj { - fn from(boxed: PinBox) -> Self { - LocalTaskObj::new(boxed) +impl + 'static> Into> for PinBox { + fn into(self) -> LocalFutureObj { + LocalFutureObj::new(self) } } #[unstable(feature = "futures_api", issue = "50547")] -impl + 'static> From> for LocalTaskObj { - fn from(boxed: Box) -> Self { - LocalTaskObj::new(PinBox::from(boxed)) +impl + 'static> Into> for Box { + fn into(self) -> LocalFutureObj { + LocalFutureObj::new(PinBox::from(self)) } } diff --git a/src/libcore/task/executor.rs b/src/libcore/task/executor.rs index 73bf80d2f99..55ea5e724c1 100644 --- a/src/libcore/task/executor.rs +++ b/src/libcore/task/executor.rs @@ -13,7 +13,7 @@ issue = "50547")] use fmt; -use super::{TaskObj, LocalTaskObj}; +use super::{FutureObj, LocalFutureObj}; /// A task executor. /// @@ -29,7 +29,7 @@ pub trait Executor { /// /// The executor may be unable to spawn tasks, either because it has /// been shut down or is resource-constrained. - fn spawn_obj(&mut self, task: TaskObj) -> Result<(), SpawnObjError>; + fn spawn_obj(&mut self, task: FutureObj<()>) -> Result<(), SpawnObjError>; /// Determine whether the executor is able to spawn new tasks. /// @@ -76,7 +76,7 @@ pub struct SpawnObjError { pub kind: SpawnErrorKind, /// The task for which spawning was attempted - pub task: TaskObj, + pub task: FutureObj<()>, } /// The result of a failed spawn @@ -86,5 +86,5 @@ pub struct SpawnLocalObjError { pub kind: SpawnErrorKind, /// The task for which spawning was attempted - pub task: LocalTaskObj, + pub task: LocalFutureObj<()>, } diff --git a/src/libcore/task/future_obj.rs b/src/libcore/task/future_obj.rs new file mode 100644 index 00000000000..3ed3bd51cf6 --- /dev/null +++ b/src/libcore/task/future_obj.rs @@ -0,0 +1,147 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use fmt; +use future::Future; +use marker::PhantomData; +use mem::PinMut; +use task::{Context, Poll}; + +/// A custom trait object for polling futures, roughly akin to +/// `Box>`. +/// Contrary to `FutureObj`, `LocalFutureObj` does not have a `Send` bound. +pub struct LocalFutureObj { + ptr: *mut (), + poll_fn: unsafe fn(*mut (), &mut Context) -> Poll, + drop_fn: unsafe fn(*mut ()), + _marker: PhantomData, +} + +impl LocalFutureObj { + /// Create a `LocalFutureObj` from a custom trait object representation. + #[inline] + pub fn new>(f: F) -> LocalFutureObj { + LocalFutureObj { + ptr: f.into_raw(), + poll_fn: F::poll, + drop_fn: F::drop, + _marker: PhantomData, + } + } + + /// Converts the `LocalFutureObj` into a `FutureObj` + /// To make this operation safe one has to ensure that the `UnsafeFutureObj` + /// instance from which this `LocalFutureObj` was created actually + /// implements `Send`. + #[inline] + pub unsafe fn as_future_obj(self) -> FutureObj { + FutureObj(self) + } +} + +impl fmt::Debug for LocalFutureObj { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("LocalFutureObj") + .finish() + } +} + +impl From> for LocalFutureObj { + #[inline] + fn from(f: FutureObj) -> LocalFutureObj { + f.0 + } +} + +impl Future for LocalFutureObj { + type Output = T; + + #[inline] + fn poll(self: PinMut, cx: &mut Context) -> Poll { + unsafe { + (self.poll_fn)(self.ptr, cx) + } + } +} + +impl Drop for LocalFutureObj { + fn drop(&mut self) { + unsafe { + (self.drop_fn)(self.ptr) + } + } +} + +/// A custom trait object for polling futures, roughly akin to +/// `Box> + Send`. +pub struct FutureObj(LocalFutureObj); + +unsafe impl Send for FutureObj {} + +impl FutureObj { + /// Create a `FutureObj` from a custom trait object representation. + #[inline] + pub fn new + Send>(f: F) -> FutureObj { + FutureObj(LocalFutureObj::new(f)) + } +} + +impl fmt::Debug for FutureObj { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("FutureObj") + .finish() + } +} + +impl Future for FutureObj { + type Output = T; + + #[inline] + fn poll(self: PinMut, cx: &mut Context) -> Poll { + let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) }; + pinned_field.poll(cx) + } +} + +/// A custom implementation of a future trait object for `FutureObj`, providing +/// a hand-rolled vtable. +/// +/// This custom representation is typically used only in `no_std` contexts, +/// where the default `Box`-based implementation is not available. +/// +/// The implementor must guarantee that it is safe to call `poll` repeatedly (in +/// a non-concurrent fashion) with the result of `into_raw` until `drop` is +/// called. +pub unsafe trait UnsafeFutureObj: 'static { + /// Convert a owned instance into a (conceptually owned) void pointer. + fn into_raw(self) -> *mut (); + + /// Poll the future represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to repeatedly call + /// `poll` with the result of `into_raw` until `drop` is called; such calls + /// are not, however, allowed to race with each other or with calls to `drop`. + unsafe fn poll(future: *mut (), cx: &mut Context) -> Poll; + + /// Drops the future represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to call this + /// function once per `into_raw` invocation; that call cannot race with + /// other calls to `drop` or `poll`. + unsafe fn drop(future: *mut ()); +} diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index d167a374105..06cd7a9dd77 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -25,8 +25,8 @@ pub use self::executor::{ mod poll; pub use self::poll::Poll; -mod task; -pub use self::task::{TaskObj, LocalTaskObj, UnsafeTask}; +mod future_obj; +pub use self::future_obj::{FutureObj, LocalFutureObj, UnsafeFutureObj}; mod wake; pub use self::wake::{Waker, LocalWaker, UnsafeWake}; diff --git a/src/libcore/task/task.rs b/src/libcore/task/task.rs deleted file mode 100644 index c5a41873db4..00000000000 --- a/src/libcore/task/task.rs +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] - -use fmt; -use future::Future; -use mem::PinMut; -use super::{Context, Poll}; - -/// A custom trait object for polling tasks, roughly akin to -/// `Box>`. -/// Contrary to `TaskObj`, `LocalTaskObj` does not have a `Send` bound. -pub struct LocalTaskObj { - ptr: *mut (), - poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<()>, - drop_fn: unsafe fn(*mut ()), -} - -impl LocalTaskObj { - /// Create a `LocalTaskObj` from a custom trait object representation. - #[inline] - pub fn new(t: T) -> LocalTaskObj { - LocalTaskObj { - ptr: t.into_raw(), - poll_fn: T::poll, - drop_fn: T::drop, - } - } - - /// Converts the `LocalTaskObj` into a `TaskObj` - /// To make this operation safe one has to ensure that the `UnsafeTask` - /// instance from which this `LocalTaskObj` was created actually implements - /// `Send`. - pub unsafe fn as_task_obj(self) -> TaskObj { - TaskObj(self) - } -} - -impl fmt::Debug for LocalTaskObj { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("LocalTaskObj") - .finish() - } -} - -impl From for LocalTaskObj { - fn from(task: TaskObj) -> LocalTaskObj { - task.0 - } -} - -impl Future for LocalTaskObj { - type Output = (); - - #[inline] - fn poll(self: PinMut, cx: &mut Context) -> Poll<()> { - unsafe { - (self.poll_fn)(self.ptr, cx) - } - } -} - -impl Drop for LocalTaskObj { - fn drop(&mut self) { - unsafe { - (self.drop_fn)(self.ptr) - } - } -} - -/// A custom trait object for polling tasks, roughly akin to -/// `Box + Send>`. -pub struct TaskObj(LocalTaskObj); - -unsafe impl Send for TaskObj {} - -impl TaskObj { - /// Create a `TaskObj` from a custom trait object representation. - #[inline] - pub fn new(t: T) -> TaskObj { - TaskObj(LocalTaskObj::new(t)) - } -} - -impl fmt::Debug for TaskObj { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("TaskObj") - .finish() - } -} - -impl Future for TaskObj { - type Output = (); - - #[inline] - fn poll(self: PinMut, cx: &mut Context) -> Poll<()> { - let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) }; - pinned_field.poll(cx) - } -} - -/// A custom implementation of a task trait object for `TaskObj`, providing -/// a hand-rolled vtable. -/// -/// This custom representation is typically used only in `no_std` contexts, -/// where the default `Box`-based implementation is not available. -/// -/// The implementor must guarantee that it is safe to call `poll` repeatedly (in -/// a non-concurrent fashion) with the result of `into_raw` until `drop` is -/// called. -pub unsafe trait UnsafeTask: 'static { - /// Convert a owned instance into a (conceptually owned) void pointer. - fn into_raw(self) -> *mut (); - - /// Poll the task represented by the given void pointer. - /// - /// # Safety - /// - /// The trait implementor must guarantee that it is safe to repeatedly call - /// `poll` with the result of `into_raw` until `drop` is called; such calls - /// are not, however, allowed to race with each other or with calls to `drop`. - unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()>; - - /// Drops the task represented by the given void pointer. - /// - /// # Safety - /// - /// The trait implementor must guarantee that it is safe to call this - /// function once per `into_raw` invocation; that call cannot race with - /// other calls to `drop` or `poll`. - unsafe fn drop(task: *mut ()); -} diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs index 8b649f6ef7b..3a67750e77e 100644 --- a/src/test/run-pass/async-await.rs +++ b/src/test/run-pass/async-await.rs @@ -21,7 +21,7 @@ use std::sync::{ }; use std::task::{ Context, Poll, Wake, - Executor, TaskObj, SpawnObjError, + Executor, FutureObj, SpawnObjError, local_waker_from_nonlocal, }; @@ -37,7 +37,7 @@ impl Wake for Counter { struct NoopExecutor; impl Executor for NoopExecutor { - fn spawn_obj(&mut self, _: TaskObj) -> Result<(), SpawnObjError> { + fn spawn_obj(&mut self, _: FutureObj) -> Result<(), SpawnObjError> { Ok(()) } } diff --git a/src/test/run-pass/futures-api.rs b/src/test/run-pass/futures-api.rs index 3b5a1725b66..a427b82af6a 100644 --- a/src/test/run-pass/futures-api.rs +++ b/src/test/run-pass/futures-api.rs @@ -22,7 +22,7 @@ use std::sync::{ use std::task::{ Context, Poll, Wake, Waker, LocalWaker, - Executor, TaskObj, SpawnObjError, + Executor, FutureObj, SpawnObjError, local_waker, local_waker_from_nonlocal, }; @@ -44,7 +44,7 @@ impl Wake for Counter { struct NoopExecutor; impl Executor for NoopExecutor { - fn spawn_obj(&mut self, _: TaskObj) -> Result<(), SpawnObjError> { + fn spawn_obj(&mut self, _: FutureObj<()>) -> Result<(), SpawnObjError> { Ok(()) } } -- cgit 1.4.1-3-g733a5 From d8bf2223672973f9d86f6c173793bcfce7890cd8 Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Sat, 30 Jun 2018 21:16:44 +0200 Subject: Add lifetime to `FutureObj` --- src/liballoc/boxed.rs | 17 ++--- src/libcore/future.rs | 114 ------------------------------ src/libcore/future/future.rs | 112 +++++++++++++++++++++++++++++ src/libcore/future/future_obj.rs | 149 +++++++++++++++++++++++++++++++++++++++ src/libcore/future/mod.rs | 21 ++++++ src/libcore/task/executor.rs | 8 +-- src/libcore/task/future_obj.rs | 147 -------------------------------------- src/libcore/task/mod.rs | 3 - src/test/run-pass/async-await.rs | 5 +- src/test/run-pass/futures-api.rs | 5 +- 10 files changed, 301 insertions(+), 280 deletions(-) delete mode 100644 src/libcore/future.rs create mode 100644 src/libcore/future/future.rs create mode 100644 src/libcore/future/future_obj.rs create mode 100644 src/libcore/future/mod.rs delete mode 100644 src/libcore/task/future_obj.rs (limited to 'src/libcore') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 918ad657be9..5984a992afc 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -66,7 +66,8 @@ use core::marker::{Unpin, Unsize}; use core::mem::{self, PinMut}; use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; use core::ptr::{self, NonNull, Unique}; -use core::task::{Context, Poll, UnsafeFutureObj, FutureObj, LocalFutureObj}; +use core::future::{FutureObj, LocalFutureObj, UnsafeFutureObj}; +use core::task::{Context, Poll}; use core::convert::From; use raw_vec::RawVec; @@ -915,7 +916,7 @@ impl, U: ?Sized> CoerceUnsized> for PinBox {} impl Unpin for PinBox {} #[unstable(feature = "futures_api", issue = "50547")] -impl<'a, F: ?Sized + Future + Unpin> Future for Box { +impl Future for Box { type Output = F::Output; fn poll(mut self: PinMut, cx: &mut Context) -> Poll { @@ -924,7 +925,7 @@ impl<'a, F: ?Sized + Future + Unpin> Future for Box { } #[unstable(feature = "futures_api", issue = "50547")] -impl<'a, F: ?Sized + Future> Future for PinBox { +impl Future for PinBox { type Output = F::Output; fn poll(mut self: PinMut, cx: &mut Context) -> Poll { @@ -933,7 +934,7 @@ impl<'a, F: ?Sized + Future> Future for PinBox { } #[unstable(feature = "futures_api", issue = "50547")] -unsafe impl + 'static> UnsafeFutureObj for PinBox { +unsafe impl<'a, T, F: Future + 'a> UnsafeFutureObj<'a, T> for PinBox { fn into_raw(self) -> *mut () { PinBox::into_raw(self) as *mut () } @@ -950,28 +951,28 @@ unsafe impl + 'static> UnsafeFutureObj for PinBox } #[unstable(feature = "futures_api", issue = "50547")] -impl + Send + 'static> From> for FutureObj<()> { +impl<'a, F: Future + Send + 'a> From> for FutureObj<'a, ()> { fn from(boxed: PinBox) -> Self { FutureObj::new(boxed) } } #[unstable(feature = "futures_api", issue = "50547")] -impl + Send + 'static> From> for FutureObj<()> { +impl<'a, F: Future + Send + 'a> From> for FutureObj<'a, ()> { fn from(boxed: Box) -> Self { FutureObj::new(PinBox::from(boxed)) } } #[unstable(feature = "futures_api", issue = "50547")] -impl + 'static> From> for LocalFutureObj<()> { +impl<'a, F: Future + 'a> From> for LocalFutureObj<'a, ()> { fn from(boxed: PinBox) -> Self { LocalFutureObj::new(boxed) } } #[unstable(feature = "futures_api", issue = "50547")] -impl + 'static> From> for LocalFutureObj<()> { +impl<'a, F: Future + 'a> From> for LocalFutureObj<'a, ()> { fn from(boxed: Box) -> Self { LocalFutureObj::new(PinBox::from(boxed)) } diff --git a/src/libcore/future.rs b/src/libcore/future.rs deleted file mode 100644 index 153cd6c0724..00000000000 --- a/src/libcore/future.rs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] - -//! Asynchronous values. - -use mem::PinMut; -use marker::Unpin; -use task::{self, Poll}; - -/// A future represents an asychronous computation. -/// -/// A future is a value that may not have finished computing yet. This kind of -/// "asynchronous value" makes it possible for a thread to continue doing useful -/// work while it waits for the value to become available. -/// -/// # The `poll` method -/// -/// The core method of future, `poll`, *attempts* to resolve the future into a -/// final value. This method does not block if the value is not ready. Instead, -/// the current task is scheduled to be woken up when it's possible to make -/// further progress by `poll`ing again. The wake up is performed using -/// `cx.waker()`, a handle for waking up the current task. -/// -/// When using a future, you generally won't call `poll` directly, but instead -/// `await!` the value. -pub trait Future { - /// The result of the `Future`. - type Output; - - /// Attempt to resolve the future to a final value, registering - /// the current task for wakeup if the value is not yet available. - /// - /// # Return value - /// - /// This function returns: - /// - /// - [`Poll::Pending`] if the future is not ready yet - /// - [`Poll::Ready(val)`] with the result `val` of this future if it - /// finished successfully. - /// - /// Once a future has finished, clients should not `poll` it again. - /// - /// When a future is not ready yet, `poll` returns - /// `Poll::Pending`. The future will *also* register the - /// interest of the current task in the value being produced. For example, - /// if the future represents the availability of data on a socket, then the - /// task is recorded so that when data arrives, it is woken up (via - /// [`cx.waker()`]). Once a task has been woken up, - /// it should attempt to `poll` the future again, which may or may not - /// produce a final value. - /// - /// Note that if `Pending` is returned it only means that the *current* task - /// (represented by the argument `cx`) will receive a notification. Tasks - /// from previous calls to `poll` will *not* receive notifications. - /// - /// # Runtime characteristics - /// - /// Futures alone are *inert*; they must be *actively* `poll`ed to make - /// progress, meaning that each time the current task is woken up, it should - /// actively re-`poll` pending futures that it still has an interest in. - /// - /// The `poll` function is not called repeatedly in a tight loop for - /// futures, but only whenever the future itself is ready, as signaled via - /// the `Waker` inside `task::Context`. If you're familiar with the - /// `poll(2)` or `select(2)` syscalls on Unix it's worth noting that futures - /// typically do *not* suffer the same problems of "all wakeups must poll - /// all events"; they are more like `epoll(4)`. - /// - /// An implementation of `poll` should strive to return quickly, and must - /// *never* block. Returning quickly prevents unnecessarily clogging up - /// threads or event loops. If it is known ahead of time that a call to - /// `poll` may end up taking awhile, the work should be offloaded to a - /// thread pool (or something similar) to ensure that `poll` can return - /// quickly. - /// - /// # Panics - /// - /// Once a future has completed (returned `Ready` from `poll`), - /// then any future calls to `poll` may panic, block forever, or otherwise - /// cause bad behavior. The `Future` trait itself provides no guarantees - /// about the behavior of `poll` after a future has completed. - /// - /// [`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending - /// [`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready - /// [`cx.waker()`]: ../task/struct.Context.html#method.waker - fn poll(self: PinMut, cx: &mut task::Context) -> Poll; -} - -impl<'a, F: ?Sized + Future + Unpin> Future for &'a mut F { - type Output = F::Output; - - fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { - F::poll(PinMut::new(&mut **self), cx) - } -} - -impl<'a, F: ?Sized + Future> Future for PinMut<'a, F> { - type Output = F::Output; - - fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { - F::poll((*self).reborrow(), cx) - } -} diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs new file mode 100644 index 00000000000..10b4ca9b0b2 --- /dev/null +++ b/src/libcore/future/future.rs @@ -0,0 +1,112 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use mem::PinMut; +use marker::Unpin; +use task::{self, Poll}; + +/// A future represents an asychronous computation. +/// +/// A future is a value that may not have finished computing yet. This kind of +/// "asynchronous value" makes it possible for a thread to continue doing useful +/// work while it waits for the value to become available. +/// +/// # The `poll` method +/// +/// The core method of future, `poll`, *attempts* to resolve the future into a +/// final value. This method does not block if the value is not ready. Instead, +/// the current task is scheduled to be woken up when it's possible to make +/// further progress by `poll`ing again. The wake up is performed using +/// `cx.waker()`, a handle for waking up the current task. +/// +/// When using a future, you generally won't call `poll` directly, but instead +/// `await!` the value. +pub trait Future { + /// The result of the `Future`. + type Output; + + /// Attempt to resolve the future to a final value, registering + /// the current task for wakeup if the value is not yet available. + /// + /// # Return value + /// + /// This function returns: + /// + /// - [`Poll::Pending`] if the future is not ready yet + /// - [`Poll::Ready(val)`] with the result `val` of this future if it + /// finished successfully. + /// + /// Once a future has finished, clients should not `poll` it again. + /// + /// When a future is not ready yet, `poll` returns + /// `Poll::Pending`. The future will *also* register the + /// interest of the current task in the value being produced. For example, + /// if the future represents the availability of data on a socket, then the + /// task is recorded so that when data arrives, it is woken up (via + /// [`cx.waker()`]). Once a task has been woken up, + /// it should attempt to `poll` the future again, which may or may not + /// produce a final value. + /// + /// Note that if `Pending` is returned it only means that the *current* task + /// (represented by the argument `cx`) will receive a notification. Tasks + /// from previous calls to `poll` will *not* receive notifications. + /// + /// # Runtime characteristics + /// + /// Futures alone are *inert*; they must be *actively* `poll`ed to make + /// progress, meaning that each time the current task is woken up, it should + /// actively re-`poll` pending futures that it still has an interest in. + /// + /// The `poll` function is not called repeatedly in a tight loop for + /// futures, but only whenever the future itself is ready, as signaled via + /// the `Waker` inside `task::Context`. If you're familiar with the + /// `poll(2)` or `select(2)` syscalls on Unix it's worth noting that futures + /// typically do *not* suffer the same problems of "all wakeups must poll + /// all events"; they are more like `epoll(4)`. + /// + /// An implementation of `poll` should strive to return quickly, and must + /// *never* block. Returning quickly prevents unnecessarily clogging up + /// threads or event loops. If it is known ahead of time that a call to + /// `poll` may end up taking awhile, the work should be offloaded to a + /// thread pool (or something similar) to ensure that `poll` can return + /// quickly. + /// + /// # Panics + /// + /// Once a future has completed (returned `Ready` from `poll`), + /// then any future calls to `poll` may panic, block forever, or otherwise + /// cause bad behavior. The `Future` trait itself provides no guarantees + /// about the behavior of `poll` after a future has completed. + /// + /// [`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending + /// [`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready + /// [`cx.waker()`]: ../task/struct.Context.html#method.waker + fn poll(self: PinMut, cx: &mut task::Context) -> Poll; +} + +impl<'a, F: ?Sized + Future + Unpin> Future for &'a mut F { + type Output = F::Output; + + fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { + F::poll(PinMut::new(&mut **self), cx) + } +} + +impl<'a, F: ?Sized + Future> Future for PinMut<'a, F> { + type Output = F::Output; + + fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { + F::poll((*self).reborrow(), cx) + } +} diff --git a/src/libcore/future/future_obj.rs b/src/libcore/future/future_obj.rs new file mode 100644 index 00000000000..c60b8b97d34 --- /dev/null +++ b/src/libcore/future/future_obj.rs @@ -0,0 +1,149 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use fmt; +use future::Future; +use marker::PhantomData; +use mem::PinMut; +use task::{Context, Poll}; + +/// A custom trait object for polling futures, roughly akin to +/// `Box>`. +/// Contrary to `FutureObj`, `LocalFutureObj` does not have a `Send` bound. +pub struct LocalFutureObj<'a, T> { + ptr: *mut (), + poll_fn: unsafe fn(*mut (), &mut Context) -> Poll, + drop_fn: unsafe fn(*mut ()), + _marker1: PhantomData, + _marker2: PhantomData<&'a ()>, +} + +impl<'a, T> LocalFutureObj<'a, T> { + /// Create a `LocalFutureObj` from a custom trait object representation. + #[inline] + pub fn new + 'a>(f: F) -> LocalFutureObj<'a, T> { + LocalFutureObj { + ptr: f.into_raw(), + poll_fn: F::poll, + drop_fn: F::drop, + _marker1: PhantomData, + _marker2: PhantomData, + } + } + + /// Converts the `LocalFutureObj` into a `FutureObj` + /// To make this operation safe one has to ensure that the `UnsafeFutureObj` + /// instance from which this `LocalFutureObj` was created actually + /// implements `Send`. + #[inline] + pub unsafe fn as_future_obj(self) -> FutureObj<'a, T> { + FutureObj(self) + } +} + +impl<'a, T> fmt::Debug for LocalFutureObj<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("LocalFutureObj") + .finish() + } +} + +impl<'a, T> From> for LocalFutureObj<'a, T> { + #[inline] + fn from(f: FutureObj<'a, T>) -> LocalFutureObj<'a, T> { + f.0 + } +} + +impl<'a, T> Future for LocalFutureObj<'a, T> { + type Output = T; + + #[inline] + fn poll(self: PinMut, cx: &mut Context) -> Poll { + unsafe { + (self.poll_fn)(self.ptr, cx) + } + } +} + +impl<'a, T> Drop for LocalFutureObj<'a, T> { + fn drop(&mut self) { + unsafe { + (self.drop_fn)(self.ptr) + } + } +} + +/// A custom trait object for polling futures, roughly akin to +/// `Box> + Send`. +pub struct FutureObj<'a, T>(LocalFutureObj<'a, T>); + +unsafe impl<'a, T> Send for FutureObj<'a, T> {} + +impl<'a, T> FutureObj<'a, T> { + /// Create a `FutureObj` from a custom trait object representation. + #[inline] + pub fn new + Send>(f: F) -> FutureObj<'a, T> { + FutureObj(LocalFutureObj::new(f)) + } +} + +impl<'a, T> fmt::Debug for FutureObj<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("FutureObj") + .finish() + } +} + +impl<'a, T> Future for FutureObj<'a, T> { + type Output = T; + + #[inline] + fn poll(self: PinMut, cx: &mut Context) -> Poll { + let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) }; + pinned_field.poll(cx) + } +} + +/// A custom implementation of a future trait object for `FutureObj`, providing +/// a hand-rolled vtable. +/// +/// This custom representation is typically used only in `no_std` contexts, +/// where the default `Box`-based implementation is not available. +/// +/// The implementor must guarantee that it is safe to call `poll` repeatedly (in +/// a non-concurrent fashion) with the result of `into_raw` until `drop` is +/// called. +pub unsafe trait UnsafeFutureObj<'a, T>: 'a { + /// Convert a owned instance into a (conceptually owned) void pointer. + fn into_raw(self) -> *mut (); + + /// Poll the future represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to repeatedly call + /// `poll` with the result of `into_raw` until `drop` is called; such calls + /// are not, however, allowed to race with each other or with calls to `drop`. + unsafe fn poll(future: *mut (), cx: &mut Context) -> Poll; + + /// Drops the future represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to call this + /// function once per `into_raw` invocation; that call cannot race with + /// other calls to `drop` or `poll`. + unsafe fn drop(future: *mut ()); +} diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs new file mode 100644 index 00000000000..f9361a0f4e7 --- /dev/null +++ b/src/libcore/future/mod.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +//! Asynchronous values. + +mod future; +pub use self::future::Future; + +mod future_obj; +pub use self::future_obj::{FutureObj, LocalFutureObj, UnsafeFutureObj}; diff --git a/src/libcore/task/executor.rs b/src/libcore/task/executor.rs index 55ea5e724c1..f1db5093e98 100644 --- a/src/libcore/task/executor.rs +++ b/src/libcore/task/executor.rs @@ -13,7 +13,7 @@ issue = "50547")] use fmt; -use super::{FutureObj, LocalFutureObj}; +use future::{FutureObj, LocalFutureObj}; /// A task executor. /// @@ -29,7 +29,7 @@ pub trait Executor { /// /// The executor may be unable to spawn tasks, either because it has /// been shut down or is resource-constrained. - fn spawn_obj(&mut self, task: FutureObj<()>) -> Result<(), SpawnObjError>; + fn spawn_obj(&mut self, task: FutureObj<'static, ()>) -> Result<(), SpawnObjError>; /// Determine whether the executor is able to spawn new tasks. /// @@ -76,7 +76,7 @@ pub struct SpawnObjError { pub kind: SpawnErrorKind, /// The task for which spawning was attempted - pub task: FutureObj<()>, + pub task: FutureObj<'static, ()>, } /// The result of a failed spawn @@ -86,5 +86,5 @@ pub struct SpawnLocalObjError { pub kind: SpawnErrorKind, /// The task for which spawning was attempted - pub task: LocalFutureObj<()>, + pub task: LocalFutureObj<'static, ()>, } diff --git a/src/libcore/task/future_obj.rs b/src/libcore/task/future_obj.rs deleted file mode 100644 index 3ed3bd51cf6..00000000000 --- a/src/libcore/task/future_obj.rs +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] - -use fmt; -use future::Future; -use marker::PhantomData; -use mem::PinMut; -use task::{Context, Poll}; - -/// A custom trait object for polling futures, roughly akin to -/// `Box>`. -/// Contrary to `FutureObj`, `LocalFutureObj` does not have a `Send` bound. -pub struct LocalFutureObj { - ptr: *mut (), - poll_fn: unsafe fn(*mut (), &mut Context) -> Poll, - drop_fn: unsafe fn(*mut ()), - _marker: PhantomData, -} - -impl LocalFutureObj { - /// Create a `LocalFutureObj` from a custom trait object representation. - #[inline] - pub fn new>(f: F) -> LocalFutureObj { - LocalFutureObj { - ptr: f.into_raw(), - poll_fn: F::poll, - drop_fn: F::drop, - _marker: PhantomData, - } - } - - /// Converts the `LocalFutureObj` into a `FutureObj` - /// To make this operation safe one has to ensure that the `UnsafeFutureObj` - /// instance from which this `LocalFutureObj` was created actually - /// implements `Send`. - #[inline] - pub unsafe fn as_future_obj(self) -> FutureObj { - FutureObj(self) - } -} - -impl fmt::Debug for LocalFutureObj { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("LocalFutureObj") - .finish() - } -} - -impl From> for LocalFutureObj { - #[inline] - fn from(f: FutureObj) -> LocalFutureObj { - f.0 - } -} - -impl Future for LocalFutureObj { - type Output = T; - - #[inline] - fn poll(self: PinMut, cx: &mut Context) -> Poll { - unsafe { - (self.poll_fn)(self.ptr, cx) - } - } -} - -impl Drop for LocalFutureObj { - fn drop(&mut self) { - unsafe { - (self.drop_fn)(self.ptr) - } - } -} - -/// A custom trait object for polling futures, roughly akin to -/// `Box> + Send`. -pub struct FutureObj(LocalFutureObj); - -unsafe impl Send for FutureObj {} - -impl FutureObj { - /// Create a `FutureObj` from a custom trait object representation. - #[inline] - pub fn new + Send>(f: F) -> FutureObj { - FutureObj(LocalFutureObj::new(f)) - } -} - -impl fmt::Debug for FutureObj { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("FutureObj") - .finish() - } -} - -impl Future for FutureObj { - type Output = T; - - #[inline] - fn poll(self: PinMut, cx: &mut Context) -> Poll { - let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) }; - pinned_field.poll(cx) - } -} - -/// A custom implementation of a future trait object for `FutureObj`, providing -/// a hand-rolled vtable. -/// -/// This custom representation is typically used only in `no_std` contexts, -/// where the default `Box`-based implementation is not available. -/// -/// The implementor must guarantee that it is safe to call `poll` repeatedly (in -/// a non-concurrent fashion) with the result of `into_raw` until `drop` is -/// called. -pub unsafe trait UnsafeFutureObj: 'static { - /// Convert a owned instance into a (conceptually owned) void pointer. - fn into_raw(self) -> *mut (); - - /// Poll the future represented by the given void pointer. - /// - /// # Safety - /// - /// The trait implementor must guarantee that it is safe to repeatedly call - /// `poll` with the result of `into_raw` until `drop` is called; such calls - /// are not, however, allowed to race with each other or with calls to `drop`. - unsafe fn poll(future: *mut (), cx: &mut Context) -> Poll; - - /// Drops the future represented by the given void pointer. - /// - /// # Safety - /// - /// The trait implementor must guarantee that it is safe to call this - /// function once per `into_raw` invocation; that call cannot race with - /// other calls to `drop` or `poll`. - unsafe fn drop(future: *mut ()); -} diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index 06cd7a9dd77..c4f07536164 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -25,8 +25,5 @@ pub use self::executor::{ mod poll; pub use self::poll::Poll; -mod future_obj; -pub use self::future_obj::{FutureObj, LocalFutureObj, UnsafeFutureObj}; - mod wake; pub use self::wake::{Waker, LocalWaker, UnsafeWake}; diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs index 3a67750e77e..0ac37485d3d 100644 --- a/src/test/run-pass/async-await.rs +++ b/src/test/run-pass/async-await.rs @@ -19,9 +19,10 @@ use std::sync::{ Arc, atomic::{self, AtomicUsize}, }; +use std::future::FutureObj; use std::task::{ Context, Poll, Wake, - Executor, FutureObj, SpawnObjError, + Executor, SpawnObjError, local_waker_from_nonlocal, }; @@ -37,7 +38,7 @@ impl Wake for Counter { struct NoopExecutor; impl Executor for NoopExecutor { - fn spawn_obj(&mut self, _: FutureObj) -> Result<(), SpawnObjError> { + fn spawn_obj(&mut self, _: FutureObj<'static, ()>) -> Result<(), SpawnObjError> { Ok(()) } } diff --git a/src/test/run-pass/futures-api.rs b/src/test/run-pass/futures-api.rs index a427b82af6a..6cb975a9560 100644 --- a/src/test/run-pass/futures-api.rs +++ b/src/test/run-pass/futures-api.rs @@ -19,10 +19,11 @@ use std::sync::{ Arc, atomic::{self, AtomicUsize}, }; +use std::future::FutureObj; use std::task::{ Context, Poll, Wake, Waker, LocalWaker, - Executor, FutureObj, SpawnObjError, + Executor, SpawnObjError, local_waker, local_waker_from_nonlocal, }; @@ -44,7 +45,7 @@ impl Wake for Counter { struct NoopExecutor; impl Executor for NoopExecutor { - fn spawn_obj(&mut self, _: FutureObj<()>) -> Result<(), SpawnObjError> { + fn spawn_obj(&mut self, _: FutureObj<'static, ()>) -> Result<(), SpawnObjError> { Ok(()) } } -- cgit 1.4.1-3-g733a5 From 042928f0f591a63e0a2ed31c932015f4248d4fa7 Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Sun, 1 Jul 2018 09:28:16 +0200 Subject: `UnsafeFutureObj` impl for `PinMut` --- src/liballoc/boxed.rs | 13 ++++++------- src/libcore/future/future_obj.rs | 6 +++--- src/libcore/mem.rs | 17 +++++++++++++++++ 3 files changed, 26 insertions(+), 10 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 5984a992afc..7f6d27088b7 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -58,17 +58,16 @@ use core::any::Any; use core::borrow; use core::cmp::Ordering; +use core::convert::From; use core::fmt; -use core::future::Future; +use core::future::{Future, FutureObj, LocalFutureObj, UnsafeFutureObj}; use core::hash::{Hash, Hasher}; use core::iter::FusedIterator; use core::marker::{Unpin, Unsize}; use core::mem::{self, PinMut}; use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; use core::ptr::{self, NonNull, Unique}; -use core::future::{FutureObj, LocalFutureObj, UnsafeFutureObj}; use core::task::{Context, Poll}; -use core::convert::From; use raw_vec::RawVec; use str::from_boxed_utf8_unchecked; @@ -939,14 +938,14 @@ unsafe impl<'a, T, F: Future + 'a> UnsafeFutureObj<'a, T> for PinBox PinBox::into_raw(self) as *mut () } - unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll { - let ptr = task as *mut F; + unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll { + let ptr = ptr as *mut F; let pin: PinMut = PinMut::new_unchecked(&mut *ptr); pin.poll(cx) } - unsafe fn drop(task: *mut ()) { - drop(PinBox::from_raw(task as *mut F)) + unsafe fn drop(ptr: *mut ()) { + drop(PinBox::from_raw(ptr as *mut F)) } } diff --git a/src/libcore/future/future_obj.rs b/src/libcore/future/future_obj.rs index c60b8b97d34..67bd3de98c1 100644 --- a/src/libcore/future/future_obj.rs +++ b/src/libcore/future/future_obj.rs @@ -126,7 +126,7 @@ impl<'a, T> Future for FutureObj<'a, T> { /// a non-concurrent fashion) with the result of `into_raw` until `drop` is /// called. pub unsafe trait UnsafeFutureObj<'a, T>: 'a { - /// Convert a owned instance into a (conceptually owned) void pointer. + /// Convert an owned instance into a (conceptually owned) void pointer. fn into_raw(self) -> *mut (); /// Poll the future represented by the given void pointer. @@ -136,7 +136,7 @@ pub unsafe trait UnsafeFutureObj<'a, T>: 'a { /// The trait implementor must guarantee that it is safe to repeatedly call /// `poll` with the result of `into_raw` until `drop` is called; such calls /// are not, however, allowed to race with each other or with calls to `drop`. - unsafe fn poll(future: *mut (), cx: &mut Context) -> Poll; + unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll; /// Drops the future represented by the given void pointer. /// @@ -145,5 +145,5 @@ pub unsafe trait UnsafeFutureObj<'a, T>: 'a { /// The trait implementor must guarantee that it is safe to call this /// function once per `into_raw` invocation; that call cannot race with /// other calls to `drop` or `poll`. - unsafe fn drop(future: *mut ()); + unsafe fn drop(ptr: *mut ()); } diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 08bd9289ab4..5bc55300a97 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -18,10 +18,12 @@ use clone; use cmp; use fmt; +use future::{Future, UnsafeFutureObj}; use hash; use intrinsics; use marker::{Copy, PhantomData, Sized, Unpin, Unsize}; use ptr; +use task::{Context, Poll}; use ops::{Deref, DerefMut, CoerceUnsized}; #[stable(feature = "rust1", since = "1.0.0")] @@ -1227,3 +1229,18 @@ impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for PinM #[unstable(feature = "pin", issue = "49150")] impl<'a, T: ?Sized> Unpin for PinMut<'a, T> {} + +#[unstable(feature = "futures_api", issue = "50547")] +unsafe impl<'a, T, F: Future + 'a> UnsafeFutureObj<'a, T> for PinMut<'a, F> { + fn into_raw(self) -> *mut () { + unsafe { PinMut::get_mut_unchecked(self) as *mut F as *mut () } + } + + unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll { + PinMut::new_unchecked(&mut *(ptr as *mut F)).poll(cx) + } + + unsafe fn drop(ptr: *mut ()) { + drop(PinMut::new_unchecked(&mut *(ptr as *mut F))); + } +} -- cgit 1.4.1-3-g733a5 From dd3b0337ff22260ef9dfc1bfcf58bd18386d4cbe Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Sun, 1 Jul 2018 14:58:40 +0200 Subject: Improve doc comments for `FutureObj` --- src/libcore/future/future_obj.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/future/future_obj.rs b/src/libcore/future/future_obj.rs index 67bd3de98c1..b42fd2b5bd7 100644 --- a/src/libcore/future/future_obj.rs +++ b/src/libcore/future/future_obj.rs @@ -19,7 +19,7 @@ use mem::PinMut; use task::{Context, Poll}; /// A custom trait object for polling futures, roughly akin to -/// `Box>`. +/// `Box + 'a>`. /// Contrary to `FutureObj`, `LocalFutureObj` does not have a `Send` bound. pub struct LocalFutureObj<'a, T> { ptr: *mut (), @@ -86,7 +86,7 @@ impl<'a, T> Drop for LocalFutureObj<'a, T> { } /// A custom trait object for polling futures, roughly akin to -/// `Box> + Send`. +/// `Box + Send + 'a>`. pub struct FutureObj<'a, T>(LocalFutureObj<'a, T>); unsafe impl<'a, T> Send for FutureObj<'a, T> {} @@ -135,7 +135,8 @@ pub unsafe trait UnsafeFutureObj<'a, T>: 'a { /// /// The trait implementor must guarantee that it is safe to repeatedly call /// `poll` with the result of `into_raw` until `drop` is called; such calls - /// are not, however, allowed to race with each other or with calls to `drop`. + /// are not, however, allowed to race with each other or with calls to + /// `drop`. unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll; /// Drops the future represented by the given void pointer. -- cgit 1.4.1-3-g733a5 From 4e617291c2c7b918ec9a183dd2ce72ac92edf940 Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Sun, 1 Jul 2018 15:27:53 +0200 Subject: Make `drop` method for `PinMut`'s `UnsafeFutureObj` impl empty --- src/libcore/mem.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 5bc55300a97..b83c2e21a1a 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1240,7 +1240,5 @@ unsafe impl<'a, T, F: Future + 'a> UnsafeFutureObj<'a, T> for PinMut PinMut::new_unchecked(&mut *(ptr as *mut F)).poll(cx) } - unsafe fn drop(ptr: *mut ()) { - drop(PinMut::new_unchecked(&mut *(ptr as *mut F))); - } + unsafe fn drop(_ptr: *mut ()) {} } -- cgit 1.4.1-3-g733a5 From 9eee0d2288c067be081f2ca35f5b2d3cfc95fcf2 Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Mon, 2 Jul 2018 18:16:36 +0200 Subject: Fix naming convention issue --- src/libcore/future/future_obj.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/future/future_obj.rs b/src/libcore/future/future_obj.rs index b42fd2b5bd7..86fe9825ded 100644 --- a/src/libcore/future/future_obj.rs +++ b/src/libcore/future/future_obj.rs @@ -47,7 +47,7 @@ impl<'a, T> LocalFutureObj<'a, T> { /// instance from which this `LocalFutureObj` was created actually /// implements `Send`. #[inline] - pub unsafe fn as_future_obj(self) -> FutureObj<'a, T> { + pub unsafe fn into_future_obj(self) -> FutureObj<'a, T> { FutureObj(self) } } -- cgit 1.4.1-3-g733a5 From cb2c7570db807eab35b3decd813f5cbec844ddb3 Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Mon, 2 Jul 2018 18:55:42 +0200 Subject: Add explanation for custom trait object --- src/libcore/future/future_obj.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/future/future_obj.rs b/src/libcore/future/future_obj.rs index 86fe9825ded..173e381ca50 100644 --- a/src/libcore/future/future_obj.rs +++ b/src/libcore/future/future_obj.rs @@ -20,7 +20,15 @@ use task::{Context, Poll}; /// A custom trait object for polling futures, roughly akin to /// `Box + 'a>`. -/// Contrary to `FutureObj`, `LocalFutureObj` does not have a `Send` bound. +/// +/// This custom trait object was introduced for two reasons: +/// - Currently it is not possible to take `dyn Trait` by value and +/// `Box` is not available in no_std contexts. +/// - The `Future` trait is currently not object safe: The `Future::poll` +/// method makes uses the arbitrary self types feature and traits in which +/// this feature is used are currently not object safe due to current compiler +/// limitations. (See tracking issue for arbitray self types for more +/// information #44874) pub struct LocalFutureObj<'a, T> { ptr: *mut (), poll_fn: unsafe fn(*mut (), &mut Context) -> Poll, @@ -87,6 +95,15 @@ impl<'a, T> Drop for LocalFutureObj<'a, T> { /// A custom trait object for polling futures, roughly akin to /// `Box + Send + 'a>`. +/// +/// This custom trait object was introduced for two reasons: +/// - Currently it is not possible to take `dyn Trait` by value and +/// `Box` is not available in no_std contexts. +/// - The `Future` trait is currently not object safe: The `Future::poll` +/// method makes uses the arbitrary self types feature and traits in which +/// this feature is used are currently not object safe due to current compiler +/// limitations. (See tracking issue for arbitray self types for more +/// information #44874) pub struct FutureObj<'a, T>(LocalFutureObj<'a, T>); unsafe impl<'a, T> Send for FutureObj<'a, T> {} -- cgit 1.4.1-3-g733a5 From 5fde8b92372f02deaf5c7fb638447a60112f9015 Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Mon, 2 Jul 2018 18:57:58 +0200 Subject: Remove unnecessary `PhantomData` field --- src/libcore/future/future_obj.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/future/future_obj.rs b/src/libcore/future/future_obj.rs index 173e381ca50..99f21272538 100644 --- a/src/libcore/future/future_obj.rs +++ b/src/libcore/future/future_obj.rs @@ -33,8 +33,7 @@ pub struct LocalFutureObj<'a, T> { ptr: *mut (), poll_fn: unsafe fn(*mut (), &mut Context) -> Poll, drop_fn: unsafe fn(*mut ()), - _marker1: PhantomData, - _marker2: PhantomData<&'a ()>, + _marker: PhantomData<&'a ()>, } impl<'a, T> LocalFutureObj<'a, T> { @@ -45,8 +44,7 @@ impl<'a, T> LocalFutureObj<'a, T> { ptr: f.into_raw(), poll_fn: F::poll, drop_fn: F::drop, - _marker1: PhantomData, - _marker2: PhantomData, + _marker: PhantomData, } } -- cgit 1.4.1-3-g733a5 From ae408947de1311f9673d0ae34028933cd191ac90 Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Mon, 2 Jul 2018 19:07:59 +0200 Subject: Implement `UnsafeFutureObj` for `&mut Future` --- src/liballoc/boxed.rs | 4 +++- src/libcore/future/future_obj.rs | 16 +++++++++++++++- src/libcore/mem.rs | 4 +++- 3 files changed, 21 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 7f6d27088b7..fabeaa1c144 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -933,7 +933,9 @@ impl Future for PinBox { } #[unstable(feature = "futures_api", issue = "50547")] -unsafe impl<'a, T, F: Future + 'a> UnsafeFutureObj<'a, T> for PinBox { +unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for PinBox + where F: Future + 'a +{ fn into_raw(self) -> *mut () { PinBox::into_raw(self) as *mut () } diff --git a/src/libcore/future/future_obj.rs b/src/libcore/future/future_obj.rs index 99f21272538..98c504a3f7b 100644 --- a/src/libcore/future/future_obj.rs +++ b/src/libcore/future/future_obj.rs @@ -14,7 +14,7 @@ use fmt; use future::Future; -use marker::PhantomData; +use marker::{PhantomData, Unpin}; use mem::PinMut; use task::{Context, Poll}; @@ -163,3 +163,17 @@ pub unsafe trait UnsafeFutureObj<'a, T>: 'a { /// other calls to `drop` or `poll`. unsafe fn drop(ptr: *mut ()); } + +unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for &'a mut F + where F: Future + Unpin + 'a +{ + fn into_raw(self) -> *mut () { + self as *mut F as *mut () + } + + unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll { + PinMut::new_unchecked(&mut *(ptr as *mut F)).poll(cx) + } + + unsafe fn drop(_ptr: *mut ()) {} +} diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index b83c2e21a1a..84173654655 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1231,7 +1231,9 @@ impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for PinM impl<'a, T: ?Sized> Unpin for PinMut<'a, T> {} #[unstable(feature = "futures_api", issue = "50547")] -unsafe impl<'a, T, F: Future + 'a> UnsafeFutureObj<'a, T> for PinMut<'a, F> { +unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for PinMut<'a, F> + where F: Future + 'a +{ fn into_raw(self) -> *mut () { unsafe { PinMut::get_mut_unchecked(self) as *mut F as *mut () } } -- cgit 1.4.1-3-g733a5 From 6f223cfc07fbeef10b8a1c408a51daa0106bbaff Mon Sep 17 00:00:00 2001 From: Ethan McCue Date: Tue, 3 Jul 2018 13:13:49 -0700 Subject: Any docs preposition change This changes the docs referring to where a user should be wary of depending on "Any" trait impls from warning about relying on them "outside" of their code to warning about relying on them "inside" of their code. --- src/libcore/any.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 4437c36c15a..94f23db1ccc 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -431,7 +431,7 @@ impl Any+Send+Sync { /// /// While `TypeId` implements `Hash`, `PartialOrd`, and `Ord`, it is worth /// noting that the hashes and ordering will vary between Rust releases. Beware -/// of relying on them outside of your code! +/// of relying on them inside of your code! #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct TypeId { -- cgit 1.4.1-3-g733a5 From 603553458639cd65f3cc75b9b74f8176af81aa2b Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Wed, 4 Jul 2018 21:54:45 +0200 Subject: Implement `Option::replace` in the core library --- src/libcore/option.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 20bc173f7e1..db0a807d152 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -845,6 +845,33 @@ impl Option { pub fn take(&mut self) -> Option { mem::replace(self, None) } + + /// Replaces the actual value in the option by the value given in parameter, + /// returning the old value if present, + /// leaving a `Some` in its place without deinitializing either one. + /// + /// [`Some`]: #variant.Some + /// + /// # Examples + /// + /// ``` + /// #![feature(option_replace)] + /// + /// let mut x = Some(2); + /// let old = x.replace(5); + /// assert_eq!(x, Some(5)); + /// assert_eq!(old, Some(2)); + /// + /// let mut x = None; + /// let old = x.replace(3); + /// assert_eq!(x, Some(3)); + /// assert_eq!(old, None); + /// ``` + #[inline] + #[unstable(feature = "option_replace", issue = "51998")] + pub fn replace(&mut self, value: T) -> Option { + mem::replace(self, Some(value)) + } } impl<'a, T: Clone> Option<&'a T> { -- cgit 1.4.1-3-g733a5 From dc425e2e64863d4e1aa0f2bb41f7bfa3cd14b558 Mon Sep 17 00:00:00 2001 From: Val Markovic Date: Wed, 4 Jul 2018 17:26:45 -0700 Subject: Clarifying how the alignment of the struct works The docs were not specifying how to compute the alignment of the struct, so I had to spend some time trying to figure out how that works. Found the answer [on this page](http://camlorn.net/posts/April%202017/rust-struct-field-reordering.html): > The total size of this struct is 5, but the most-aligned field is b with alignment 2, so we round up to 6 and give the struct an alignment of 2 bytes. --- src/libcore/mem.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 84173654655..8fb4e0d6a02 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -229,6 +229,8 @@ pub fn forget(t: T) { /// 2. Round up the current size to the nearest multiple of the next field's [alignment]. /// /// Finally, round the size of the struct to the nearest multiple of its [alignment]. +/// The alignment of the struct is usually the largest alignment of all its +/// fields; this can be changed with the use of `repr(align(N))`. /// /// Unlike `C`, zero sized structs are not rounded up to one byte in size. /// @@ -283,7 +285,8 @@ pub fn forget(t: T) { /// // The size of the second field is 2, so add 2 to the size. Size is 4. /// // The alignment of the third field is 1, so add 0 to the size for padding. Size is 4. /// // The size of the third field is 1, so add 1 to the size. Size is 5. -/// // Finally, the alignment of the struct is 2, so add 1 to the size for padding. Size is 6. +/// // Finally, the alignment of the struct is 2 (because the largest alignment amongst its +/// // fields is 2), so add 1 to the size for padding. Size is 6. /// assert_eq!(6, mem::size_of::()); /// /// #[repr(C)] -- cgit 1.4.1-3-g733a5 From bbf688a84de7001d033764b848a50cbad42f3d5a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 30 Jun 2018 14:56:08 -0500 Subject: enable Atomic*.{load,store} for ARMv6-M / MSP430 closes #45085 this commit adds an `atomic_cas` target option and an unstable `#[cfg(target_has_atomic_cas)]` attribute to enable a subset of the `Atomic*` API on architectures that don't support atomic CAS natively, like MSP430 and ARMv6-M. --- src/liballoc/lib.rs | 4 +++- src/liballoc/task.rs | 9 ++++++--- src/libcore/lib.rs | 1 + src/libcore/sync/atomic.rs | 16 ++++++++++++++++ src/librustc/session/config.rs | 4 ++++ src/librustc_target/spec/mod.rs | 6 ++++++ src/librustc_target/spec/msp430_none_elf.rs | 6 ++++-- src/librustc_target/spec/thumbv6m_none_eabi.rs | 2 +- src/libsyntax/feature_gate.rs | 4 ++++ 9 files changed, 45 insertions(+), 7 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 493448eaf88..66bf8de1993 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -86,6 +86,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] +#![cfg_attr(not(stage0), feature(cfg_target_has_atomic_cas))] #![feature(coerce_unsized)] #![feature(collections_range)] #![feature(const_fn)] @@ -162,7 +163,8 @@ mod boxed { #[cfg(test)] mod boxed_test; pub mod collections; -#[cfg(target_has_atomic = "ptr")] +#[cfg_attr(stage0, cfg(target_has_atomic = "ptr"))] +#[cfg_attr(not(stage0), cfg(all(target_has_atomic = "ptr", target_has_atomic_cas)))] pub mod sync; pub mod rc; pub mod raw_vec; diff --git a/src/liballoc/task.rs b/src/liballoc/task.rs index f14fe3a20da..c8e3e770ed2 100644 --- a/src/liballoc/task.rs +++ b/src/liballoc/task.rs @@ -12,10 +12,12 @@ pub use core::task::*; -#[cfg(target_has_atomic = "ptr")] +#[cfg_attr(stage0, cfg(target_has_atomic = "ptr"))] +#[cfg_attr(not(stage0), cfg(all(target_has_atomic = "ptr", target_has_atomic_cas)))] pub use self::if_arc::*; -#[cfg(target_has_atomic = "ptr")] +#[cfg_attr(stage0, cfg(target_has_atomic = "ptr"))] +#[cfg_attr(not(stage0), cfg(all(target_has_atomic = "ptr", target_has_atomic_cas)))] mod if_arc { use super::*; use core::marker::PhantomData; @@ -47,7 +49,8 @@ mod if_arc { } } - #[cfg(target_has_atomic = "ptr")] + #[cfg_attr(stage0, cfg(target_has_atomic = "ptr"))] + #[cfg_attr(not(stage0), cfg(all(target_has_atomic = "ptr", target_has_atomic_cas)))] struct ArcWrapped(PhantomData); unsafe impl UnsafeWake for ArcWrapped { diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index b2b38820a89..fe328bdd107 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -79,6 +79,7 @@ #![feature(associated_type_defaults)] #![feature(attr_literals)] #![feature(cfg_target_has_atomic)] +#![cfg_attr(not(stage0), feature(cfg_target_has_atomic_cas))] #![feature(concat_idents)] #![feature(const_fn)] #![feature(const_int_ops)] diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 7aba8b51cff..647bf4fb40a 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -371,6 +371,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] pub fn swap(&self, val: bool, order: Ordering) -> bool { unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 } } @@ -401,6 +402,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool { match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) { Ok(x) => x, @@ -446,6 +448,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] + #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] pub fn compare_exchange(&self, current: bool, new: bool, @@ -537,6 +540,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] pub fn fetch_and(&self, val: bool, order: Ordering) -> bool { unsafe { atomic_and(self.v.get(), val as u8, order) != 0 } } @@ -568,6 +572,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool { // We can't use atomic_nand here because it can result in a bool with // an invalid value. This happens because the atomic operation is done @@ -610,6 +615,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] pub fn fetch_or(&self, val: bool, order: Ordering) -> bool { unsafe { atomic_or(self.v.get(), val as u8, order) != 0 } } @@ -640,6 +646,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool { unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 } } @@ -786,6 +793,7 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T { unsafe { atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T } } @@ -815,6 +823,7 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T { match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) { Ok(x) => x, @@ -853,6 +862,7 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] + #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] pub fn compare_exchange(&self, current: *mut T, new: *mut T, @@ -1138,6 +1148,7 @@ assert_eq!(some_var.swap(10, Ordering::Relaxed), 5); ```"), #[inline] #[$stable] + #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type { unsafe { atomic_swap(self.v.get(), val, order) } } @@ -1170,6 +1181,7 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10); ```"), #[inline] #[$stable] + #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] pub fn compare_and_swap(&self, current: $int_type, new: $int_type, @@ -1223,6 +1235,7 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10); ```"), #[inline] #[$stable_cxchg] + #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] pub fn compare_exchange(&self, current: $int_type, new: $int_type, @@ -1677,6 +1690,7 @@ atomic_int!{ } #[inline] +#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] fn strongest_failure_ordering(order: Ordering) -> Ordering { match order { Release => Relaxed, @@ -1713,6 +1727,7 @@ unsafe fn atomic_load(dst: *const T, order: Ordering) -> T { } #[inline] +#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xchg_acq(dst, val), @@ -1751,6 +1766,7 @@ unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] +#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] unsafe fn atomic_compare_exchange(dst: *mut T, old: T, new: T, diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index f97e11ef72f..93bfe1fc638 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1367,6 +1367,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { let vendor = &sess.target.target.target_vendor; let min_atomic_width = sess.target.target.min_atomic_width(); let max_atomic_width = sess.target.target.max_atomic_width(); + let atomic_cas = sess.target.target.options.atomic_cas; let mut ret = HashSet::new(); // Target bindings. @@ -1406,6 +1407,9 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { } } } + if atomic_cas { + ret.insert((Symbol::intern("target_has_atomic_cas"), None)); + } if sess.opts.debug_assertions { ret.insert((Symbol::intern("debug_assertions"), None)); } diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index e54cd773123..8ebf5f7c64d 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -572,6 +572,9 @@ pub struct TargetOptions { /// Don't use this field; instead use the `.max_atomic_width()` method. pub max_atomic_width: Option, + /// Whether the target supports atomic CAS operations natively + pub atomic_cas: bool, + /// Panic strategy: "unwind" or "abort" pub panic_strategy: PanicStrategy, @@ -690,6 +693,7 @@ impl Default for TargetOptions { no_integrated_as: false, min_atomic_width: None, max_atomic_width: None, + atomic_cas: true, panic_strategy: PanicStrategy::Unwind, abi_blacklist: vec![], crt_static_allows_dylibs: false, @@ -946,6 +950,7 @@ impl Target { key!(no_integrated_as, bool); key!(max_atomic_width, Option); key!(min_atomic_width, Option); + key!(atomic_cas, bool); try!(key!(panic_strategy, PanicStrategy)); key!(crt_static_allows_dylibs, bool); key!(crt_static_default, bool); @@ -1154,6 +1159,7 @@ impl ToJson for Target { target_option_val!(no_integrated_as); target_option_val!(min_atomic_width); target_option_val!(max_atomic_width); + target_option_val!(atomic_cas); target_option_val!(panic_strategy); target_option_val!(crt_static_allows_dylibs); target_option_val!(crt_static_default); diff --git a/src/librustc_target/spec/msp430_none_elf.rs b/src/librustc_target/spec/msp430_none_elf.rs index ce42a908b0e..291511dd429 100644 --- a/src/librustc_target/spec/msp430_none_elf.rs +++ b/src/librustc_target/spec/msp430_none_elf.rs @@ -34,9 +34,11 @@ pub fn target() -> TargetResult { linker: Some("msp430-elf-gcc".to_string()), no_integrated_as: true, - // There are no atomic instructions available in the MSP430 + // There are no atomic CAS instructions available in the MSP430 // instruction set - max_atomic_width: Some(0), + max_atomic_width: Some(16), + + atomic_cas: false, // Because these devices have very little resources having an // unwinder is too onerous so we default to "abort" because the diff --git a/src/librustc_target/spec/thumbv6m_none_eabi.rs b/src/librustc_target/spec/thumbv6m_none_eabi.rs index 9fea07c36f4..0c45178b47a 100644 --- a/src/librustc_target/spec/thumbv6m_none_eabi.rs +++ b/src/librustc_target/spec/thumbv6m_none_eabi.rs @@ -31,7 +31,7 @@ pub fn target() -> TargetResult { features: "+strict-align".to_string(), // There are no atomic instructions available in the instruction set of the ARMv6-M // architecture - max_atomic_width: Some(0), + atomic_cas: false, .. super::thumb_base::opts() } }) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 2ae0e669fd0..59418f8bf2a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -479,6 +479,9 @@ declare_features! ( // Allows async and await syntax (active, async_await, "1.28.0", Some(50547), None), + + // Allows async and await syntax + (active, cfg_target_has_atomic_cas, "1.28.0", Some(0), None), ); declare_features! ( @@ -1099,6 +1102,7 @@ const GATED_CFGS: &[(&str, &str, fn(&Features) -> bool)] = &[ ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)), ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)), ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)), + ("target_has_atomic_cas", "cfg_target_has_atomic_cas", cfg_fn!(cfg_target_has_atomic_cas)), ]; #[derive(Debug, Eq, PartialEq)] -- cgit 1.4.1-3-g733a5 From 0ed32313a223dbe1a1d5f61cd66d533992e26f6d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 5 Jul 2018 16:44:13 -0500 Subject: #[cfg(target_has_atomic_cas)] -> #[cfg(target_has_atomic = "cas")] --- src/liballoc/lib.rs | 7 +++--- src/liballoc/task.rs | 18 ++++++++++----- src/libcore/lib.rs | 1 - src/libcore/sync/atomic.rs | 32 +++++++++++++------------- src/librustc/session/config.rs | 2 +- src/librustc_target/spec/msp430_none_elf.rs | 1 - src/librustc_target/spec/thumbv6m_none_eabi.rs | 2 +- src/libsyntax/feature_gate.rs | 4 ---- 8 files changed, 34 insertions(+), 33 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 66bf8de1993..35bf8d1b792 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -86,7 +86,6 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] -#![cfg_attr(not(stage0), feature(cfg_target_has_atomic_cas))] #![feature(coerce_unsized)] #![feature(collections_range)] #![feature(const_fn)] @@ -163,8 +162,10 @@ mod boxed { #[cfg(test)] mod boxed_test; pub mod collections; -#[cfg_attr(stage0, cfg(target_has_atomic = "ptr"))] -#[cfg_attr(not(stage0), cfg(all(target_has_atomic = "ptr", target_has_atomic_cas)))] +#[cfg(any( + all(stage0, target_has_atomic = "ptr"), + all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas") +))] pub mod sync; pub mod rc; pub mod raw_vec; diff --git a/src/liballoc/task.rs b/src/liballoc/task.rs index c8e3e770ed2..9792d52dd66 100644 --- a/src/liballoc/task.rs +++ b/src/liballoc/task.rs @@ -12,12 +12,16 @@ pub use core::task::*; -#[cfg_attr(stage0, cfg(target_has_atomic = "ptr"))] -#[cfg_attr(not(stage0), cfg(all(target_has_atomic = "ptr", target_has_atomic_cas)))] +#[cfg(any( + all(stage0, target_has_atomic = "ptr"), + all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas") +))] pub use self::if_arc::*; -#[cfg_attr(stage0, cfg(target_has_atomic = "ptr"))] -#[cfg_attr(not(stage0), cfg(all(target_has_atomic = "ptr", target_has_atomic_cas)))] +#[cfg(any( + all(stage0, target_has_atomic = "ptr"), + all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas") +))] mod if_arc { use super::*; use core::marker::PhantomData; @@ -49,8 +53,10 @@ mod if_arc { } } - #[cfg_attr(stage0, cfg(target_has_atomic = "ptr"))] - #[cfg_attr(not(stage0), cfg(all(target_has_atomic = "ptr", target_has_atomic_cas)))] + #[cfg(any( + all(stage0, target_has_atomic = "ptr"), + all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas") + ))] struct ArcWrapped(PhantomData); unsafe impl UnsafeWake for ArcWrapped { diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index fe328bdd107..b2b38820a89 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -79,7 +79,6 @@ #![feature(associated_type_defaults)] #![feature(attr_literals)] #![feature(cfg_target_has_atomic)] -#![cfg_attr(not(stage0), feature(cfg_target_has_atomic_cas))] #![feature(concat_idents)] #![feature(const_fn)] #![feature(const_int_ops)] diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 647bf4fb40a..e9d1fb89115 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -371,7 +371,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn swap(&self, val: bool, order: Ordering) -> bool { unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 } } @@ -402,7 +402,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool { match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) { Ok(x) => x, @@ -448,7 +448,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] - #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn compare_exchange(&self, current: bool, new: bool, @@ -540,7 +540,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn fetch_and(&self, val: bool, order: Ordering) -> bool { unsafe { atomic_and(self.v.get(), val as u8, order) != 0 } } @@ -572,7 +572,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool { // We can't use atomic_nand here because it can result in a bool with // an invalid value. This happens because the atomic operation is done @@ -615,7 +615,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn fetch_or(&self, val: bool, order: Ordering) -> bool { unsafe { atomic_or(self.v.get(), val as u8, order) != 0 } } @@ -646,7 +646,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool { unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 } } @@ -793,7 +793,7 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T { unsafe { atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T } } @@ -823,7 +823,7 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T { match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) { Ok(x) => x, @@ -862,7 +862,7 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] - #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn compare_exchange(&self, current: *mut T, new: *mut T, @@ -1148,7 +1148,7 @@ assert_eq!(some_var.swap(10, Ordering::Relaxed), 5); ```"), #[inline] #[$stable] - #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type { unsafe { atomic_swap(self.v.get(), val, order) } } @@ -1181,7 +1181,7 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10); ```"), #[inline] #[$stable] - #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn compare_and_swap(&self, current: $int_type, new: $int_type, @@ -1235,7 +1235,7 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10); ```"), #[inline] #[$stable_cxchg] - #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn compare_exchange(&self, current: $int_type, new: $int_type, @@ -1690,7 +1690,7 @@ atomic_int!{ } #[inline] -#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] +#[cfg(any(stage0, target_has_atomic = "cas"))] fn strongest_failure_ordering(order: Ordering) -> Ordering { match order { Release => Relaxed, @@ -1727,7 +1727,7 @@ unsafe fn atomic_load(dst: *const T, order: Ordering) -> T { } #[inline] -#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] +#[cfg(any(stage0, target_has_atomic = "cas"))] unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xchg_acq(dst, val), @@ -1766,7 +1766,7 @@ unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] +#[cfg(any(stage0, target_has_atomic = "cas"))] unsafe fn atomic_compare_exchange(dst: *mut T, old: T, new: T, diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 93bfe1fc638..342799d41bb 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1408,7 +1408,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { } } if atomic_cas { - ret.insert((Symbol::intern("target_has_atomic_cas"), None)); + ret.insert((Symbol::intern("target_has_atomic"), Some(Symbol::intern("cas")))); } if sess.opts.debug_assertions { ret.insert((Symbol::intern("debug_assertions"), None)); diff --git a/src/librustc_target/spec/msp430_none_elf.rs b/src/librustc_target/spec/msp430_none_elf.rs index 291511dd429..3ac4c459c63 100644 --- a/src/librustc_target/spec/msp430_none_elf.rs +++ b/src/librustc_target/spec/msp430_none_elf.rs @@ -37,7 +37,6 @@ pub fn target() -> TargetResult { // There are no atomic CAS instructions available in the MSP430 // instruction set max_atomic_width: Some(16), - atomic_cas: false, // Because these devices have very little resources having an diff --git a/src/librustc_target/spec/thumbv6m_none_eabi.rs b/src/librustc_target/spec/thumbv6m_none_eabi.rs index 0c45178b47a..26812501814 100644 --- a/src/librustc_target/spec/thumbv6m_none_eabi.rs +++ b/src/librustc_target/spec/thumbv6m_none_eabi.rs @@ -29,7 +29,7 @@ pub fn target() -> TargetResult { // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them // with +strict-align. features: "+strict-align".to_string(), - // There are no atomic instructions available in the instruction set of the ARMv6-M + // There are no atomic CAS instructions available in the instruction set of the ARMv6-M // architecture atomic_cas: false, .. super::thumb_base::opts() diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 59418f8bf2a..2ae0e669fd0 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -479,9 +479,6 @@ declare_features! ( // Allows async and await syntax (active, async_await, "1.28.0", Some(50547), None), - - // Allows async and await syntax - (active, cfg_target_has_atomic_cas, "1.28.0", Some(0), None), ); declare_features! ( @@ -1102,7 +1099,6 @@ const GATED_CFGS: &[(&str, &str, fn(&Features) -> bool)] = &[ ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)), ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)), ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)), - ("target_has_atomic_cas", "cfg_target_has_atomic_cas", cfg_fn!(cfg_target_has_atomic_cas)), ]; #[derive(Debug, Eq, PartialEq)] -- cgit 1.4.1-3-g733a5 From 15a196ec3684bfe03c9db219e17b064f4e65647e Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Fri, 6 Jul 2018 01:06:17 -0600 Subject: Remove unnecessary feature gate. To fix a warning. --- src/libcore/lib.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index b2b38820a89..bbe6ae8619f 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -122,7 +122,6 @@ #![feature(const_slice_len)] #![feature(const_str_as_bytes)] #![feature(const_str_len)] -#![cfg_attr(stage0, feature(repr_transparent))] #[prelude_import] #[allow(unused)] -- cgit 1.4.1-3-g733a5 From ad7621d42ee90143cd15715cc546177575fd5844 Mon Sep 17 00:00:00 2001 From: Pazzaz Date: Fri, 6 Jul 2018 17:20:39 +0200 Subject: Handle array manually in string case conversion methods --- src/liballoc/str.rs | 29 +++++++++++++++++++++++++++-- src/libcore/unicode/mod.rs | 3 +++ 2 files changed, 30 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index bb99d0401d3..4d6434c378e 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -45,6 +45,7 @@ use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; use core::ptr; use core::iter::FusedIterator; +use core::unicode::conversions; use borrow::{Borrow, ToOwned}; use boxed::Box; @@ -369,7 +370,18 @@ impl str { // See https://github.com/rust-lang/rust/issues/26035 map_uppercase_sigma(self, i, &mut s) } else { - s.extend(c.to_lowercase()); + match conversions::to_lower(c) { + [a, '\0', _] => s.push(a), + [a, b, '\0'] => { + s.push(a); + s.push(b); + } + [a, b, c] => { + s.push(a); + s.push(b); + s.push(c); + } + } } } return s; @@ -423,7 +435,20 @@ impl str { #[stable(feature = "unicode_case_mapping", since = "1.2.0")] pub fn to_uppercase(&self) -> String { let mut s = String::with_capacity(self.len()); - s.extend(self.chars().flat_map(|c| c.to_uppercase())); + for c in self[..].chars() { + match conversions::to_upper(c) { + [a, '\0', _] => s.push(a), + [a, b, '\0'] => { + s.push(a); + s.push(b); + } + [a, b, c] => { + s.push(a); + s.push(b); + s.push(c); + } + } + } return s; } diff --git a/src/libcore/unicode/mod.rs b/src/libcore/unicode/mod.rs index b6b033adc04..e5cda880f88 100644 --- a/src/libcore/unicode/mod.rs +++ b/src/libcore/unicode/mod.rs @@ -20,6 +20,9 @@ pub(crate) mod version; pub mod derived_property { pub use unicode::tables::derived_property::{Case_Ignorable, Cased}; } +pub mod conversions { + pub use unicode::tables::conversions::{to_lower, to_upper}; +} // For use in libsyntax pub mod property { -- cgit 1.4.1-3-g733a5 From e769deca998479c7b78931af45a26c6c822c74f7 Mon Sep 17 00:00:00 2001 From: willmo Date: Sat, 7 Jul 2018 20:09:34 -0700 Subject: Add #[repr(transparent)] to Atomic* types This allows them to be used in #[repr(C)] structs without warnings. Since rust-lang/rfcs#1649 and rust-lang/rust#35603 they are already documented to have "the same in-memory representation as" their corresponding primitive types. This just makes that explicit. --- src/libcore/sync/atomic.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index e9d1fb89115..1e2b18bf9b0 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -124,6 +124,7 @@ pub fn spin_loop_hint() { /// [`bool`]: ../../../std/primitive.bool.html #[cfg(target_has_atomic = "8")] #[stable(feature = "rust1", since = "1.0.0")] +#[repr(transparent)] pub struct AtomicBool { v: UnsafeCell, } @@ -147,6 +148,7 @@ unsafe impl Sync for AtomicBool {} /// This type has the same in-memory representation as a `*mut T`. #[cfg(target_has_atomic = "ptr")] #[stable(feature = "rust1", since = "1.0.0")] +#[repr(transparent)] pub struct AtomicPtr { p: UnsafeCell<*mut T>, } @@ -976,6 +978,7 @@ macro_rules! atomic_int { /// /// [module-level documentation]: index.html #[$stable] + #[repr(transparent)] pub struct $atomic_type { v: UnsafeCell<$int_type>, } -- cgit 1.4.1-3-g733a5 From 26615b8f20432c2332a8ca93b18301872870dd01 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 8 Jul 2018 15:07:17 +0200 Subject: Fix some links --- src/libcore/num/flt2dec/strategy/dragon.rs | 4 ++-- src/libcore/num/flt2dec/strategy/grisu.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/flt2dec/strategy/dragon.rs b/src/libcore/num/flt2dec/strategy/dragon.rs index 6aa4f297e75..9c9e531c593 100644 --- a/src/libcore/num/flt2dec/strategy/dragon.rs +++ b/src/libcore/num/flt2dec/strategy/dragon.rs @@ -9,9 +9,9 @@ // except according to those terms. /*! -Almost direct (but slightly optimized) Rust translation of Figure 3 of [1]. +Almost direct (but slightly optimized) Rust translation of Figure 3 of \[1\]. -[1] Burger, R. G. and Dybvig, R. K. 1996. Printing floating-point numbers +\[1\] Burger, R. G. and Dybvig, R. K. 1996. Printing floating-point numbers quickly and accurately. SIGPLAN Not. 31, 5 (May. 1996), 108-116. */ diff --git a/src/libcore/num/flt2dec/strategy/grisu.rs b/src/libcore/num/flt2dec/strategy/grisu.rs index cf70a1978f5..5c023a191db 100644 --- a/src/libcore/num/flt2dec/strategy/grisu.rs +++ b/src/libcore/num/flt2dec/strategy/grisu.rs @@ -9,10 +9,10 @@ // except according to those terms. /*! -Rust adaptation of Grisu3 algorithm described in [1]. It uses about +Rust adaptation of Grisu3 algorithm described in \[1\]. It uses about 1KB of precomputed table, and in turn, it's very quick for most inputs. -[1] Florian Loitsch. 2010. Printing floating-point numbers quickly and +\[1\] Florian Loitsch. 2010. Printing floating-point numbers quickly and accurately with integers. SIGPLAN Not. 45, 6 (June 2010), 233-243. */ -- cgit 1.4.1-3-g733a5 From af87a3594a9f852de0eb7fec7a2f2e7c5fdb4fe8 Mon Sep 17 00:00:00 2001 From: Clément RENAULT Date: Mon, 9 Jul 2018 14:50:54 +0200 Subject: Add a basic test to `Option::replace` --- src/libcore/tests/lib.rs | 1 + src/libcore/tests/option.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 9d4a5213992..ca7db6e4639 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -44,6 +44,7 @@ #![feature(reverse_bits)] #![feature(iterator_find_map)] #![feature(slice_internals)] +#![feature(option_replace)] extern crate core; extern crate test; diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs index 22109e28edd..bc3e61a4f54 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -297,3 +297,18 @@ fn test_try() { } assert_eq!(try_option_err(), Err(NoneError)); } + +#[test] +fn test_replace() { + let mut x = Some(2); + let old = x.replace(5); + + assert_eq!(x, Some(5)); + assert_eq!(old, Some(2)); + + let mut x = None; + let old = x.replace(3); + + assert_eq!(x, Some(3)); + assert_eq!(old, None); +} -- cgit 1.4.1-3-g733a5 From c8f0e6f210caccdaea7dc59fd970c81018ddfb00 Mon Sep 17 00:00:00 2001 From: Clément RENAULT Date: Mon, 9 Jul 2018 14:52:32 +0200 Subject: Fix the documentation of `Option::replace` --- src/libcore/option.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/option.rs b/src/libcore/option.rs index db0a807d152..f3e823670aa 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -848,7 +848,7 @@ impl Option { /// Replaces the actual value in the option by the value given in parameter, /// returning the old value if present, - /// leaving a `Some` in its place without deinitializing either one. + /// leaving a [`Some`] in its place without deinitializing either one. /// /// [`Some`]: #variant.Some /// -- cgit 1.4.1-3-g733a5 From c90a821d43dee1ff0d04d84a9adb4ec11dbe6c47 Mon Sep 17 00:00:00 2001 From: Anirudh Balaji Date: Mon, 9 Jul 2018 13:41:46 -0700 Subject: Add "or destination" to {copy, clone}_from_slice example --- src/libcore/slice/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 0ee4c0bdbe7..c41776a1460 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1541,8 +1541,8 @@ impl [T] { /// let src = [1, 2, 3, 4]; /// let mut dst = [0, 0]; /// - /// // Note: the slices must be the same length, so you can slice the - /// // source to be the same size. Here we slice the source, four elements, + /// // Note: the slices must be the same length, so you can slice the source + /// // or the destination to be the same size. Here we slice the source, four elements, /// // to two, the same size as the destination slice. It *will* panic if we don't do this. /// dst.clone_from_slice(&src[2..]); /// @@ -1610,8 +1610,8 @@ impl [T] { /// let src = [1, 2, 3, 4]; /// let mut dst = [0, 0]; /// - /// // Note: the slices must be the same length, so you can slice the - /// // source to be the same size. Here we slice the source, four elements, + /// // Note: the slices must be the same length, so you can slice the source + /// // or the destination to be the same size. Here we slice the source, four elements, /// // to two, the same size as the destination slice. It *will* panic if we don't do this. /// dst.copy_from_slice(&src[2..]); /// -- cgit 1.4.1-3-g733a5 From 239ec7d2dce9c19de16c9ee64addbb834119397c Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 6 Jul 2018 15:49:52 +0200 Subject: Implement #[alloc_error_handler] This to-be-stable attribute is equivalent to `#[lang = "oom"]`. It is required when using the alloc crate without the std crate. It is called by `handle_alloc_error`, which is in turned called by "infallible" allocations APIs such as `Vec::push`. --- src/libcore/alloc.rs | 1 + src/librustc/middle/dead.rs | 12 +++++- src/librustc/middle/lang_items.rs | 3 ++ src/librustc/middle/weak_lang_items.rs | 3 ++ src/librustc_typeck/check/mod.rs | 47 ++++++++++++++++++++++ src/libstd/alloc.rs | 3 +- src/libstd/lib.rs | 3 +- src/libsyntax/feature_gate.rs | 8 ++++ .../alloc-error-handler-bad-signature-1.rs | 28 +++++++++++++ .../alloc-error-handler-bad-signature-2.rs | 27 +++++++++++++ .../alloc-error-handler-bad-signature-3.rs | 25 ++++++++++++ .../feature-gate-alloc-error-handler.rs | 21 ++++++++++ src/test/run-make-fulldeps/issue-51671/app.rs | 5 ++- src/test/ui/missing-alloc_error_handler.rs | 33 +++++++++++++++ src/test/ui/missing-alloc_error_handler.stderr | 4 ++ src/test/ui/missing-allocator.rs | 8 ++-- 16 files changed, 224 insertions(+), 7 deletions(-) create mode 100644 src/test/compile-fail/alloc-error-handler-bad-signature-1.rs create mode 100644 src/test/compile-fail/alloc-error-handler-bad-signature-2.rs create mode 100644 src/test/compile-fail/alloc-error-handler-bad-signature-3.rs create mode 100644 src/test/compile-fail/feature-gate-alloc-error-handler.rs create mode 100644 src/test/ui/missing-alloc_error_handler.rs create mode 100644 src/test/ui/missing-alloc_error_handler.stderr (limited to 'src/libcore') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 01221aecb62..b6ac248b79f 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -48,6 +48,7 @@ fn size_align() -> (usize, usize) { /// use specific allocators with looser requirements.) #[stable(feature = "alloc_layout", since = "1.28.0")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(not(stage0), lang = "alloc_layout")] pub struct Layout { // size of the requested block of memory, measured in bytes. size_: usize, diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 226d19a9124..42775e3a183 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -288,7 +288,17 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt, id: ast::NodeId, attrs: &[ast::Attribute]) -> bool { - if attr::contains_name(attrs, "lang") || attr::contains_name(attrs, "panic_implementation") { + if attr::contains_name(attrs, "lang") { + return true; + } + + // (To be) stable attribute for #[lang = "panic_impl"] + if attr::contains_name(attrs, "panic_implementation") { + return true; + } + + // (To be) stable attribute for #[lang = "oom"] + if attr::contains_name(attrs, "alloc_error_handler") { return true; } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index fe676919a7d..6c1ef851cbe 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -187,6 +187,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { } } else if attribute.check_name("panic_implementation") { return Some((Symbol::intern("panic_impl"), attribute.span)) + } else if attribute.check_name("alloc_error_handler") { + return Some((Symbol::intern("oom"), attribute.span)) } } @@ -308,6 +310,7 @@ language_item_table! { BoxFreeFnLangItem, "box_free", box_free_fn; DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn; OomLangItem, "oom", oom; + AllocLayoutLangItem, "alloc_layout", alloc_layout; StartFnLangItem, "start", start_fn; diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 180e75df1a6..d8570b43fbe 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -115,6 +115,9 @@ fn verify<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if lang_items::$item == lang_items::PanicImplLangItem { tcx.sess.err(&format!("`#[panic_implementation]` function required, \ but not found")); + } else if lang_items::$item == lang_items::OomLangItem { + tcx.sess.err(&format!("`#[alloc_error_handler]` function required, \ + but not found")); } else { tcx.sess.err(&format!("language item required, but not found: `{}`", stringify!($name))); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 646c4f17568..c7ad3398873 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1182,7 +1182,54 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.tcx.sess.err("language item required, but not found: `panic_info`"); } } + } + + // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !` + if let Some(alloc_error_handler_did) = fcx.tcx.lang_items().oom() { + if alloc_error_handler_did == fcx.tcx.hir.local_def_id(fn_id) { + if let Some(alloc_layout_did) = fcx.tcx.lang_items().alloc_layout() { + if declared_ret_ty.sty != ty::TyNever { + fcx.tcx.sess.span_err( + decl.output.span(), + "return type should be `!`", + ); + } + + let inputs = fn_sig.inputs(); + let span = fcx.tcx.hir.span(fn_id); + if inputs.len() == 1 { + let arg_is_alloc_layout = match inputs[0].sty { + ty::TyAdt(ref adt, _) => { + adt.did == alloc_layout_did + }, + _ => false, + }; + + if !arg_is_alloc_layout { + fcx.tcx.sess.span_err( + decl.inputs[0].span, + "argument should be `Layout`", + ); + } + if let Node::NodeItem(item) = fcx.tcx.hir.get(fn_id) { + if let Item_::ItemFn(_, _, ref generics, _) = item.node { + if !generics.params.is_empty() { + fcx.tcx.sess.span_err( + span, + "`#[alloc_error_handler]` function should have no type \ + parameters", + ); + } + } + } + } else { + fcx.tcx.sess.span_err(span, "function should have one argument"); + } + } else { + fcx.tcx.sess.err("language item required, but not found: `alloc_layout`"); + } + } } (fcx, gen_ty) diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index cfdfbe1357d..8db365cd21d 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -125,7 +125,8 @@ fn default_alloc_error_hook(layout: Layout) { #[cfg(not(test))] #[doc(hidden)] -#[lang = "oom"] +#[cfg_attr(stage0, lang = "oom")] +#[cfg_attr(not(stage0), alloc_error_handler)] #[unstable(feature = "alloc_internals", issue = "0")] pub fn rust_oom(layout: Layout) -> ! { let hook = HOOK.load(Ordering::SeqCst); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d73cb1f8349..fec14b8d67d 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -233,8 +233,9 @@ // std is implemented with unstable features, many of which are internal // compiler details that will never be stable #![feature(alloc)] -#![feature(allocator_api)] +#![feature(alloc_error_handler)] #![feature(alloc_system)] +#![feature(allocator_api)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index cbc421dbd32..e70d93ae85a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -481,6 +481,9 @@ declare_features! ( // Allows async and await syntax (active, async_await, "1.28.0", Some(50547), None), + + // #[alloc_error_handler] + (active, alloc_error_handler, "1.29.0", Some(51540), None), ); declare_features! ( @@ -1083,6 +1086,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "#[panic_implementation] is an unstable feature", cfg_fn!(panic_implementation))), + ("alloc_error_handler", Normal, Gated(Stability::Unstable, + "alloc_error_handler", + "#[alloc_error_handler] is an unstable feature", + cfg_fn!(alloc_error_handler))), + // Crate level attributes ("crate_name", CrateLevel, Ungated), ("crate_type", CrateLevel, Ungated), diff --git a/src/test/compile-fail/alloc-error-handler-bad-signature-1.rs b/src/test/compile-fail/alloc-error-handler-bad-signature-1.rs new file mode 100644 index 00000000000..e398f16a065 --- /dev/null +++ b/src/test/compile-fail/alloc-error-handler-bad-signature-1.rs @@ -0,0 +1,28 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![feature(alloc_error_handler, panic_implementation)] +#![no_std] +#![no_main] + +use core::alloc::Layout; + +#[alloc_error_handler] +fn oom( + info: &Layout, //~ ERROR argument should be `Layout` +) -> () //~ ERROR return type should be `!` +{ + loop {} +} + +#[panic_implementation] +fn panic(_: &core::panic::PanicInfo) -> ! { loop {} } diff --git a/src/test/compile-fail/alloc-error-handler-bad-signature-2.rs b/src/test/compile-fail/alloc-error-handler-bad-signature-2.rs new file mode 100644 index 00000000000..4fee9d27e51 --- /dev/null +++ b/src/test/compile-fail/alloc-error-handler-bad-signature-2.rs @@ -0,0 +1,27 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![feature(alloc_error_handler, panic_implementation)] +#![no_std] +#![no_main] + +struct Layout; + +#[alloc_error_handler] +fn oom( + info: Layout, //~ ERROR argument should be `Layout` +) { //~ ERROR return type should be `!` + loop {} +} + +#[panic_implementation] +fn panic(_: &core::panic::PanicInfo) -> ! { loop {} } diff --git a/src/test/compile-fail/alloc-error-handler-bad-signature-3.rs b/src/test/compile-fail/alloc-error-handler-bad-signature-3.rs new file mode 100644 index 00000000000..828a78055d5 --- /dev/null +++ b/src/test/compile-fail/alloc-error-handler-bad-signature-3.rs @@ -0,0 +1,25 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![feature(alloc_error_handler, panic_implementation)] +#![no_std] +#![no_main] + +struct Layout; + +#[alloc_error_handler] +fn oom() -> ! { //~ ERROR function should have one argument + loop {} +} + +#[panic_implementation] +fn panic(_: &core::panic::PanicInfo) -> ! { loop {} } diff --git a/src/test/compile-fail/feature-gate-alloc-error-handler.rs b/src/test/compile-fail/feature-gate-alloc-error-handler.rs new file mode 100644 index 00000000000..66691af2d03 --- /dev/null +++ b/src/test/compile-fail/feature-gate-alloc-error-handler.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![no_std] +#![no_main] + +use core::alloc::Layout; + +#[alloc_error_handler] //~ ERROR #[alloc_error_handler] is an unstable feature (see issue #51540) +fn oom(info: Layout) -> ! { + loop {} +} diff --git a/src/test/run-make-fulldeps/issue-51671/app.rs b/src/test/run-make-fulldeps/issue-51671/app.rs index 720ce1512f2..453602b800b 100644 --- a/src/test/run-make-fulldeps/issue-51671/app.rs +++ b/src/test/run-make-fulldeps/issue-51671/app.rs @@ -14,6 +14,7 @@ #![no_main] #![no_std] +use core::alloc::Layout; use core::panic::PanicInfo; #[panic_implementation] @@ -25,4 +26,6 @@ fn panic(_: &PanicInfo) -> ! { fn eh() {} #[lang = "oom"] -fn oom() {} +fn oom(_: Layout) -> ! { + loop {} +} diff --git a/src/test/ui/missing-alloc_error_handler.rs b/src/test/ui/missing-alloc_error_handler.rs new file mode 100644 index 00000000000..3842d48f8fa --- /dev/null +++ b/src/test/ui/missing-alloc_error_handler.rs @@ -0,0 +1,33 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C panic=abort +// no-prefer-dynamic + +#![no_std] +#![crate_type = "staticlib"] +#![feature(panic_implementation, alloc_error_handler, alloc)] + +#[panic_implementation] +fn panic(_: &core::panic::PanicInfo) -> ! { + loop {} +} + +extern crate alloc; + +#[global_allocator] +static A: MyAlloc = MyAlloc; + +struct MyAlloc; + +unsafe impl core::alloc::GlobalAlloc for MyAlloc { + unsafe fn alloc(&self, _: core::alloc::Layout) -> *mut u8 { 0 as _ } + unsafe fn dealloc(&self, _: *mut u8, _: core::alloc::Layout) {} +} diff --git a/src/test/ui/missing-alloc_error_handler.stderr b/src/test/ui/missing-alloc_error_handler.stderr new file mode 100644 index 00000000000..5489b2cbbfa --- /dev/null +++ b/src/test/ui/missing-alloc_error_handler.stderr @@ -0,0 +1,4 @@ +error: `#[alloc_error_handler]` function required, but not found + +error: aborting due to previous error + diff --git a/src/test/ui/missing-allocator.rs b/src/test/ui/missing-allocator.rs index 24282631b7e..c949dcb635a 100644 --- a/src/test/ui/missing-allocator.rs +++ b/src/test/ui/missing-allocator.rs @@ -13,14 +13,16 @@ #![no_std] #![crate_type = "staticlib"] -#![feature(panic_implementation, lang_items, alloc)] +#![feature(panic_implementation, alloc_error_handler, alloc)] #[panic_implementation] fn panic(_: &core::panic::PanicInfo) -> ! { loop {} } -#[lang = "oom"] -fn oom() {} +#[alloc_error_handler] +fn oom(_: core::alloc::Layout) -> ! { + loop {} +} extern crate alloc; -- cgit 1.4.1-3-g733a5 From 39fcfa8ccb4605e307eed4c7515b58c5edc97c74 Mon Sep 17 00:00:00 2001 From: Emerentius Date: Tue, 10 Jul 2018 00:00:51 +0200 Subject: step_by: leave time of item skip unspecified this gives us some leeway when optimizing --- src/libcore/iter/iterator.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 8836de3edc8..c0681619bf8 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -271,9 +271,30 @@ pub trait Iterator { /// Creates an iterator starting at the same point, but stepping by /// the given amount at each iteration. /// - /// Note that it will always return the first element of the iterator, + /// Note 1: The first element of the iterator will always be returned, /// regardless of the step given. /// + /// Note 2: The time at which ignored elements are pulled is not fixed. + /// `StepBy` behaves like the sequence `next(), nth(step-1), nth(step-1), …`, + /// but is also free to behave like the sequence + /// `advance_n_and_return_first(step), advance_n_and_return_first(step), …` + /// Which way is used may change for some iterators for performance reasons. + /// The second way will advance the iterator earlier and may consume more items. + /// + /// `advance_n_and_return_first` is the equivalent of: + /// ``` + /// fn advance_n_and_return_first(iter: &mut I, total_step: usize) -> Option + /// where + /// I: Iterator, + /// { + /// let next = iter.next(); + /// if total_step > 1 { + /// iter.nth(total_step-2); + /// } + /// next + /// } + /// ``` + /// /// # Panics /// /// The method will panic if the given step is `0`. -- cgit 1.4.1-3-g733a5 From ede1a5d5edcebe28f98057d915ae4602378354dc Mon Sep 17 00:00:00 2001 From: Ben Berman Date: Tue, 10 Jul 2018 13:26:44 -0400 Subject: Amend option.take examples It wasn't abundantly clear to me what `.take` returned. Perhaps this is a slightly frivolous change, but I think it's an improvement. =) Apologies if I'm not following proper procedures. --- src/libcore/option.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 20bc173f7e1..c219a9fb521 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -833,12 +833,14 @@ impl Option { /// /// ``` /// let mut x = Some(2); - /// x.take(); + /// let y = x.take(); /// assert_eq!(x, None); + /// assert_eq!(y, Some(2)); /// /// let mut x: Option = None; - /// x.take(); + /// let y = x.take(); /// assert_eq!(x, None); + /// assert_eq!(y, None); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -- cgit 1.4.1-3-g733a5 From 4b51484fed75750a84d8422d26a9a7e6c06294e0 Mon Sep 17 00:00:00 2001 From: Anirudh Balaji Date: Tue, 10 Jul 2018 10:56:58 -0700 Subject: Change wording for {copy, clone}_from_slice --- src/libcore/slice/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index c41776a1460..a0270d747a9 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1541,9 +1541,9 @@ impl [T] { /// let src = [1, 2, 3, 4]; /// let mut dst = [0, 0]; /// - /// // Note: the slices must be the same length, so you can slice the source - /// // or the destination to be the same size. Here we slice the source, four elements, - /// // to two, the same size as the destination slice. It *will* panic if we don't do this. + /// // Because the slices have to be the same length, + /// // we slice the source slice from four elements + /// // to two. It will panic if we don't do this. /// dst.clone_from_slice(&src[2..]); /// /// assert_eq!(src, [1, 2, 3, 4]); @@ -1610,9 +1610,9 @@ impl [T] { /// let src = [1, 2, 3, 4]; /// let mut dst = [0, 0]; /// - /// // Note: the slices must be the same length, so you can slice the source - /// // or the destination to be the same size. Here we slice the source, four elements, - /// // to two, the same size as the destination slice. It *will* panic if we don't do this. + /// // Because the slices have to be the same length, + /// // we slice the source slice from four elements + /// // to two. It will panic if we don't do this. /// dst.copy_from_slice(&src[2..]); /// /// assert_eq!(src, [1, 2, 3, 4]); -- cgit 1.4.1-3-g733a5 From b8c96ce530227c345908bddd91e0380d9a206e06 Mon Sep 17 00:00:00 2001 From: Rémy Rakic Date: Tue, 10 Jul 2018 23:10:13 +0200 Subject: Fix typo in error message E0277 --- src/libcore/marker.rs | 2 +- src/test/compile-fail/associated-types-unsized.rs | 2 +- src/test/compile-fail/bad-sized.rs | 4 +-- src/test/compile-fail/dst-bad-assign-2.rs | 2 +- src/test/compile-fail/dst-bad-assign-3.rs | 2 +- src/test/compile-fail/dst-bad-assign.rs | 2 +- src/test/compile-fail/dst-bad-deep-2.rs | 2 +- src/test/compile-fail/dst-bad-deep.rs | 2 +- .../compile-fail/dst-object-from-unsized-type.rs | 8 ++--- src/test/compile-fail/dst-sized-trait-param.rs | 4 +-- src/test/compile-fail/extern-types-unsized.rs | 8 ++--- src/test/compile-fail/issue-14366.rs | 2 +- src/test/compile-fail/issue-15756.rs | 2 +- src/test/compile-fail/issue-17651.rs | 2 +- src/test/compile-fail/issue-18107.rs | 2 +- src/test/compile-fail/issue-18919.rs | 2 +- src/test/compile-fail/issue-20005.rs | 2 +- src/test/compile-fail/issue-20433.rs | 2 +- src/test/compile-fail/issue-20605.rs | 2 +- src/test/compile-fail/issue-22874.rs | 2 +- src/test/compile-fail/issue-23281.rs | 2 +- src/test/compile-fail/issue-24446.rs | 2 +- src/test/compile-fail/issue-27060-2.rs | 2 +- src/test/compile-fail/issue-27078.rs | 2 +- src/test/compile-fail/issue-35988.rs | 2 +- src/test/compile-fail/issue-38954.rs | 2 +- src/test/compile-fail/issue-41229-ref-str.rs | 2 +- src/test/compile-fail/issue-42312.rs | 4 +-- src/test/compile-fail/issue-5883.rs | 4 +-- src/test/compile-fail/range-1.rs | 2 +- src/test/compile-fail/str-mut-idx.rs | 4 +-- src/test/compile-fail/substs-ppaux.rs | 4 +-- .../compile-fail/trait-bounds-not-on-bare-trait.rs | 2 +- src/test/compile-fail/union/union-unsized.rs | 4 +-- src/test/compile-fail/unsized-bare-typaram.rs | 2 +- src/test/compile-fail/unsized-enum.rs | 2 +- .../unsized-inherent-impl-self-type.rs | 2 +- src/test/compile-fail/unsized-struct.rs | 4 +-- .../compile-fail/unsized-trait-impl-self-type.rs | 2 +- .../compile-fail/unsized-trait-impl-trait-arg.rs | 2 +- src/test/compile-fail/unsized3.rs | 12 +++---- src/test/compile-fail/unsized5.rs | 12 +++---- src/test/compile-fail/unsized6.rs | 26 +++++++------- src/test/compile-fail/unsized7.rs | 2 +- src/test/ui/const-unsized.rs | 8 ++--- src/test/ui/const-unsized.stderr | 8 ++--- src/test/ui/error-codes/E0277.rs | 2 +- src/test/ui/error-codes/E0277.stderr | 2 +- src/test/ui/feature-gate-trivial_bounds.stderr | 6 ++-- src/test/ui/generator/sized-yield.rs | 4 +-- src/test/ui/generator/sized-yield.stderr | 6 ++-- src/test/ui/mismatched_types/cast-rfc0401.rs | 4 +-- src/test/ui/mismatched_types/cast-rfc0401.stderr | 8 ++--- src/test/ui/resolve/issue-5035-2.rs | 2 +- src/test/ui/resolve/issue-5035-2.stderr | 2 +- src/test/ui/suggestions/str-array-assignment.rs | 2 +- .../ui/suggestions/str-array-assignment.stderr | 2 +- src/test/ui/trait-suggest-where-clause.rs | 8 ++--- src/test/ui/trait-suggest-where-clause.stderr | 8 ++--- src/test/ui/trivial-bounds-leak.stderr | 2 +- src/test/ui/union/union-sized-field.rs | 6 ++-- src/test/ui/union/union-sized-field.stderr | 6 ++-- src/test/ui/unsized-enum2.rs | 40 +++++++++++----------- src/test/ui/unsized-enum2.stderr | 40 +++++++++++----------- 64 files changed, 163 insertions(+), 163 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 4a54ebce0a3..090f61a5d69 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -92,7 +92,7 @@ impl !Send for *mut T { } #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sized"] #[rustc_on_unimplemented( - message="the size for value values of type `{Self}` cannot be known at compilation time", + message="the size for values of type `{Self}` cannot be known at compilation time", label="doesn't have a size known at compile-time", note="to learn more, visit ", diff --git a/src/test/compile-fail/associated-types-unsized.rs b/src/test/compile-fail/associated-types-unsized.rs index 3bb0382ef03..c561ae861ed 100644 --- a/src/test/compile-fail/associated-types-unsized.rs +++ b/src/test/compile-fail/associated-types-unsized.rs @@ -14,7 +14,7 @@ trait Get { } fn foo(t: T) { - let x = t.get(); //~ ERROR the size for value values of type + let x = t.get(); //~ ERROR the size for values of type } fn main() { diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs index 9b87ec4d446..a58aebee77b 100644 --- a/src/test/compile-fail/bad-sized.rs +++ b/src/test/compile-fail/bad-sized.rs @@ -13,6 +13,6 @@ trait Trait {} pub fn main() { let x: Vec = Vec::new(); //~^ ERROR only auto traits can be used as additional traits in a trait object - //~| ERROR the size for value values of type - //~| ERROR the size for value values of type + //~| ERROR the size for values of type + //~| ERROR the size for values of type } diff --git a/src/test/compile-fail/dst-bad-assign-2.rs b/src/test/compile-fail/dst-bad-assign-2.rs index 1dbdd42ca36..372f3187805 100644 --- a/src/test/compile-fail/dst-bad-assign-2.rs +++ b/src/test/compile-fail/dst-bad-assign-2.rs @@ -43,6 +43,6 @@ pub fn main() { let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; let z: Box = Box::new(Bar1 {f: 36}); f5.ptr = *z; - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } diff --git a/src/test/compile-fail/dst-bad-assign-3.rs b/src/test/compile-fail/dst-bad-assign-3.rs index 2a209a2959b..339cfb5443d 100644 --- a/src/test/compile-fail/dst-bad-assign-3.rs +++ b/src/test/compile-fail/dst-bad-assign-3.rs @@ -45,5 +45,5 @@ pub fn main() { //~| expected type `dyn ToBar` //~| found type `Bar1` //~| expected trait ToBar, found struct `Bar1` - //~| ERROR the size for value values of type + //~| ERROR the size for values of type } diff --git a/src/test/compile-fail/dst-bad-assign.rs b/src/test/compile-fail/dst-bad-assign.rs index e28586c4755..9a329c636ae 100644 --- a/src/test/compile-fail/dst-bad-assign.rs +++ b/src/test/compile-fail/dst-bad-assign.rs @@ -47,5 +47,5 @@ pub fn main() { //~| expected type `dyn ToBar` //~| found type `Bar1` //~| expected trait ToBar, found struct `Bar1` - //~| ERROR the size for value values of type + //~| ERROR the size for values of type } diff --git a/src/test/compile-fail/dst-bad-deep-2.rs b/src/test/compile-fail/dst-bad-deep-2.rs index 82d81913cd3..a54301071ba 100644 --- a/src/test/compile-fail/dst-bad-deep-2.rs +++ b/src/test/compile-fail/dst-bad-deep-2.rs @@ -19,5 +19,5 @@ pub fn main() { let f: ([isize; 3],) = ([5, 6, 7],); let g: &([isize],) = &f; let h: &(([isize],),) = &(*g,); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } diff --git a/src/test/compile-fail/dst-bad-deep.rs b/src/test/compile-fail/dst-bad-deep.rs index b8ca22185bc..3d7e2b8f671 100644 --- a/src/test/compile-fail/dst-bad-deep.rs +++ b/src/test/compile-fail/dst-bad-deep.rs @@ -21,5 +21,5 @@ pub fn main() { let f: Fat<[isize; 3]> = Fat { ptr: [5, 6, 7] }; let g: &Fat<[isize]> = &f; let h: &Fat> = &Fat { ptr: *g }; - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } diff --git a/src/test/compile-fail/dst-object-from-unsized-type.rs b/src/test/compile-fail/dst-object-from-unsized-type.rs index 4a892753595..70b46b1bd79 100644 --- a/src/test/compile-fail/dst-object-from-unsized-type.rs +++ b/src/test/compile-fail/dst-object-from-unsized-type.rs @@ -16,22 +16,22 @@ impl Foo for [u8] {} fn test1(t: &T) { let u: &Foo = t; - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn test2(t: &T) { let v: &Foo = t as &Foo; - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn test3() { let _: &[&Foo] = &["hi"]; - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn test4(x: &[u8]) { let _: &Foo = x as &Foo; - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn main() { } diff --git a/src/test/compile-fail/dst-sized-trait-param.rs b/src/test/compile-fail/dst-sized-trait-param.rs index 06795567432..7316a48970f 100644 --- a/src/test/compile-fail/dst-sized-trait-param.rs +++ b/src/test/compile-fail/dst-sized-trait-param.rs @@ -15,9 +15,9 @@ trait Foo : Sized { fn take(self, x: &T) { } } // Note: T is sized impl Foo<[isize]> for usize { } -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type impl Foo for [usize] { } -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type pub fn main() { } diff --git a/src/test/compile-fail/extern-types-unsized.rs b/src/test/compile-fail/extern-types-unsized.rs index 135b466161d..f2db4553868 100644 --- a/src/test/compile-fail/extern-types-unsized.rs +++ b/src/test/compile-fail/extern-types-unsized.rs @@ -30,14 +30,14 @@ fn assert_sized() { } fn main() { assert_sized::(); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type assert_sized::(); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type assert_sized::>(); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type assert_sized::>>(); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } diff --git a/src/test/compile-fail/issue-14366.rs b/src/test/compile-fail/issue-14366.rs index 5212cbb004e..0b154d0a3ea 100644 --- a/src/test/compile-fail/issue-14366.rs +++ b/src/test/compile-fail/issue-14366.rs @@ -10,5 +10,5 @@ fn main() { let _x = "test" as &::std::any::Any; - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } diff --git a/src/test/compile-fail/issue-15756.rs b/src/test/compile-fail/issue-15756.rs index 4756099ab95..c123e85a0e0 100644 --- a/src/test/compile-fail/issue-15756.rs +++ b/src/test/compile-fail/issue-15756.rs @@ -15,7 +15,7 @@ fn dft_iter<'a, T>(arg1: Chunks<'a,T>, arg2: ChunksMut<'a,T>) { for &mut something - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type in arg2 { } diff --git a/src/test/compile-fail/issue-17651.rs b/src/test/compile-fail/issue-17651.rs index e7019ff7c0d..cbd0da4b53c 100644 --- a/src/test/compile-fail/issue-17651.rs +++ b/src/test/compile-fail/issue-17651.rs @@ -13,5 +13,5 @@ fn main() { (|| Box::new(*(&[0][..])))(); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } diff --git a/src/test/compile-fail/issue-18107.rs b/src/test/compile-fail/issue-18107.rs index 9239ceb341f..260038b7add 100644 --- a/src/test/compile-fail/issue-18107.rs +++ b/src/test/compile-fail/issue-18107.rs @@ -12,7 +12,7 @@ pub trait AbstractRenderer {} fn _create_render(_: &()) -> AbstractRenderer -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type { match 0 { _ => unimplemented!() diff --git a/src/test/compile-fail/issue-18919.rs b/src/test/compile-fail/issue-18919.rs index 0b717ec6413..cc87a0977a0 100644 --- a/src/test/compile-fail/issue-18919.rs +++ b/src/test/compile-fail/issue-18919.rs @@ -11,7 +11,7 @@ type FuncType<'f> = Fn(&isize) -> isize + 'f; fn ho_func(f: Option) { - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn main() {} diff --git a/src/test/compile-fail/issue-20005.rs b/src/test/compile-fail/issue-20005.rs index 426657ac92e..8db09182fa3 100644 --- a/src/test/compile-fail/issue-20005.rs +++ b/src/test/compile-fail/issue-20005.rs @@ -15,7 +15,7 @@ trait From { } trait To { - fn to( //~ ERROR the size for value values of type + fn to( //~ ERROR the size for values of type self ) -> >::Result where Dst: From { From::from(self) diff --git a/src/test/compile-fail/issue-20433.rs b/src/test/compile-fail/issue-20433.rs index 8b7f2d5a458..f760cd59968 100644 --- a/src/test/compile-fail/issue-20433.rs +++ b/src/test/compile-fail/issue-20433.rs @@ -14,5 +14,5 @@ struct The; impl The { fn iceman(c: Vec<[i32]>) {} - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } diff --git a/src/test/compile-fail/issue-20605.rs b/src/test/compile-fail/issue-20605.rs index 2d8d9c65655..60d012ab134 100644 --- a/src/test/compile-fail/issue-20605.rs +++ b/src/test/compile-fail/issue-20605.rs @@ -10,7 +10,7 @@ fn changer<'a>(mut things: Box>) { for item in *things { *item = 0 } -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type } fn main() {} diff --git a/src/test/compile-fail/issue-22874.rs b/src/test/compile-fail/issue-22874.rs index cb199580b10..e0a87b3a174 100644 --- a/src/test/compile-fail/issue-22874.rs +++ b/src/test/compile-fail/issue-22874.rs @@ -10,7 +10,7 @@ struct Table { rows: [[String]], - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn f(table: &Table) -> &[String] { diff --git a/src/test/compile-fail/issue-23281.rs b/src/test/compile-fail/issue-23281.rs index d6b5c329825..5de00eb8f68 100644 --- a/src/test/compile-fail/issue-23281.rs +++ b/src/test/compile-fail/issue-23281.rs @@ -14,7 +14,7 @@ pub struct Struct; impl Struct { pub fn function(funs: Vec ()>) {} - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn main() {} diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index 74c68c50ae3..a9c7978642d 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -11,7 +11,7 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { //~^ ERROR mismatched types - //~| ERROR the size for value values of type + //~| ERROR the size for values of type 0 }; } diff --git a/src/test/compile-fail/issue-27060-2.rs b/src/test/compile-fail/issue-27060-2.rs index bc5567e1686..619616adda6 100644 --- a/src/test/compile-fail/issue-27060-2.rs +++ b/src/test/compile-fail/issue-27060-2.rs @@ -10,7 +10,7 @@ #[repr(packed)] pub struct Bad { - data: T, //~ ERROR the size for value values of type + data: T, //~ ERROR the size for values of type } fn main() {} diff --git a/src/test/compile-fail/issue-27078.rs b/src/test/compile-fail/issue-27078.rs index 6efc1f10243..294c288a970 100644 --- a/src/test/compile-fail/issue-27078.rs +++ b/src/test/compile-fail/issue-27078.rs @@ -13,7 +13,7 @@ trait Foo { const BAR: i32; fn foo(self) -> &'static i32 { - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type &::BAR } } diff --git a/src/test/compile-fail/issue-35988.rs b/src/test/compile-fail/issue-35988.rs index 805b1a48a03..5909322ff1f 100644 --- a/src/test/compile-fail/issue-35988.rs +++ b/src/test/compile-fail/issue-35988.rs @@ -10,7 +10,7 @@ enum E { V([Box]), - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn main() {} diff --git a/src/test/compile-fail/issue-38954.rs b/src/test/compile-fail/issue-38954.rs index 1b64d17bbef..7f01ed3f820 100644 --- a/src/test/compile-fail/issue-38954.rs +++ b/src/test/compile-fail/issue-38954.rs @@ -9,6 +9,6 @@ // except according to those terms. fn _test(ref _p: str) {} -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type fn main() { } diff --git a/src/test/compile-fail/issue-41229-ref-str.rs b/src/test/compile-fail/issue-41229-ref-str.rs index 6207e669d00..5d7546e1bc4 100644 --- a/src/test/compile-fail/issue-41229-ref-str.rs +++ b/src/test/compile-fail/issue-41229-ref-str.rs @@ -9,6 +9,6 @@ // except according to those terms. pub fn example(ref s: str) {} -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type fn main() {} diff --git a/src/test/compile-fail/issue-42312.rs b/src/test/compile-fail/issue-42312.rs index 2ab44433ede..f7705297dfd 100644 --- a/src/test/compile-fail/issue-42312.rs +++ b/src/test/compile-fail/issue-42312.rs @@ -12,10 +12,10 @@ use std::ops::Deref; pub trait Foo { fn baz(_: Self::Target) where Self: Deref {} - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } pub fn f(_: ToString) {} -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type fn main() { } diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index 82d4666ce54..a91f5d281dd 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -15,8 +15,8 @@ struct Struct { } fn new_struct(r: A+'static) - -> Struct { //~^ ERROR the size for value values of type - //~^ ERROR the size for value values of type + -> Struct { //~^ ERROR the size for values of type + //~^ ERROR the size for values of type Struct { r: r } } diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index ed26204bbe1..59c78052e15 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -22,5 +22,5 @@ pub fn main() { // Unsized type. let arr: &[_] = &[1, 2, 3]; let range = *arr..; - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } diff --git a/src/test/compile-fail/str-mut-idx.rs b/src/test/compile-fail/str-mut-idx.rs index cc5fd7e3f24..136bfaefa71 100644 --- a/src/test/compile-fail/str-mut-idx.rs +++ b/src/test/compile-fail/str-mut-idx.rs @@ -12,8 +12,8 @@ fn bot() -> T { loop {} } fn mutate(s: &mut str) { s[1..2] = bot(); - //~^ ERROR the size for value values of type - //~| ERROR the size for value values of type + //~^ ERROR the size for values of type + //~| ERROR the size for values of type s[1usize] = bot(); //~^ ERROR the type `str` cannot be mutably indexed by `usize` } diff --git a/src/test/compile-fail/substs-ppaux.rs b/src/test/compile-fail/substs-ppaux.rs index b8557cb79e3..d0e9a7f4a40 100644 --- a/src/test/compile-fail/substs-ppaux.rs +++ b/src/test/compile-fail/substs-ppaux.rs @@ -56,6 +56,6 @@ fn foo<'z>() where &'z (): Sized { //[normal]~| found type `fn() {foo::<'static>}` >::bar; - //[verbose]~^ ERROR the size for value values of type - //[normal]~^^ ERROR the size for value values of type + //[verbose]~^ ERROR the size for values of type + //[normal]~^^ ERROR the size for values of type } diff --git a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs index 89fddf1f65f..9c38d8a9e2a 100644 --- a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs +++ b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs @@ -15,7 +15,7 @@ trait Foo { // This should emit the less confusing error, not the more confusing one. fn foo(_x: Foo + Send) { - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn main() { } diff --git a/src/test/compile-fail/union/union-unsized.rs b/src/test/compile-fail/union/union-unsized.rs index a9a2a3c4c92..d79c2ed710e 100644 --- a/src/test/compile-fail/union/union-unsized.rs +++ b/src/test/compile-fail/union/union-unsized.rs @@ -12,7 +12,7 @@ union U { a: str, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type b: u8, } @@ -20,7 +20,7 @@ union U { union W { a: u8, b: str, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn main() {} diff --git a/src/test/compile-fail/unsized-bare-typaram.rs b/src/test/compile-fail/unsized-bare-typaram.rs index 736794ac538..498bdded350 100644 --- a/src/test/compile-fail/unsized-bare-typaram.rs +++ b/src/test/compile-fail/unsized-bare-typaram.rs @@ -10,5 +10,5 @@ fn bar() { } fn foo() { bar::() } -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type fn main() { } diff --git a/src/test/compile-fail/unsized-enum.rs b/src/test/compile-fail/unsized-enum.rs index f9702e29f1d..4a6a5557c95 100644 --- a/src/test/compile-fail/unsized-enum.rs +++ b/src/test/compile-fail/unsized-enum.rs @@ -15,7 +15,7 @@ fn not_sized() { } enum Foo { FooSome(U), FooNone } fn foo1() { not_sized::>() } // Hunky dory. fn foo2() { not_sized::>() } -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type // // Not OK: `T` is not sized. diff --git a/src/test/compile-fail/unsized-inherent-impl-self-type.rs b/src/test/compile-fail/unsized-inherent-impl-self-type.rs index 03d3d98b59f..a679bf77015 100644 --- a/src/test/compile-fail/unsized-inherent-impl-self-type.rs +++ b/src/test/compile-fail/unsized-inherent-impl-self-type.rs @@ -15,7 +15,7 @@ struct S5(Y); impl S5 { - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn main() { } diff --git a/src/test/compile-fail/unsized-struct.rs b/src/test/compile-fail/unsized-struct.rs index 8cb1f760664..f2c63455c51 100644 --- a/src/test/compile-fail/unsized-struct.rs +++ b/src/test/compile-fail/unsized-struct.rs @@ -15,14 +15,14 @@ fn not_sized() { } struct Foo { data: T } fn foo1() { not_sized::>() } // Hunky dory. fn foo2() { not_sized::>() } -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type // // Not OK: `T` is not sized. struct Bar { data: T } fn bar1() { not_sized::>() } fn bar2() { is_sized::>() } -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type // // Not OK: `Bar` is not sized, but it should be. diff --git a/src/test/compile-fail/unsized-trait-impl-self-type.rs b/src/test/compile-fail/unsized-trait-impl-self-type.rs index b3610a4c9b9..5c0b8f12402 100644 --- a/src/test/compile-fail/unsized-trait-impl-self-type.rs +++ b/src/test/compile-fail/unsized-trait-impl-self-type.rs @@ -18,7 +18,7 @@ trait T3 { struct S5(Y); impl T3 for S5 { - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn main() { } diff --git a/src/test/compile-fail/unsized-trait-impl-trait-arg.rs b/src/test/compile-fail/unsized-trait-impl-trait-arg.rs index 50a058a4338..875a52e11c0 100644 --- a/src/test/compile-fail/unsized-trait-impl-trait-arg.rs +++ b/src/test/compile-fail/unsized-trait-impl-trait-arg.rs @@ -16,7 +16,7 @@ trait T2 { } struct S4(Box); impl T2 for S4 { - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn main() { } diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs index 945f20b2877..2e346e473ca 100644 --- a/src/test/compile-fail/unsized3.rs +++ b/src/test/compile-fail/unsized3.rs @@ -15,7 +15,7 @@ use std::marker; // Unbounded. fn f1(x: &X) { f2::(x); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn f2(x: &X) { } @@ -26,7 +26,7 @@ trait T { } fn f3(x: &X) { f4::(x); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn f4(x: &X) { } @@ -41,20 +41,20 @@ struct S { fn f8(x1: &S, x2: &S) { f5(x1); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type f6(x2); // ok } // Test some tuples. fn f9(x1: Box>) { f5(&(*x1, 34)); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn f10(x1: Box>) { f5(&(32, *x1)); - //~^ ERROR the size for value values of type - //~| ERROR the size for value values of type + //~^ ERROR the size for values of type + //~| ERROR the size for values of type } pub fn main() { diff --git a/src/test/compile-fail/unsized5.rs b/src/test/compile-fail/unsized5.rs index e04aa3599e9..a50786e306a 100644 --- a/src/test/compile-fail/unsized5.rs +++ b/src/test/compile-fail/unsized5.rs @@ -12,32 +12,32 @@ struct S1 { f1: X, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type f2: isize, } struct S2 { f: isize, g: X, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type h: isize, } struct S3 { f: str, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type g: [usize] } struct S4 { f: [u8], - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type g: usize } enum E { V1(X, isize), - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } enum F { V2{f1: X, f: isize}, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } pub fn main() { diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index 8ac9fe4c587..1a57f2caf8d 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -15,40 +15,40 @@ trait T {} fn f1(x: &X) { let _: W; // <-- this is OK, no bindings created, no initializer. let _: (isize, (X, isize)); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type let y: Y; - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type let y: (isize, (Z, usize)); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn f2(x: &X) { let y: X; - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type let y: (isize, (Y, isize)); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn f3(x1: Box, x2: Box, x3: Box) { let y: X = *x1; - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type let y = *x2; - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type let (y, z) = (*x3, 4); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn f4(x1: Box, x2: Box, x3: Box) { let y: X = *x1; - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type let y = *x2; - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type let (y, z) = (*x3, 4); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn g1(x: X) {} -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type fn g2(x: X) {} -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type pub fn main() { } diff --git a/src/test/compile-fail/unsized7.rs b/src/test/compile-fail/unsized7.rs index 44d7df35680..07b4ae4c394 100644 --- a/src/test/compile-fail/unsized7.rs +++ b/src/test/compile-fail/unsized7.rs @@ -20,7 +20,7 @@ trait T1 { struct S3(Box); impl T1 for S3 { - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn main() { } diff --git a/src/test/ui/const-unsized.rs b/src/test/ui/const-unsized.rs index c0a367604c3..39ac969b80e 100644 --- a/src/test/ui/const-unsized.rs +++ b/src/test/ui/const-unsized.rs @@ -11,16 +11,16 @@ use std::fmt::Debug; const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type const CONST_FOO: str = *"foo"; -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type static STATIC_BAR: str = *"bar"; -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type fn main() { println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR); diff --git a/src/test/ui/const-unsized.stderr b/src/test/ui/const-unsized.stderr index d6fc5391ba8..e0b31510260 100644 --- a/src/test/ui/const-unsized.stderr +++ b/src/test/ui/const-unsized.stderr @@ -1,4 +1,4 @@ -error[E0277]: the size for value values of type `(dyn std::fmt::Debug + std::marker::Sync + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn std::fmt::Debug + std::marker::Sync + 'static)` cannot be known at compilation time --> $DIR/const-unsized.rs:13:29 | LL | const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); @@ -8,7 +8,7 @@ LL | const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); = note: to learn more, visit = note: constant expressions must have a statically known size -error[E0277]: the size for value values of type `str` cannot be known at compilation time +error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/const-unsized.rs:16:24 | LL | const CONST_FOO: str = *"foo"; @@ -18,7 +18,7 @@ LL | const CONST_FOO: str = *"foo"; = note: to learn more, visit = note: constant expressions must have a statically known size -error[E0277]: the size for value values of type `(dyn std::fmt::Debug + std::marker::Sync + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn std::fmt::Debug + std::marker::Sync + 'static)` cannot be known at compilation time --> $DIR/const-unsized.rs:19:31 | LL | static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); @@ -28,7 +28,7 @@ LL | static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); = note: to learn more, visit = note: constant expressions must have a statically known size -error[E0277]: the size for value values of type `str` cannot be known at compilation time +error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/const-unsized.rs:22:26 | LL | static STATIC_BAR: str = *"bar"; diff --git a/src/test/ui/error-codes/E0277.rs b/src/test/ui/error-codes/E0277.rs index 95f10e7206f..80cb5eb7a4b 100644 --- a/src/test/ui/error-codes/E0277.rs +++ b/src/test/ui/error-codes/E0277.rs @@ -21,7 +21,7 @@ fn some_func(foo: T) { } fn f(p: Path) { } -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type fn main() { some_func(5i32); diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr index ca5b0d2b987..3ea057d7922 100644 --- a/src/test/ui/error-codes/E0277.stderr +++ b/src/test/ui/error-codes/E0277.stderr @@ -1,4 +1,4 @@ -error[E0277]: the size for value values of type `[u8]` cannot be known at compilation time +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/E0277.rs:23:6 | LL | fn f(p: Path) { } diff --git a/src/test/ui/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gate-trivial_bounds.stderr index 19a6a863795..52963671da9 100644 --- a/src/test/ui/feature-gate-trivial_bounds.stderr +++ b/src/test/ui/feature-gate-trivial_bounds.stderr @@ -87,7 +87,7 @@ LL | | } = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable -error[E0277]: the size for value values of type `str` cannot be known at compilation time +error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/feature-gate-trivial_bounds.rs:62:1 | LL | struct TwoStrs(str, str) where str: Sized; //~ ERROR @@ -98,7 +98,7 @@ LL | struct TwoStrs(str, str) where str: Sized; //~ ERROR = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable -error[E0277]: the size for value values of type `(dyn A + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time --> $DIR/feature-gate-trivial_bounds.rs:65:1 | LL | / fn unsized_local() where Dst: Sized { //~ ERROR @@ -112,7 +112,7 @@ LL | | } = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable -error[E0277]: the size for value values of type `str` cannot be known at compilation time +error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/feature-gate-trivial_bounds.rs:69:1 | LL | / fn return_str() -> str where str: Sized { //~ ERROR diff --git a/src/test/ui/generator/sized-yield.rs b/src/test/ui/generator/sized-yield.rs index efaee4095c1..461da94dde0 100644 --- a/src/test/ui/generator/sized-yield.rs +++ b/src/test/ui/generator/sized-yield.rs @@ -15,9 +15,9 @@ use std::ops::Generator; fn main() { let s = String::from("foo"); let mut gen = move || { - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type yield s[..]; }; unsafe { gen.resume(); } - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr index 2938268a804..dfccd7c4d23 100644 --- a/src/test/ui/generator/sized-yield.stderr +++ b/src/test/ui/generator/sized-yield.stderr @@ -1,9 +1,9 @@ -error[E0277]: the size for value values of type `str` cannot be known at compilation time +error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/sized-yield.rs:17:26 | LL | let mut gen = move || { | __________________________^ -LL | | //~^ ERROR the size for value values of type +LL | | //~^ ERROR the size for values of type LL | | yield s[..]; LL | | }; | |____^ doesn't have a size known at compile-time @@ -12,7 +12,7 @@ LL | | }; = note: to learn more, visit = note: the yield type of a generator must have a statically known size -error[E0277]: the size for value values of type `str` cannot be known at compilation time +error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/sized-yield.rs:21:17 | LL | unsafe { gen.resume(); } diff --git a/src/test/ui/mismatched_types/cast-rfc0401.rs b/src/test/ui/mismatched_types/cast-rfc0401.rs index d76c4a015a2..6be6bb4391a 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.rs +++ b/src/test/ui/mismatched_types/cast-rfc0401.rs @@ -60,7 +60,7 @@ fn main() let _ = 42usize as *const [u8]; //~ ERROR is invalid let _ = v as *const [u8]; //~ ERROR cannot cast - let _ = fat_v as *const Foo; //~ ERROR the size for value values of type + let _ = fat_v as *const Foo; //~ ERROR the size for values of type let _ = foo as *const str; //~ ERROR is invalid let _ = foo as *mut str; //~ ERROR is invalid let _ = main as *mut str; //~ ERROR is invalid @@ -69,7 +69,7 @@ fn main() let _ = fat_sv as usize; //~ ERROR is invalid let a : *const str = "hello"; - let _ = a as *const Foo; //~ ERROR the size for value values of type + let _ = a as *const Foo; //~ ERROR the size for values of type // check no error cascade let _ = main.f as *const u32; //~ ERROR no field diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 9335795f6b8..ef877d6e04e 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -216,20 +216,20 @@ LL | let _ = cf as *const Bar; //~ ERROR is invalid | = note: vtable kinds may not match -error[E0277]: the size for value values of type `[u8]` cannot be known at compilation time +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/cast-rfc0401.rs:63:13 | -LL | let _ = fat_v as *const Foo; //~ ERROR the size for value values of type +LL | let _ = fat_v as *const Foo; //~ ERROR the size for values of type | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` = note: to learn more, visit = note: required for the cast to the object type `dyn Foo` -error[E0277]: the size for value values of type `str` cannot be known at compilation time +error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/cast-rfc0401.rs:72:13 | -LL | let _ = a as *const Foo; //~ ERROR the size for value values of type +LL | let _ = a as *const Foo; //~ ERROR the size for values of type | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` diff --git a/src/test/ui/resolve/issue-5035-2.rs b/src/test/ui/resolve/issue-5035-2.rs index ca854f9f701..5e465ca18f4 100644 --- a/src/test/ui/resolve/issue-5035-2.rs +++ b/src/test/ui/resolve/issue-5035-2.rs @@ -12,6 +12,6 @@ trait I {} type K = I+'static; fn foo(_x: K) {} -//~^ ERROR the size for value values of type +//~^ ERROR the size for values of type fn main() {} diff --git a/src/test/ui/resolve/issue-5035-2.stderr b/src/test/ui/resolve/issue-5035-2.stderr index 72bd270165f..7c1ebc353ac 100644 --- a/src/test/ui/resolve/issue-5035-2.stderr +++ b/src/test/ui/resolve/issue-5035-2.stderr @@ -1,4 +1,4 @@ -error[E0277]: the size for value values of type `(dyn I + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn I + 'static)` cannot be known at compilation time --> $DIR/issue-5035-2.rs:14:8 | LL | fn foo(_x: K) {} diff --git a/src/test/ui/suggestions/str-array-assignment.rs b/src/test/ui/suggestions/str-array-assignment.rs index 8fbab402232..9d6cf5fe598 100644 --- a/src/test/ui/suggestions/str-array-assignment.rs +++ b/src/test/ui/suggestions/str-array-assignment.rs @@ -15,7 +15,7 @@ fn main() { let u: &str = if true { s[..2] } else { s }; //~^ ERROR mismatched types let v = s[..2]; - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type let w: &str = s[..2]; //~^ ERROR mismatched types } diff --git a/src/test/ui/suggestions/str-array-assignment.stderr b/src/test/ui/suggestions/str-array-assignment.stderr index 5af936eec5b..e0576cee8f5 100644 --- a/src/test/ui/suggestions/str-array-assignment.stderr +++ b/src/test/ui/suggestions/str-array-assignment.stderr @@ -19,7 +19,7 @@ LL | let u: &str = if true { s[..2] } else { s }; = note: expected type `&str` found type `str` -error[E0277]: the size for value values of type `str` cannot be known at compilation time +error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/str-array-assignment.rs:17:7 | LL | let v = s[..2]; diff --git a/src/test/ui/trait-suggest-where-clause.rs b/src/test/ui/trait-suggest-where-clause.rs index dd74f4f4797..a43b75d2fe8 100644 --- a/src/test/ui/trait-suggest-where-clause.rs +++ b/src/test/ui/trait-suggest-where-clause.rs @@ -15,10 +15,10 @@ struct Misc(T); fn check() { // suggest a where-clause, if needed mem::size_of::(); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type mem::size_of::>(); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type // ... even if T occurs as a type parameter @@ -36,10 +36,10 @@ fn check() { // ... and also not if the error is not related to the type mem::size_of::<[T]>(); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type mem::size_of::<[&U]>(); - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn main() { diff --git a/src/test/ui/trait-suggest-where-clause.stderr b/src/test/ui/trait-suggest-where-clause.stderr index feb31ae22d8..f62e43e2a46 100644 --- a/src/test/ui/trait-suggest-where-clause.stderr +++ b/src/test/ui/trait-suggest-where-clause.stderr @@ -1,4 +1,4 @@ -error[E0277]: the size for value values of type `U` cannot be known at compilation time +error[E0277]: the size for values of type `U` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:17:5 | LL | mem::size_of::(); @@ -9,7 +9,7 @@ LL | mem::size_of::(); = help: consider adding a `where U: std::marker::Sized` bound = note: required by `std::mem::size_of` -error[E0277]: the size for value values of type `U` cannot be known at compilation time +error[E0277]: the size for values of type `U` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:20:5 | LL | mem::size_of::>(); @@ -47,7 +47,7 @@ LL | as From>::from; | = note: required by `std::convert::From::from` -error[E0277]: the size for value values of type `[T]` cannot be known at compilation time +error[E0277]: the size for values of type `[T]` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:38:5 | LL | mem::size_of::<[T]>(); @@ -57,7 +57,7 @@ LL | mem::size_of::<[T]>(); = note: to learn more, visit = note: required by `std::mem::size_of` -error[E0277]: the size for value values of type `[&U]` cannot be known at compilation time +error[E0277]: the size for values of type `[&U]` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:41:5 | LL | mem::size_of::<[&U]>(); diff --git a/src/test/ui/trivial-bounds-leak.stderr b/src/test/ui/trivial-bounds-leak.stderr index d08574c3d87..960123b5d3a 100644 --- a/src/test/ui/trivial-bounds-leak.stderr +++ b/src/test/ui/trivial-bounds-leak.stderr @@ -1,4 +1,4 @@ -error[E0277]: the size for value values of type `str` cannot be known at compilation time +error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/trivial-bounds-leak.rs:22:25 | LL | fn cant_return_str() -> str { //~ ERROR diff --git a/src/test/ui/union/union-sized-field.rs b/src/test/ui/union/union-sized-field.rs index 15822ae4299..66d6632ff5a 100644 --- a/src/test/ui/union/union-sized-field.rs +++ b/src/test/ui/union/union-sized-field.rs @@ -12,18 +12,18 @@ union Foo { value: T, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } struct Foo2 { value: T, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type t: u32, } enum Foo3 { Value(T), - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } fn main() {} diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr index c6b7cf4e078..2b1f4b4e8f3 100644 --- a/src/test/ui/union/union-sized-field.stderr +++ b/src/test/ui/union/union-sized-field.stderr @@ -1,4 +1,4 @@ -error[E0277]: the size for value values of type `T` cannot be known at compilation time +error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/union-sized-field.rs:14:5 | LL | value: T, @@ -9,7 +9,7 @@ LL | value: T, = help: consider adding a `where T: std::marker::Sized` bound = note: no field of a union may have a dynamically sized type -error[E0277]: the size for value values of type `T` cannot be known at compilation time +error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/union-sized-field.rs:19:5 | LL | value: T, @@ -20,7 +20,7 @@ LL | value: T, = help: consider adding a `where T: std::marker::Sized` bound = note: only the last field of a struct may have a dynamically sized type -error[E0277]: the size for value values of type `T` cannot be known at compilation time +error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/union-sized-field.rs:25:11 | LL | Value(T), diff --git a/src/test/ui/unsized-enum2.rs b/src/test/ui/unsized-enum2.rs index 9082ea4abdd..dadcc4206c3 100644 --- a/src/test/ui/unsized-enum2.rs +++ b/src/test/ui/unsized-enum2.rs @@ -31,53 +31,53 @@ struct Path4(PathHelper4); enum E { // parameter VA(W), - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type VB{x: X}, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type VC(isize, Y), - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type VD{u: isize, x: Z}, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type // slice / str VE([u8]), - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type VF{x: str}, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type VG(isize, [f32]), - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type VH{u: isize, x: [u32]}, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type // unsized struct VI(Path1), - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type VJ{x: Path2}, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type VK(isize, Path3), - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type VL{u: isize, x: Path4}, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type // plain trait VM(Foo), - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type VN{x: Bar}, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type VO(isize, FooBar), - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type VP{u: isize, x: BarFoo}, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type // projected VQ(<&'static [i8] as Deref>::Target), - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type VR{x: <&'static [char] as Deref>::Target}, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type VS(isize, <&'static [f64] as Deref>::Target), - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type VT{u: isize, x: <&'static [i32] as Deref>::Target}, - //~^ ERROR the size for value values of type + //~^ ERROR the size for values of type } diff --git a/src/test/ui/unsized-enum2.stderr b/src/test/ui/unsized-enum2.stderr index 1f30c815d30..47d75f33851 100644 --- a/src/test/ui/unsized-enum2.stderr +++ b/src/test/ui/unsized-enum2.stderr @@ -1,4 +1,4 @@ -error[E0277]: the size for value values of type `W` cannot be known at compilation time +error[E0277]: the size for values of type `W` cannot be known at compilation time --> $DIR/unsized-enum2.rs:33:8 | LL | VA(W), @@ -9,7 +9,7 @@ LL | VA(W), = help: consider adding a `where W: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `X` cannot be known at compilation time +error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized-enum2.rs:35:8 | LL | VB{x: X}, @@ -20,7 +20,7 @@ LL | VB{x: X}, = help: consider adding a `where X: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `Y` cannot be known at compilation time +error[E0277]: the size for values of type `Y` cannot be known at compilation time --> $DIR/unsized-enum2.rs:37:15 | LL | VC(isize, Y), @@ -31,7 +31,7 @@ LL | VC(isize, Y), = help: consider adding a `where Y: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `Z` cannot be known at compilation time +error[E0277]: the size for values of type `Z` cannot be known at compilation time --> $DIR/unsized-enum2.rs:39:18 | LL | VD{u: isize, x: Z}, @@ -42,7 +42,7 @@ LL | VD{u: isize, x: Z}, = help: consider adding a `where Z: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `[u8]` cannot be known at compilation time +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:43:8 | LL | VE([u8]), @@ -52,7 +52,7 @@ LL | VE([u8]), = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `str` cannot be known at compilation time +error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/unsized-enum2.rs:45:8 | LL | VF{x: str}, @@ -62,7 +62,7 @@ LL | VF{x: str}, = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `[f32]` cannot be known at compilation time +error[E0277]: the size for values of type `[f32]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:47:15 | LL | VG(isize, [f32]), @@ -72,7 +72,7 @@ LL | VG(isize, [f32]), = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `[u32]` cannot be known at compilation time +error[E0277]: the size for values of type `[u32]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:49:18 | LL | VH{u: isize, x: [u32]}, @@ -82,7 +82,7 @@ LL | VH{u: isize, x: [u32]}, = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `(dyn Foo + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:63:8 | LL | VM(Foo), @@ -92,7 +92,7 @@ LL | VM(Foo), = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `(dyn Bar + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn Bar + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:65:8 | LL | VN{x: Bar}, @@ -102,7 +102,7 @@ LL | VN{x: Bar}, = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `(dyn FooBar + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn FooBar + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:67:15 | LL | VO(isize, FooBar), @@ -112,7 +112,7 @@ LL | VO(isize, FooBar), = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `(dyn BarFoo + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn BarFoo + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:69:18 | LL | VP{u: isize, x: BarFoo}, @@ -122,7 +122,7 @@ LL | VP{u: isize, x: BarFoo}, = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `[i8]` cannot be known at compilation time +error[E0277]: the size for values of type `[i8]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:73:8 | LL | VQ(<&'static [i8] as Deref>::Target), @@ -132,7 +132,7 @@ LL | VQ(<&'static [i8] as Deref>::Target), = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `[char]` cannot be known at compilation time +error[E0277]: the size for values of type `[char]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:75:8 | LL | VR{x: <&'static [char] as Deref>::Target}, @@ -142,7 +142,7 @@ LL | VR{x: <&'static [char] as Deref>::Target}, = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `[f64]` cannot be known at compilation time +error[E0277]: the size for values of type `[f64]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:77:15 | LL | VS(isize, <&'static [f64] as Deref>::Target), @@ -152,7 +152,7 @@ LL | VS(isize, <&'static [f64] as Deref>::Target), = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `[i32]` cannot be known at compilation time +error[E0277]: the size for values of type `[i32]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:79:18 | LL | VT{u: isize, x: <&'static [i32] as Deref>::Target}, @@ -162,7 +162,7 @@ LL | VT{u: isize, x: <&'static [i32] as Deref>::Target}, = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `(dyn PathHelper1 + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn PathHelper1 + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:53:8 | LL | VI(Path1), @@ -173,7 +173,7 @@ LL | VI(Path1), = note: required because it appears within the type `Path1` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `(dyn PathHelper2 + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn PathHelper2 + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:55:8 | LL | VJ{x: Path2}, @@ -184,7 +184,7 @@ LL | VJ{x: Path2}, = note: required because it appears within the type `Path2` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `(dyn PathHelper3 + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn PathHelper3 + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:57:15 | LL | VK(isize, Path3), @@ -195,7 +195,7 @@ LL | VK(isize, Path3), = note: required because it appears within the type `Path3` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the size for value values of type `(dyn PathHelper4 + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn PathHelper4 + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:59:18 | LL | VL{u: isize, x: Path4}, -- cgit 1.4.1-3-g733a5 From d2fb2fb2a5f58839eda54e5f347e0959ed6eec7c Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 10 Jul 2018 22:25:38 -0400 Subject: Avoid unwrapping in PanicInfo doc example. Fixes https://github.com/rust-lang/rust/issues/51768. --- src/libcore/panic.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 1b4129b99fc..10f02ca2fdc 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -30,7 +30,11 @@ use fmt; /// use std::panic; /// /// panic::set_hook(Box::new(|panic_info| { -/// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); +/// if let Some(s) = panic_info.payload().downcast_ref::<&str>() { +/// println!("panic occurred: {:?}", s); +/// } else { +/// println!("panic occurred"); +/// } /// })); /// /// panic!("Normal panic"); -- cgit 1.4.1-3-g733a5 From f5f21aa9d6dc2f60a7e4b103055cfd052e732036 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sun, 8 Jul 2018 18:02:33 -0400 Subject: use proper footnote syntax for references The previous syntax was causing rustdoc to interpret them as links. --- src/libcore/num/flt2dec/strategy/dragon.rs | 11 +++++------ src/libcore/num/flt2dec/strategy/grisu.rs | 13 ++++++------- 2 files changed, 11 insertions(+), 13 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/flt2dec/strategy/dragon.rs b/src/libcore/num/flt2dec/strategy/dragon.rs index 9c9e531c593..aa6a08cb205 100644 --- a/src/libcore/num/flt2dec/strategy/dragon.rs +++ b/src/libcore/num/flt2dec/strategy/dragon.rs @@ -8,12 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! -Almost direct (but slightly optimized) Rust translation of Figure 3 of \[1\]. - -\[1\] Burger, R. G. and Dybvig, R. K. 1996. Printing floating-point numbers - quickly and accurately. SIGPLAN Not. 31, 5 (May. 1996), 108-116. -*/ +//! Almost direct (but slightly optimized) Rust translation of Figure 3 of "Printing +//! Floating-Point Numbers Quickly and Accurately"[^1]. +//! +//! [^1]: Burger, R. G. and Dybvig, R. K. 1996. Printing floating-point numbers +//! quickly and accurately. SIGPLAN Not. 31, 5 (May. 1996), 108-116. use cmp::Ordering; diff --git a/src/libcore/num/flt2dec/strategy/grisu.rs b/src/libcore/num/flt2dec/strategy/grisu.rs index 5c023a191db..f33186e59c2 100644 --- a/src/libcore/num/flt2dec/strategy/grisu.rs +++ b/src/libcore/num/flt2dec/strategy/grisu.rs @@ -8,13 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! -Rust adaptation of Grisu3 algorithm described in \[1\]. It uses about -1KB of precomputed table, and in turn, it's very quick for most inputs. - -\[1\] Florian Loitsch. 2010. Printing floating-point numbers quickly and - accurately with integers. SIGPLAN Not. 45, 6 (June 2010), 233-243. -*/ +//! Rust adaptation of the Grisu3 algorithm described in "Printing Floating-Point Numbers Quickly +//! and Accurately with Integers"[^1]. It uses about 1KB of precomputed table, and in turn, it's +//! very quick for most inputs. +//! +//! [^1]: Florian Loitsch. 2010. Printing floating-point numbers quickly and +//! accurately with integers. SIGPLAN Not. 45, 6 (June 2010), 233-243. use num::diy_float::Fp; use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; -- cgit 1.4.1-3-g733a5 From 808bcfbe53cec7aa6d728148fc2fcb3a4c951009 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Thu, 12 Jul 2018 19:49:55 +0300 Subject: deprecation message improvement --- src/libcore/str/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index e7bebc891d9..d642f3d696f 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2453,7 +2453,7 @@ impl str { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.29.0", reason = "duplicates `get_unchecked`")] + #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked(begin..end)` instead")] #[inline] pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { (begin..end).get_unchecked(self) @@ -2484,7 +2484,7 @@ impl str { /// * `begin` and `end` must be byte positions within the string slice. /// * `begin` and `end` must lie on UTF-8 sequence boundaries. #[stable(feature = "str_slice_mut", since = "1.5.0")] - #[rustc_deprecated(since = "1.29.0", reason = "duplicates `get_unchecked_mut`")] + #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked_mut(begin..end)` instead")] #[inline] pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { (begin..end).get_unchecked_mut(self) -- cgit 1.4.1-3-g733a5 From 4f4e91a69d75b5de66d53399027cc1835387a423 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Thu, 12 Jul 2018 15:43:57 -0700 Subject: task: remove wrong comments about non-existent LocalWake trait --- src/libcore/task/wake.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs index 418d5af006f..d3df8b50ee2 100644 --- a/src/libcore/task/wake.rs +++ b/src/libcore/task/wake.rs @@ -113,8 +113,8 @@ impl LocalWaker { /// but you otherwise shouldn't call it directly. /// /// If you're working with the standard library then it's recommended to - /// use the `LocalWaker::from` function instead which works with the safe - /// `Rc` type and the safe `LocalWake` trait. + /// use the `local_waker_from_nonlocal` or `local_waker` to convert a `Waker` + /// into a `LocalWaker`. /// /// For this function to be used safely, it must be sound to call `inner.wake_local()` /// on the current thread. @@ -197,9 +197,7 @@ impl Drop for LocalWaker { /// customization. /// /// When using `std`, a default implementation of the `UnsafeWake` trait is provided for -/// `Arc` where `T: Wake` and `Rc` where `T: LocalWake`. -/// -/// Although the methods on `UnsafeWake` take pointers rather than references, +/// `Arc` where `T: Wake`. pub unsafe trait UnsafeWake: Send + Sync { /// Creates a clone of this `UnsafeWake` and stores it behind a `Waker`. /// -- cgit 1.4.1-3-g733a5 From 0d7e9933d3cac85bc1f11dc0fec67fcad77784ca Mon Sep 17 00:00:00 2001 From: kennytm Date: Tue, 19 Jun 2018 04:08:20 +0800 Subject: Change RangeInclusive to a three-field struct. Fix #45222. --- src/libcore/iter/range.rs | 100 ++++++++++++---------------------------- src/libcore/ops/range.rs | 38 ++++++++++++--- src/libcore/slice/mod.rs | 20 ++++---- src/libcore/str/mod.rs | 20 ++++---- src/test/codegen/issue-45222.rs | 74 +++++++++++++++++++++++++++++ 5 files changed, 155 insertions(+), 97 deletions(-) create mode 100644 src/test/codegen/issue-45222.rs (limited to 'src/libcore') diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 0b279f66b88..16849e84f27 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -10,7 +10,7 @@ use convert::TryFrom; use mem; -use ops::{self, Add, Sub, Try}; +use ops::{self, Add, Sub}; use usize; use super::{FusedIterator, TrustedLen}; @@ -330,23 +330,23 @@ impl Iterator for ops::RangeInclusive { #[inline] fn next(&mut self) -> Option { - if self.start <= self.end { - if self.start < self.end { - let n = self.start.add_one(); - Some(mem::replace(&mut self.start, n)) - } else { - let last = self.start.replace_one(); - self.end.replace_zero(); - Some(last) - } + if self.is_empty() { + self.is_iterating = Some(false); + return None; + } + if self.start < self.end { + let n = self.start.add_one(); + self.is_iterating = Some(true); + Some(mem::replace(&mut self.start, n)) } else { - None + self.is_iterating = Some(false); + Some(self.start.clone()) } } #[inline] fn size_hint(&self) -> (usize, Option) { - if !(self.start <= self.end) { + if self.is_empty() { return (0, Some(0)); } @@ -358,25 +358,29 @@ impl Iterator for ops::RangeInclusive { #[inline] fn nth(&mut self, n: usize) -> Option { + if self.is_empty() { + self.is_iterating = Some(false); + return None; + } + if let Some(plus_n) = self.start.add_usize(n) { use cmp::Ordering::*; match plus_n.partial_cmp(&self.end) { Some(Less) => { + self.is_iterating = Some(true); self.start = plus_n.add_one(); return Some(plus_n) } Some(Equal) => { - self.start.replace_one(); - self.end.replace_zero(); + self.is_iterating = Some(false); return Some(plus_n) } _ => {} } } - self.start.replace_one(); - self.end.replace_zero(); + self.is_iterating = Some(false); None } @@ -394,68 +398,24 @@ impl Iterator for ops::RangeInclusive { fn max(mut self) -> Option { self.next_back() } - - #[inline] - fn try_fold(&mut self, init: B, mut f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try - { - let mut accum = init; - if self.start <= self.end { - loop { - let (x, done) = - if self.start < self.end { - let n = self.start.add_one(); - (mem::replace(&mut self.start, n), false) - } else { - self.end.replace_zero(); - (self.start.replace_one(), true) - }; - accum = f(accum, x)?; - if done { break } - } - } - Try::from_ok(accum) - } } #[stable(feature = "inclusive_range", since = "1.26.0")] impl DoubleEndedIterator for ops::RangeInclusive { #[inline] fn next_back(&mut self) -> Option { - if self.start <= self.end { - if self.start < self.end { - let n = self.end.sub_one(); - Some(mem::replace(&mut self.end, n)) - } else { - let last = self.end.replace_zero(); - self.start.replace_one(); - Some(last) - } - } else { - None + if self.is_empty() { + self.is_iterating = Some(false); + return None; } - } - - #[inline] - fn try_rfold(&mut self, init: B, mut f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try - { - let mut accum = init; - if self.start <= self.end { - loop { - let (x, done) = - if self.start < self.end { - let n = self.end.sub_one(); - (mem::replace(&mut self.end, n), false) - } else { - self.start.replace_one(); - (self.end.replace_zero(), true) - }; - accum = f(accum, x)?; - if done { break } - } + if self.start < self.end { + let n = self.end.sub_one(); + self.is_iterating = Some(true); + Some(mem::replace(&mut self.end, n)) + } else { + self.is_iterating = Some(false); + Some(self.end.clone()) } - Try::from_ok(accum) } } diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 01e279589da..3f9ac8a54bf 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -9,6 +9,7 @@ // except according to those terms. use fmt; +use hash::{Hash, Hasher}; /// An unbounded range (`..`). /// @@ -326,15 +327,37 @@ impl> RangeTo { /// assert_eq!(arr[1..=2], [ 1,2 ]); // RangeInclusive /// ``` #[doc(alias = "..=")] -#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 +#[derive(Clone)] // not Copy -- see #27186 #[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeInclusive { - // FIXME: The current representation follows RFC 1980, - // but it is known that LLVM is not able to optimize loops following that RFC. - // Consider adding an extra `bool` field to indicate emptiness of the range. - // See #45222 for performance test cases. pub(crate) start: Idx, pub(crate) end: Idx, + pub(crate) is_iterating: Option, + // This field is: + // - `None` when next() or next_back() was never called + // - `Some(true)` when `start <= end` assuming no overflow + // - `Some(false)` otherwise + // The field cannot be a simple `bool` because the `..=` constructor can + // accept non-PartialOrd types, also we want the constructor to be const. +} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +impl PartialEq for RangeInclusive { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.start == other.start && self.end == other.end + } +} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +impl Eq for RangeInclusive {} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +impl Hash for RangeInclusive { + fn hash(&self, state: &mut H) { + self.start.hash(state); + self.end.hash(state); + } } impl RangeInclusive { @@ -350,7 +373,7 @@ impl RangeInclusive { #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] pub const fn new(start: Idx, end: Idx) -> Self { - Self { start, end } + Self { start, end, is_iterating: None } } /// Returns the lower bound of the range (inclusive). @@ -492,8 +515,9 @@ impl> RangeInclusive { /// assert!(r.is_empty()); /// ``` #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] + #[inline] pub fn is_empty(&self) -> bool { - !(self.start <= self.end) + !self.is_iterating.unwrap_or_else(|| self.start <= self.end) } } diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index ed29d80cb90..e6db4cb38ec 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2262,36 +2262,36 @@ impl SliceIndex<[T]> for ops::RangeInclusive { #[inline] fn get(self, slice: &[T]) -> Option<&[T]> { - if self.end == usize::max_value() { None } - else { (self.start..self.end + 1).get(slice) } + if *self.end() == usize::max_value() { None } + else { (*self.start()..self.end() + 1).get(slice) } } #[inline] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - if self.end == usize::max_value() { None } - else { (self.start..self.end + 1).get_mut(slice) } + if *self.end() == usize::max_value() { None } + else { (*self.start()..self.end() + 1).get_mut(slice) } } #[inline] unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { - (self.start..self.end + 1).get_unchecked(slice) + (*self.start()..self.end() + 1).get_unchecked(slice) } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { - (self.start..self.end + 1).get_unchecked_mut(slice) + (*self.start()..self.end() + 1).get_unchecked_mut(slice) } #[inline] fn index(self, slice: &[T]) -> &[T] { - if self.end == usize::max_value() { slice_index_overflow_fail(); } - (self.start..self.end + 1).index(slice) + if *self.end() == usize::max_value() { slice_index_overflow_fail(); } + (*self.start()..self.end() + 1).index(slice) } #[inline] fn index_mut(self, slice: &mut [T]) -> &mut [T] { - if self.end == usize::max_value() { slice_index_overflow_fail(); } - (self.start..self.end + 1).index_mut(slice) + if *self.end() == usize::max_value() { slice_index_overflow_fail(); } + (*self.start()..self.end() + 1).index_mut(slice) } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 5ae2f6349e5..255e8a07d75 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2004,31 +2004,31 @@ mod traits { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { - if self.end == usize::max_value() { None } - else { (self.start..self.end+1).get(slice) } + if *self.end() == usize::max_value() { None } + else { (*self.start()..self.end()+1).get(slice) } } #[inline] fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if self.end == usize::max_value() { None } - else { (self.start..self.end+1).get_mut(slice) } + if *self.end() == usize::max_value() { None } + else { (*self.start()..self.end()+1).get_mut(slice) } } #[inline] unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { - (self.start..self.end+1).get_unchecked(slice) + (*self.start()..self.end()+1).get_unchecked(slice) } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { - (self.start..self.end+1).get_unchecked_mut(slice) + (*self.start()..self.end()+1).get_unchecked_mut(slice) } #[inline] fn index(self, slice: &str) -> &Self::Output { - if self.end == usize::max_value() { str_index_overflow_fail(); } - (self.start..self.end+1).index(slice) + if *self.end() == usize::max_value() { str_index_overflow_fail(); } + (*self.start()..self.end()+1).index(slice) } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { - if self.end == usize::max_value() { str_index_overflow_fail(); } - (self.start..self.end+1).index_mut(slice) + if *self.end() == usize::max_value() { str_index_overflow_fail(); } + (*self.start()..self.end()+1).index_mut(slice) } } diff --git a/src/test/codegen/issue-45222.rs b/src/test/codegen/issue-45222.rs new file mode 100644 index 00000000000..30a03243f01 --- /dev/null +++ b/src/test/codegen/issue-45222.rs @@ -0,0 +1,74 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -O +// min-llvm-version 6.0 + +#![crate_type = "lib"] + +// verify that LLVM recognizes a loop involving 0..=n and will const-fold it. + +//------------------------------------------------------------------------------ +// Example from original issue #45222 + +fn foo2(n: u64) -> u64 { + let mut count = 0; + for _ in 0..n { + for j in (0..=n).rev() { + count += j; + } + } + count +} + +// CHECK-LABEL: @check_foo2 +#[no_mangle] +pub fn check_foo2() -> u64 { + // CHECK: ret i64 500005000000000 + foo2(100000) +} + +//------------------------------------------------------------------------------ +// Simplified example of #45222 + +fn triangle_inc(n: u64) -> u64 { + let mut count = 0; + for j in 0 ..= n { + count += j; + } + count +} + +// CHECK-LABEL: @check_triangle_inc +#[no_mangle] +pub fn check_triangle_inc() -> u64 { + // CHECK: ret i64 5000050000 + triangle_inc(100000) +} + +//------------------------------------------------------------------------------ +// Demo in #48012 + +fn foo3r(n: u64) -> u64 { + let mut count = 0; + (0..n).for_each(|_| { + (0 ..= n).rev().for_each(|j| { + count += j; + }) + }); + count +} + +// CHECK-LABEL: @check_foo3r +#[no_mangle] +pub fn check_foo3r() -> u64 { + // CHECK: ret i64 500005000000000 + foo3r(100000) +} -- cgit 1.4.1-3-g733a5 From b6ea93e46410cccf8d115e57283d1df5968dd0f2 Mon Sep 17 00:00:00 2001 From: kennytm Date: Sat, 23 Jun 2018 01:42:29 +0800 Subject: Upgrade implementation of StepBy>. --- src/libcore/iter/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 86b297557dd..32134783516 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -787,17 +787,19 @@ where #[inline] fn spec_next(&mut self) -> Option { self.first_take = false; - if !(self.iter.start <= self.iter.end) { + if self.iter.is_empty() { + self.iter.is_iterating = Some(false); return None; } // add 1 to self.step to get original step size back // it was decremented for the general case on construction if let Some(n) = self.iter.start.add_usize(self.step+1) { + self.iter.is_iterating = Some(n <= self.iter.end); let next = mem::replace(&mut self.iter.start, n); Some(next) } else { - let last = self.iter.start.replace_one(); - self.iter.end.replace_zero(); + let last = self.iter.start.clone(); + self.iter.is_iterating = Some(false); Some(last) } } -- cgit 1.4.1-3-g733a5 From 6e0dd9ec0362af41996cf2d2a0afd520bf873d3a Mon Sep 17 00:00:00 2001 From: kennytm Date: Sat, 30 Jun 2018 17:13:21 +0800 Subject: Include is_empty() in PartialEq and Hash. When the index is not PartialOrd, always treat the range as empty. --- src/libcore/ops/range.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 3f9ac8a54bf..0f119789a75 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -341,11 +341,29 @@ pub struct RangeInclusive { // accept non-PartialOrd types, also we want the constructor to be const. } +trait RangeInclusiveEquality: Sized { + fn canonicalized_is_empty(range: &RangeInclusive) -> bool; +} +impl RangeInclusiveEquality for T { + #[inline] + default fn canonicalized_is_empty(range: &RangeInclusive) -> bool { + !range.is_iterating.unwrap_or(false) + } +} +impl RangeInclusiveEquality for T { + #[inline] + fn canonicalized_is_empty(range: &RangeInclusive) -> bool { + range.is_empty() + } +} + #[stable(feature = "inclusive_range", since = "1.26.0")] impl PartialEq for RangeInclusive { #[inline] fn eq(&self, other: &Self) -> bool { self.start == other.start && self.end == other.end + && RangeInclusiveEquality::canonicalized_is_empty(self) + == RangeInclusiveEquality::canonicalized_is_empty(other) } } @@ -357,6 +375,7 @@ impl Hash for RangeInclusive { fn hash(&self, state: &mut H) { self.start.hash(state); self.end.hash(state); + RangeInclusiveEquality::canonicalized_is_empty(self).hash(state); } } -- cgit 1.4.1-3-g733a5 From 6093128ef3c5ae661ec66fbf3685833d6be217bb Mon Sep 17 00:00:00 2001 From: kennytm Date: Fri, 13 Jul 2018 13:08:28 +0800 Subject: Changed implementation of the third field to make LLVM optimize it better. --- src/libcore/iter/mod.rs | 8 ++++---- src/libcore/iter/range.rs | 42 +++++++++++++++++++++--------------------- src/libcore/ops/range.rs | 20 ++++++++++++++------ 3 files changed, 39 insertions(+), 31 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 32134783516..35ae7741106 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -787,19 +787,19 @@ where #[inline] fn spec_next(&mut self) -> Option { self.first_take = false; - if self.iter.is_empty() { - self.iter.is_iterating = Some(false); + self.iter.compute_is_empty(); + if self.iter.is_empty.unwrap_or_default() { return None; } // add 1 to self.step to get original step size back // it was decremented for the general case on construction if let Some(n) = self.iter.start.add_usize(self.step+1) { - self.iter.is_iterating = Some(n <= self.iter.end); + self.iter.is_empty = Some(!(n <= self.iter.end)); let next = mem::replace(&mut self.iter.start, n); Some(next) } else { let last = self.iter.start.clone(); - self.iter.is_iterating = Some(false); + self.iter.is_empty = Some(true); Some(last) } } diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 16849e84f27..651c7a35d41 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -330,18 +330,18 @@ impl Iterator for ops::RangeInclusive { #[inline] fn next(&mut self) -> Option { - if self.is_empty() { - self.is_iterating = Some(false); + self.compute_is_empty(); + if self.is_empty.unwrap_or_default() { return None; } - if self.start < self.end { + let is_iterating = self.start < self.end; + self.is_empty = Some(!is_iterating); + Some(if is_iterating { let n = self.start.add_one(); - self.is_iterating = Some(true); - Some(mem::replace(&mut self.start, n)) + mem::replace(&mut self.start, n) } else { - self.is_iterating = Some(false); - Some(self.start.clone()) - } + self.start.clone() + }) } #[inline] @@ -358,8 +358,8 @@ impl Iterator for ops::RangeInclusive { #[inline] fn nth(&mut self, n: usize) -> Option { - if self.is_empty() { - self.is_iterating = Some(false); + self.compute_is_empty(); + if self.is_empty.unwrap_or_default() { return None; } @@ -368,19 +368,19 @@ impl Iterator for ops::RangeInclusive { match plus_n.partial_cmp(&self.end) { Some(Less) => { - self.is_iterating = Some(true); + self.is_empty = Some(false); self.start = plus_n.add_one(); return Some(plus_n) } Some(Equal) => { - self.is_iterating = Some(false); + self.is_empty = Some(true); return Some(plus_n) } _ => {} } } - self.is_iterating = Some(false); + self.is_empty = Some(true); None } @@ -404,18 +404,18 @@ impl Iterator for ops::RangeInclusive { impl DoubleEndedIterator for ops::RangeInclusive { #[inline] fn next_back(&mut self) -> Option { - if self.is_empty() { - self.is_iterating = Some(false); + self.compute_is_empty(); + if self.is_empty.unwrap_or_default() { return None; } - if self.start < self.end { + let is_iterating = self.start < self.end; + self.is_empty = Some(!is_iterating); + Some(if is_iterating { let n = self.end.sub_one(); - self.is_iterating = Some(true); - Some(mem::replace(&mut self.end, n)) + mem::replace(&mut self.end, n) } else { - self.is_iterating = Some(false); - Some(self.end.clone()) - } + self.end.clone() + }) } } diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 0f119789a75..9c635678d7a 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -332,11 +332,11 @@ impl> RangeTo { pub struct RangeInclusive { pub(crate) start: Idx, pub(crate) end: Idx, - pub(crate) is_iterating: Option, + pub(crate) is_empty: Option, // This field is: // - `None` when next() or next_back() was never called - // - `Some(true)` when `start <= end` assuming no overflow - // - `Some(false)` otherwise + // - `Some(false)` when `start <= end` assuming no overflow + // - `Some(true)` otherwise // The field cannot be a simple `bool` because the `..=` constructor can // accept non-PartialOrd types, also we want the constructor to be const. } @@ -347,7 +347,7 @@ trait RangeInclusiveEquality: Sized { impl RangeInclusiveEquality for T { #[inline] default fn canonicalized_is_empty(range: &RangeInclusive) -> bool { - !range.is_iterating.unwrap_or(false) + range.is_empty.unwrap_or_default() } } impl RangeInclusiveEquality for T { @@ -392,7 +392,7 @@ impl RangeInclusive { #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] pub const fn new(start: Idx, end: Idx) -> Self { - Self { start, end, is_iterating: None } + Self { start, end, is_empty: None } } /// Returns the lower bound of the range (inclusive). @@ -536,7 +536,15 @@ impl> RangeInclusive { #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] #[inline] pub fn is_empty(&self) -> bool { - !self.is_iterating.unwrap_or_else(|| self.start <= self.end) + self.is_empty.unwrap_or_else(|| !(self.start <= self.end)) + } + + // If this range's `is_empty` is field is unknown (`None`), update it to be a concrete value. + #[inline] + pub(crate) fn compute_is_empty(&mut self) { + if self.is_empty.is_none() { + self.is_empty = Some(!(self.start <= self.end)); + } } } -- cgit 1.4.1-3-g733a5 From 9a86e3df991fc008ed96c0dce9d77b3dc1ff792c Mon Sep 17 00:00:00 2001 From: Karoline Plum Date: Sat, 14 Jul 2018 15:48:52 +0200 Subject: Make rounding down clear in duration documentation Now also the documentations of `subsec_millis`, `subsec_micros`, `as_millis` and `as_micros` make clear that the fractional nanosecond component is rounded down to whole units. --- src/libcore/time.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 25721b7fcec..54973b7b778 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -208,7 +208,7 @@ impl Duration { #[inline] pub const fn as_secs(&self) -> u64 { self.secs } - /// Returns the fractional part of this `Duration`, in milliseconds. + /// Returns the fractional part of this `Duration`, in whole milliseconds. /// /// This method does **not** return the length of the duration when /// represented by milliseconds. The returned number always represents a @@ -228,7 +228,7 @@ impl Duration { #[inline] pub const fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI } - /// Returns the fractional part of this `Duration`, in microseconds. + /// Returns the fractional part of this `Duration`, in whole microseconds. /// /// This method does **not** return the length of the duration when /// represented by microseconds. The returned number always represents a @@ -268,7 +268,7 @@ impl Duration { #[inline] pub const fn subsec_nanos(&self) -> u32 { self.nanos } - /// Returns the total number of milliseconds contained by this `Duration`. + /// Returns the total number of whole milliseconds contained by this `Duration`. /// /// # Examples /// @@ -285,7 +285,7 @@ impl Duration { self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos / NANOS_PER_MILLI) as u128 } - /// Returns the total number of microseconds contained by this `Duration`. + /// Returns the total number of whole microseconds contained by this `Duration`. /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 303306cf5ede678719ec1324bb02d3d02c014183 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 14 Jul 2018 23:28:39 +0100 Subject: Add unaligned volatile intrinsics --- src/libcore/intrinsics.rs | 9 +++++++++ src/librustc_codegen_llvm/builder.rs | 8 +++++++- src/librustc_codegen_llvm/intrinsic.rs | 14 ++++++++++++-- src/librustc_codegen_llvm/mir/operand.rs | 4 ++++ src/librustc_typeck/check/intrinsic.rs | 4 ++-- src/test/run-make-fulldeps/volatile-intrinsics/main.rs | 13 ++++++++++--- 6 files changed, 44 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 89fe2d941a3..854cb5f4e3b 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1085,6 +1085,15 @@ extern "rust-intrinsic" { /// [`std::ptr::write_volatile`](../../std/ptr/fn.write_volatile.html). pub fn volatile_store(dst: *mut T, val: T); + /// Perform a volatile load from the `src` pointer + /// The pointer is not required to be aligned. + #[cfg(not(stage0))] + pub fn unaligned_volatile_load(src: *const T) -> T; + /// Perform a volatile store to the `dst` pointer. + /// The pointer is not required to be aligned. + #[cfg(not(stage0))] + pub fn unaligned_volatile_store(dst: *mut T, val: T); + /// Returns the square root of an `f32` pub fn sqrtf32(x: f32) -> f32; /// Returns the square root of an `f64` diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index 7b4998e8588..c8dc579cd62 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -54,6 +54,7 @@ bitflags! { pub struct MemFlags: u8 { const VOLATILE = 1 << 0; const NONTEMPORAL = 1 << 1; + const UNALIGNED = 1 << 2; } } @@ -602,7 +603,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let ptr = self.check_store(val, ptr); unsafe { let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr); - llvm::LLVMSetAlignment(store, align.abi() as c_uint); + let align = if flags.contains(MemFlags::UNALIGNED) { + 1 + } else { + align.abi() as c_uint + }; + llvm::LLVMSetAlignment(store, align); if flags.contains(MemFlags::VOLATILE) { llvm::LLVMSetVolatile(store, llvm::True); } diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 6bb5456f903..567595b6997 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -234,15 +234,20 @@ pub fn codegen_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, memset_intrinsic(bx, true, substs.type_at(0), args[0].immediate(), args[1].immediate(), args[2].immediate()) } - "volatile_load" => { + "volatile_load" | "unaligned_volatile_load" => { let tp_ty = substs.type_at(0); let mut ptr = args[0].immediate(); if let PassMode::Cast(ty) = fn_ty.ret.mode { ptr = bx.pointercast(ptr, ty.llvm_type(cx).ptr_to()); } let load = bx.volatile_load(ptr); + let align = if name == "unaligned_volatile_load" { + 1 + } else { + cx.align_of(tp_ty).abi() as u32 + }; unsafe { - llvm::LLVMSetAlignment(load, cx.align_of(tp_ty).abi() as u32); + llvm::LLVMSetAlignment(load, align); } to_immediate(bx, load, cx.layout_of(tp_ty)) }, @@ -251,6 +256,11 @@ pub fn codegen_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, args[1].val.volatile_store(bx, dst); return; }, + "unaligned_volatile_store" => { + let dst = args[0].deref(bx.cx); + args[1].val.unaligned_volatile_store(bx, dst); + return; + }, "prefetch_read_data" | "prefetch_write_data" | "prefetch_read_instruction" | "prefetch_write_instruction" => { let expect = cx.get_intrinsic(&("llvm.prefetch")); diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs index 3d3a4400bd8..49cc07d6854 100644 --- a/src/librustc_codegen_llvm/mir/operand.rs +++ b/src/librustc_codegen_llvm/mir/operand.rs @@ -286,6 +286,10 @@ impl<'a, 'tcx> OperandValue { self.store_with_flags(bx, dest, MemFlags::VOLATILE); } + pub fn unaligned_volatile_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { + self.store_with_flags(bx, dest, MemFlags::VOLATILE | MemFlags::UNALIGNED); + } + pub fn nontemporal_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { self.store_with_flags(bx, dest, MemFlags::NONTEMPORAL); } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index c93023edcea..46cf9d1fa7f 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -270,9 +270,9 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "roundf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), "roundf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), - "volatile_load" => + "volatile_load" | "unaligned_volatile_load" => (1, vec![ tcx.mk_imm_ptr(param(0)) ], param(0)), - "volatile_store" => + "volatile_store" | "unaligned_volatile_store" => (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil()), "ctpop" | "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | diff --git a/src/test/run-make-fulldeps/volatile-intrinsics/main.rs b/src/test/run-make-fulldeps/volatile-intrinsics/main.rs index 4d0d7672101..d214a20139c 100644 --- a/src/test/run-make-fulldeps/volatile-intrinsics/main.rs +++ b/src/test/run-make-fulldeps/volatile-intrinsics/main.rs @@ -10,17 +10,24 @@ #![feature(core_intrinsics, volatile)] -use std::intrinsics::{volatile_load, volatile_store}; +use std::intrinsics::{ + unaligned_volatile_load, unaligned_volatile_store, volatile_load, volatile_store, +}; use std::ptr::{read_volatile, write_volatile}; pub fn main() { unsafe { - let mut i : isize = 1; + let mut i: isize = 1; volatile_store(&mut i, 2); assert_eq!(volatile_load(&i), 2); } unsafe { - let mut i : isize = 1; + let mut i: isize = 1; + unaligned_volatile_store(&mut i, 2); + assert_eq!(unaligned_volatile_load(&i), 2); + } + unsafe { + let mut i: isize = 1; write_volatile(&mut i, 2); assert_eq!(read_volatile(&i), 2); } -- cgit 1.4.1-3-g733a5 From 02edc7e4ffde4c020832f5248cd4fc12650d9810 Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Sun, 15 Jul 2018 10:16:36 +1000 Subject: AsRef doc wording tweaks --- src/libcore/convert.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 7324df95bc5..11cc4ffecf0 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -63,9 +63,9 @@ /// /// The key difference between the two traits is the intention: /// -/// - Use `AsRef` when goal is to simply convert into a reference -/// - Use `Borrow` when goal is related to writing code that is agnostic to the -/// type of borrow and if is reference or value +/// - Use `AsRef` when the goal is to simply convert into a reference +/// - Use `Borrow` when the goal is related to writing code that is agnostic to +/// the type of borrow and whether it is a reference or value /// /// See [the book][book] for a more detailed comparison. /// -- cgit 1.4.1-3-g733a5 From b1d2a91f3260b5ee045310f4eb28abd2c62773e1 Mon Sep 17 00:00:00 2001 From: Marco Neumann Date: Sun, 15 Jul 2018 17:37:46 +0200 Subject: impl PartialEq+Eq for BuildHasherDefault --- src/libcore/hash/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index e6f8dfffd63..e7907e03444 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -542,6 +542,16 @@ impl Default for BuildHasherDefault { } } +#[stable(since = "1.29.0", feature = "build_hasher_eq")] +impl PartialEq for BuildHasherDefault { + fn eq(&self, _other: &BuildHasherDefault) -> bool { + true + } +} + +#[stable(since = "1.29.0", feature = "build_hasher_eq")] +impl Eq for BuildHasherDefault {} + ////////////////////////////////////////////////////////////////////////////// mod impls { -- cgit 1.4.1-3-g733a5 From 9928baa786f645a22072fd2fb4b68173eced61f9 Mon Sep 17 00:00:00 2001 From: F001 Date: Mon, 7 May 2018 15:24:45 +0800 Subject: implement rfc 1789 --- src/libcore/cell.rs | 147 +++++++++++++++++-------- src/test/run-pass/rfc-1789-as-cell/from-mut.rs | 22 ++++ 2 files changed, 125 insertions(+), 44 deletions(-) create mode 100644 src/test/run-pass/rfc-1789-as-cell/from-mut.rs (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 2292617f51e..3536588f9df 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -200,8 +200,9 @@ use cmp::Ordering; use fmt::{self, Debug, Display}; use marker::Unsize; use mem; -use ops::{Deref, DerefMut, CoerceUnsized}; +use ops::{Deref, DerefMut, CoerceUnsized, Index}; use ptr; +use slice::SliceIndex; /// A mutable memory location. /// @@ -236,7 +237,7 @@ use ptr; /// See the [module-level documentation](index.html) for more. #[stable(feature = "rust1", since = "1.0.0")] #[repr(transparent)] -pub struct Cell { +pub struct Cell { value: UnsafeCell, } @@ -287,10 +288,10 @@ impl Cell { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for Cell where T: Send {} +unsafe impl Send for Cell where T: Send {} #[stable(feature = "rust1", since = "1.0.0")] -impl !Sync for Cell {} +impl !Sync for Cell {} #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Cell { @@ -381,46 +382,6 @@ impl Cell { } } - /// Returns a raw pointer to the underlying data in this cell. - /// - /// # Examples - /// - /// ``` - /// use std::cell::Cell; - /// - /// let c = Cell::new(5); - /// - /// let ptr = c.as_ptr(); - /// ``` - #[inline] - #[stable(feature = "cell_as_ptr", since = "1.12.0")] - pub fn as_ptr(&self) -> *mut T { - self.value.get() - } - - /// Returns a mutable reference to the underlying data. - /// - /// This call borrows `Cell` mutably (at compile-time) which guarantees - /// that we possess the only reference. - /// - /// # Examples - /// - /// ``` - /// use std::cell::Cell; - /// - /// let mut c = Cell::new(5); - /// *c.get_mut() += 1; - /// - /// assert_eq!(c.get(), 6); - /// ``` - #[inline] - #[stable(feature = "cell_get_mut", since = "1.11.0")] - pub fn get_mut(&mut self) -> &mut T { - unsafe { - &mut *self.value.get() - } - } - /// Sets the contained value. /// /// # Examples @@ -499,6 +460,90 @@ impl Cell { } } +impl Cell { + /// Returns a raw pointer to the underlying data in this cell. + /// + /// # Examples + /// + /// ``` + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// + /// let ptr = c.as_ptr(); + /// ``` + #[inline] + #[stable(feature = "cell_as_ptr", since = "1.12.0")] + pub fn as_ptr(&self) -> *mut T { + self.value.get() + } + + /// Returns a mutable reference to the underlying data. + /// + /// This call borrows `Cell` mutably (at compile-time) which guarantees + /// that we possess the only reference. + /// + /// # Examples + /// + /// ``` + /// use std::cell::Cell; + /// + /// let mut c = Cell::new(5); + /// *c.get_mut() += 1; + /// + /// assert_eq!(c.get(), 6); + /// ``` + #[inline] + #[stable(feature = "cell_get_mut", since = "1.11.0")] + pub fn get_mut(&mut self) -> &mut T { + unsafe { + &mut *self.value.get() + } + } + + /// Returns a `&Cell` from a `&mut T` + /// + /// # Examples + /// + /// ``` + /// #![feature(as_cell)] + /// use std::cell::Cell; + /// let slice: &mut [i32] = &mut [1,2,3]; + /// let cell_slice: &Cell<[i32]> = Cell::from_mut(slice); + /// + /// assert_eq!(cell_slice.get_with(|v|v.len()), 3) + /// ``` + #[inline] + #[unstable(feature = "as_cell", issue="43038")] + pub fn from_mut<'a>(t: &'a mut T) -> &'a Cell { + unsafe { + &*(t as *mut T as *const Cell) + } + } + + /// Returns a value by applying a function on contained value + /// + /// # Examples + /// + /// ``` + /// #![feature(as_cell)] + /// use std::cell::Cell; + /// let c : Cell> = Cell::new(vec![1,2,3]); + /// let sum : i32 = c.get_with(|v|v.iter().sum()); + /// assert_eq!(sum, 6_i32); + /// ``` + #[inline] + #[unstable(feature = "as_cell", issue="43038")] + pub fn get_with(&self, f: F) -> U + where + F: Fn(&T) -> U, U: 'static + { + unsafe { + f(&*self.value.get()) + } + } +} + impl Cell { /// Takes the value of the cell, leaving `Default::default()` in its place. /// @@ -522,6 +567,20 @@ impl Cell { #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U> CoerceUnsized> for Cell {} +#[unstable(feature = "as_cell", issue="43038")] +impl Index for Cell<[T]> +where + I: SliceIndex<[Cell]> +{ + type Output = I::Output; + + fn index(&self, index: I) -> &Self::Output { + unsafe { + Index::index(&*(self as *const Cell<[T]> as *const [Cell]), index) + } + } +} + /// A mutable memory location with dynamically checked borrow rules /// /// See the [module-level documentation](index.html) for more. diff --git a/src/test/run-pass/rfc-1789-as-cell/from-mut.rs b/src/test/run-pass/rfc-1789-as-cell/from-mut.rs new file mode 100644 index 00000000000..33257124f57 --- /dev/null +++ b/src/test/run-pass/rfc-1789-as-cell/from-mut.rs @@ -0,0 +1,22 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(as_cell)] + +use std::cell::Cell; + +fn main() { + let slice: &mut [i32] = &mut [1,2,3]; + let cell_slice: &Cell<[i32]> = Cell::from_mut(slice); + assert_eq!(cell_slice.get_with(|v|v.len()), 3); + + let sub_slice : &[Cell] = &cell_slice[1..]; + assert_eq!(sub_slice.len(), 2); +} -- cgit 1.4.1-3-g733a5 From 20b50f591f6ba43958c9d51cc43f1e7b421994bb Mon Sep 17 00:00:00 2001 From: F001 Date: Tue, 8 May 2018 09:00:05 +0800 Subject: add repr transparent --- src/libcore/lib.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index bbe6ae8619f..368c9208d8d 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -112,6 +112,7 @@ #![feature(unwind_attributes)] #![feature(doc_alias)] #![feature(inclusive_range_methods)] +#![feature(repr_transparent)] #![feature(mmx_target_feature)] #![feature(tbm_target_feature)] #![feature(sse4a_target_feature)] -- cgit 1.4.1-3-g733a5 From 4bf8b57950ff6e1a447156f19461eeed480499e8 Mon Sep 17 00:00:00 2001 From: F001 Date: Sat, 26 May 2018 19:55:40 +0800 Subject: remove "get_with" method --- src/libcore/cell.rs | 26 ++------------------------ src/test/run-pass/rfc-1789-as-cell/from-mut.rs | 2 -- 2 files changed, 2 insertions(+), 26 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 3536588f9df..78ae1346175 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -510,8 +510,8 @@ impl Cell { /// use std::cell::Cell; /// let slice: &mut [i32] = &mut [1,2,3]; /// let cell_slice: &Cell<[i32]> = Cell::from_mut(slice); - /// - /// assert_eq!(cell_slice.get_with(|v|v.len()), 3) + /// let slice_cell : &[Cell] = &cell_slice[..]; + /// assert_eq!(slice_cell.len(), 3) /// ``` #[inline] #[unstable(feature = "as_cell", issue="43038")] @@ -520,28 +520,6 @@ impl Cell { &*(t as *mut T as *const Cell) } } - - /// Returns a value by applying a function on contained value - /// - /// # Examples - /// - /// ``` - /// #![feature(as_cell)] - /// use std::cell::Cell; - /// let c : Cell> = Cell::new(vec![1,2,3]); - /// let sum : i32 = c.get_with(|v|v.iter().sum()); - /// assert_eq!(sum, 6_i32); - /// ``` - #[inline] - #[unstable(feature = "as_cell", issue="43038")] - pub fn get_with(&self, f: F) -> U - where - F: Fn(&T) -> U, U: 'static - { - unsafe { - f(&*self.value.get()) - } - } } impl Cell { diff --git a/src/test/run-pass/rfc-1789-as-cell/from-mut.rs b/src/test/run-pass/rfc-1789-as-cell/from-mut.rs index 33257124f57..28b6d8213f7 100644 --- a/src/test/run-pass/rfc-1789-as-cell/from-mut.rs +++ b/src/test/run-pass/rfc-1789-as-cell/from-mut.rs @@ -15,8 +15,6 @@ use std::cell::Cell; fn main() { let slice: &mut [i32] = &mut [1,2,3]; let cell_slice: &Cell<[i32]> = Cell::from_mut(slice); - assert_eq!(cell_slice.get_with(|v|v.len()), 3); - let sub_slice : &[Cell] = &cell_slice[1..]; assert_eq!(sub_slice.len(), 2); } -- cgit 1.4.1-3-g733a5 From 4d99957ce30b6c5021d14c2812b12e817ec60c59 Mon Sep 17 00:00:00 2001 From: F001 Date: Sun, 27 May 2018 20:07:10 +0800 Subject: use lifetime elision for consistency --- src/libcore/cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 78ae1346175..97fee5d06f4 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -515,7 +515,7 @@ impl Cell { /// ``` #[inline] #[unstable(feature = "as_cell", issue="43038")] - pub fn from_mut<'a>(t: &'a mut T) -> &'a Cell { + pub fn from_mut(t: &mut T) -> &Cell { unsafe { &*(t as *mut T as *const Cell) } -- cgit 1.4.1-3-g733a5 From bdf86300b4170abef1399bb9b7bc63bac52a0092 Mon Sep 17 00:00:00 2001 From: F001 Date: Mon, 28 May 2018 07:52:39 +0800 Subject: impl `Deref` instead of `Index` --- src/libcore/cell.rs | 18 ++++++++---------- src/test/run-pass/rfc-1789-as-cell/from-mut.rs | 1 + 2 files changed, 9 insertions(+), 10 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 97fee5d06f4..85ef417ea15 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -200,9 +200,8 @@ use cmp::Ordering; use fmt::{self, Debug, Display}; use marker::Unsize; use mem; -use ops::{Deref, DerefMut, CoerceUnsized, Index}; +use ops::{Deref, DerefMut, CoerceUnsized}; use ptr; -use slice::SliceIndex; /// A mutable memory location. /// @@ -510,8 +509,9 @@ impl Cell { /// use std::cell::Cell; /// let slice: &mut [i32] = &mut [1,2,3]; /// let cell_slice: &Cell<[i32]> = Cell::from_mut(slice); + /// assert_eq!(cell_slice.len(), 3); /// let slice_cell : &[Cell] = &cell_slice[..]; - /// assert_eq!(slice_cell.len(), 3) + /// assert_eq!(slice_cell.len(), 3); /// ``` #[inline] #[unstable(feature = "as_cell", issue="43038")] @@ -546,15 +546,13 @@ impl Cell { impl, U> CoerceUnsized> for Cell {} #[unstable(feature = "as_cell", issue="43038")] -impl Index for Cell<[T]> -where - I: SliceIndex<[Cell]> -{ - type Output = I::Output; +impl Deref for Cell<[T]> { + type Target = [Cell]; - fn index(&self, index: I) -> &Self::Output { + #[inline] + fn deref(&self) -> &[Cell] { unsafe { - Index::index(&*(self as *const Cell<[T]> as *const [Cell]), index) + &*(self as *const Cell<[T]> as *const [Cell]) } } } diff --git a/src/test/run-pass/rfc-1789-as-cell/from-mut.rs b/src/test/run-pass/rfc-1789-as-cell/from-mut.rs index 28b6d8213f7..9989690bc79 100644 --- a/src/test/run-pass/rfc-1789-as-cell/from-mut.rs +++ b/src/test/run-pass/rfc-1789-as-cell/from-mut.rs @@ -15,6 +15,7 @@ use std::cell::Cell; fn main() { let slice: &mut [i32] = &mut [1,2,3]; let cell_slice: &Cell<[i32]> = Cell::from_mut(slice); + assert_eq!(cell_slice.len(), 3); let sub_slice : &[Cell] = &cell_slice[1..]; assert_eq!(sub_slice.len(), 2); } -- cgit 1.4.1-3-g733a5 From b1344abc58f0bd2eb6a8c9e664f8318864f640fe Mon Sep 17 00:00:00 2001 From: F001 Date: Mon, 28 May 2018 14:35:12 +0800 Subject: code style fixes --- src/libcore/cell.rs | 6 ++++-- src/test/run-pass/rfc-1789-as-cell/from-mut.rs | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 85ef417ea15..a85eee85450 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -507,10 +507,12 @@ impl Cell { /// ``` /// #![feature(as_cell)] /// use std::cell::Cell; - /// let slice: &mut [i32] = &mut [1,2,3]; + /// + /// let slice: &mut [i32] = &mut [1, 2, 3]; /// let cell_slice: &Cell<[i32]> = Cell::from_mut(slice); /// assert_eq!(cell_slice.len(), 3); - /// let slice_cell : &[Cell] = &cell_slice[..]; + /// + /// let slice_cell: &[Cell] = &cell_slice[..]; /// assert_eq!(slice_cell.len(), 3); /// ``` #[inline] diff --git a/src/test/run-pass/rfc-1789-as-cell/from-mut.rs b/src/test/run-pass/rfc-1789-as-cell/from-mut.rs index 9989690bc79..8c7317b0e9a 100644 --- a/src/test/run-pass/rfc-1789-as-cell/from-mut.rs +++ b/src/test/run-pass/rfc-1789-as-cell/from-mut.rs @@ -13,9 +13,10 @@ use std::cell::Cell; fn main() { - let slice: &mut [i32] = &mut [1,2,3]; + let slice: &mut [i32] = &mut [1, 2, 3]; let cell_slice: &Cell<[i32]> = Cell::from_mut(slice); assert_eq!(cell_slice.len(), 3); - let sub_slice : &[Cell] = &cell_slice[1..]; + + let sub_slice: &[Cell] = &cell_slice[1..]; assert_eq!(sub_slice.len(), 2); } -- cgit 1.4.1-3-g733a5 From 3eee486e270347f39e41f4429cdb253b40219b89 Mon Sep 17 00:00:00 2001 From: F001 Date: Thu, 7 Jun 2018 17:47:55 +0800 Subject: impl DerefMut for Cell<[T]> --- src/libcore/cell.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index a85eee85450..7e2ece0f02c 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -559,6 +559,16 @@ impl Deref for Cell<[T]> { } } +#[unstable(feature = "as_cell", issue="43038")] +impl DerefMut for Cell<[T]> { + #[inline] + fn deref_mut(&mut self) -> &mut [Cell] { + unsafe { + &mut *(self as *mut Cell<[T]> as *mut [Cell]) + } + } +} + /// A mutable memory location with dynamically checked borrow rules /// /// See the [module-level documentation](index.html) for more. -- cgit 1.4.1-3-g733a5 From 7e1b983579ec582dfbe409342756252f6b080918 Mon Sep 17 00:00:00 2001 From: F001 Date: Fri, 6 Jul 2018 17:43:30 +0800 Subject: remove useless feature(repr_transparent) --- src/libcore/lib.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 368c9208d8d..bbe6ae8619f 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -112,7 +112,6 @@ #![feature(unwind_attributes)] #![feature(doc_alias)] #![feature(inclusive_range_methods)] -#![feature(repr_transparent)] #![feature(mmx_target_feature)] #![feature(tbm_target_feature)] #![feature(sse4a_target_feature)] -- cgit 1.4.1-3-g733a5 From 88e9af0375ba31d91523143b45088f5a481cb76e Mon Sep 17 00:00:00 2001 From: Felix Rabe Date: Sun, 15 Jul 2018 19:10:47 +0200 Subject: Fix doc link The link for comparison: - https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types--sized (broken) - https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-sized (fixed) This commit is the result of (first) searching via: find src -type f -print0 | xargs -0 fgrep -l dynamically-sized-types--sized and then replacing all relevant occurrences via: find src/{libcore,test/ui} -type f -print0 | xargs -0 sed -i.bak \ s/dynamically-sized-types--sized/dynamically-sized-types-and-sized/g find src/{libcore,test/ui} -type f -name '*.bak' -print0 | xargs -0 rm (Note: Commands run on macOS 10.13 (BSD). `sed -i.bak` should work on GNU/Linux as well, but not tested.) --- src/libcore/marker.rs | 2 +- src/test/ui/const-unsized.stderr | 8 ++--- src/test/ui/error-codes/E0277.stderr | 2 +- src/test/ui/feature-gate-trivial_bounds.stderr | 6 ++-- src/test/ui/generator/sized-yield.stderr | 4 +-- src/test/ui/issue-14366.stderr | 2 +- src/test/ui/issue-15756.stderr | 2 +- src/test/ui/issue-17651.stderr | 2 +- src/test/ui/issue-18107.stderr | 2 +- src/test/ui/issue-18919.stderr | 2 +- src/test/ui/issue-20005.stderr | 2 +- src/test/ui/issue-20433.stderr | 2 +- src/test/ui/issue-20605.stderr | 2 +- src/test/ui/issue-22874.stderr | 2 +- src/test/ui/issue-23281.stderr | 2 +- src/test/ui/issue-24446.stderr | 2 +- src/test/ui/issue-27060-2.stderr | 2 +- src/test/ui/issue-27078.stderr | 2 +- src/test/ui/issue-35988.stderr | 2 +- src/test/ui/issue-38954.stderr | 2 +- src/test/ui/issue-41229-ref-str.stderr | 2 +- src/test/ui/issue-42312.stderr | 4 +-- src/test/ui/issue-5883.stderr | 4 +-- src/test/ui/mismatched_types/cast-rfc0401.stderr | 4 +-- src/test/ui/resolve/issue-5035-2.stderr | 2 +- .../ui/suggestions/str-array-assignment.stderr | 2 +- src/test/ui/trait-suggest-where-clause.stderr | 8 ++--- src/test/ui/trivial-bounds-leak.stderr | 2 +- src/test/ui/union/union-sized-field.stderr | 6 ++-- src/test/ui/unsized-enum2.stderr | 40 +++++++++++----------- 30 files changed, 63 insertions(+), 63 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 090f61a5d69..4f37b462583 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -95,7 +95,7 @@ impl !Send for *mut T { } message="the size for values of type `{Self}` cannot be known at compilation time", label="doesn't have a size known at compile-time", note="to learn more, visit ", + ch19-04-advanced-types.html#dynamically-sized-types-and-sized>", )] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable pub trait Sized { diff --git a/src/test/ui/const-unsized.stderr b/src/test/ui/const-unsized.stderr index e0b31510260..4103ea02f2e 100644 --- a/src/test/ui/const-unsized.stderr +++ b/src/test/ui/const-unsized.stderr @@ -5,7 +5,7 @@ LL | const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::fmt::Debug + std::marker::Sync + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: constant expressions must have a statically known size error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -15,7 +15,7 @@ LL | const CONST_FOO: str = *"foo"; | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit + = note: to learn more, visit = note: constant expressions must have a statically known size error[E0277]: the size for values of type `(dyn std::fmt::Debug + std::marker::Sync + 'static)` cannot be known at compilation time @@ -25,7 +25,7 @@ LL | static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::fmt::Debug + std::marker::Sync + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: constant expressions must have a statically known size error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -35,7 +35,7 @@ LL | static STATIC_BAR: str = *"bar"; | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit + = note: to learn more, visit = note: constant expressions must have a statically known size error: aborting due to 4 previous errors diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr index 3ea057d7922..3f934b60f06 100644 --- a/src/test/ui/error-codes/E0277.stderr +++ b/src/test/ui/error-codes/E0277.stderr @@ -5,7 +5,7 @@ LL | fn f(p: Path) { } | ^ doesn't have a size known at compile-time | = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit + = note: to learn more, visit = note: required because it appears within the type `std::path::Path` = note: all local variables must have a statically known size diff --git a/src/test/ui/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gate-trivial_bounds.stderr index 52963671da9..02b2f99d992 100644 --- a/src/test/ui/feature-gate-trivial_bounds.stderr +++ b/src/test/ui/feature-gate-trivial_bounds.stderr @@ -94,7 +94,7 @@ LL | struct TwoStrs(str, str) where str: Sized; //~ ERROR | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit + = note: to learn more, visit = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable @@ -107,7 +107,7 @@ LL | | } | |_^ doesn't have a size known at compile-time | = help: within `Dst<(dyn A + 'static)>`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: required because it appears within the type `Dst<(dyn A + 'static)>` = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable @@ -121,7 +121,7 @@ LL | | } | |_^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit + = note: to learn more, visit = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr index dfccd7c4d23..953268ec30f 100644 --- a/src/test/ui/generator/sized-yield.stderr +++ b/src/test/ui/generator/sized-yield.stderr @@ -9,7 +9,7 @@ LL | | }; | |____^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit + = note: to learn more, visit = note: the yield type of a generator must have a statically known size error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -19,7 +19,7 @@ LL | unsafe { gen.resume(); } | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit + = note: to learn more, visit error: aborting due to 2 previous errors diff --git a/src/test/ui/issue-14366.stderr b/src/test/ui/issue-14366.stderr index 260ca443689..ff61ef0bde3 100644 --- a/src/test/ui/issue-14366.stderr +++ b/src/test/ui/issue-14366.stderr @@ -5,7 +5,7 @@ LL | let _x = "test" as &::std::any::Any; | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit + = note: to learn more, visit = note: required for the cast to the object type `dyn std::any::Any` error: aborting due to previous error diff --git a/src/test/ui/issue-15756.stderr b/src/test/ui/issue-15756.stderr index af70f125302..cea201816ec 100644 --- a/src/test/ui/issue-15756.stderr +++ b/src/test/ui/issue-15756.stderr @@ -5,7 +5,7 @@ LL | &mut something | ^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[T]` - = note: to learn more, visit + = note: to learn more, visit = note: all local variables must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/issue-17651.stderr b/src/test/ui/issue-17651.stderr index d21b3060315..7b7e5b5f07e 100644 --- a/src/test/ui/issue-17651.stderr +++ b/src/test/ui/issue-17651.stderr @@ -5,7 +5,7 @@ LL | (|| Box::new(*(&[0][..])))(); | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` - = note: to learn more, visit + = note: to learn more, visit = note: required by `>::new` error: aborting due to previous error diff --git a/src/test/ui/issue-18107.stderr b/src/test/ui/issue-18107.stderr index 4a273ab6735..6fa9fb6f016 100644 --- a/src/test/ui/issue-18107.stderr +++ b/src/test/ui/issue-18107.stderr @@ -5,7 +5,7 @@ LL | AbstractRenderer | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn AbstractRenderer + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: the return type of a function must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/issue-18919.stderr b/src/test/ui/issue-18919.stderr index 012a1eb4d21..f9a098ba290 100644 --- a/src/test/ui/issue-18919.stderr +++ b/src/test/ui/issue-18919.stderr @@ -7,7 +7,7 @@ LL | | } | |_^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::ops::Fn(&'r isize) -> isize` - = note: to learn more, visit + = note: to learn more, visit = note: required by `std::option::Option` error: aborting due to previous error diff --git a/src/test/ui/issue-20005.stderr b/src/test/ui/issue-20005.stderr index 2fdfa4ba6f8..645dcb1a9dc 100644 --- a/src/test/ui/issue-20005.stderr +++ b/src/test/ui/issue-20005.stderr @@ -9,7 +9,7 @@ LL | | } | |_____^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit + = note: to learn more, visit = help: consider adding a `where Self: std::marker::Sized` bound note: required by `From` --> $DIR/issue-20005.rs:11:1 diff --git a/src/test/ui/issue-20433.stderr b/src/test/ui/issue-20433.stderr index 38dd4e5e7fe..5e8bf2858bf 100644 --- a/src/test/ui/issue-20433.stderr +++ b/src/test/ui/issue-20433.stderr @@ -5,7 +5,7 @@ LL | fn iceman(c: Vec<[i32]>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i32]` - = note: to learn more, visit + = note: to learn more, visit = note: required by `std::vec::Vec` error: aborting due to previous error diff --git a/src/test/ui/issue-20605.stderr b/src/test/ui/issue-20605.stderr index 10e90faf2df..e85ea873e68 100644 --- a/src/test/ui/issue-20605.stderr +++ b/src/test/ui/issue-20605.stderr @@ -5,7 +5,7 @@ LL | for item in *things { *item = 0 } | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn std::iter::Iterator` - = note: to learn more, visit + = note: to learn more, visit = note: required by `std::iter::IntoIterator::into_iter` error: aborting due to previous error diff --git a/src/test/ui/issue-22874.stderr b/src/test/ui/issue-22874.stderr index 64c77a6a666..a8144dc6dad 100644 --- a/src/test/ui/issue-22874.stderr +++ b/src/test/ui/issue-22874.stderr @@ -5,7 +5,7 @@ LL | rows: [[String]], | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[std::string::String]` - = note: to learn more, visit + = note: to learn more, visit = note: slice and array elements must have `Sized` type error: aborting due to previous error diff --git a/src/test/ui/issue-23281.stderr b/src/test/ui/issue-23281.stderr index ee5a9930df2..c7391ad8b5f 100644 --- a/src/test/ui/issue-23281.stderr +++ b/src/test/ui/issue-23281.stderr @@ -5,7 +5,7 @@ LL | pub fn function(funs: Vec ()>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: required by `std::vec::Vec` error: aborting due to previous error diff --git a/src/test/ui/issue-24446.stderr b/src/test/ui/issue-24446.stderr index 2c13dd36558..8614fc647dd 100644 --- a/src/test/ui/issue-24446.stderr +++ b/src/test/ui/issue-24446.stderr @@ -24,7 +24,7 @@ LL | | }; | |_____^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() -> u32 + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: constant expressions must have a statically known size error: aborting due to 2 previous errors diff --git a/src/test/ui/issue-27060-2.stderr b/src/test/ui/issue-27060-2.stderr index bb284138ebf..7961b1720f3 100644 --- a/src/test/ui/issue-27060-2.stderr +++ b/src/test/ui/issue-27060-2.stderr @@ -5,7 +5,7 @@ LL | data: T, //~ ERROR the size for values of type | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit + = note: to learn more, visit = help: consider adding a `where T: std::marker::Sized` bound = note: only the last field of a struct may have a dynamically sized type diff --git a/src/test/ui/issue-27078.stderr b/src/test/ui/issue-27078.stderr index 1a729c00fc1..dcfd82fec0b 100644 --- a/src/test/ui/issue-27078.stderr +++ b/src/test/ui/issue-27078.stderr @@ -5,7 +5,7 @@ LL | fn foo(self) -> &'static i32 { | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit + = note: to learn more, visit = help: consider adding a `where Self: std::marker::Sized` bound = note: all local variables must have a statically known size diff --git a/src/test/ui/issue-35988.stderr b/src/test/ui/issue-35988.stderr index 35452fcf392..38a9409b6a0 100644 --- a/src/test/ui/issue-35988.stderr +++ b/src/test/ui/issue-35988.stderr @@ -5,7 +5,7 @@ LL | V([Box]), | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[std::boxed::Box]` - = note: to learn more, visit + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error: aborting due to previous error diff --git a/src/test/ui/issue-38954.stderr b/src/test/ui/issue-38954.stderr index f9c380317b4..714ab00b00c 100644 --- a/src/test/ui/issue-38954.stderr +++ b/src/test/ui/issue-38954.stderr @@ -5,7 +5,7 @@ LL | fn _test(ref _p: str) {} | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit + = note: to learn more, visit error: aborting due to previous error diff --git a/src/test/ui/issue-41229-ref-str.stderr b/src/test/ui/issue-41229-ref-str.stderr index 889da66a4e8..d8933a3dfab 100644 --- a/src/test/ui/issue-41229-ref-str.stderr +++ b/src/test/ui/issue-41229-ref-str.stderr @@ -5,7 +5,7 @@ LL | pub fn example(ref s: str) {} | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit + = note: to learn more, visit error: aborting due to previous error diff --git a/src/test/ui/issue-42312.stderr b/src/test/ui/issue-42312.stderr index ae6496c037a..8c7d5d8828f 100644 --- a/src/test/ui/issue-42312.stderr +++ b/src/test/ui/issue-42312.stderr @@ -5,7 +5,7 @@ LL | fn baz(_: Self::Target) where Self: Deref {} | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `::Target` - = note: to learn more, visit + = note: to learn more, visit = help: consider adding a `where ::Target: std::marker::Sized` bound error[E0277]: the size for values of type `(dyn std::string::ToString + 'static)` cannot be known at compilation time @@ -15,7 +15,7 @@ LL | pub fn f(_: ToString) {} | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::string::ToString + 'static)` - = note: to learn more, visit + = note: to learn more, visit error: aborting due to 2 previous errors diff --git a/src/test/ui/issue-5883.stderr b/src/test/ui/issue-5883.stderr index 43ce3697d83..8dfeaa7f888 100644 --- a/src/test/ui/issue-5883.stderr +++ b/src/test/ui/issue-5883.stderr @@ -5,7 +5,7 @@ LL | fn new_struct(r: A+'static) | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: all local variables must have a statically known size error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time @@ -15,7 +15,7 @@ LL | -> Struct { //~^ ERROR the size for values of type | ^^^^^^ doesn't have a size known at compile-time | = help: within `Struct`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: required because it appears within the type `Struct` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index ef877d6e04e..d3b9adeff40 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -223,7 +223,7 @@ LL | let _ = fat_v as *const Foo; //~ ERROR the size for values of type | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit + = note: to learn more, visit = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -233,7 +233,7 @@ LL | let _ = a as *const Foo; //~ ERROR the size for values of type | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit + = note: to learn more, visit = note: required for the cast to the object type `dyn Foo` error[E0606]: casting `&{float}` as `f32` is invalid diff --git a/src/test/ui/resolve/issue-5035-2.stderr b/src/test/ui/resolve/issue-5035-2.stderr index 7c1ebc353ac..21c0a620f69 100644 --- a/src/test/ui/resolve/issue-5035-2.stderr +++ b/src/test/ui/resolve/issue-5035-2.stderr @@ -5,7 +5,7 @@ LL | fn foo(_x: K) {} | ^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn I + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: all local variables must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/suggestions/str-array-assignment.stderr b/src/test/ui/suggestions/str-array-assignment.stderr index e0576cee8f5..7a774cab38e 100644 --- a/src/test/ui/suggestions/str-array-assignment.stderr +++ b/src/test/ui/suggestions/str-array-assignment.stderr @@ -28,7 +28,7 @@ LL | let v = s[..2]; | doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit + = note: to learn more, visit = note: all local variables must have a statically known size error[E0308]: mismatched types diff --git a/src/test/ui/trait-suggest-where-clause.stderr b/src/test/ui/trait-suggest-where-clause.stderr index f62e43e2a46..f50644042bb 100644 --- a/src/test/ui/trait-suggest-where-clause.stderr +++ b/src/test/ui/trait-suggest-where-clause.stderr @@ -5,7 +5,7 @@ LL | mem::size_of::(); | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `U` - = note: to learn more, visit + = note: to learn more, visit = help: consider adding a `where U: std::marker::Sized` bound = note: required by `std::mem::size_of` @@ -16,7 +16,7 @@ LL | mem::size_of::>(); | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `Misc`, the trait `std::marker::Sized` is not implemented for `U` - = note: to learn more, visit + = note: to learn more, visit = help: consider adding a `where U: std::marker::Sized` bound = note: required because it appears within the type `Misc` = note: required by `std::mem::size_of` @@ -54,7 +54,7 @@ LL | mem::size_of::<[T]>(); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[T]` - = note: to learn more, visit + = note: to learn more, visit = note: required by `std::mem::size_of` error[E0277]: the size for values of type `[&U]` cannot be known at compilation time @@ -64,7 +64,7 @@ LL | mem::size_of::<[&U]>(); | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[&U]` - = note: to learn more, visit + = note: to learn more, visit = note: required by `std::mem::size_of` error: aborting due to 7 previous errors diff --git a/src/test/ui/trivial-bounds-leak.stderr b/src/test/ui/trivial-bounds-leak.stderr index 960123b5d3a..5510b9f2874 100644 --- a/src/test/ui/trivial-bounds-leak.stderr +++ b/src/test/ui/trivial-bounds-leak.stderr @@ -5,7 +5,7 @@ LL | fn cant_return_str() -> str { //~ ERROR | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit + = note: to learn more, visit = note: the return type of a function must have a statically known size error[E0599]: no method named `test` found for type `i32` in the current scope diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr index 2b1f4b4e8f3..75a6542fe23 100644 --- a/src/test/ui/union/union-sized-field.stderr +++ b/src/test/ui/union/union-sized-field.stderr @@ -5,7 +5,7 @@ LL | value: T, | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit + = note: to learn more, visit = help: consider adding a `where T: std::marker::Sized` bound = note: no field of a union may have a dynamically sized type @@ -16,7 +16,7 @@ LL | value: T, | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit + = note: to learn more, visit = help: consider adding a `where T: std::marker::Sized` bound = note: only the last field of a struct may have a dynamically sized type @@ -27,7 +27,7 @@ LL | Value(T), | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit + = note: to learn more, visit = help: consider adding a `where T: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type diff --git a/src/test/ui/unsized-enum2.stderr b/src/test/ui/unsized-enum2.stderr index 47d75f33851..bd97978ea64 100644 --- a/src/test/ui/unsized-enum2.stderr +++ b/src/test/ui/unsized-enum2.stderr @@ -5,7 +5,7 @@ LL | VA(W), | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `W` - = note: to learn more, visit + = note: to learn more, visit = help: consider adding a `where W: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type @@ -16,7 +16,7 @@ LL | VB{x: X}, | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit + = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type @@ -27,7 +27,7 @@ LL | VC(isize, Y), | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Y` - = note: to learn more, visit + = note: to learn more, visit = help: consider adding a `where Y: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type @@ -38,7 +38,7 @@ LL | VD{u: isize, x: Z}, | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Z` - = note: to learn more, visit + = note: to learn more, visit = help: consider adding a `where Z: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type @@ -49,7 +49,7 @@ LL | VE([u8]), | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -59,7 +59,7 @@ LL | VF{x: str}, | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `[f32]` cannot be known at compilation time @@ -69,7 +69,7 @@ LL | VG(isize, [f32]), | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[f32]` - = note: to learn more, visit + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `[u32]` cannot be known at compilation time @@ -79,7 +79,7 @@ LL | VH{u: isize, x: [u32]}, | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u32]` - = note: to learn more, visit + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time @@ -89,7 +89,7 @@ LL | VM(Foo), | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `(dyn Bar + 'static)` cannot be known at compilation time @@ -99,7 +99,7 @@ LL | VN{x: Bar}, | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn Bar + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `(dyn FooBar + 'static)` cannot be known at compilation time @@ -109,7 +109,7 @@ LL | VO(isize, FooBar), | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn FooBar + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `(dyn BarFoo + 'static)` cannot be known at compilation time @@ -119,7 +119,7 @@ LL | VP{u: isize, x: BarFoo}, | ^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn BarFoo + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `[i8]` cannot be known at compilation time @@ -129,7 +129,7 @@ LL | VQ(<&'static [i8] as Deref>::Target), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i8]` - = note: to learn more, visit + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `[char]` cannot be known at compilation time @@ -139,7 +139,7 @@ LL | VR{x: <&'static [char] as Deref>::Target}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[char]` - = note: to learn more, visit + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `[f64]` cannot be known at compilation time @@ -149,7 +149,7 @@ LL | VS(isize, <&'static [f64] as Deref>::Target), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[f64]` - = note: to learn more, visit + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `[i32]` cannot be known at compilation time @@ -159,7 +159,7 @@ LL | VT{u: isize, x: <&'static [i32] as Deref>::Target}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i32]` - = note: to learn more, visit + = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type error[E0277]: the size for values of type `(dyn PathHelper1 + 'static)` cannot be known at compilation time @@ -169,7 +169,7 @@ LL | VI(Path1), | ^^^^^ doesn't have a size known at compile-time | = help: within `Path1`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper1 + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: required because it appears within the type `Path1` = note: no field of an enum variant may have a dynamically sized type @@ -180,7 +180,7 @@ LL | VJ{x: Path2}, | ^^^^^^^^ doesn't have a size known at compile-time | = help: within `Path2`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper2 + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: required because it appears within the type `Path2` = note: no field of an enum variant may have a dynamically sized type @@ -191,7 +191,7 @@ LL | VK(isize, Path3), | ^^^^^ doesn't have a size known at compile-time | = help: within `Path3`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper3 + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: required because it appears within the type `Path3` = note: no field of an enum variant may have a dynamically sized type @@ -202,7 +202,7 @@ LL | VL{u: isize, x: Path4}, | ^^^^^^^^ doesn't have a size known at compile-time | = help: within `Path4`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper4 + 'static)` - = note: to learn more, visit + = note: to learn more, visit = note: required because it appears within the type `Path4` = note: no field of an enum variant may have a dynamically sized type -- cgit 1.4.1-3-g733a5 From 2d4011db07f08d5c9f3bf9622955f54321877f7b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 17 Jul 2018 23:39:37 -0400 Subject: Clarify short-circuiting behvaior of Iterator::zip. Fixes https://github.com/rust-lang/rust/issues/52279. --- src/libcore/iter/iterator.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index c0681619bf8..afc273d265b 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -384,7 +384,9 @@ pub trait Iterator { /// /// In other words, it zips two iterators together, into a single one. /// - /// If either iterator returns [`None`], [`next`] will return [`None`]. + /// If either iterator returns [`None`], [`next`] from the zipped iterator + /// will return [`None`]. If the first iterator returns [`None`], `zip` will + /// short-circuit and `next` will not be called on the second iterator. /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 8812c6bae92d1a8e3a255d3eacd40cd9b65bb7f6 Mon Sep 17 00:00:00 2001 From: F001 Date: Tue, 17 Jul 2018 11:30:17 +0800 Subject: revert Deref --- src/libcore/cell.rs | 26 +++++++++----------------- src/test/run-pass/rfc-1789-as-cell/from-mut.rs | 2 +- 2 files changed, 10 insertions(+), 18 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 7e2ece0f02c..8a0f499b598 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -200,8 +200,9 @@ use cmp::Ordering; use fmt::{self, Debug, Display}; use marker::Unsize; use mem; -use ops::{Deref, DerefMut, CoerceUnsized}; +use ops::{Deref, DerefMut, CoerceUnsized, Index}; use ptr; +use slice::SliceIndex; /// A mutable memory location. /// @@ -510,7 +511,7 @@ impl Cell { /// /// let slice: &mut [i32] = &mut [1, 2, 3]; /// let cell_slice: &Cell<[i32]> = Cell::from_mut(slice); - /// assert_eq!(cell_slice.len(), 3); + /// assert_eq!(cell_slice[..].len(), 3); /// /// let slice_cell: &[Cell] = &cell_slice[..]; /// assert_eq!(slice_cell.len(), 3); @@ -548,23 +549,14 @@ impl Cell { impl, U> CoerceUnsized> for Cell {} #[unstable(feature = "as_cell", issue="43038")] -impl Deref for Cell<[T]> { - type Target = [Cell]; +impl Index for Cell<[T]> + where I: SliceIndex<[Cell]> +{ + type Output = I::Output; - #[inline] - fn deref(&self) -> &[Cell] { - unsafe { - &*(self as *const Cell<[T]> as *const [Cell]) - } - } -} - -#[unstable(feature = "as_cell", issue="43038")] -impl DerefMut for Cell<[T]> { - #[inline] - fn deref_mut(&mut self) -> &mut [Cell] { + fn index(&self, index: I) -> &Self::Output { unsafe { - &mut *(self as *mut Cell<[T]> as *mut [Cell]) + Index::index(&*(self as *const Cell<[T]> as *const [Cell]), index) } } } diff --git a/src/test/run-pass/rfc-1789-as-cell/from-mut.rs b/src/test/run-pass/rfc-1789-as-cell/from-mut.rs index 8c7317b0e9a..bd00f305cc4 100644 --- a/src/test/run-pass/rfc-1789-as-cell/from-mut.rs +++ b/src/test/run-pass/rfc-1789-as-cell/from-mut.rs @@ -15,7 +15,7 @@ use std::cell::Cell; fn main() { let slice: &mut [i32] = &mut [1, 2, 3]; let cell_slice: &Cell<[i32]> = Cell::from_mut(slice); - assert_eq!(cell_slice.len(), 3); + assert_eq!(cell_slice[..].len(), 3); let sub_slice: &[Cell] = &cell_slice[1..]; assert_eq!(sub_slice.len(), 2); -- cgit 1.4.1-3-g733a5 From ce756321ba888c7701cb81febd1de2bd98f87724 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 18 Jul 2018 12:50:13 -0700 Subject: Document that Unique::empty() and NonNull::dangling() aren't sentinel values The documentation of Unique::empty() and NonNull::dangling() could potentially suggest that they work as sentinel values indicating a not-yet-initialized pointer. However, they both declare a non-null pointer equal to the alignment of the type, which could potentially reference a valid value of that type (specifically, the first such valid value in memory). Explicitly document that the return value of these functions does not work as a sentinel value. --- src/libcore/ptr.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 0af642258c2..d8e061496d9 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2703,6 +2703,11 @@ impl Unique { /// /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. + /// + /// Note that the pointer value may potentially represent a valid pointer to + /// a `T`, which means this must not be used as a "not yet initialized" + /// sentinel value. Types that lazily allocate must track initialization by + /// some other means. // FIXME: rename to dangling() to match NonNull? pub const fn empty() -> Self { unsafe { @@ -2834,6 +2839,11 @@ impl NonNull { /// /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. + /// + /// Note that the pointer value may potentially represent a valid pointer to + /// a `T`, which means this must not be used as a "not yet initialized" + /// sentinel value. Types that lazily allocate must track initialization by + /// some other means. #[stable(feature = "nonnull", since = "1.25.0")] pub fn dangling() -> Self { unsafe { -- cgit 1.4.1-3-g733a5 From 16c057256f68b39df70737838f367cf645d6e0c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 19 Jul 2018 09:11:56 +0200 Subject: fix safety-related comment in slice::rotate --- src/libcore/slice/rotate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/slice/rotate.rs b/src/libcore/slice/rotate.rs index e4a4e33c172..28ef53ccb5c 100644 --- a/src/libcore/slice/rotate.rs +++ b/src/libcore/slice/rotate.rs @@ -48,7 +48,6 @@ impl RawArray { /// # Safety /// /// The specified range must be valid for reading and writing. -/// The type `T` must have non-zero size. /// /// # Algorithm /// @@ -73,6 +72,7 @@ pub unsafe fn ptr_rotate(mut left: usize, mid: *mut T, mut right: usize) { loop { let delta = cmp::min(left, right); if delta <= RawArray::::cap() { + // We will always hit this immediately for ZST. break; } -- cgit 1.4.1-3-g733a5 From a18be44d6318b04a604d1a9b3f965fbdaab8abf6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 21 Jul 2018 02:49:34 +0300 Subject: Avoid using `#[macro_export]` for documenting builtin macros --- src/libcore/macros.rs | 49 +++++++++++++++---------------------------- src/librustc/hir/lowering.rs | 3 ++- src/librustdoc/clean/mod.rs | 12 +++++------ src/libstd/macros.rs | 34 +++++++++++++++--------------- src/libsyntax/feature_gate.rs | 3 ++- 5 files changed, 43 insertions(+), 58 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index c830c22ee5f..83f9dfea8f2 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -543,6 +543,7 @@ macro_rules! unimplemented { /// into libsyntax itself. /// /// For more information, see documentation for `std`'s macros. +#[cfg(dox)] mod builtin { /// Unconditionally causes compilation to fail with the given error message when encountered. @@ -551,8 +552,7 @@ mod builtin { /// /// [`std::compile_error!`]: ../std/macro.compile_error.html #[stable(feature = "compile_error_macro", since = "1.20.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }); ($msg:expr,) => ({ /* compiler built-in */ }); @@ -564,8 +564,7 @@ mod builtin { /// /// [`std::format_args!`]: ../std/macro.format_args.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! format_args { ($fmt:expr) => ({ /* compiler built-in */ }); ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }); @@ -577,8 +576,7 @@ mod builtin { /// /// [`std::env!`]: ../std/macro.env.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! env { ($name:expr) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ }); @@ -590,8 +588,7 @@ mod builtin { /// /// [`std::option_env!`]: ../std/macro.option_env.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ }); @@ -603,8 +600,7 @@ mod builtin { /// /// [`std::concat_idents!`]: ../std/macro.concat_idents.html #[unstable(feature = "concat_idents_macro", issue = "29599")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! concat_idents { ($($e:ident),+) => ({ /* compiler built-in */ }); ($($e:ident,)+) => ({ /* compiler built-in */ }); @@ -616,8 +612,7 @@ mod builtin { /// /// [`std::concat!`]: ../std/macro.concat.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }); ($($e:expr,)*) => ({ /* compiler built-in */ }); @@ -629,8 +624,7 @@ mod builtin { /// /// [`std::line!`]: ../std/macro.line.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! line { () => ({ /* compiler built-in */ }) } /// A macro which expands to the column number on which it was invoked. @@ -639,8 +633,7 @@ mod builtin { /// /// [`std::column!`]: ../std/macro.column.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! column { () => ({ /* compiler built-in */ }) } /// A macro which expands to the file name from which it was invoked. @@ -649,8 +642,7 @@ mod builtin { /// /// [`std::file!`]: ../std/macro.file.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! file { () => ({ /* compiler built-in */ }) } /// A macro which stringifies its arguments. @@ -659,8 +651,7 @@ mod builtin { /// /// [`std::stringify!`]: ../std/macro.stringify.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! stringify { ($($t:tt)*) => ({ /* compiler built-in */ }) } /// Includes a utf8-encoded file as a string. @@ -669,8 +660,7 @@ mod builtin { /// /// [`std::include_str!`]: ../std/macro.include_str.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -682,8 +672,7 @@ mod builtin { /// /// [`std::include_bytes!`]: ../std/macro.include_bytes.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -695,8 +684,7 @@ mod builtin { /// /// [`std::module_path!`]: ../std/macro.module_path.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! module_path { () => ({ /* compiler built-in */ }) } /// Boolean evaluation of configuration flags, at compile-time. @@ -705,8 +693,7 @@ mod builtin { /// /// [`std::cfg!`]: ../std/macro.cfg.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) } /// Parse a file as an expression or an item according to the context. @@ -715,8 +702,7 @@ mod builtin { /// /// [`std::include!`]: ../std/macro.include.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -727,9 +713,8 @@ mod builtin { /// For more information, see the documentation for [`std::assert!`]. /// /// [`std::assert!`]: ../std/macro.assert.html - #[macro_export] + #[rustc_doc_only_macro] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(dox)] macro_rules! assert { ($cond:expr) => ({ /* compiler built-in */ }); ($cond:expr,) => ({ /* compiler built-in */ }); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 99db718bdf8..8e27a9914f4 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3191,7 +3191,8 @@ impl<'a> LoweringContext<'a> { let mut vis = self.lower_visibility(&i.vis, None); let attrs = self.lower_attrs(&i.attrs); if let ItemKind::MacroDef(ref def) = i.node { - if !def.legacy || attr::contains_name(&i.attrs, "macro_export") { + if !def.legacy || attr::contains_name(&i.attrs, "macro_export") || + attr::contains_name(&i.attrs, "rustc_doc_only_macro") { let body = self.lower_token_stream(def.stream()); self.exported_macros.push(hir::MacroDef { name, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b7edf73f7ce..44a1cfa6246 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1253,15 +1253,13 @@ fn macro_resolve(cx: &DocContext, path_str: &str) -> Option { .resolve_macro_to_def_inner(mark, &path, MacroKind::Bang, false); if let Ok(def) = res { if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(def) { - Some(def) - } else { - None + return Some(def); } - } else if let Some(def) = resolver.all_macros.get(&Symbol::intern(path_str)) { - Some(*def) - } else { - None } + if let Some(def) = resolver.all_macros.get(&Symbol::intern(path_str)) { + return Some(*def); + } + None } #[derive(Debug)] diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 75f038407c1..57ae5d3f862 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -303,7 +303,7 @@ macro_rules! assert_approx_eq { /// macro, but are documented here. Their implementations can be found hardcoded /// into libsyntax itself. #[cfg(dox)] -pub mod builtin { +mod builtin { /// Unconditionally causes compilation to fail with the given error message when encountered. /// @@ -341,7 +341,7 @@ pub mod builtin { /// /// [`panic!`]: ../std/macro.panic.html #[stable(feature = "compile_error_macro", since = "1.20.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }); ($msg:expr,) => ({ /* compiler built-in */ }); @@ -393,7 +393,7 @@ pub mod builtin { /// assert_eq!(s, format!("hello {}", "world")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! format_args { ($fmt:expr) => ({ /* compiler built-in */ }); ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }); @@ -431,7 +431,7 @@ pub mod builtin { /// error: what's that?! /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! env { ($name:expr) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ }); @@ -457,7 +457,7 @@ pub mod builtin { /// println!("the secret key might be: {:?}", key); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ }); @@ -488,7 +488,7 @@ pub mod builtin { /// # } /// ``` #[unstable(feature = "concat_idents_macro", issue = "29599")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! concat_idents { ($($e:ident),+) => ({ /* compiler built-in */ }); ($($e:ident,)+) => ({ /* compiler built-in */ }); @@ -510,7 +510,7 @@ pub mod builtin { /// assert_eq!(s, "test10btrue"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }); ($($e:expr,)*) => ({ /* compiler built-in */ }); @@ -538,7 +538,7 @@ pub mod builtin { /// println!("defined on line: {}", current_line); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! line { () => ({ /* compiler built-in */ }) } /// A macro which expands to the column number on which it was invoked. @@ -563,7 +563,7 @@ pub mod builtin { /// println!("defined on column: {}", current_col); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! column { () => ({ /* compiler built-in */ }) } /// A macro which expands to the file name from which it was invoked. @@ -587,7 +587,7 @@ pub mod builtin { /// println!("defined in file: {}", this_file); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! file { () => ({ /* compiler built-in */ }) } /// A macro which stringifies its arguments. @@ -606,7 +606,7 @@ pub mod builtin { /// assert_eq!(one_plus_one, "1 + 1"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! stringify { ($($t:tt)*) => ({ /* compiler built-in */ }) } /// Includes a utf8-encoded file as a string. @@ -640,7 +640,7 @@ pub mod builtin { /// /// Compiling 'main.rs' and running the resulting binary will print "adiós". #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -677,7 +677,7 @@ pub mod builtin { /// /// Compiling 'main.rs' and running the resulting binary will print "adiós". #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -701,7 +701,7 @@ pub mod builtin { /// test::foo(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! module_path { () => ({ /* compiler built-in */ }) } /// Boolean evaluation of configuration flags, at compile-time. @@ -723,7 +723,7 @@ pub mod builtin { /// }; /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) } /// Parse a file as an expression or an item according to the context. @@ -766,7 +766,7 @@ pub mod builtin { /// Compiling 'main.rs' and running the resulting binary will print /// "🙈🙊🙉🙈🙊🙉". #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -819,7 +819,7 @@ pub mod builtin { /// assert!(a + b == 30, "a = {}, b = {}", a, b); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! assert { ($cond:expr) => ({ /* compiler built-in */ }); ($cond:expr,) => ({ /* compiler built-in */ }); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d35249b6343..6164a2bf42f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -686,7 +686,8 @@ pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, Att } pub fn is_builtin_attr(attr: &ast::Attribute) -> bool { - BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name)) + BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name)) || + attr.name().as_str().starts_with("rustc_") } // Attributes that have a special meaning to rustc or rustdoc -- cgit 1.4.1-3-g733a5 From d77defcca114c14e6bbedc24697ead76a249a567 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 19 Jul 2018 07:01:37 -0700 Subject: Update stdsimd to undo an accidental stabilization Closes #52403 --- src/libcore/lib.rs | 3 --- src/libstd/lib.rs | 4 ---- src/stdsimd | 2 +- src/test/rustdoc-js/multi-query.js | 1 - 4 files changed, 1 insertion(+), 9 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index bbe6ae8619f..72074e1dbce 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -244,9 +244,6 @@ macro_rules! vector_impl { ($([$f:ident, $($args:tt)*]),*) => { $($f!($($args)*) #[cfg(not(stage0))] // allow changes to how stdsimd works in stage0 mod coresimd; -#[unstable(feature = "stdsimd", issue = "48556")] -#[cfg(not(stage0))] -pub use coresimd::simd; #[stable(feature = "simd_arch", since = "1.27.0")] #[cfg(not(stage0))] pub use coresimd::arch; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index fec14b8d67d..3c01de2e997 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -532,12 +532,8 @@ mod stdsimd; #[cfg(not(stage0))] mod coresimd { pub use core::arch; - pub use core::simd; } -#[unstable(feature = "stdsimd", issue = "48556")] -#[cfg(all(not(stage0), not(test)))] -pub use stdsimd::simd; #[stable(feature = "simd_arch", since = "1.27.0")] #[cfg(all(not(stage0), not(test)))] pub use stdsimd::arch; diff --git a/src/stdsimd b/src/stdsimd index 886ff388fbb..b9de11ab430 160000 --- a/src/stdsimd +++ b/src/stdsimd @@ -1 +1 @@ -Subproject commit 886ff388fbbe8798e292431d824a5ff3c3458f4d +Subproject commit b9de11ab43090c71ff7ab159a479394df1f968ab diff --git a/src/test/rustdoc-js/multi-query.js b/src/test/rustdoc-js/multi-query.js index 3793ca6599c..3f583a3600a 100644 --- a/src/test/rustdoc-js/multi-query.js +++ b/src/test/rustdoc-js/multi-query.js @@ -15,6 +15,5 @@ const EXPECTED = { { 'path': 'std', 'name': 'str' }, { 'path': 'std', 'name': 'u8' }, { 'path': 'std::ffi', 'name': 'CStr' }, - { 'path': 'std::simd', 'name': 'u8x2' }, ], }; -- cgit 1.4.1-3-g733a5 From e6fc62a1ef6cfb545d4f33914a4440c6bbcbf9eb Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 4 Jul 2018 02:48:30 -0700 Subject: Don't use SIMD in mem::swap for types smaller than the block size LLVM isn't able to remove the alloca for the unaligned block in the SIMD tail in some cases, so doing this helps SRoA work in cases where it currently doesn't. Found in the `replace_with` RFC discussion. --- src/libcore/mem.rs | 2 +- src/libcore/ptr.rs | 13 +++++++++++++ src/test/codegen/swap-small-types.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/test/codegen/swap-small-types.rs (limited to 'src/libcore') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 8fb4e0d6a02..a0fe6e98806 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -638,7 +638,7 @@ pub unsafe fn uninitialized() -> T { #[stable(feature = "rust1", since = "1.0.0")] pub fn swap(x: &mut T, y: &mut T) { unsafe { - ptr::swap_nonoverlapping(x, y, 1); + ptr::swap_nonoverlapping_one(x, y); } } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 0af642258c2..f1405b58e1b 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -187,6 +187,19 @@ pub unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { swap_nonoverlapping_bytes(x, y, len) } +#[inline] +pub(crate) unsafe fn swap_nonoverlapping_one(x: *mut T, y: *mut T) { + // For types smaller than the block optimization below, + // just swap directly to avoid pessimizing codegen. + if mem::size_of::() < 32 { + let z = read(x); + copy_nonoverlapping(y, x, 1); + write(y, z); + } else { + swap_nonoverlapping(x, y, 1); + } +} + #[inline] unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { // The approach here is to utilize simd to swap x & y efficiently. Testing reveals diff --git a/src/test/codegen/swap-small-types.rs b/src/test/codegen/swap-small-types.rs new file mode 100644 index 00000000000..f34a1d669bd --- /dev/null +++ b/src/test/codegen/swap-small-types.rs @@ -0,0 +1,26 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -O + +#![crate_type = "lib"] + +use std::mem::swap; + +type RGB48 = [u16; 3]; + +// CHECK-LABEL: @swap_rgb48 +#[no_mangle] +pub fn swap_rgb48(x: &mut RGB48, y: &mut RGB48) { +// CHECK-NOT: alloca +// CHECK: load i48 +// CHECK: store i48 + swap(x, y) +} -- cgit 1.4.1-3-g733a5 From 89495f3ca33b8a236ee8bc4f89a64a500fe2391f Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Mon, 23 Jul 2018 13:39:21 +0200 Subject: Forget Waker when cloning LocalWaker Since NonNull is Copy the inner field of the cloned Waker was copied for use in the new LocalWaker, however this left Waker to be dropped. Which means that when cloning LocalWaker would also erroneously call drop_raw. This change forgets the Waker, rather then dropping it, leaving the inner field to be used by the returned LocalWaker. Closes #52629. --- src/libcore/task/wake.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs index d3df8b50ee2..3b901c9aef0 100644 --- a/src/libcore/task/wake.rs +++ b/src/libcore/task/wake.rs @@ -12,7 +12,7 @@ reason = "futures in libcore are unstable", issue = "50547")] -use fmt; +use {fmt, mem}; use marker::Unpin; use ptr::NonNull; @@ -166,9 +166,10 @@ impl From for Waker { impl Clone for LocalWaker { #[inline] fn clone(&self) -> Self { - unsafe { - LocalWaker { inner: self.inner.as_ref().clone_raw().inner } - } + let waker = unsafe { self.inner.as_ref().clone_raw() }; + let inner = waker.inner; + mem::forget(waker); + LocalWaker { inner } } } -- cgit 1.4.1-3-g733a5 From 489101cc45d21d3909a728d16864e26599c12bee Mon Sep 17 00:00:00 2001 From: F001 Date: Mon, 23 Jul 2018 19:20:50 +0800 Subject: use inherent method instead --- src/libcore/cell.rs | 32 ++++++++++++++++---------- src/test/run-pass/rfc-1789-as-cell/from-mut.rs | 5 ++-- 2 files changed, 22 insertions(+), 15 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 8a0f499b598..b6087628ea6 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -200,9 +200,8 @@ use cmp::Ordering; use fmt::{self, Debug, Display}; use marker::Unsize; use mem; -use ops::{Deref, DerefMut, CoerceUnsized, Index}; +use ops::{Deref, DerefMut, CoerceUnsized}; use ptr; -use slice::SliceIndex; /// A mutable memory location. /// @@ -511,9 +510,8 @@ impl Cell { /// /// let slice: &mut [i32] = &mut [1, 2, 3]; /// let cell_slice: &Cell<[i32]> = Cell::from_mut(slice); - /// assert_eq!(cell_slice[..].len(), 3); + /// let slice_cell: &[Cell] = cell_slice.as_slice_of_cells(); /// - /// let slice_cell: &[Cell] = &cell_slice[..]; /// assert_eq!(slice_cell.len(), 3); /// ``` #[inline] @@ -548,15 +546,25 @@ impl Cell { #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U> CoerceUnsized> for Cell {} -#[unstable(feature = "as_cell", issue="43038")] -impl Index for Cell<[T]> - where I: SliceIndex<[Cell]> -{ - type Output = I::Output; - - fn index(&self, index: I) -> &Self::Output { +impl Cell<[T]> { + /// Returns a `&[Cell]` from a `&Cell<[T]>` + /// + /// # Examples + /// + /// ``` + /// #![feature(as_cell)] + /// use std::cell::Cell; + /// + /// let slice: &mut [i32] = &mut [1, 2, 3]; + /// let cell_slice: &Cell<[i32]> = Cell::from_mut(slice); + /// let slice_cell: &[Cell] = cell_slice.as_slice_of_cells(); + /// + /// assert_eq!(slice_cell.len(), 3); + /// ``` + #[unstable(feature = "as_cell", issue="43038")] + pub fn as_slice_of_cells(&self) -> &[Cell] { unsafe { - Index::index(&*(self as *const Cell<[T]> as *const [Cell]), index) + &*(self as *const Cell<[T]> as *const [Cell]) } } } diff --git a/src/test/run-pass/rfc-1789-as-cell/from-mut.rs b/src/test/run-pass/rfc-1789-as-cell/from-mut.rs index bd00f305cc4..88f7fbc86df 100644 --- a/src/test/run-pass/rfc-1789-as-cell/from-mut.rs +++ b/src/test/run-pass/rfc-1789-as-cell/from-mut.rs @@ -15,8 +15,7 @@ use std::cell::Cell; fn main() { let slice: &mut [i32] = &mut [1, 2, 3]; let cell_slice: &Cell<[i32]> = Cell::from_mut(slice); - assert_eq!(cell_slice[..].len(), 3); + let slice_cell: &[Cell] = cell_slice.as_slice_of_cells(); - let sub_slice: &[Cell] = &cell_slice[1..]; - assert_eq!(sub_slice.len(), 2); + assert_eq!(slice_cell.len(), 3); } -- cgit 1.4.1-3-g733a5 From 727bd7de7e6332482ee2765d46bfd00d89386d4b Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Mon, 23 Jul 2018 22:04:33 -0700 Subject: libcore: Prefer `Option::map` over `match` where applicable --- src/libcore/str/mod.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 3e215de58dd..86b8349fa3c 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -696,13 +696,10 @@ impl<'a> Iterator for CharIndices<'a> { impl<'a> DoubleEndedIterator for CharIndices<'a> { #[inline] fn next_back(&mut self) -> Option<(usize, char)> { - match self.iter.next_back() { - None => None, - Some(ch) => { - let index = self.front_offset + self.iter.iter.len(); - Some((index, ch)) - } - } + self.iter.next_back().map(|ch| { + let index = self.front_offset + self.iter.iter.len(); + (index, ch) + }) } } -- cgit 1.4.1-3-g733a5 From fb089156220ec2932b11de21226296c7fe3503f3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Jul 2018 18:23:10 +0200 Subject: clarify offset function safety concerns --- src/libcore/ptr.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index d020e14be4c..be82ab44cd1 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -591,7 +591,7 @@ impl *const T { /// Behavior: /// /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of an allocated object. + /// byte past the end of *the same* allocated object. /// /// * The computed offset, **in bytes**, cannot overflow an `isize`. /// @@ -643,9 +643,15 @@ impl *const T { /// /// The resulting pointer does not need to be in bounds, but it is /// potentially hazardous to dereference (which requires `unsafe`). + /// In particular, the resulting pointer may *not* be used to access a + /// different allocated object than the one `self` points to. In other + /// words, `x.wrapping_offset(y.wrapping_offset_from(x))` is + /// *not* the same as `y`, and dereferencing it is undefined behavior + /// unless `x` and `y` point into the same allocated object. /// /// Always use `.offset(count)` instead when possible, because `offset` - /// allows the compiler to optimize better. + /// allows the compiler to optimize better. If you need to cross object + /// boundaries, cast the pointer to an integer and do the arithmetic there. /// /// # Examples /// @@ -1340,7 +1346,7 @@ impl *mut T { /// Behavior: /// /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of an allocated object. + /// byte past the end of *the same* allocated object. /// /// * The computed offset, **in bytes**, cannot overflow an `isize`. /// @@ -1391,9 +1397,15 @@ impl *mut T { /// /// The resulting pointer does not need to be in bounds, but it is /// potentially hazardous to dereference (which requires `unsafe`). + /// In particular, the resulting pointer may *not* be used to access a + /// different allocated object than the one `self` points to. In other + /// words, `x.wrapping_offset(y.wrapping_offset_from(x))` is + /// *not* the same as `y`, and dereferencing it is undefined behavior + /// unless `x` and `y` point into the same allocated object. /// /// Always use `.offset(count)` instead when possible, because `offset` - /// allows the compiler to optimize better. + /// allows the compiler to optimize better. If you need to cross object + /// boundaries, cast the pointer to an integer and do the arithmetic there. /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 8646a1714306473011e79e1c1a213928bfa6025f Mon Sep 17 00:00:00 2001 From: ljedrz Date: Tue, 10 Jul 2018 20:39:28 +0200 Subject: Enforce #![deny(bare_trait_objects)] in src/libcore --- src/libcore/any.rs | 16 ++++++++-------- src/libcore/cell.rs | 6 +++--- src/libcore/fmt/builders.rs | 14 +++++++------- src/libcore/fmt/mod.rs | 10 +++++----- src/libcore/iter/iterator.rs | 2 +- src/libcore/lib.rs | 1 + src/libcore/panic.rs | 10 +++++----- src/libcore/task/context.rs | 6 +++--- src/libcore/task/wake.rs | 8 ++++---- 9 files changed, 37 insertions(+), 36 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 94f23db1ccc..6b26093439e 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -120,7 +120,7 @@ impl Any for T { /////////////////////////////////////////////////////////////////////////////// #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Any { +impl fmt::Debug for dyn Any { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Any") } @@ -130,20 +130,20 @@ impl fmt::Debug for Any { // hence used with `unwrap`. May eventually no longer be needed if // dispatch works with upcasting. #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Any + Send { +impl fmt::Debug for dyn Any + Send { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Any") } } #[stable(feature = "any_send_sync_methods", since = "1.28.0")] -impl fmt::Debug for Any + Send + Sync { +impl fmt::Debug for dyn Any + Send + Sync { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Any") } } -impl Any { +impl dyn Any { /// Returns `true` if the boxed type is the same as `T`. /// /// # Examples @@ -203,7 +203,7 @@ impl Any { pub fn downcast_ref(&self) -> Option<&T> { if self.is::() { unsafe { - Some(&*(self as *const Any as *const T)) + Some(&*(self as *const dyn Any as *const T)) } } else { None @@ -240,7 +240,7 @@ impl Any { pub fn downcast_mut(&mut self) -> Option<&mut T> { if self.is::() { unsafe { - Some(&mut *(self as *mut Any as *mut T)) + Some(&mut *(self as *mut dyn Any as *mut T)) } } else { None @@ -248,7 +248,7 @@ impl Any { } } -impl Any+Send { +impl dyn Any+Send { /// Forwards to the method defined on the type `Any`. /// /// # Examples @@ -332,7 +332,7 @@ impl Any+Send { } } -impl Any+Send+Sync { +impl dyn Any+Send+Sync { /// Forwards to the method defined on the type `Any`. /// /// # Examples diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index b6087628ea6..137e9fe2c15 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1532,7 +1532,7 @@ impl, U> CoerceUnsized> for UnsafeCell {} #[allow(unused)] fn assert_coerce_unsized(a: UnsafeCell<&i32>, b: Cell<&i32>, c: RefCell<&i32>) { - let _: UnsafeCell<&Send> = a; - let _: Cell<&Send> = b; - let _: RefCell<&Send> = c; + let _: UnsafeCell<&dyn Send> = a; + let _: Cell<&dyn Send> = b; + let _: RefCell<&dyn Send> = c; } diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index e8ea2e743da..3c5f934d4d8 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -11,7 +11,7 @@ use fmt; struct PadAdapter<'a> { - buf: &'a mut (fmt::Write + 'a), + buf: &'a mut (dyn fmt::Write + 'a), on_newline: bool, } @@ -107,7 +107,7 @@ pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, impl<'a, 'b: 'a> DebugStruct<'a, 'b> { /// Adds a new field to the generated struct output. #[stable(feature = "debug_builders", since = "1.2.0")] - pub fn field(&mut self, name: &str, value: &fmt::Debug) -> &mut DebugStruct<'a, 'b> { + pub fn field(&mut self, name: &str, value: &dyn fmt::Debug) -> &mut DebugStruct<'a, 'b> { self.result = self.result.and_then(|_| { let prefix = if self.has_fields { "," @@ -204,7 +204,7 @@ pub fn debug_tuple_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> D impl<'a, 'b: 'a> DebugTuple<'a, 'b> { /// Adds a new field to the generated tuple struct output. #[stable(feature = "debug_builders", since = "1.2.0")] - pub fn field(&mut self, value: &fmt::Debug) -> &mut DebugTuple<'a, 'b> { + pub fn field(&mut self, value: &dyn fmt::Debug) -> &mut DebugTuple<'a, 'b> { self.result = self.result.and_then(|_| { let (prefix, space) = if self.fields > 0 { (",", " ") @@ -258,7 +258,7 @@ struct DebugInner<'a, 'b: 'a> { } impl<'a, 'b: 'a> DebugInner<'a, 'b> { - fn entry(&mut self, entry: &fmt::Debug) { + fn entry(&mut self, entry: &dyn fmt::Debug) { self.result = self.result.and_then(|_| { if self.is_pretty() { let mut slot = None; @@ -340,7 +340,7 @@ pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b impl<'a, 'b: 'a> DebugSet<'a, 'b> { /// Adds a new entry to the set output. #[stable(feature = "debug_builders", since = "1.2.0")] - pub fn entry(&mut self, entry: &fmt::Debug) -> &mut DebugSet<'a, 'b> { + pub fn entry(&mut self, entry: &dyn fmt::Debug) -> &mut DebugSet<'a, 'b> { self.inner.entry(entry); self } @@ -411,7 +411,7 @@ pub fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a, impl<'a, 'b: 'a> DebugList<'a, 'b> { /// Adds a new entry to the list output. #[stable(feature = "debug_builders", since = "1.2.0")] - pub fn entry(&mut self, entry: &fmt::Debug) -> &mut DebugList<'a, 'b> { + pub fn entry(&mut self, entry: &dyn fmt::Debug) -> &mut DebugList<'a, 'b> { self.inner.entry(entry); self } @@ -482,7 +482,7 @@ pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// Adds a new entry to the map output. #[stable(feature = "debug_builders", since = "1.2.0")] - pub fn entry(&mut self, key: &fmt::Debug, value: &fmt::Debug) -> &mut DebugMap<'a, 'b> { + pub fn entry(&mut self, key: &dyn fmt::Debug, value: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> { self.result = self.result.and_then(|_| { if self.is_pretty() { let mut slot = None; diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index d91bf463383..928f95e3ba2 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -255,7 +255,7 @@ pub struct Formatter<'a> { width: Option, precision: Option, - buf: &'a mut (Write+'a), + buf: &'a mut (dyn Write+'a), curarg: slice::Iter<'a, ArgumentV1<'a>>, args: &'a [ArgumentV1<'a>], } @@ -272,7 +272,7 @@ struct Void { /// /// 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 Fn()>, + _oibit_remover: PhantomData<*mut dyn Fn()>, } /// This struct represents the generic "argument" which is taken by the Xprintf @@ -1020,7 +1020,7 @@ pub trait UpperExp { /// /// [`write!`]: ../../std/macro.write.html #[stable(feature = "rust1", since = "1.0.0")] -pub fn write(output: &mut Write, args: Arguments) -> Result { +pub fn write(output: &mut dyn Write, args: Arguments) -> Result { let mut formatter = Formatter { flags: 0, width: None, @@ -1062,7 +1062,7 @@ pub fn write(output: &mut Write, args: Arguments) -> Result { impl<'a> Formatter<'a> { fn wrap_buf<'b, 'c, F>(&'b mut self, wrap: F) -> Formatter<'c> - where 'b: 'c, F: FnOnce(&'b mut (Write+'b)) -> &'c mut (Write+'c) + where 'b: 'c, F: FnOnce(&'b mut (dyn Write+'b)) -> &'c mut (dyn Write+'c) { Formatter { // We want to change this @@ -1342,7 +1342,7 @@ impl<'a> Formatter<'a> { } fn write_formatted_parts(&mut self, formatted: &flt2dec::Formatted) -> Result { - fn write_bytes(buf: &mut Write, s: &[u8]) -> Result { + fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result { buf.write_str(unsafe { str::from_utf8_unchecked(s) }) } diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index afc273d265b..48c6eb94144 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -18,7 +18,7 @@ use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhi use super::{Zip, Sum, Product}; use super::{ChainState, FromIterator, ZipImpl}; -fn _assert_is_object_safe(_: &Iterator) {} +fn _assert_is_object_safe(_: &dyn Iterator) {} /// An interface for dealing with iterators. /// diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 72074e1dbce..ae0469bfa04 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -70,6 +70,7 @@ test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] #![no_core] +#![deny(bare_trait_objects)] #![deny(missing_docs)] #![deny(missing_debug_implementations)] diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 10f02ca2fdc..17cac5aa0a0 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -43,7 +43,7 @@ use fmt; #[stable(feature = "panic_hooks", since = "1.10.0")] #[derive(Debug)] pub struct PanicInfo<'a> { - payload: &'a (Any + Send), + payload: &'a (dyn Any + Send), message: Option<&'a fmt::Arguments<'a>>, location: Location<'a>, } @@ -64,7 +64,7 @@ impl<'a> PanicInfo<'a> { #[doc(hidden)] #[inline] - pub fn set_payload(&mut self, info: &'a (Any + Send)) { + pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) { self.payload = info; } @@ -86,7 +86,7 @@ impl<'a> PanicInfo<'a> { /// panic!("Normal panic"); /// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn payload(&self) -> &(Any + Send) { + pub fn payload(&self) -> &(dyn Any + Send) { self.payload } @@ -270,6 +270,6 @@ impl<'a> fmt::Display for Location<'a> { #[unstable(feature = "std_internals", issue = "0")] #[doc(hidden)] pub unsafe trait BoxMeUp { - fn box_me_up(&mut self) -> *mut (Any + Send); - fn get(&mut self) -> &(Any + Send); + fn box_me_up(&mut self) -> *mut (dyn Any + Send); + fn get(&mut self) -> &(dyn Any + Send); } diff --git a/src/libcore/task/context.rs b/src/libcore/task/context.rs index c69d45248a5..1fc975cb178 100644 --- a/src/libcore/task/context.rs +++ b/src/libcore/task/context.rs @@ -21,7 +21,7 @@ use super::{Executor, Waker, LocalWaker}; /// when performing a single `poll` step on a task. pub struct Context<'a> { local_waker: &'a LocalWaker, - executor: &'a mut Executor, + executor: &'a mut dyn Executor, } impl<'a> fmt::Debug for Context<'a> { @@ -34,7 +34,7 @@ impl<'a> fmt::Debug for Context<'a> { impl<'a> Context<'a> { /// Create a new task `Context` with the provided `local_waker`, `waker`, and `executor`. #[inline] - pub fn new(local_waker: &'a LocalWaker, executor: &'a mut Executor) -> Context<'a> { + pub fn new(local_waker: &'a LocalWaker, executor: &'a mut dyn Executor) -> Context<'a> { Context { local_waker, executor, @@ -58,7 +58,7 @@ impl<'a> Context<'a> { /// This method is useful primarily if you want to explicitly handle /// spawn failures. #[inline] - pub fn executor(&mut self) -> &mut Executor { + pub fn executor(&mut self) -> &mut dyn Executor { self.executor } diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs index 3b901c9aef0..321b432d3f4 100644 --- a/src/libcore/task/wake.rs +++ b/src/libcore/task/wake.rs @@ -23,7 +23,7 @@ use ptr::NonNull; /// trait, allowing notifications to get routed through it. #[repr(transparent)] pub struct Waker { - inner: NonNull, + inner: NonNull, } impl Unpin for Waker {} @@ -41,7 +41,7 @@ impl Waker { /// use the `Waker::from` function instead which works with the safe /// `Arc` type and the safe `Wake` trait. #[inline] - pub unsafe fn new(inner: NonNull) -> Self { + pub unsafe fn new(inner: NonNull) -> Self { Waker { inner: inner } } @@ -98,7 +98,7 @@ impl Drop for Waker { /// behavior. #[repr(transparent)] pub struct LocalWaker { - inner: NonNull, + inner: NonNull, } impl Unpin for LocalWaker {} @@ -119,7 +119,7 @@ impl LocalWaker { /// For this function to be used safely, it must be sound to call `inner.wake_local()` /// on the current thread. #[inline] - pub unsafe fn new(inner: NonNull) -> Self { + pub unsafe fn new(inner: NonNull) -> Self { LocalWaker { inner: inner } } -- cgit 1.4.1-3-g733a5 From 66c4dc9769b7ae456fe2960dc5a1e037b2432184 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Fri, 13 Jul 2018 14:25:22 +0900 Subject: Add missing dyn --- src/liballoc/tests/arc.rs | 6 +++--- src/liballoc/tests/btree/set.rs | 2 +- src/liballoc/tests/lib.rs | 2 +- src/liballoc/tests/rc.rs | 6 +++--- src/libcore/tests/any.rs | 16 +++++++++------ src/libcore/tests/hash/mod.rs | 2 +- src/libcore/tests/intrinsics.rs | 2 +- src/libcore/tests/mem.rs | 4 ++-- src/libcore/tests/option.rs | 2 +- src/libcore/tests/ptr.rs | 20 +++++++++--------- src/libcore/tests/result.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/core.rs | 2 +- src/librustdoc/html/highlight.rs | 4 ++-- src/librustdoc/html/layout.rs | 4 ++-- src/librustdoc/html/render.rs | 2 +- src/librustdoc/test.rs | 2 +- src/libstd/sys/redox/process.rs | 4 ++-- src/tools/compiletest/src/header.rs | 2 +- src/tools/compiletest/src/read2.rs | 6 +++--- src/tools/error_index_generator/main.rs | 36 ++++++++++++++++----------------- src/tools/tidy/src/features.rs | 2 +- src/tools/tidy/src/lib.rs | 4 ++-- 23 files changed, 69 insertions(+), 65 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/tests/arc.rs b/src/liballoc/tests/arc.rs index 753873dd294..d90c22a3b18 100644 --- a/src/liballoc/tests/arc.rs +++ b/src/liballoc/tests/arc.rs @@ -18,7 +18,7 @@ fn uninhabited() { a = a.clone(); assert!(a.upgrade().is_none()); - let mut a: Weak = a; // Unsizing + let mut a: Weak = a; // Unsizing a = a.clone(); assert!(a.upgrade().is_none()); } @@ -39,7 +39,7 @@ fn slice() { #[test] fn trait_object() { let a: Arc = Arc::new(4); - let a: Arc = a; // Unsizing + let a: Arc = a; // Unsizing // Exercise is_dangling() with a DST let mut a = Arc::downgrade(&a); @@ -49,7 +49,7 @@ fn trait_object() { let mut b = Weak::::new(); b = b.clone(); assert!(b.upgrade().is_none()); - let mut b: Weak = b; // Unsizing + let mut b: Weak = b; // Unsizing b = b.clone(); assert!(b.upgrade().is_none()); } diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index 6171b8ba624..0330bda5e32 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -40,7 +40,7 @@ fn test_hash() { } fn check(a: &[i32], b: &[i32], expected: &[i32], f: F) - where F: FnOnce(&BTreeSet, &BTreeSet, &mut FnMut(&i32) -> bool) -> bool + where F: FnOnce(&BTreeSet, &BTreeSet, &mut dyn FnMut(&i32) -> bool) -> bool { let mut set_a = BTreeSet::new(); let mut set_b = BTreeSet::new(); diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 2c361598e89..91bc778ad4c 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -63,7 +63,7 @@ fn test_boxed_hasher() { 5u32.hash(&mut hasher_1); assert_eq!(ordinary_hash, hasher_1.finish()); - let mut hasher_2 = Box::new(DefaultHasher::new()) as Box; + let mut hasher_2 = Box::new(DefaultHasher::new()) as Box; 5u32.hash(&mut hasher_2); assert_eq!(ordinary_hash, hasher_2.finish()); } diff --git a/src/liballoc/tests/rc.rs b/src/liballoc/tests/rc.rs index baa0406acfc..9ec7c831444 100644 --- a/src/liballoc/tests/rc.rs +++ b/src/liballoc/tests/rc.rs @@ -18,7 +18,7 @@ fn uninhabited() { a = a.clone(); assert!(a.upgrade().is_none()); - let mut a: Weak = a; // Unsizing + let mut a: Weak = a; // Unsizing a = a.clone(); assert!(a.upgrade().is_none()); } @@ -39,7 +39,7 @@ fn slice() { #[test] fn trait_object() { let a: Rc = Rc::new(4); - let a: Rc = a; // Unsizing + let a: Rc = a; // Unsizing // Exercise is_dangling() with a DST let mut a = Rc::downgrade(&a); @@ -49,7 +49,7 @@ fn trait_object() { let mut b = Weak::::new(); b = b.clone(); assert!(b.upgrade().is_none()); - let mut b: Weak = b; // Unsizing + let mut b: Weak = b; // Unsizing b = b.clone(); assert!(b.upgrade().is_none()); } diff --git a/src/libcore/tests/any.rs b/src/libcore/tests/any.rs index 2d3e81aa131..a80bf939530 100644 --- a/src/libcore/tests/any.rs +++ b/src/libcore/tests/any.rs @@ -17,7 +17,7 @@ static TEST: &'static str = "Test"; #[test] fn any_referenced() { - let (a, b, c) = (&5 as &Any, &TEST as &Any, &Test as &Any); + let (a, b, c) = (&5 as &dyn Any, &TEST as &dyn Any, &Test as &dyn Any); assert!(a.is::()); assert!(!b.is::()); @@ -34,7 +34,11 @@ fn any_referenced() { #[test] fn any_owning() { - let (a, b, c) = (box 5_usize as Box, box TEST as Box, box Test as Box); + let (a, b, c) = ( + box 5_usize as Box, + box TEST as Box, + box Test as Box, + ); assert!(a.is::()); assert!(!b.is::()); @@ -51,7 +55,7 @@ fn any_owning() { #[test] fn any_downcast_ref() { - let a = &5_usize as &Any; + let a = &5_usize as &dyn Any; match a.downcast_ref::() { Some(&5) => {} @@ -69,9 +73,9 @@ fn any_downcast_mut() { let mut a = 5_usize; let mut b: Box<_> = box 7_usize; - let a_r = &mut a as &mut Any; + let a_r = &mut a as &mut dyn Any; let tmp: &mut usize = &mut *b; - let b_r = tmp as &mut Any; + let b_r = tmp as &mut dyn Any; match a_r.downcast_mut::() { Some(x) => { @@ -113,7 +117,7 @@ fn any_downcast_mut() { #[test] fn any_fixed_vec() { let test = [0_usize; 8]; - let test = &test as &Any; + let test = &test as &dyn Any; assert!(test.is::<[usize; 8]>()); assert!(!test.is::<[usize; 10]>()); } diff --git a/src/libcore/tests/hash/mod.rs b/src/libcore/tests/hash/mod.rs index 8716421b424..85c9d41b65b 100644 --- a/src/libcore/tests/hash/mod.rs +++ b/src/libcore/tests/hash/mod.rs @@ -128,7 +128,7 @@ fn test_custom_state() { fn test_indirect_hasher() { let mut hasher = MyHasher { hash: 0 }; { - let mut indirect_hasher: &mut Hasher = &mut hasher; + let mut indirect_hasher: &mut dyn Hasher = &mut hasher; 5u32.hash(&mut indirect_hasher); } assert_eq!(hasher.hash, 5); diff --git a/src/libcore/tests/intrinsics.rs b/src/libcore/tests/intrinsics.rs index 2b380abf63c..9f3cba26a62 100644 --- a/src/libcore/tests/intrinsics.rs +++ b/src/libcore/tests/intrinsics.rs @@ -22,7 +22,7 @@ fn test_typeid_sized_types() { #[test] fn test_typeid_unsized_types() { trait Z {} - struct X(str); struct Y(Z + 'static); + struct X(str); struct Y(dyn Z + 'static); assert_eq!(TypeId::of::(), TypeId::of::()); assert_eq!(TypeId::of::(), TypeId::of::()); diff --git a/src/libcore/tests/mem.rs b/src/libcore/tests/mem.rs index f55a1c81463..714f2babbdf 100644 --- a/src/libcore/tests/mem.rs +++ b/src/libcore/tests/mem.rs @@ -109,11 +109,11 @@ fn test_transmute() { trait Foo { fn dummy(&self) { } } impl Foo for isize {} - let a = box 100isize as Box; + let a = box 100isize as Box; unsafe { let x: ::core::raw::TraitObject = transmute(a); assert!(*(x.data as *const isize) == 100); - let _x: Box = transmute(x); + let _x: Box = transmute(x); } unsafe { diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs index bc3e61a4f54..324ebf43565 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -240,7 +240,7 @@ fn test_collect() { assert!(v == None); // test that it does not take more elements than it needs - let mut functions: [Box Option<()>>; 3] = + let mut functions: [Box Option<()>>; 3] = [box || Some(()), box || None, box || panic!()]; let v: Option> = functions.iter_mut().map(|f| (*f)()).collect(); diff --git a/src/libcore/tests/ptr.rs b/src/libcore/tests/ptr.rs index 31bc1d67768..92160910d8f 100644 --- a/src/libcore/tests/ptr.rs +++ b/src/libcore/tests/ptr.rs @@ -84,16 +84,16 @@ fn test_is_null() { assert!(nms.is_null()); // Pointers to unsized types -- trait objects - let ci: *const ToString = &3; + let ci: *const dyn ToString = &3; assert!(!ci.is_null()); - let mi: *mut ToString = &mut 3; + let mi: *mut dyn ToString = &mut 3; assert!(!mi.is_null()); - let nci: *const ToString = null::(); + let nci: *const dyn ToString = null::(); assert!(nci.is_null()); - let nmi: *mut ToString = null_mut::(); + let nmi: *mut dyn ToString = null_mut::(); assert!(nmi.is_null()); } @@ -140,16 +140,16 @@ fn test_as_ref() { assert_eq!(nms.as_ref(), None); // Pointers to unsized types -- trait objects - let ci: *const ToString = &3; + let ci: *const dyn ToString = &3; assert!(ci.as_ref().is_some()); - let mi: *mut ToString = &mut 3; + let mi: *mut dyn ToString = &mut 3; assert!(mi.as_ref().is_some()); - let nci: *const ToString = null::(); + let nci: *const dyn ToString = null::(); assert!(nci.as_ref().is_none()); - let nmi: *mut ToString = null_mut::(); + let nmi: *mut dyn ToString = null_mut::(); assert!(nmi.as_ref().is_none()); } } @@ -182,10 +182,10 @@ fn test_as_mut() { assert_eq!(nms.as_mut(), None); // Pointers to unsized types -- trait objects - let mi: *mut ToString = &mut 3; + let mi: *mut dyn ToString = &mut 3; assert!(mi.as_mut().is_some()); - let nmi: *mut ToString = null_mut::(); + let nmi: *mut dyn ToString = null_mut::(); assert!(nmi.as_mut().is_none()); } } diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs index d9927ce4487..0616252c82c 100644 --- a/src/libcore/tests/result.rs +++ b/src/libcore/tests/result.rs @@ -81,7 +81,7 @@ fn test_collect() { assert!(v == Err(2)); // test that it does not take more elements than it needs - let mut functions: [Box Result<(), isize>>; 3] = + let mut functions: [Box Result<(), isize>>; 3] = [box || Ok(()), box || Err(1), box || panic!()]; let v: Result, isize> = functions.iter_mut().map(|f| (*f)()).collect(); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 98684b27973..c601f138d0a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -375,7 +375,7 @@ impl fmt::Debug for Item { let fake = MAX_DEF_ID.with(|m| m.borrow().get(&self.def_id.krate) .map(|id| self.def_id >= *id).unwrap_or(false)); - let def_id: &fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id }; + let def_id: &dyn fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id }; fmt.debug_struct("Item") .field("source", &self.source) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 6e1b4589547..4b8dbaf4211 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -55,7 +55,7 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> { /// The stack of module NodeIds up till this point pub mod_ids: RefCell>, pub crate_name: Option, - pub cstore: Rc, + pub cstore: Rc, pub populated_all_crate_impls: Cell, // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 5939d5341e3..6cf9b143373 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -395,7 +395,7 @@ impl Class { fn write_header(class: Option<&str>, id: Option<&str>, - out: &mut Write) + out: &mut dyn Write) -> io::Result<()> { write!(out, "

,
     write!(out, "class=\"rust {}\">\n", class.unwrap_or(""))
 }
 
-fn write_footer(out: &mut Write) -> io::Result<()> {
+fn write_footer(out: &mut dyn Write) -> io::Result<()> {
     write!(out, "
\n") } diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 5e93b20ea17..af7c0a04215 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -32,7 +32,7 @@ pub struct Page<'a> { } pub fn render( - dst: &mut io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T, + dst: &mut dyn io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T, css_file_extension: bool, themes: &[PathBuf]) -> io::Result<()> { @@ -194,7 +194,7 @@ pub fn render( ) } -pub fn redirect(dst: &mut io::Write, url: &str) -> io::Result<()> { +pub fn redirect(dst: &mut dyn io::Write, url: &str) -> io::Result<()> { //

(&mut self, mut predicate: P) -> Option where Self: Sized, P: FnMut(&Self::Item) -> bool diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index e04968a6359..8a34660d556 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -28,7 +28,6 @@ #![feature(iterator_try_fold)] #![feature(iterator_flatten)] #![cfg_attr(stage0, feature(conservative_impl_trait))] -#![feature(iter_rfind)] #![feature(iterator_repeat_with)] #![feature(nonzero)] #![feature(pattern)] -- cgit 1.4.1-3-g733a5 From 9db63bb033271c7b9c9f4315eb6db3314758a33e Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 2 Apr 2018 16:40:53 -0700 Subject: Stabilize iterator_try_fold in 1.27.0 --- src/libcore/iter/iterator.rs | 7 ++----- src/libcore/iter/traits.rs | 4 +--- src/libcore/tests/lib.rs | 1 - 3 files changed, 3 insertions(+), 9 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 31f77f92435..a54e0e00655 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1446,7 +1446,6 @@ pub trait Iterator { /// Basic usage: /// /// ``` - /// #![feature(iterator_try_fold)] /// let a = [1, 2, 3]; /// /// // the checked sum of all of the elements of the array @@ -1458,7 +1457,6 @@ pub trait Iterator { /// Short-circuiting: /// /// ``` - /// #![feature(iterator_try_fold)] /// let a = [10, 20, 30, 100, 40, 50]; /// let mut it = a.iter(); /// @@ -1472,7 +1470,7 @@ pub trait Iterator { /// assert_eq!(it.next(), Some(&40)); /// ``` #[inline] - #[unstable(feature = "iterator_try_fold", issue = "45594")] + #[stable(feature = "iterator_try_fold", since = "1.27.0")] fn try_fold(&mut self, init: B, mut f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try { @@ -1495,7 +1493,6 @@ pub trait Iterator { /// # Examples /// /// ``` - /// #![feature(iterator_try_fold)] /// use std::fs::rename; /// use std::io::{stdout, Write}; /// use std::path::Path; @@ -1512,7 +1509,7 @@ pub trait Iterator { /// assert_eq!(it.next(), Some("stale_bread.json")); /// ``` #[inline] - #[unstable(feature = "iterator_try_fold", issue = "45594")] + #[stable(feature = "iterator_try_fold", since = "1.27.0")] fn try_for_each(&mut self, mut f: F) -> R where Self: Sized, F: FnMut(Self::Item) -> R, R: Try { diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index ee278651c8d..ddbb5998942 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -427,7 +427,6 @@ pub trait DoubleEndedIterator: Iterator { /// Basic usage: /// /// ``` - /// #![feature(iterator_try_fold)] /// let a = ["1", "2", "3"]; /// let sum = a.iter() /// .map(|&s| s.parse::()) @@ -438,7 +437,6 @@ pub trait DoubleEndedIterator: Iterator { /// Short-circuiting: /// /// ``` - /// #![feature(iterator_try_fold)] /// let a = ["1", "rust", "3"]; /// let mut it = a.iter(); /// let sum = it @@ -452,7 +450,7 @@ pub trait DoubleEndedIterator: Iterator { /// assert_eq!(it.next_back(), Some(&"1")); /// ``` #[inline] - #[unstable(feature = "iterator_try_fold", issue = "45594")] + #[stable(feature = "iterator_try_fold", since = "1.27.0")] fn try_rfold(&mut self, init: B, mut f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try { diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 8a34660d556..16150cd82be 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -25,7 +25,6 @@ #![feature(iterator_step_by)] #![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] -#![feature(iterator_try_fold)] #![feature(iterator_flatten)] #![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(iterator_repeat_with)] -- cgit 1.4.1-3-g733a5 From 9b5859aea199d5f34a4d4b5ae7112c5c41f3b242 Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Sun, 18 Feb 2018 17:39:40 +0000 Subject: Remove all unstable placement features Closes #22181, #27779 --- src/grammar/parser-lalr.y | 3 - src/liballoc/binary_heap.rs | 66 +------- src/liballoc/boxed.rs | 151 +---------------- src/liballoc/lib.rs | 12 +- src/liballoc/linked_list.rs | 178 +-------------------- src/liballoc/tests/binary_heap.rs | 20 --- src/liballoc/tests/lib.rs | 2 - src/liballoc/tests/vec.rs | 20 +-- src/liballoc/tests/vec_deque.rs | 22 --- src/liballoc/vec.rs | 76 +-------- src/liballoc/vec_deque.rs | 144 +---------------- src/libcore/ops/mod.rs | 4 - src/libcore/ops/place.rs | 143 ----------------- src/librustc/hir/lowering.rs | 133 --------------- src/librustc/ich/impls_syntax.rs | 1 - src/librustc_lint/unused.rs | 1 - src/librustc_mir/build/matches/test.rs | 7 +- src/librustc_mir/lib.rs | 2 - src/librustc_typeck/diagnostics.rs | 10 -- src/libstd/collections/hash/map.rs | 151 +---------------- src/libstd/collections/hash/table.rs | 26 --- src/libstd/lib.rs | 1 - src/libsyntax/ast.rs | 3 - src/libsyntax/feature_gate.rs | 7 - src/libsyntax/fold.rs | 3 - src/libsyntax/parse/parser.rs | 13 -- src/libsyntax/print/pprust.rs | 13 -- src/libsyntax/util/parser.rs | 14 +- src/libsyntax/visit.rs | 4 - src/libsyntax_pos/hygiene.rs | 2 - src/test/compile-fail/issue-14084.rs | 17 -- src/test/compile-fail/placement-expr-unsafe.rs | 24 --- src/test/compile-fail/placement-expr-unstable.rs | 21 --- src/test/parse-fail/assoc-oddities-1.rs | 3 +- src/test/pretty/stmt_expr_attributes.rs | 1 - src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs | 10 -- .../run-pass-fulldeps/pprust-expr-roundtrip.rs | 39 ++--- src/test/run-pass/new-box-syntax.rs | 10 +- src/test/run-pass/placement-in-syntax.rs | 37 ----- src/test/ui/feature-gate-placement-expr.rs | 26 --- src/test/ui/feature-gate-placement-expr.stderr | 11 -- 41 files changed, 39 insertions(+), 1392 deletions(-) delete mode 100644 src/libcore/ops/place.rs delete mode 100644 src/test/compile-fail/issue-14084.rs delete mode 100644 src/test/compile-fail/placement-expr-unsafe.rs delete mode 100644 src/test/compile-fail/placement-expr-unstable.rs delete mode 100644 src/test/run-pass/placement-in-syntax.rs delete mode 100644 src/test/ui/feature-gate-placement-expr.rs delete mode 100644 src/test/ui/feature-gate-placement-expr.stderr (limited to 'src/libcore') diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y index de1f96aac50..a7da69f65fa 100644 --- a/src/grammar/parser-lalr.y +++ b/src/grammar/parser-lalr.y @@ -1400,7 +1400,6 @@ nonblock_expr | BREAK lifetime { $$ = mk_node("ExprBreak", 1, $2); } | YIELD { $$ = mk_node("ExprYield", 0); } | YIELD expr { $$ = mk_node("ExprYield", 1, $2); } -| nonblock_expr LARROW expr { $$ = mk_node("ExprInPlace", 2, $1, $3); } | nonblock_expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); } | nonblock_expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } | nonblock_expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); } @@ -1463,7 +1462,6 @@ expr | BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } | YIELD { $$ = mk_node("ExprYield", 0); } | YIELD expr { $$ = mk_node("ExprYield", 1, $2); } -| expr LARROW expr { $$ = mk_node("ExprInPlace", 2, $1, $3); } | expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); } | expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } | expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); } @@ -1527,7 +1525,6 @@ expr_nostruct | BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } | YIELD { $$ = mk_node("ExprYield", 0); } | YIELD expr { $$ = mk_node("ExprYield", 1, $2); } -| expr_nostruct LARROW expr_nostruct { $$ = mk_node("ExprInPlace", 2, $1, $3); } | expr_nostruct '=' expr_nostruct { $$ = mk_node("ExprAssign", 2, $1, $3); } | expr_nostruct SHLEQ expr_nostruct { $$ = mk_node("ExprAssignShl", 2, $1, $3); } | expr_nostruct SHREQ expr_nostruct { $$ = mk_node("ExprAssignShr", 2, $1, $3); } diff --git a/src/liballoc/binary_heap.rs b/src/liballoc/binary_heap.rs index f6a666b599b..668b61c51d8 100644 --- a/src/liballoc/binary_heap.rs +++ b/src/liballoc/binary_heap.rs @@ -155,7 +155,7 @@ #![allow(missing_docs)] #![stable(feature = "rust1", since = "1.0.0")] -use core::ops::{Deref, DerefMut, Place, Placer, InPlace}; +use core::ops::{Deref, DerefMut}; use core::iter::{FromIterator, FusedIterator}; use core::mem::{swap, size_of}; use core::ptr; @@ -1195,67 +1195,3 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap { self.extend(iter.into_iter().cloned()); } } - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -pub struct BinaryHeapPlace<'a, T: 'a> -where T: Clone + Ord { - heap: *mut BinaryHeap, - place: vec::PlaceBack<'a, T>, -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T: Clone + Ord + fmt::Debug> fmt::Debug for BinaryHeapPlace<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("BinaryHeapPlace") - .field(&self.place) - .finish() - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T: 'a> Placer for &'a mut BinaryHeap -where T: Clone + Ord { - type Place = BinaryHeapPlace<'a, T>; - - fn make_place(self) -> Self::Place { - let ptr = self as *mut BinaryHeap; - let place = Placer::make_place(self.data.place_back()); - BinaryHeapPlace { - heap: ptr, - place, - } - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -unsafe impl<'a, T> Place for BinaryHeapPlace<'a, T> -where T: Clone + Ord { - fn pointer(&mut self) -> *mut T { - self.place.pointer() - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> InPlace for BinaryHeapPlace<'a, T> -where T: Clone + Ord { - type Owner = &'a T; - - unsafe fn finalize(self) -> &'a T { - self.place.finalize(); - - let heap: &mut BinaryHeap = &mut *self.heap; - let len = heap.len(); - let i = heap.sift_up(0, len - 1); - heap.data.get_unchecked(i) - } -} diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index e59a6e9fdea..4f9dc61ce19 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -55,7 +55,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use heap::Heap; use raw_vec::RawVec; use core::any::Any; @@ -63,47 +62,14 @@ use core::borrow; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; -use core::heap::{Alloc, Layout}; use core::iter::FusedIterator; -use core::marker::{self, Unpin, Unsize}; +use core::marker::{Unpin, Unsize}; use core::mem::{self, Pin}; use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; -use core::ops::{BoxPlace, Boxed, InPlace, Place, Placer}; use core::ptr::{self, NonNull, Unique}; use core::convert::From; use str::from_boxed_utf8_unchecked; -/// A value that represents the heap. This is the default place that the `box` -/// keyword allocates into when no place is supplied. -/// -/// The following two examples are equivalent: -/// -/// ``` -/// #![feature(box_heap)] -/// -/// #![feature(box_syntax, placement_in_syntax)] -/// use std::boxed::HEAP; -/// -/// fn main() { -/// let foo: Box = in HEAP { 5 }; -/// let foo = box 5; -/// } -/// ``` -#[unstable(feature = "box_heap", - reason = "may be renamed; uncertain about custom allocator design", - issue = "27779")] -pub const HEAP: ExchangeHeapSingleton = ExchangeHeapSingleton { _force_singleton: () }; - -/// This the singleton type used solely for `boxed::HEAP`. -#[unstable(feature = "box_heap", - reason = "may be renamed; uncertain about custom allocator design", - issue = "27779")] -#[allow(missing_debug_implementations)] -#[derive(Copy, Clone)] -pub struct ExchangeHeapSingleton { - _force_singleton: (), -} - /// A pointer type for heap allocation. /// /// See the [module-level documentation](../../std/boxed/index.html) for more. @@ -112,121 +78,6 @@ pub struct ExchangeHeapSingleton { #[stable(feature = "rust1", since = "1.0.0")] pub struct Box(Unique); -/// `IntermediateBox` represents uninitialized backing storage for `Box`. -/// -/// FIXME (pnkfelix): Ideally we would just reuse `Box` instead of -/// introducing a separate `IntermediateBox`; but then you hit -/// issues when you e.g. attempt to destructure an instance of `Box`, -/// since it is a lang item and so it gets special handling by the -/// compiler. Easier just to make this parallel type for now. -/// -/// FIXME (pnkfelix): Currently the `box` protocol only supports -/// creating instances of sized types. This IntermediateBox is -/// designed to be forward-compatible with a future protocol that -/// supports creating instances of unsized types; that is why the type -/// parameter has the `?Sized` generalization marker, and is also why -/// this carries an explicit size. However, it probably does not need -/// to carry the explicit alignment; that is just a work-around for -/// the fact that the `align_of` intrinsic currently requires the -/// input type to be Sized (which I do not think is strictly -/// necessary). -#[unstable(feature = "placement_in", - reason = "placement box design is still being worked out.", - issue = "27779")] -#[allow(missing_debug_implementations)] -pub struct IntermediateBox { - ptr: *mut u8, - layout: Layout, - marker: marker::PhantomData<*mut T>, -} - -#[unstable(feature = "placement_in", - reason = "placement box design is still being worked out.", - issue = "27779")] -unsafe impl Place for IntermediateBox { - fn pointer(&mut self) -> *mut T { - self.ptr as *mut T - } -} - -unsafe fn finalize(b: IntermediateBox) -> Box { - let p = b.ptr as *mut T; - mem::forget(b); - Box::from_raw(p) -} - -fn make_place() -> IntermediateBox { - let layout = Layout::new::(); - - let p = if layout.size() == 0 { - mem::align_of::() as *mut u8 - } else { - unsafe { - Heap.alloc(layout.clone()).unwrap_or_else(|err| { - Heap.oom(err) - }) - } - }; - - IntermediateBox { - ptr: p, - layout, - marker: marker::PhantomData, - } -} - -#[unstable(feature = "placement_in", - reason = "placement box design is still being worked out.", - issue = "27779")] -impl BoxPlace for IntermediateBox { - fn make_place() -> IntermediateBox { - make_place() - } -} - -#[unstable(feature = "placement_in", - reason = "placement box design is still being worked out.", - issue = "27779")] -impl InPlace for IntermediateBox { - type Owner = Box; - unsafe fn finalize(self) -> Box { - finalize(self) - } -} - -#[unstable(feature = "placement_new_protocol", issue = "27779")] -impl Boxed for Box { - type Data = T; - type Place = IntermediateBox; - unsafe fn finalize(b: IntermediateBox) -> Box { - finalize(b) - } -} - -#[unstable(feature = "placement_in", - reason = "placement box design is still being worked out.", - issue = "27779")] -impl Placer for ExchangeHeapSingleton { - type Place = IntermediateBox; - - fn make_place(self) -> IntermediateBox { - make_place() - } -} - -#[unstable(feature = "placement_in", - reason = "placement box design is still being worked out.", - issue = "27779")] -impl Drop for IntermediateBox { - fn drop(&mut self) { - if self.layout.size() > 0 { - unsafe { - Heap.dealloc(self.ptr, self.layout.clone()) - } - } - } -} - impl Box { /// Allocates memory on the heap and then places `x` into it. /// diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index e6a311041f5..2fad3b0bad4 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -76,7 +76,6 @@ #![deny(missing_debug_implementations)] #![cfg_attr(test, allow(deprecated))] // rand -#![cfg_attr(test, feature(placement_in))] #![cfg_attr(not(test), feature(core_float))] #![cfg_attr(not(test), feature(exact_size_is_empty))] #![cfg_attr(not(test), feature(generator_trait))] @@ -108,8 +107,6 @@ #![feature(optin_builtin_traits)] #![feature(pattern)] #![feature(pin)] -#![feature(placement_in_syntax)] -#![feature(placement_new_protocol)] #![feature(ptr_internals)] #![feature(rustc_attrs)] #![feature(slice_get_slice)] @@ -128,8 +125,8 @@ #![feature(pointer_methods)] #![feature(inclusive_range_fields)] -#![cfg_attr(not(test), feature(fn_traits, placement_new_protocol, swap_with_slice, i128))] -#![cfg_attr(test, feature(test, box_heap))] +#![cfg_attr(not(test), feature(fn_traits, swap_with_slice, i128))] +#![cfg_attr(test, feature(test))] // Allow testing this library @@ -159,13 +156,12 @@ pub mod heap; // Need to conditionally define the mod from `boxed.rs` to avoid // duplicating the lang-items when building in test cfg; but also need -// to allow code to have `use boxed::HEAP;` -// and `use boxed::Box;` declarations. +// to allow code to have `use boxed::Box;` declarations. #[cfg(not(test))] pub mod boxed; #[cfg(test)] mod boxed { - pub use std::boxed::{Box, IntermediateBox, HEAP}; + pub use std::boxed::Box; } #[cfg(test)] mod boxed_test; diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs index 097d2e414f5..129b3bc6764 100644 --- a/src/liballoc/linked_list.rs +++ b/src/liballoc/linked_list.rs @@ -28,10 +28,9 @@ use core::hash::{Hasher, Hash}; use core::iter::{FromIterator, FusedIterator}; use core::marker::PhantomData; use core::mem; -use core::ops::{BoxPlace, InPlace, Place, Placer}; -use core::ptr::{self, NonNull}; +use core::ptr::NonNull; -use boxed::{Box, IntermediateBox}; +use boxed::Box; use super::SpecExtend; /// A doubly-linked list with owned nodes. @@ -786,62 +785,6 @@ impl LinkedList { old_len: old_len, } } - - /// Returns a place for insertion at the front of the list. - /// - /// Using this method with placement syntax is equivalent to - /// [`push_front`](#method.push_front), but may be more efficient. - /// - /// # Examples - /// - /// ``` - /// #![feature(collection_placement)] - /// #![feature(placement_in_syntax)] - /// - /// use std::collections::LinkedList; - /// - /// let mut list = LinkedList::new(); - /// list.front_place() <- 2; - /// list.front_place() <- 4; - /// assert!(list.iter().eq(&[4, 2])); - /// ``` - #[unstable(feature = "collection_placement", - reason = "method name and placement protocol are subject to change", - issue = "30172")] - pub fn front_place(&mut self) -> FrontPlace { - FrontPlace { - list: self, - node: IntermediateBox::make_place(), - } - } - - /// Returns a place for insertion at the back of the list. - /// - /// Using this method with placement syntax is equivalent to [`push_back`](#method.push_back), - /// but may be more efficient. - /// - /// # Examples - /// - /// ``` - /// #![feature(collection_placement)] - /// #![feature(placement_in_syntax)] - /// - /// use std::collections::LinkedList; - /// - /// let mut list = LinkedList::new(); - /// list.back_place() <- 2; - /// list.back_place() <- 4; - /// assert!(list.iter().eq(&[2, 4])); - /// ``` - #[unstable(feature = "collection_placement", - reason = "method name and placement protocol are subject to change", - issue = "30172")] - pub fn back_place(&mut self) -> BackPlace { - BackPlace { - list: self, - node: IntermediateBox::make_place(), - } - } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1242,123 +1185,6 @@ impl Hash for LinkedList { } } -unsafe fn finalize(node: IntermediateBox>) -> Box> { - let mut node = node.finalize(); - ptr::write(&mut node.next, None); - ptr::write(&mut node.prev, None); - node -} - -/// A place for insertion at the front of a `LinkedList`. -/// -/// See [`LinkedList::front_place`](struct.LinkedList.html#method.front_place) for details. -#[must_use = "places do nothing unless written to with `<-` syntax"] -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol are subject to change", - issue = "30172")] -pub struct FrontPlace<'a, T: 'a> { - list: &'a mut LinkedList, - node: IntermediateBox>, -} - -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol are subject to change", - issue = "30172")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for FrontPlace<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("FrontPlace") - .field(&self.list) - .finish() - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> Placer for FrontPlace<'a, T> { - type Place = Self; - - fn make_place(self) -> Self { - self - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -unsafe impl<'a, T> Place for FrontPlace<'a, T> { - fn pointer(&mut self) -> *mut T { - unsafe { &mut (*self.node.pointer()).element } - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> InPlace for FrontPlace<'a, T> { - type Owner = (); - - unsafe fn finalize(self) { - let FrontPlace { list, node } = self; - list.push_front_node(finalize(node)); - } -} - -/// A place for insertion at the back of a `LinkedList`. -/// -/// See [`LinkedList::back_place`](struct.LinkedList.html#method.back_place) for details. -#[must_use = "places do nothing unless written to with `<-` syntax"] -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol are subject to change", - issue = "30172")] -pub struct BackPlace<'a, T: 'a> { - list: &'a mut LinkedList, - node: IntermediateBox>, -} - -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol are subject to change", - issue = "30172")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for BackPlace<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("BackPlace") - .field(&self.list) - .finish() - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> Placer for BackPlace<'a, T> { - type Place = Self; - - fn make_place(self) -> Self { - self - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -unsafe impl<'a, T> Place for BackPlace<'a, T> { - fn pointer(&mut self) -> *mut T { - unsafe { &mut (*self.node.pointer()).element } - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> InPlace for BackPlace<'a, T> { - type Owner = (); - - unsafe fn finalize(self) { - let BackPlace { list, node } = self; - list.push_back_node(finalize(node)); - } -} - // Ensure that `LinkedList` and its read-only iterators are covariant in their type parameters. #[allow(dead_code)] fn assert_covariance() { diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs index 5c979d82e55..8494463463c 100644 --- a/src/liballoc/tests/binary_heap.rs +++ b/src/liballoc/tests/binary_heap.rs @@ -278,26 +278,6 @@ fn test_extend_specialization() { assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]); } -#[test] -fn test_placement() { - let mut a = BinaryHeap::new(); - &mut a <- 2; - &mut a <- 4; - &mut a <- 3; - assert_eq!(a.peek(), Some(&4)); - assert_eq!(a.len(), 3); - &mut a <- 1; - assert_eq!(a.into_sorted_vec(), vec![1, 2, 3, 4]); -} - -#[test] -fn test_placement_panic() { - let mut heap = BinaryHeap::from(vec![1, 2, 3]); - fn mkpanic() -> usize { panic!() } - let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { &mut heap <- mkpanic(); })); - assert_eq!(heap.len(), 3); -} - #[allow(dead_code)] fn assert_covariance() { fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 0a7e9a8be94..1a49fb9964a 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -15,13 +15,11 @@ #![feature(attr_literals)] #![feature(box_syntax)] #![cfg_attr(stage0, feature(inclusive_range_syntax))] -#![feature(collection_placement)] #![feature(const_fn)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] #![feature(iterator_step_by)] #![feature(pattern)] -#![feature(placement_in_syntax)] #![feature(rand)] #![feature(slice_sort_by_cached_key)] #![feature(splice)] diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 3c17a401bba..2895c53009d 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -10,7 +10,7 @@ use std::borrow::Cow; use std::mem::size_of; -use std::{usize, isize, panic}; +use std::{usize, isize}; use std::vec::{Drain, IntoIter}; use std::collections::CollectionAllocErr::*; @@ -753,24 +753,6 @@ fn assert_covariance() { } } -#[test] -fn test_placement() { - let mut vec = vec![1]; - assert_eq!(vec.place_back() <- 2, &2); - assert_eq!(vec.len(), 2); - assert_eq!(vec.place_back() <- 3, &3); - assert_eq!(vec.len(), 3); - assert_eq!(&vec, &[1, 2, 3]); -} - -#[test] -fn test_placement_panic() { - let mut vec = vec![1, 2, 3]; - fn mkpanic() -> usize { panic!() } - let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { vec.place_back() <- mkpanic(); })); - assert_eq!(vec.len(), 3); -} - #[test] fn from_into_inner() { let vec = vec![1, 2, 3]; diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index fc1a0b624a5..75d3f01f8b6 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -1004,28 +1004,6 @@ fn test_is_empty() { assert!(v.into_iter().is_empty()); } -#[test] -fn test_placement_in() { - let mut buf: VecDeque = VecDeque::new(); - buf.place_back() <- 1; - buf.place_back() <- 2; - assert_eq!(buf, [1,2]); - - buf.place_front() <- 3; - buf.place_front() <- 4; - assert_eq!(buf, [4,3,1,2]); - - { - let ptr_head = buf.place_front() <- 5; - assert_eq!(*ptr_head, 5); - } - { - let ptr_tail = buf.place_back() <- 6; - assert_eq!(*ptr_tail, 6); - } - assert_eq!(buf, [5,4,3,1,2,6]); -} - #[test] fn test_reserve_exact_2() { // This is all the same as test_reserve diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 2eedb964f88..47c92028b14 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -76,7 +76,7 @@ use core::mem; #[cfg(not(test))] use core::num::Float; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{InPlace, Index, IndexMut, Place, Placer, RangeBounds}; +use core::ops::{Index, IndexMut, RangeBounds}; use core::ops; use core::ptr; use core::ptr::NonNull; @@ -1065,29 +1065,6 @@ impl Vec { } } - /// Returns a place for insertion at the back of the `Vec`. - /// - /// Using this method with placement syntax is equivalent to [`push`](#method.push), - /// but may be more efficient. - /// - /// # Examples - /// - /// ``` - /// #![feature(collection_placement)] - /// #![feature(placement_in_syntax)] - /// - /// let mut vec = vec![1, 2]; - /// vec.place_back() <- 3; - /// vec.place_back() <- 4; - /// assert_eq!(&vec, &[1, 2, 3, 4]); - /// ``` - #[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] - pub fn place_back(&mut self) -> PlaceBack { - PlaceBack { vec: self } - } - /// Removes the last element from a vector and returns it, or [`None`] if it /// is empty. /// @@ -2492,57 +2469,6 @@ impl<'a, T> ExactSizeIterator for Drain<'a, T> { #[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Drain<'a, T> {} -/// A place for insertion at the back of a `Vec`. -/// -/// See [`Vec::place_back`](struct.Vec.html#method.place_back) for details. -#[must_use = "places do nothing unless written to with `<-` syntax"] -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol are subject to change", - issue = "30172")] -#[derive(Debug)] -pub struct PlaceBack<'a, T: 'a> { - vec: &'a mut Vec, -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> Placer for PlaceBack<'a, T> { - type Place = PlaceBack<'a, T>; - - fn make_place(self) -> Self { - // This will panic or abort if we would allocate > isize::MAX bytes - // or if the length increment would overflow for zero-sized types. - if self.vec.len == self.vec.buf.cap() { - self.vec.buf.double(); - } - self - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -unsafe impl<'a, T> Place for PlaceBack<'a, T> { - fn pointer(&mut self) -> *mut T { - unsafe { self.vec.as_mut_ptr().offset(self.vec.len as isize) } - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> InPlace for PlaceBack<'a, T> { - type Owner = &'a mut T; - - unsafe fn finalize(mut self) -> &'a mut T { - let ptr = self.pointer(); - self.vec.len += 1; - &mut *ptr - } -} - - /// A splicing iterator for `Vec`. /// /// This struct is created by the [`splice()`] method on [`Vec`]. See its diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index 94d042a45aa..f28c8e38996 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -22,7 +22,7 @@ use core::fmt; use core::iter::{repeat, FromIterator, FusedIterator}; use core::mem; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{Index, IndexMut, Place, Placer, InPlace, RangeBounds}; +use core::ops::{Index, IndexMut, RangeBounds}; use core::ptr; use core::ptr::NonNull; use core::slice; @@ -1885,56 +1885,6 @@ impl VecDeque { debug_assert!(!self.is_full()); } } - - /// Returns a place for insertion at the back of the `VecDeque`. - /// - /// Using this method with placement syntax is equivalent to [`push_back`](#method.push_back), - /// but may be more efficient. - /// - /// # Examples - /// - /// ``` - /// #![feature(collection_placement)] - /// #![feature(placement_in_syntax)] - /// - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// buf.place_back() <- 3; - /// buf.place_back() <- 4; - /// assert_eq!(&buf, &[3, 4]); - /// ``` - #[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] - pub fn place_back(&mut self) -> PlaceBack { - PlaceBack { vec_deque: self } - } - - /// Returns a place for insertion at the front of the `VecDeque`. - /// - /// Using this method with placement syntax is equivalent to [`push_front`](#method.push_front), - /// but may be more efficient. - /// - /// # Examples - /// - /// ``` - /// #![feature(collection_placement)] - /// #![feature(placement_in_syntax)] - /// - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// buf.place_front() <- 3; - /// buf.place_front() <- 4; - /// assert_eq!(&buf, &[4, 3]); - /// ``` - #[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] - pub fn place_front(&mut self) -> PlaceFront { - PlaceFront { vec_deque: self } - } } impl VecDeque { @@ -2662,98 +2612,6 @@ impl From> for Vec { } } -/// A place for insertion at the back of a `VecDeque`. -/// -/// See [`VecDeque::place_back`](struct.VecDeque.html#method.place_back) for details. -#[must_use = "places do nothing unless written to with `<-` syntax"] -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol are subject to change", - issue = "30172")] -#[derive(Debug)] -pub struct PlaceBack<'a, T: 'a> { - vec_deque: &'a mut VecDeque, -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> Placer for PlaceBack<'a, T> { - type Place = PlaceBack<'a, T>; - - fn make_place(self) -> Self { - self.vec_deque.grow_if_necessary(); - self - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -unsafe impl<'a, T> Place for PlaceBack<'a, T> { - fn pointer(&mut self) -> *mut T { - unsafe { self.vec_deque.ptr().offset(self.vec_deque.head as isize) } - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> InPlace for PlaceBack<'a, T> { - type Owner = &'a mut T; - - unsafe fn finalize(self) -> &'a mut T { - let head = self.vec_deque.head; - self.vec_deque.head = self.vec_deque.wrap_add(head, 1); - &mut *(self.vec_deque.ptr().offset(head as isize)) - } -} - -/// A place for insertion at the front of a `VecDeque`. -/// -/// See [`VecDeque::place_front`](struct.VecDeque.html#method.place_front) for details. -#[must_use = "places do nothing unless written to with `<-` syntax"] -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol are subject to change", - issue = "30172")] -#[derive(Debug)] -pub struct PlaceFront<'a, T: 'a> { - vec_deque: &'a mut VecDeque, -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> Placer for PlaceFront<'a, T> { - type Place = PlaceFront<'a, T>; - - fn make_place(self) -> Self { - self.vec_deque.grow_if_necessary(); - self - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -unsafe impl<'a, T> Place for PlaceFront<'a, T> { - fn pointer(&mut self) -> *mut T { - let tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1); - unsafe { self.vec_deque.ptr().offset(tail as isize) } - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> InPlace for PlaceFront<'a, T> { - type Owner = &'a mut T; - - unsafe fn finalize(self) -> &'a mut T { - self.vec_deque.tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1); - &mut *(self.vec_deque.ptr().offset(self.vec_deque.tail as isize)) - } -} - #[cfg(test)] mod tests { use test; diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index 0b480b618fc..ce4f45762de 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -161,7 +161,6 @@ mod drop; mod function; mod generator; mod index; -mod place; mod range; mod try; mod unsize; @@ -200,8 +199,5 @@ pub use self::try::Try; #[unstable(feature = "generator_trait", issue = "43122")] pub use self::generator::{Generator, GeneratorState}; -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub use self::place::{Place, Placer, InPlace, Boxed, BoxPlace}; - #[unstable(feature = "coerce_unsized", issue = "27732")] pub use self::unsize::CoerceUnsized; diff --git a/src/libcore/ops/place.rs b/src/libcore/ops/place.rs deleted file mode 100644 index b3dcf4e7ee9..00000000000 --- a/src/libcore/ops/place.rs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// Both `PLACE <- EXPR` and `box EXPR` desugar into expressions -/// that allocate an intermediate "place" that holds uninitialized -/// state. The desugaring evaluates EXPR, and writes the result at -/// the address returned by the `pointer` method of this trait. -/// -/// A `Place` can be thought of as a special representation for a -/// hypothetical `&uninit` reference (which Rust cannot currently -/// express directly). That is, it represents a pointer to -/// uninitialized storage. -/// -/// The client is responsible for two steps: First, initializing the -/// payload (it can access its address via `pointer`). Second, -/// converting the agent to an instance of the owning pointer, via the -/// appropriate `finalize` method (see the `InPlace`. -/// -/// If evaluating EXPR fails, then it is up to the destructor for the -/// implementation of Place to clean up any intermediate state -/// (e.g. deallocate box storage, pop a stack, etc). -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub unsafe trait Place { - /// Returns the address where the input value will be written. - /// Note that the data at this address is generally uninitialized, - /// and thus one should use `ptr::write` for initializing it. - /// - /// This function must return a pointer through which a value - /// of type `Data` can be written. - fn pointer(&mut self) -> *mut Data; -} - -/// Interface to implementations of `PLACE <- EXPR`. -/// -/// `PLACE <- EXPR` effectively desugars into: -/// -/// ``` -/// # #![feature(placement_new_protocol, box_heap)] -/// # use std::ops::{Placer, Place, InPlace}; -/// # #[allow(non_snake_case)] -/// # fn main() { -/// # let PLACE = std::boxed::HEAP; -/// # let EXPR = 1; -/// let p = PLACE; -/// let mut place = Placer::make_place(p); -/// let raw_place = Place::pointer(&mut place); -/// let value = EXPR; -/// unsafe { -/// std::ptr::write(raw_place, value); -/// InPlace::finalize(place) -/// } -/// # ; } -/// ``` -/// -/// The type of `PLACE <- EXPR` is derived from the type of `PLACE`; -/// if the type of `PLACE` is `P`, then the final type of the whole -/// expression is `P::Place::Owner` (see the `InPlace` and `Boxed` -/// traits). -/// -/// Values for types implementing this trait usually are transient -/// intermediate values (e.g. the return value of `Vec::emplace_back`) -/// or `Copy`, since the `make_place` method takes `self` by value. -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait Placer { - /// `Place` is the intermediate agent guarding the - /// uninitialized state for `Data`. - type Place: InPlace; - - /// Creates a fresh place from `self`. - fn make_place(self) -> Self::Place; -} - -/// Specialization of `Place` trait supporting `PLACE <- EXPR`. -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait InPlace: Place { - /// `Owner` is the type of the end value of `PLACE <- EXPR` - /// - /// Note that when `PLACE <- EXPR` is solely used for - /// side-effecting an existing data-structure, - /// e.g. `Vec::emplace_back`, then `Owner` need not carry any - /// information at all (e.g. it can be the unit type `()` in that - /// case). - type Owner; - - /// Converts self into the final value, shifting - /// deallocation/cleanup responsibilities (if any remain), over to - /// the returned instance of `Owner` and forgetting self. - unsafe fn finalize(self) -> Self::Owner; -} - -/// Core trait for the `box EXPR` form. -/// -/// `box EXPR` effectively desugars into: -/// -/// ``` -/// # #![feature(placement_new_protocol)] -/// # use std::ops::{BoxPlace, Place, Boxed}; -/// # #[allow(non_snake_case)] -/// # fn main() { -/// # let EXPR = 1; -/// let mut place = BoxPlace::make_place(); -/// let raw_place = Place::pointer(&mut place); -/// let value = EXPR; -/// # let _: Box<_> = -/// unsafe { -/// ::std::ptr::write(raw_place, value); -/// Boxed::finalize(place) -/// } -/// # ; } -/// ``` -/// -/// The type of `box EXPR` is supplied from its surrounding -/// context; in the above expansion, the result type `T` is used -/// to determine which implementation of `Boxed` to use, and that -/// `` in turn dictates determines which -/// implementation of `BoxPlace` to use, namely: -/// `<::Place as BoxPlace>`. -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait Boxed { - /// The kind of data that is stored in this kind of box. - type Data; /* (`Data` unused b/c cannot yet express below bound.) */ - /// The place that will negotiate the storage of the data. - type Place: BoxPlace; - - /// Converts filled place into final owning value, shifting - /// deallocation/cleanup responsibilities (if any remain), over to - /// returned instance of `Self` and forgetting `filled`. - unsafe fn finalize(filled: Self::Place) -> Self; -} - -/// Specialization of `Place` trait supporting `box EXPR`. -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait BoxPlace : Place { - /// Creates a globally fresh place. - fn make_place() -> Self; -} diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 536d682566a..5f9f37094f5 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2911,118 +2911,8 @@ impl<'a> LoweringContext<'a> { fn lower_expr(&mut self, e: &Expr) -> hir::Expr { let kind = match e.node { - // Issue #22181: - // Eventually a desugaring for `box EXPR` - // (similar to the desugaring above for `in PLACE BLOCK`) - // should go here, desugaring - // - // to: - // - // let mut place = BoxPlace::make_place(); - // let raw_place = Place::pointer(&mut place); - // let value = $value; - // unsafe { - // ::std::ptr::write(raw_place, value); - // Boxed::finalize(place) - // } - // - // But for now there are type-inference issues doing that. ExprKind::Box(ref inner) => hir::ExprBox(P(self.lower_expr(inner))), - // Desugar ExprBox: `in (PLACE) EXPR` - ExprKind::InPlace(ref placer, ref value_expr) => { - // to: - // - // let p = PLACE; - // let mut place = Placer::make_place(p); - // let raw_place = Place::pointer(&mut place); - // push_unsafe!({ - // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); - // InPlace::finalize(place) - // }) - let placer_expr = P(self.lower_expr(placer)); - let value_expr = P(self.lower_expr(value_expr)); - - let placer_ident = self.str_to_ident("placer"); - let place_ident = self.str_to_ident("place"); - let p_ptr_ident = self.str_to_ident("p_ptr"); - - let make_place = ["ops", "Placer", "make_place"]; - let place_pointer = ["ops", "Place", "pointer"]; - let move_val_init = ["intrinsics", "move_val_init"]; - let inplace_finalize = ["ops", "InPlace", "finalize"]; - - let unstable_span = - self.allow_internal_unstable(CompilerDesugaringKind::BackArrow, e.span); - let make_call = |this: &mut LoweringContext, p, args| { - let path = P(this.expr_std_path(unstable_span, p, ThinVec::new())); - P(this.expr_call(e.span, path, args)) - }; - - let mk_stmt_let = |this: &mut LoweringContext, bind, expr| { - this.stmt_let(e.span, false, bind, expr) - }; - - let mk_stmt_let_mut = |this: &mut LoweringContext, bind, expr| { - this.stmt_let(e.span, true, bind, expr) - }; - - // let placer = ; - let (s1, placer_binding) = { mk_stmt_let(self, placer_ident, placer_expr) }; - - // let mut place = Placer::make_place(placer); - let (s2, place_binding) = { - let placer = self.expr_ident(e.span, placer_ident, placer_binding); - let call = make_call(self, &make_place, hir_vec![placer]); - mk_stmt_let_mut(self, place_ident, call) - }; - - // let p_ptr = Place::pointer(&mut place); - let (s3, p_ptr_binding) = { - let agent = P(self.expr_ident(e.span, place_ident, place_binding)); - let args = hir_vec![self.expr_mut_addr_of(e.span, agent)]; - let call = make_call(self, &place_pointer, args); - mk_stmt_let(self, p_ptr_ident, call) - }; - - // pop_unsafe!(EXPR)); - let pop_unsafe_expr = { - self.signal_block_expr( - hir_vec![], - value_expr, - e.span, - hir::PopUnsafeBlock(hir::CompilerGenerated), - ThinVec::new(), - ) - }; - - // push_unsafe!({ - // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); - // InPlace::finalize(place) - // }) - let expr = { - let ptr = self.expr_ident(e.span, p_ptr_ident, p_ptr_binding); - let call_move_val_init = hir::StmtSemi( - make_call(self, &move_val_init, hir_vec![ptr, pop_unsafe_expr]), - self.next_id().node_id, - ); - let call_move_val_init = respan(e.span, call_move_val_init); - - let place = self.expr_ident(e.span, place_ident, place_binding); - let call = make_call(self, &inplace_finalize, hir_vec![place]); - P(self.signal_block_expr( - hir_vec![call_move_val_init], - call, - e.span, - hir::PushUnsafeBlock(hir::CompilerGenerated), - ThinVec::new(), - )) - }; - - let block = self.block_all(e.span, hir_vec![s1, s2, s3], Some(expr)); - hir::ExprBlock(P(block)) - } - ExprKind::Array(ref exprs) => { hir::ExprArray(exprs.iter().map(|x| self.lower_expr(x)).collect()) } @@ -4069,29 +3959,6 @@ impl<'a> LoweringContext<'a> { .resolve_str_path(span, self.crate_root, components, is_value) } - fn signal_block_expr( - &mut self, - stmts: hir::HirVec, - expr: P, - span: Span, - rule: hir::BlockCheckMode, - attrs: ThinVec, - ) -> hir::Expr { - let LoweredNodeId { node_id, hir_id } = self.next_id(); - - let block = P(hir::Block { - rules: rule, - span, - id: node_id, - hir_id, - stmts, - expr: Some(expr), - targeted_by_break: false, - recovered: false, - }); - self.expr_block(block, attrs) - } - fn ty_path(&mut self, id: LoweredNodeId, span: Span, qpath: hir::QPath) -> P { let mut id = id; let node = match qpath { diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 0b037964981..425459f448f 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -371,7 +371,6 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat { }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind { - BackArrow, DotFill, QuestionMark }); diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 86f79c553c3..aa93b3098e0 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -301,7 +301,6 @@ impl EarlyLintPass for UnusedParens { Ret(Some(ref value)) => (value, "`return` value", false), Assign(_, ref value) => (value, "assigned value", false), AssignOp(.., ref value) => (value, "assigned value", false), - InPlace(_, ref value) => (value, "emplacement value", false), // either function/method call, or something this lint doesn't care about ref call_or_other => { let args_to_check; diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 09579eaecb2..c50d84c10d8 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -196,15 +196,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let mut values = Vec::with_capacity(used_variants); let tcx = self.hir.tcx(); for (idx, discr) in adt_def.discriminants(tcx).enumerate() { - target_blocks.place_back() <- if variants.contains(idx) { + target_blocks.push(if variants.contains(idx) { values.push(discr.val); - *(targets.place_back() <- self.cfg.start_new_block()) + targets.push(self.cfg.start_new_block()); + *targets.last().unwrap() } else { if otherwise_block.is_none() { otherwise_block = Some(self.cfg.start_new_block()); } otherwise_block.unwrap() - }; + }); } if let Some(otherwise_block) = otherwise_block { targets.push(otherwise_block); diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 7af3a397666..84baa8c5417 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -34,8 +34,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(exhaustive_patterns)] #![feature(range_contains)] #![feature(rustc_diagnostic_macros)] -#![feature(placement_in_syntax)] -#![feature(collection_placement)] #![feature(nonzero)] #![cfg_attr(stage0, feature(underscore_lifetimes))] #![cfg_attr(stage0, feature(never_type))] diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 1f882676f61..ca5858299c5 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -721,16 +721,6 @@ fn main() { ``` "##, -E0066: r##" -Box placement expressions (like C++'s "placement new") do not yet support any -place expression except the exchange heap (i.e. `std::boxed::HEAP`). -Furthermore, the syntax is changing to use `in` instead of `box`. See [RFC 470] -and [RFC 809] for more details. - -[RFC 470]: https://github.com/rust-lang/rfcs/pull/470 -[RFC 809]: https://github.com/rust-lang/rfcs/blob/master/text/0809-box-and-in-for-stdlib.md -"##, - E0067: r##" The left-hand side of a compound assignment expression must be a place expression. A place expression represents a memory location and includes diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 452fa4e471c..e0b48e565d0 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -22,8 +22,7 @@ use fmt::{self, Debug}; use hash::{Hash, Hasher, BuildHasher, SipHasher13}; use iter::{FromIterator, FusedIterator}; use mem::{self, replace}; -use ops::{Deref, Index, InPlace, Place, Placer}; -use ptr; +use ops::{Deref, Index}; use sys; use super::table::{self, Bucket, EmptyBucket, FullBucket, FullBucketMut, RawTable, SafeHash}; @@ -2043,80 +2042,6 @@ impl<'a, K, V> fmt::Debug for Drain<'a, K, V> } } -/// A place for insertion to a `Entry`. -/// -/// See [`HashMap::entry`](struct.HashMap.html#method.entry) for details. -#[must_use = "places do nothing unless written to with `<-` syntax"] -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol is subject to change", - issue = "30172")] -pub struct EntryPlace<'a, K: 'a, V: 'a> { - bucket: FullBucketMut<'a, K, V>, -} - -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol is subject to change", - issue = "30172")] -impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for EntryPlace<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("EntryPlace") - .field("key", self.bucket.read().0) - .field("value", self.bucket.read().1) - .finish() - } -} - -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol is subject to change", - issue = "30172")] -impl<'a, K, V> Drop for EntryPlace<'a, K, V> { - fn drop(&mut self) { - // Inplacement insertion failed. Only key need to drop. - // The value is failed to insert into map. - unsafe { self.bucket.remove_key() }; - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, K, V> Placer for Entry<'a, K, V> { - type Place = EntryPlace<'a, K, V>; - - fn make_place(self) -> EntryPlace<'a, K, V> { - let b = match self { - Occupied(mut o) => { - unsafe { ptr::drop_in_place(o.elem.read_mut().1); } - o.elem - } - Vacant(v) => { - unsafe { v.insert_key() } - } - }; - EntryPlace { bucket: b } - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -unsafe impl<'a, K, V> Place for EntryPlace<'a, K, V> { - fn pointer(&mut self) -> *mut V { - self.bucket.read_mut().1 - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, K, V> InPlace for EntryPlace<'a, K, V> { - type Owner = (); - - unsafe fn finalize(self) { - mem::forget(self); - } -} - impl<'a, K, V> Entry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] /// Ensures a value is in the entry by inserting the default if empty, and returns @@ -2539,26 +2464,6 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { }; b.into_mut_refs().1 } - - // Only used for InPlacement insert. Avoid unnecessary value copy. - // The value remains uninitialized. - unsafe fn insert_key(self) -> FullBucketMut<'a, K, V> { - match self.elem { - NeqElem(mut bucket, disp) => { - if disp >= DISPLACEMENT_THRESHOLD { - bucket.table_mut().set_tag(true); - } - let uninit = mem::uninitialized(); - robin_hood(bucket, disp, self.hash, self.key, uninit) - }, - NoElem(mut bucket, disp) => { - if disp >= DISPLACEMENT_THRESHOLD { - bucket.table_mut().set_tag(true); - } - bucket.put_key(self.hash, self.key) - }, - } - } } #[stable(feature = "rust1", since = "1.0.0")] @@ -2823,7 +2728,6 @@ mod test_map { use super::RandomState; use cell::RefCell; use rand::{thread_rng, Rng}; - use panic; use realstd::collections::CollectionAllocErr::*; use realstd::mem::size_of; use realstd::usize; @@ -3709,59 +3613,6 @@ mod test_map { panic!("Adaptive early resize failed"); } - #[test] - fn test_placement_in() { - let mut map = HashMap::new(); - map.extend((0..10).map(|i| (i, i))); - - map.entry(100) <- 100; - assert_eq!(map[&100], 100); - - map.entry(0) <- 10; - assert_eq!(map[&0], 10); - - assert_eq!(map.len(), 11); - } - - #[test] - fn test_placement_panic() { - let mut map = HashMap::new(); - map.extend((0..10).map(|i| (i, i))); - - fn mkpanic() -> usize { panic!() } - - // modify existing key - // when panic happens, previous key is removed. - let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { map.entry(0) <- mkpanic(); })); - assert_eq!(map.len(), 9); - assert!(!map.contains_key(&0)); - - // add new key - let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { map.entry(100) <- mkpanic(); })); - assert_eq!(map.len(), 9); - assert!(!map.contains_key(&100)); - } - - #[test] - fn test_placement_drop() { - // correctly drop - struct TestV<'a>(&'a mut bool); - impl<'a> Drop for TestV<'a> { - fn drop(&mut self) { - if !*self.0 { panic!("value double drop!"); } // no double drop - *self.0 = false; - } - } - - fn makepanic<'a>() -> TestV<'a> { panic!() } - - let mut can_drop = true; - let mut hm = HashMap::new(); - hm.insert(0, TestV(&mut can_drop)); - let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { hm.entry(0) <- makepanic(); })); - assert_eq!(hm.len(), 0); - } - #[test] fn test_try_reserve() { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index c6861c82a23..fa6053d3f6d 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -486,21 +486,6 @@ impl EmptyBucket table: self.table, } } - - /// Puts given key, remain value uninitialized. - /// It is only used for inplacement insertion. - pub unsafe fn put_key(mut self, hash: SafeHash, key: K) -> FullBucket { - *self.raw.hash() = hash.inspect(); - let pair_ptr = self.raw.pair(); - ptr::write(&mut (*pair_ptr).0, key); - - self.table.borrow_table_mut().size += 1; - - FullBucket { - raw: self.raw, - table: self.table, - } - } } impl>> FullBucket { @@ -576,17 +561,6 @@ impl<'t, K, V> FullBucket> { v) } } - - /// Remove this bucket's `key` from the hashtable. - /// Only used for inplacement insertion. - /// NOTE: `Value` is uninitialized when this function is called, don't try to drop the `Value`. - pub unsafe fn remove_key(&mut self) { - self.table.size -= 1; - - *self.raw.hash() = EMPTY_BUCKET; - let pair_ptr = self.raw.pair(); - ptr::drop_in_place(&mut (*pair_ptr).0); // only drop key - } } // This use of `Put` is misleading and restrictive, but safe and sufficient for our use cases diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 68d3b946d9e..e18e055654b 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -290,7 +290,6 @@ #![feature(panic_internals)] #![feature(panic_unwind)] #![feature(peek)] -#![feature(placement_in_syntax)] #![feature(placement_new_protocol)] #![feature(prelude_import)] #![feature(ptr_internals)] diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c90b0aecfc0..31bb1c88b87 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1011,7 +1011,6 @@ impl Expr { pub fn precedence(&self) -> ExprPrecedence { match self.node { ExprKind::Box(_) => ExprPrecedence::Box, - ExprKind::InPlace(..) => ExprPrecedence::InPlace, ExprKind::Array(_) => ExprPrecedence::Array, ExprKind::Call(..) => ExprPrecedence::Call, ExprKind::MethodCall(..) => ExprPrecedence::MethodCall, @@ -1071,8 +1070,6 @@ pub enum RangeLimits { pub enum ExprKind { /// A `box x` expression. Box(P), - /// First expr is the place; second expr is the value. - InPlace(P, P), /// An array (`[a, b, c, d]`) Array(Vec>), /// A function call diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 463e76e1461..e734a4e3735 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -146,7 +146,6 @@ declare_features! ( (active, rustc_diagnostic_macros, "1.0.0", None, None), (active, rustc_const_unstable, "1.0.0", None, None), (active, box_syntax, "1.0.0", Some(27779), None), - (active, placement_in_syntax, "1.0.0", Some(27779), None), (active, unboxed_closures, "1.0.0", Some(29625), None), (active, fundamental, "1.0.0", Some(29635), None), @@ -1287,9 +1286,6 @@ pub const EXPLAIN_VIS_MATCHER: &'static str = pub const EXPLAIN_LIFETIME_MATCHER: &'static str = ":lifetime fragment specifier is experimental and subject to change"; -pub const EXPLAIN_PLACEMENT_IN: &'static str = - "placement-in expression syntax is experimental and subject to change."; - pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str = "Unsized tuple coercion is not stable enough for use and is subject to change"; @@ -1636,9 +1632,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, type_ascription, e.span, "type ascription is experimental"); } - ast::ExprKind::InPlace(..) => { - gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN); - } ast::ExprKind::Yield(..) => { gate_feature_post!(&self, generators, e.span, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 05a3150c139..e702bf56e7f 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1167,9 +1167,6 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::Box(e) => { ExprKind::Box(folder.fold_expr(e)) } - ExprKind::InPlace(p, e) => { - ExprKind::InPlace(folder.fold_expr(p), folder.fold_expr(e)) - } ExprKind::Array(exprs) => { ExprKind::Array(folder.fold_exprs(exprs)) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f7cdd4ba2b4..f5ab023b30e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2850,17 +2850,6 @@ impl<'a> Parser<'a> { let (span, e) = self.interpolated_or_expr_span(e)?; (lo.to(span), ExprKind::AddrOf(m, e)) } - token::Ident(..) if self.token.is_keyword(keywords::In) => { - self.bump(); - let place = self.parse_expr_res( - Restrictions::NO_STRUCT_LITERAL, - None, - )?; - let blk = self.parse_block()?; - let span = blk.span; - let blk_expr = self.mk_expr(span, ExprKind::Block(blk), ThinVec::new()); - (lo.to(span), ExprKind::InPlace(place, blk_expr)) - } token::Ident(..) if self.token.is_keyword(keywords::Box) => { self.bump(); let e = self.parse_prefix_expr(None); @@ -3023,8 +3012,6 @@ impl<'a> Parser<'a> { } AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()), - AssocOp::Inplace => - self.mk_expr(span, ExprKind::InPlace(lhs, rhs), ThinVec::new()), AssocOp::AssignOp(k) => { let aop = match k { token::Plus => BinOpKind::Add, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ae045fc095a..c3785c10f69 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1877,16 +1877,6 @@ impl<'a> State<'a> { Ok(()) } - fn print_expr_in_place(&mut self, - place: &ast::Expr, - expr: &ast::Expr) -> io::Result<()> { - let prec = AssocOp::Inplace.precedence() as i8; - self.print_expr_maybe_paren(place, prec + 1)?; - self.s.space()?; - self.word_space("<-")?; - self.print_expr_maybe_paren(expr, prec) - } - fn print_expr_vec(&mut self, exprs: &[P], attrs: &[Attribute]) -> io::Result<()> { self.ibox(INDENT_UNIT)?; @@ -2056,9 +2046,6 @@ impl<'a> State<'a> { self.word_space("box")?; self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)?; } - ast::ExprKind::InPlace(ref place, ref expr) => { - self.print_expr_in_place(place, expr)?; - } ast::ExprKind::Array(ref exprs) => { self.print_expr_vec(&exprs[..], attrs)?; } diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs index 86963c4000b..4770273e8c4 100644 --- a/src/libsyntax/util/parser.rs +++ b/src/libsyntax/util/parser.rs @@ -56,8 +56,6 @@ pub enum AssocOp { GreaterEqual, /// `=` Assign, - /// `<-` - Inplace, /// `?=` where ? is one of the BinOpToken AssignOp(BinOpToken), /// `as` @@ -86,7 +84,6 @@ impl AssocOp { use self::AssocOp::*; match *t { Token::BinOpEq(k) => Some(AssignOp(k)), - Token::LArrow => Some(Inplace), Token::Eq => Some(Assign), Token::BinOp(BinOpToken::Star) => Some(Multiply), Token::BinOp(BinOpToken::Slash) => Some(Divide), @@ -156,7 +153,6 @@ impl AssocOp { LAnd => 6, LOr => 5, DotDot | DotDotEq => 4, - Inplace => 3, Assign | AssignOp(_) => 2, } } @@ -166,7 +162,7 @@ impl AssocOp { use self::AssocOp::*; // NOTE: it is a bug to have an operators that has same precedence but different fixities! match *self { - Inplace | Assign | AssignOp(_) => Fixity::Right, + Assign | AssignOp(_) => Fixity::Right, As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | LAnd | LOr | Colon => Fixity::Left, @@ -178,7 +174,7 @@ impl AssocOp { use self::AssocOp::*; match *self { Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true, - Inplace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract | + Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq | Colon => false } @@ -187,7 +183,7 @@ impl AssocOp { pub fn is_assign_like(&self) -> bool { use self::AssocOp::*; match *self { - Assign | AssignOp(_) | Inplace => true, + Assign | AssignOp(_) => true, Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq | Colon => false @@ -215,7 +211,7 @@ impl AssocOp { BitOr => Some(BinOpKind::BitOr), LAnd => Some(BinOpKind::And), LOr => Some(BinOpKind::Or), - Inplace | Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None + Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None } } } @@ -242,7 +238,6 @@ pub enum ExprPrecedence { Binary(BinOpKind), - InPlace, Cast, Type, @@ -310,7 +305,6 @@ impl ExprPrecedence { // Binop-like expr kinds, handled by `AssocOp`. ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8, - ExprPrecedence::InPlace => AssocOp::Inplace.precedence() as i8, ExprPrecedence::Cast => AssocOp::As.precedence() as i8, ExprPrecedence::Type => AssocOp::Colon.precedence() as i8, diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index bbf1fe124f1..d8de78054ab 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -654,10 +654,6 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Box(ref subexpression) => { visitor.visit_expr(subexpression) } - ExprKind::InPlace(ref place, ref subexpression) => { - visitor.visit_expr(place); - visitor.visit_expr(subexpression) - } ExprKind::Array(ref subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 85a2940ec44..aba71bd0468 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -430,7 +430,6 @@ pub enum ExpnFormat { /// The kind of compiler desugaring. #[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum CompilerDesugaringKind { - BackArrow, DotFill, QuestionMark, } @@ -439,7 +438,6 @@ impl CompilerDesugaringKind { pub fn as_symbol(&self) -> Symbol { use CompilerDesugaringKind::*; let s = match *self { - BackArrow => "<-", DotFill => "...", QuestionMark => "?", }; diff --git a/src/test/compile-fail/issue-14084.rs b/src/test/compile-fail/issue-14084.rs deleted file mode 100644 index 446514c8dd4..00000000000 --- a/src/test/compile-fail/issue-14084.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(box_syntax)] -#![feature(placement_in_syntax)] - -fn main() { - () <- 0; - //~^ ERROR: `(): std::ops::Placer<_>` is not satisfied -} diff --git a/src/test/compile-fail/placement-expr-unsafe.rs b/src/test/compile-fail/placement-expr-unsafe.rs deleted file mode 100644 index bf6f4c52f1f..00000000000 --- a/src/test/compile-fail/placement-expr-unsafe.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Check that placement in respects unsafe code checks. - -#![feature(box_heap)] -#![feature(placement_in_syntax)] - -fn main() { - use std::boxed::HEAP; - - let p: *const i32 = &42; - let _ = HEAP <- *p; //~ ERROR requires unsafe - - let p: *const _ = &HEAP; - let _ = *p <- 42; //~ ERROR requires unsafe -} diff --git a/src/test/compile-fail/placement-expr-unstable.rs b/src/test/compile-fail/placement-expr-unstable.rs deleted file mode 100644 index 35695efe1a9..00000000000 --- a/src/test/compile-fail/placement-expr-unstable.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Check that placement in respects unstable code checks. - -#![feature(placement_in_syntax)] - -fn main() { - use std::boxed::HEAP; //~ ERROR use of unstable library feature - - let _ = HEAP <- { //~ ERROR use of unstable library feature - HEAP //~ ERROR use of unstable library feature - }; -} diff --git a/src/test/parse-fail/assoc-oddities-1.rs b/src/test/parse-fail/assoc-oddities-1.rs index 5c0c47de58a..63408b76b15 100644 --- a/src/test/parse-fail/assoc-oddities-1.rs +++ b/src/test/parse-fail/assoc-oddities-1.rs @@ -13,10 +13,9 @@ fn that_odd_parse() { // following lines below parse and must not fail x = if c { a } else { b }(); - x <- if c { a } else { b }[n]; x = if true { 1 } else { 0 } as *mut _; // however this does not parse and probably should fail to retain compat? - // NB: `..` here is arbitrary, failure happens/should happen ∀ops that aren’t `=` or `<-` + // NB: `..` here is arbitrary, failure happens/should happen ∀ops that aren’t `=` // see assoc-oddities-2 and assoc-oddities-3 ..if c { a } else { b }[n]; //~ ERROR expected one of } diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs index 17e6119f968..b34e1852079 100644 --- a/src/test/pretty/stmt_expr_attributes.rs +++ b/src/test/pretty/stmt_expr_attributes.rs @@ -12,7 +12,6 @@ #![feature(custom_attribute)] #![feature(box_syntax)] -#![feature(placement_in_syntax)] #![feature(stmt_expr_attributes)] fn main() { } diff --git a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs index f3f7777d8d4..62cb870c7bb 100644 --- a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs +++ b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs @@ -126,16 +126,6 @@ fn run() { check_expr_attrs("#[attr] box 0", outer); reject_expr_parse("box #![attr] 0"); - check_expr_attrs("#[attr] 0 <- #[attr] 0", none); - check_expr_attrs("#[attr] (0 <- 0)", outer); - reject_expr_parse("0 #[attr] <- 0"); - reject_expr_parse("0 <- #![attr] 0"); - - check_expr_attrs("in #[attr] 0 {#[attr] 0}", none); - check_expr_attrs("#[attr] (in 0 {0})", outer); - reject_expr_parse("in 0 #[attr] {0}"); - reject_expr_parse("in 0 {#![attr] 0}"); - check_expr_attrs("#[attr] [#![attr]]", both); check_expr_attrs("#[attr] [#![attr] 0]", both); check_expr_attrs("#[attr] [#![attr] 0; 0]", both); diff --git a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs index 05fe274c49f..920760cd34a 100644 --- a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs @@ -84,18 +84,11 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P)) { let mut g = |e| f(expr(e)); - for kind in 0 .. 17 { + for kind in 0 .. 16 { match kind { 0 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Box(e))), - 1 => { - // Note that for binary expressions, we explore each side separately. The - // parenthesization decisions for the LHS and RHS should be independent, and this - // way produces `O(n)` results instead of `O(n^2)`. - iter_exprs(depth - 1, &mut |e| g(ExprKind::InPlace(e, make_x()))); - iter_exprs(depth - 1, &mut |e| g(ExprKind::InPlace(make_x(), e))); - }, - 2 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Call(e, vec![]))), - 3 => { + 1 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Call(e, vec![]))), + 2 => { let seg = PathSegment { identifier: Ident::from_str("x"), span: DUMMY_SP, @@ -107,25 +100,25 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P)) { iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall( seg.clone(), vec![make_x(), e]))); }, - 4 => { + 3 => { let op = Spanned { span: DUMMY_SP, node: BinOpKind::Add }; iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x()))); iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e))); }, - 5 => { + 4 => { let op = Spanned { span: DUMMY_SP, node: BinOpKind::Mul }; iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x()))); iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e))); }, - 6 => { + 5 => { let op = Spanned { span: DUMMY_SP, node: BinOpKind::Shl }; iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x()))); iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e))); }, - 7 => { + 6 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Unary(UnOp::Deref, e))); }, - 8 => { + 7 => { let block = P(Block { stmts: Vec::new(), id: DUMMY_NODE_ID, @@ -135,7 +128,7 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P)) { }); iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None))); }, - 9 => { + 8 => { let decl = P(FnDecl { inputs: vec![], output: FunctionRetTy::Default(DUMMY_SP), @@ -148,28 +141,28 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P)) { e, DUMMY_SP))); }, - 10 => { + 9 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(e, make_x()))); iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e))); }, - 11 => { + 10 => { let ident = Spanned { span: DUMMY_SP, node: Ident::from_str("f") }; iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, ident))); }, - 12 => { + 11 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Range( Some(e), Some(make_x()), RangeLimits::HalfOpen))); iter_exprs(depth - 1, &mut |e| g(ExprKind::Range( Some(make_x()), Some(e), RangeLimits::HalfOpen))); }, - 13 => { + 12 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::AddrOf(Mutability::Immutable, e))); }, - 14 => { + 13 => { g(ExprKind::Ret(None)); iter_exprs(depth - 1, &mut |e| g(ExprKind::Ret(Some(e)))); }, - 15 => { + 14 => { let seg = PathSegment { identifier: Ident::from_str("S"), span: DUMMY_SP, @@ -181,7 +174,7 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P)) { }; g(ExprKind::Struct(path, vec![], Some(make_x()))); }, - 16 => { + 15 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e))); }, _ => panic!("bad counter value in iter_exprs"), diff --git a/src/test/run-pass/new-box-syntax.rs b/src/test/run-pass/new-box-syntax.rs index 34687c6ca1d..6598b70b3d5 100644 --- a/src/test/run-pass/new-box-syntax.rs +++ b/src/test/run-pass/new-box-syntax.rs @@ -14,16 +14,11 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ #![allow(dead_code, unused_variables)] -#![feature(box_syntax, box_heap)] -#![feature(placement_in_syntax)] - -// during check-pretty, the expanded code needs to opt into these -// features -#![feature(placement_new_protocol, core_intrinsics)] +#![feature(box_syntax)] // Tests that the new `box` syntax works with unique pointers. -use std::boxed::{Box, HEAP}; +use std::boxed::Box; struct Structure { x: isize, @@ -31,7 +26,6 @@ struct Structure { } pub fn main() { - let x: Box = in HEAP { 2 }; let y: Box = box 2; let b: Box = box (1 + 2); let c = box (3 + 4); diff --git a/src/test/run-pass/placement-in-syntax.rs b/src/test/run-pass/placement-in-syntax.rs deleted file mode 100644 index 7bda9ae2524..00000000000 --- a/src/test/run-pass/placement-in-syntax.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code, unused_variables)] -#![feature(box_heap)] -#![feature(placement_in_syntax)] - -// Tests that the new `in` syntax works with unique pointers. -// -// Compare with new-box-syntax.rs - -use std::boxed::{Box, HEAP}; - -struct Structure { - x: isize, - y: isize, -} - -pub fn main() { - let x: Box = in HEAP { 2 }; - let b: Box = in HEAP { 1 + 2 }; - let c = in HEAP { 3 + 4 }; - - let s: Box = in HEAP { - Structure { - x: 3, - y: 4, - } - }; -} diff --git a/src/test/ui/feature-gate-placement-expr.rs b/src/test/ui/feature-gate-placement-expr.rs deleted file mode 100644 index e3478876763..00000000000 --- a/src/test/ui/feature-gate-placement-expr.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// gate-test-placement_in_syntax - -// Check that `in PLACE { EXPR }` is feature-gated. -// -// See also feature-gate-box-expr.rs -// -// (Note that the two tests are separated since the checks appear to -// be performed at distinct phases, with an abort_if_errors call -// separating them.) - -fn main() { - use std::boxed::HEAP; - - let x = HEAP <- 'c'; //~ ERROR placement-in expression syntax is experimental - println!("x: {}", x); -} diff --git a/src/test/ui/feature-gate-placement-expr.stderr b/src/test/ui/feature-gate-placement-expr.stderr deleted file mode 100644 index b5c091763a1..00000000000 --- a/src/test/ui/feature-gate-placement-expr.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: placement-in expression syntax is experimental and subject to change. (see issue #27779) - --> $DIR/feature-gate-placement-expr.rs:24:13 - | -LL | let x = HEAP <- 'c'; //~ ERROR placement-in expression syntax is experimental - | ^^^^^^^^^^^ - | - = help: add #![feature(placement_in_syntax)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. -- cgit 1.4.1-3-g733a5 From c4c521457b724e147ab37fa17a42010dddc1c564 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Tue, 3 Apr 2018 14:29:28 +0200 Subject: impl Unpin for Pin --- src/libcore/mem.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index b2467c948b4..e3f08926610 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1213,3 +1213,6 @@ impl<'a, T: ?Sized> fmt::Pointer for Pin<'a, T> { #[unstable(feature = "pin", issue = "49150")] impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for Pin<'a, T> {} + +#[unstable(feature = "pin", issue = "49150")] +unsafe impl<'a, T: ?Sized> Unpin for Pin<'a, T> {} -- cgit 1.4.1-3-g733a5 From f5c42655b597d37c2e79ac48e60ef4b796d84e3e Mon Sep 17 00:00:00 2001 From: Vadzim Dambrouski Date: Tue, 3 Apr 2018 15:33:18 +0300 Subject: Fix warning when compilin libcore on 16bit targets. Fixes #49617 --- src/libcore/iter/range.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libcore') diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 72b48b56571..5d57207763e 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -488,6 +488,7 @@ macro_rules! try_from_unbounded { } // unsigned to signed (only positive bound) +#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] macro_rules! try_from_upper_bounded { ($($target:ty),*) => {$( impl PrivateTryFromUsize for $target { -- cgit 1.4.1-3-g733a5 From 93a3e93bf3015df01f9759ab4ca4fd7a6932d8a1 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Tue, 3 Apr 2018 09:11:41 -0400 Subject: tweak fmt::Arguments docs Remove an outdated claim about passing something or other to a function. Also swap the variable names in the example. --- src/libcore/fmt/mod.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 62994ed15cc..d55219d7226 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -401,10 +401,9 @@ impl<'a> Arguments<'a> { /// safely be done, so no constructors are given and the fields are private /// to prevent modification. /// -/// The [`format_args!`] macro will safely create an instance of this structure -/// and pass it to a function or closure, passed as the first argument. The -/// macro validates the format string at compile-time so usage of the [`write`] -/// and [`format`] functions can be safely performed. +/// The [`format_args!`] macro will safely create an instance of this structure. +/// The macro validates the format string at compile-time so usage of the +/// [`write`] and [`format`] functions can be safely performed. /// /// You can use the `Arguments<'a>` that [`format_args!`] returns in `Debug` /// and `Display` contexts as seen below. The example also shows that `Debug` @@ -412,8 +411,8 @@ impl<'a> Arguments<'a> { /// in `format_args!`. /// /// ```rust -/// let display = format!("{:?}", format_args!("{} foo {:?}", 1, 2)); -/// let debug = format!("{}", format_args!("{} foo {:?}", 1, 2)); +/// let debug = format!("{:?}", format_args!("{} foo {:?}", 1, 2)); +/// let display = format!("{}", format_args!("{} foo {:?}", 1, 2)); /// assert_eq!("1 foo 2", display); /// assert_eq!(display, debug); /// ``` -- cgit 1.4.1-3-g733a5 From c7ac32a1c1b35cb2206d9f09549cf93ef8b31e76 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Thu, 5 Apr 2018 00:02:33 -0600 Subject: Remove uses of option_filter feature --- src/libcore/option.rs | 2 -- src/librustc_typeck/lib.rs | 1 - 2 files changed, 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 002fe68ad9b..0dfdabee031 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -628,8 +628,6 @@ impl Option { /// # Examples /// /// ```rust - /// #![feature(option_filter)] - /// /// fn is_even(n: &i32) -> bool { /// n % 2 == 0 /// } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 44ecb32a0bf..b1431f44cda 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -81,7 +81,6 @@ This API is completely unstable and subject to change. #![feature(from_ref)] #![cfg_attr(stage0, feature(match_default_bindings))] #![feature(exhaustive_patterns)] -#![feature(option_filter)] #![feature(quote)] #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] -- cgit 1.4.1-3-g733a5 From 8958815916201421b0a6648c68d7eb31bd3197ee Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 4 Apr 2018 07:16:25 -0700 Subject: Bump the bootstrap compiler to 1.26.0 beta Holy cow that's a lot of `cfg(stage0)` removed and a lot of new stable language features! --- src/bootstrap/lib.rs | 5 ++- src/bootstrap/tool.rs | 1 - src/liballoc/benches/lib.rs | 1 - src/liballoc/lib.rs | 3 +- src/liballoc/tests/lib.rs | 1 - src/libcore/cmp.rs | 5 ++- src/libcore/intrinsics.rs | 7 ---- src/libcore/lib.rs | 5 --- src/libcore/macros.rs | 65 ------------------------------------- src/libcore/panicking.rs | 3 +- src/libcore/tests/lib.rs | 3 -- src/libpanic_unwind/gcc.rs | 3 +- src/libpanic_unwind/lib.rs | 3 +- src/libpanic_unwind/seh64_gnu.rs | 3 +- src/libpanic_unwind/windows.rs | 9 ++--- src/libproc_macro/lib.rs | 1 - src/librustc/lib.rs | 7 ---- src/librustc_apfloat/lib.rs | 4 --- src/librustc_apfloat/tests/ieee.rs | 2 -- src/librustc_borrowck/lib.rs | 1 - src/librustc_const_math/lib.rs | 2 -- src/librustc_data_structures/lib.rs | 4 --- src/librustc_errors/lib.rs | 2 -- src/librustc_incremental/lib.rs | 3 -- src/librustc_lint/lib.rs | 2 -- src/librustc_metadata/lib.rs | 2 -- src/librustc_mir/lib.rs | 6 ---- src/librustc_traits/lib.rs | 2 -- src/librustc_trans/lib.rs | 4 --- src/librustc_trans_utils/lib.rs | 2 -- src/librustc_typeck/lib.rs | 6 ---- src/librustdoc/lib.rs | 1 - src/libserialize/lib.rs | 1 - src/libstd/lib.rs | 4 --- src/libstd/panicking.rs | 6 ++-- src/libsyntax/lib.rs | 2 -- src/libsyntax_pos/lib.rs | 1 - src/libunwind/libunwind.rs | 9 ++--- src/stage0.txt | 2 +- 39 files changed, 18 insertions(+), 175 deletions(-) (limited to 'src/libcore') diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 2eeb2691eae..6c46f3e58cf 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -114,8 +114,7 @@ //! also check out the `src/bootstrap/README.md` file for more information. #![deny(warnings)] -#![feature(conservative_impl_trait, fs_read_write, core_intrinsics)] -#![feature(slice_concat_ext)] +#![feature(core_intrinsics)] #[macro_use] extern crate build_helper; @@ -1149,7 +1148,7 @@ impl Build { fn read(&self, path: &Path) -> String { if self.config.dry_run { return String::new(); } - t!(fs::read_string(path)) + t!(fs::read_to_string(path)) } fn create_dir(&self, dir: &Path) { diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 93b6153fcb2..5fc92611e65 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -12,7 +12,6 @@ use std::fs; use std::env; use std::path::PathBuf; use std::process::{Command, exit}; -use std::slice::SliceConcatExt; use Mode; use Compiler; diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index a43aadfe9a2..4d92fc67b2a 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -10,7 +10,6 @@ #![deny(warnings)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(rand)] #![feature(repr_simd)] #![feature(slice_sort_by_cached_key)] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 6ce2547ef6e..da26e7c852c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -97,8 +97,6 @@ #![feature(fmt_internals)] #![feature(from_ref)] #![feature(fundamental)] -#![cfg_attr(stage0, feature(generic_param_attrs))] -#![cfg_attr(stage0, feature(i128_type))] #![feature(lang_items)] #![feature(needs_allocator)] #![feature(nonzero)] @@ -123,6 +121,7 @@ #![feature(exact_chunks)] #![feature(pointer_methods)] #![feature(inclusive_range_fields)] +#![cfg_attr(stage0, feature(generic_param_attrs))] #![cfg_attr(not(test), feature(fn_traits, swap_with_slice, i128))] #![cfg_attr(test, feature(test))] diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 1a49fb9964a..a173ef10a81 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -14,7 +14,6 @@ #![feature(alloc_system)] #![feature(attr_literals)] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(const_fn)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 67445daa436..3ae9b05b865 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -427,7 +427,7 @@ impl Ord for Reverse { /// } /// } /// ``` -#[cfg_attr(not(stage0), lang = "ord")] +#[lang = "ord"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Ord: Eq + PartialOrd { /// This method returns an `Ordering` between `self` and `other`. @@ -597,8 +597,7 @@ impl PartialOrd for Ordering { /// assert_eq!(x < y, true); /// assert_eq!(x.lt(&y), true); /// ``` -#[cfg_attr(stage0, lang = "ord")] -#[cfg_attr(not(stage0), lang = "partial_ord")] +#[lang = "partial_ord"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialOrd: PartialEq { diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 3b740adc468..83274682250 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1293,7 +1293,6 @@ extern "rust-intrinsic" { pub fn bswap(x: T) -> T; /// Reverses the bits in an integer type `T`. - #[cfg(not(stage0))] pub fn bitreverse(x: T) -> T; /// Performs checked integer addition. @@ -1316,7 +1315,6 @@ extern "rust-intrinsic" { /// Performs an exact division, resulting in undefined behavior where /// `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` - #[cfg(not(stage0))] pub fn exact_div(x: T, y: T) -> T; /// Performs an unchecked division, resulting in undefined behavior @@ -1401,8 +1399,3 @@ extern "rust-intrinsic" { /// Probably will never become stable. pub fn nontemporal_store(ptr: *mut T, val: T); } - -#[cfg(stage0)] -pub unsafe fn exact_div(a: T, b: T) -> T { - unchecked_div(a, b) -} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5a62b8438f9..cf9abb26d3e 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -78,8 +78,6 @@ #![feature(doc_spotlight)] #![feature(fn_must_use)] #![feature(fundamental)] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(intrinsics)] #![feature(iterator_flatten)] #![feature(iterator_repeat_with)] @@ -103,9 +101,6 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] -#![cfg_attr(stage0, allow(unused_attributes))] -#![cfg_attr(stage0, feature(never_type))] - #[prelude_import] #[allow(unused)] use prelude::v1::*; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 8a87bea71e2..90a9cb3379b 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -28,71 +28,6 @@ macro_rules! panic { }); } -/// Ensure that a boolean expression is `true` at runtime. -/// -/// This will invoke the [`panic!`] macro if the provided expression cannot be -/// evaluated to `true` at runtime. -/// -/// # Uses -/// -/// Assertions are always checked in both debug and release builds, and cannot -/// be disabled. See [`debug_assert!`] for assertions that are not enabled in -/// release builds by default. -/// -/// Unsafe code relies on `assert!` to enforce run-time invariants that, if -/// violated could lead to unsafety. -/// -/// Other use-cases of `assert!` include [testing] and enforcing run-time -/// invariants in safe code (whose violation cannot result in unsafety). -/// -/// # Custom Messages -/// -/// This macro has a second form, where a custom panic message can -/// be provided with or without arguments for formatting. See [`std::fmt`] -/// for syntax for this form. -/// -/// [`panic!`]: macro.panic.html -/// [`debug_assert!`]: macro.debug_assert.html -/// [testing]: ../book/second-edition/ch11-01-writing-tests.html#checking-results-with-the-assert-macro -/// [`std::fmt`]: ../std/fmt/index.html -/// -/// # Examples -/// -/// ``` -/// // the panic message for these assertions is the stringified value of the -/// // expression given. -/// assert!(true); -/// -/// fn some_computation() -> bool { true } // a very simple function -/// -/// assert!(some_computation()); -/// -/// // assert with a custom message -/// let x = true; -/// assert!(x, "x wasn't true!"); -/// -/// let a = 3; let b = 27; -/// assert!(a + b == 30, "a = {}, b = {}", a, b); -/// ``` -#[macro_export] -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg(stage0)] -macro_rules! assert { - ($cond:expr) => ( - if !$cond { - panic!(concat!("assertion failed: ", stringify!($cond))) - } - ); - ($cond:expr,) => ( - assert!($cond) - ); - ($cond:expr, $($arg:tt)+) => ( - if !$cond { - panic!($($arg)+) - } - ); -} - /// Asserts that two expressions are equal to each other (using [`PartialEq`]). /// /// On panic, this macro will print the values of the expressions with their diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 94db0baa3f9..6b3dc75af46 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -64,8 +64,7 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) #[allow(improper_ctypes)] extern { #[lang = "panic_fmt"] - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32, col: u32) -> !; } let (file, line, col) = *file_line_col; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index de7211e718c..971759dcdd0 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -23,10 +23,7 @@ #![feature(fmt_internals)] #![feature(hashmap_internals)] #![feature(iterator_step_by)] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(iterator_flatten)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(iterator_repeat_with)] #![feature(nonzero)] #![feature(pattern)] diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index ca2fd561cad..eb6dc5b5488 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -286,8 +286,7 @@ unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) // See docs in the `unwind` module. #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] #[lang = "eh_unwind_resume"] -#[cfg_attr(stage0, unwind)] -#[cfg_attr(not(stage0), unwind(allowed))] +#[unwind(allowed)] unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! { uw::_Unwind_Resume(panic_ctx as *mut uw::_Unwind_Exception); } diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index a5cebc3e4d0..a5c227cb401 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -112,8 +112,7 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8), // Entry point for raising an exception, just delegates to the platform-specific // implementation. #[no_mangle] -#[cfg_attr(stage0, unwind)] -#[cfg_attr(not(stage0), unwind(allowed))] +#[unwind(allowed)] pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 { imp::panic(mem::transmute(raw::TraitObject { data: data as *mut (), diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs index 090cd095380..c3715f96c64 100644 --- a/src/libpanic_unwind/seh64_gnu.rs +++ b/src/libpanic_unwind/seh64_gnu.rs @@ -108,8 +108,7 @@ unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut c::EXCEPTION_RECO } #[lang = "eh_unwind_resume"] -#[cfg_attr(stage0, unwind)] -#[cfg_attr(not(stage0), unwind(allowed))] +#[unwind(allowed)] unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! { let params = [panic_ctx as c::ULONG_PTR]; c::RaiseException(RUST_PANIC, diff --git a/src/libpanic_unwind/windows.rs b/src/libpanic_unwind/windows.rs index 50fba5faee7..5f1dda36a88 100644 --- a/src/libpanic_unwind/windows.rs +++ b/src/libpanic_unwind/windows.rs @@ -79,21 +79,18 @@ pub enum EXCEPTION_DISPOSITION { pub use self::EXCEPTION_DISPOSITION::*; extern "system" { - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn RaiseException(dwExceptionCode: DWORD, dwExceptionFlags: DWORD, nNumberOfArguments: DWORD, lpArguments: *const ULONG_PTR); - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn RtlUnwindEx(TargetFrame: LPVOID, TargetIp: LPVOID, ExceptionRecord: *const EXCEPTION_RECORD, ReturnValue: LPVOID, OriginalContext: *const CONTEXT, HistoryTable: *const UNWIND_HISTORY_TABLE); - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8); } diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 007093981d3..6b2b68b1faa 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -34,7 +34,6 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] -#![cfg_attr(stage0, feature(i128_type))] #![feature(rustc_private)] #![feature(staged_api)] #![feature(lang_items)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index dcad8132c2b..7da664e6d02 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -43,19 +43,14 @@ #![feature(box_patterns)] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(const_fn)] -#![cfg_attr(stage0, feature(copy_closures, clone_closures))] #![feature(core_intrinsics)] #![feature(drain_filter)] #![feature(dyn_trait)] #![feature(entry_or_default)] #![feature(from_ref)] #![feature(fs_read_write)] -#![cfg_attr(stage0, feature(i128_type, i128))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![cfg_attr(windows, feature(libc))] -#![cfg_attr(stage0, feature(match_default_bindings))] #![feature(macro_lifetime_matcher)] #![feature(macro_vis_matcher)] #![feature(exhaustive_patterns)] @@ -68,8 +63,6 @@ #![feature(slice_patterns)] #![feature(specialization)] #![feature(unboxed_closures)] -#![cfg_attr(stage0, feature(underscore_lifetimes))] -#![cfg_attr(stage0, feature(universal_impl_trait))] #![feature(trace_macros)] #![feature(trusted_len)] #![feature(catch_expr)] diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 6f08fcf7025..276f6cd09bf 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -46,10 +46,6 @@ #![deny(warnings)] #![forbid(unsafe_code)] -#![cfg_attr(stage0, feature(slice_patterns))] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(try_from))] - // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] extern crate rustc_cratesio_shim; diff --git a/src/librustc_apfloat/tests/ieee.rs b/src/librustc_apfloat/tests/ieee.rs index 627d79724b2..6e06ea858ef 100644 --- a/src/librustc_apfloat/tests/ieee.rs +++ b/src/librustc_apfloat/tests/ieee.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![cfg_attr(stage0, feature(i128_type))] - #[macro_use] extern crate rustc_apfloat; diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index d54654c6086..6fe2ac2b0ca 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -16,7 +16,6 @@ #![allow(non_camel_case_types)] #![feature(from_ref)] -#![cfg_attr(stage0, feature(match_default_bindings))] #![feature(quote)] #[macro_use] extern crate log; diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index 7177e2818fb..c4c5886d465 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -19,8 +19,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] -#![cfg_attr(stage0, feature(i128_type, i128))] - extern crate rustc_apfloat; extern crate syntax; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 622fb423b51..1e1628936d5 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -26,14 +26,10 @@ #![feature(unboxed_closures)] #![feature(fn_traits)] #![feature(unsize)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] -#![cfg_attr(stage0, feature(i128_type, i128))] #![feature(specialization)] #![feature(optin_builtin_traits)] -#![cfg_attr(stage0, feature(underscore_lifetimes))] #![feature(macro_vis_matcher)] #![feature(allow_internal_unstable)] -#![cfg_attr(stage0, feature(universal_impl_trait))] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 37ae64cef57..c283df6ec0f 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -17,8 +17,6 @@ #![allow(unused_attributes)] #![feature(range_contains)] #![cfg_attr(unix, feature(libc))] -#![cfg_attr(stage0, feature(conservative_impl_trait))] -#![cfg_attr(stage0, feature(i128_type))] #![feature(optin_builtin_traits)] extern crate atty; diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index cad72ff778b..9e72ede309d 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -15,10 +15,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(specialization)] extern crate graphviz; diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index d024adad9d0..c915181213d 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -27,11 +27,9 @@ #![cfg_attr(test, feature(test))] #![feature(box_patterns)] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(macro_vis_matcher)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] -#![cfg_attr(stage0, feature(never_type))] #[macro_use] extern crate syntax; diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 4af5ec9ae08..e89b5a7fc1b 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -14,9 +14,7 @@ #![deny(warnings)] #![feature(box_patterns)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(libc)] #![feature(macro_lifetime_matcher)] #![feature(proc_macro_internals)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 84baa8c5417..8762e7550cd 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -21,22 +21,16 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(box_patterns)] #![feature(box_syntax)] #![feature(catch_expr)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(decl_macro)] #![feature(dyn_trait)] #![feature(fs_read_write)] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(macro_vis_matcher)] -#![cfg_attr(stage0, feature(match_default_bindings))] #![feature(exhaustive_patterns)] #![feature(range_contains)] #![feature(rustc_diagnostic_macros)] #![feature(nonzero)] -#![cfg_attr(stage0, feature(underscore_lifetimes))] -#![cfg_attr(stage0, feature(never_type))] #![feature(inclusive_range_fields)] extern crate arena; diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index 90f368edeec..cfa3b6912f2 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -14,8 +14,6 @@ #![deny(warnings)] #![feature(crate_visibility_modifier)] -#![cfg_attr(stage0, feature(match_default_bindings))] -#![cfg_attr(stage0, feature(underscore_lifetimes))] #[macro_use] extern crate log; diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index e8a1eb3071a..2ce13a2627f 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -24,13 +24,9 @@ #![feature(custom_attribute)] #![feature(fs_read_write)] #![allow(unused_attributes)] -#![cfg_attr(stage0, feature(i128_type, i128))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(libc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] -#![cfg_attr(stage0, feature(slice_patterns))] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(optin_builtin_traits)] #![feature(inclusive_range_fields)] diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index 99de124c6e1..cf47d9b62a9 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -21,10 +21,8 @@ #![feature(box_syntax)] #![feature(custom_attribute)] #![allow(unused_attributes)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] extern crate ar; extern crate flate2; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 44ecb32a0bf..6f71db998bd 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -72,22 +72,16 @@ This API is completely unstable and subject to change. #![allow(non_camel_case_types)] -#![cfg_attr(stage0, feature(advanced_slice_patterns))] #![feature(box_patterns)] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] -#![cfg_attr(stage0, feature(copy_closures, clone_closures))] #![feature(crate_visibility_modifier)] #![feature(from_ref)] -#![cfg_attr(stage0, feature(match_default_bindings))] #![feature(exhaustive_patterns)] #![feature(option_filter)] #![feature(quote)] #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(never_type))] #![feature(dyn_trait)] #[macro_use] extern crate log; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index e31390f59e2..42e87f88fd4 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -20,7 +20,6 @@ #![feature(box_syntax)] #![feature(fs_read_write)] #![feature(set_stdio)] -#![cfg_attr(stage0, feature(slice_patterns))] #![feature(test)] #![feature(unicode)] #![feature(vec_remove_item)] diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index ee952523462..f78eed30694 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -23,7 +23,6 @@ Core encoding and decoding interfaces. #![feature(box_syntax)] #![feature(core_intrinsics)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(specialization)] #![cfg_attr(test, feature(test))] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3f1fec4c317..7da2eeefaaa 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -269,7 +269,6 @@ #![cfg_attr(stage0, feature(generic_param_attrs))] #![feature(hashmap_internals)] #![feature(heap_api)] -#![cfg_attr(stage0, feature(i128_type, i128))] #![feature(int_error_internals)] #![feature(integer_atomics)] #![feature(into_cow)] @@ -321,8 +320,6 @@ #![feature(doc_spotlight)] #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] -#![cfg_attr(stage0, feature(never_type))] -#![cfg_attr(stage0, feature(termination_trait))] #![default_lib_allocator] @@ -355,7 +352,6 @@ use prelude::v1::*; // add a new crate name so we can attach the re-exports to it. #[macro_reexport(assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, unreachable, unimplemented, write, writeln, try)] -#[cfg_attr(stage0, macro_reexport(assert))] extern crate core as __core; #[macro_use] diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 454ac64735c..fba3269204e 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -55,8 +55,7 @@ extern { data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32; - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] fn __rust_start_panic(data: usize, vtable: usize) -> u32; } @@ -316,8 +315,7 @@ pub fn panicking() -> bool { /// Entry point of panic from the libcore crate. #[cfg(not(test))] #[lang = "panic_fmt"] -#[cfg_attr(stage0, unwind)] -#[cfg_attr(not(stage0), unwind(allowed))] +#[unwind(allowed)] pub extern fn rust_begin_panic(msg: fmt::Arguments, file: &'static str, line: u32, diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index dc349c1a3e6..c456dc45d21 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -22,9 +22,7 @@ #![feature(unicode)] #![feature(rustc_diagnostic_macros)] -#![cfg_attr(stage0, feature(match_default_bindings))] #![feature(non_exhaustive)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(const_atomic_usize_new)] #![feature(rustc_attrs)] diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index eb345200f41..b6315900485 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -21,7 +21,6 @@ #![feature(const_fn)] #![feature(custom_attribute)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(optin_builtin_traits)] #![allow(unused_attributes)] #![feature(specialization)] diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index aa73b11fb38..a640a2b7775 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -83,8 +83,7 @@ pub enum _Unwind_Context {} pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception); extern "C" { - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !; pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception); pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void; @@ -221,8 +220,7 @@ if #[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))] { if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { // Not 32-bit iOS extern "C" { - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, trace_argument: *mut c_void) @@ -231,8 +229,7 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { } else { // 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace() extern "C" { - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code; } diff --git a/src/stage0.txt b/src/stage0.txt index 96ec1e6834d..e8db3358cf0 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.x.0` for Cargo where they were released on `date`. -date: 2018-03-18 +date: 2018-04-04 rustc: beta cargo: beta -- cgit 1.4.1-3-g733a5 From 521e41e77d0c9213ff3ed3f2a5e863b600ce2c3a Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Thu, 5 Apr 2018 00:35:09 +0100 Subject: Correct a few stability attributes --- src/libcore/ascii.rs | 4 ++-- src/libcore/iter/range.rs | 2 +- src/libcore/panic.rs | 2 ++ src/libstd/env.rs | 8 ++++---- src/libsyntax/feature_gate.rs | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index 2c4bccebceb..e6b0569281f 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -31,7 +31,7 @@ use iter::FusedIterator; /// documentation for more. /// /// [`escape_default`]: fn.escape_default.html -#[stable(feature = "core_ascii", since = "1.26.0")] +#[stable(feature = "rust1", since = "1.0.0")] pub struct EscapeDefault { range: Range, data: [u8; 4], @@ -99,7 +99,7 @@ pub struct EscapeDefault { /// assert_eq!(b'9', escaped.next().unwrap()); /// assert_eq!(b'd', escaped.next().unwrap()); /// ``` -#[stable(feature = "core_ascii", since = "1.26.0")] +#[stable(feature = "rust1", since = "1.0.0")] pub fn escape_default(c: u8) -> EscapeDefault { let (data, len) = match c { b'\t' => ([b'\\', b't', 0, 0], 2), diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 72b48b56571..bcc0e1f05be 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -200,7 +200,7 @@ macro_rules! range_trusted_len_impl { macro_rules! range_incl_trusted_len_impl { ($($t:ty)*) => ($( - #[stable(feature = "inclusive_range", since = "1.26.0")] + #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for ops::RangeInclusive<$t> { } )*) } diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 4e72eaa57c7..1720c9d8c60 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -120,6 +120,7 @@ impl<'a> PanicInfo<'a> { } } +#[stable(feature = "panic_hook_display", since = "1.26.0")] impl<'a> fmt::Display for PanicInfo<'a> { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("panicked at ")?; @@ -244,6 +245,7 @@ impl<'a> Location<'a> { } } +#[stable(feature = "panic_hook_display", since = "1.26.0")] impl<'a> fmt::Display for Location<'a> { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "{}:{}:{}", self.file, self.line, self.col) diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 320a9f935d4..a103c0bdd59 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -723,10 +723,10 @@ pub fn args_os() -> ArgsOs { ArgsOs { inner: sys::args::args() } } -#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] impl !Send for Args {} -#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] impl !Sync for Args {} #[stable(feature = "env", since = "1.0.0")] @@ -760,10 +760,10 @@ impl fmt::Debug for Args { } } -#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] impl !Send for ArgsOs {} -#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] impl !Sync for ArgsOs {} #[stable(feature = "env", since = "1.0.0")] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e734a4e3735..d1348c89faf 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -483,7 +483,7 @@ declare_features! ( // allow empty structs and enum variants with braces (accepted, braced_empty_structs, "1.8.0", Some(29720), None), // Allows indexing into constant arrays. - (accepted, const_indexing, "1.24.0", Some(29947), None), + (accepted, const_indexing, "1.26.0", Some(29947), None), (accepted, default_type_params, "1.0.0", None, None), (accepted, globs, "1.0.0", None, None), (accepted, if_let, "1.0.0", None, None), -- cgit 1.4.1-3-g733a5 From f86deef5b6059b9a0a76d9f0dafb95ced85f7449 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 6 Apr 2018 15:02:21 +0200 Subject: Add Cell::update --- src/libcore/cell.rs | 24 ++++++++++++++++++++++++ src/libcore/tests/cell.rs | 11 +++++++++++ 2 files changed, 35 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index c8ee166fee3..2ea1b84d034 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -256,6 +256,30 @@ impl Cell { pub fn get(&self) -> T { unsafe{ *self.value.get() } } + + /// Applies a function to the contained value. + /// + /// # Examples + /// + /// ``` + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// c.update(|x| x + 1); + /// + /// assert_eq!(c.get(), 6); + /// ``` + #[inline] + #[unstable(feature = "cell_update", issue = "0")] // TODO: issue + pub fn update(&self, f: F) -> T + where + F: FnOnce(T) -> T, + { + let old = self.get(); + let new = f(old); + self.set(new); + new + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/tests/cell.rs b/src/libcore/tests/cell.rs index cc0ef6a6f17..962fb2f0e02 100644 --- a/src/libcore/tests/cell.rs +++ b/src/libcore/tests/cell.rs @@ -26,6 +26,17 @@ fn smoketest_cell() { assert!(y.get() == (30, 40)); } +#[test] +fn cell_update() { + let x = Cell::new(10); + + assert_eq!(x.update(|x| x + 5), 15); + assert_eq!(x.get(), 15); + + assert_eq!(x.update(|x| x / 3), 5); + assert_eq!(x.get(), 5); +} + #[test] fn cell_has_sensible_show() { let x = Cell::new("foo bar"); -- cgit 1.4.1-3-g733a5 From 9377340ee3f638fcb011afd5a818d6e6b66c2d27 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 6 Apr 2018 15:29:10 +0200 Subject: Change TODO to FIXME --- src/libcore/cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 2ea1b84d034..c0f7183b06c 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -270,7 +270,7 @@ impl Cell { /// assert_eq!(c.get(), 6); /// ``` #[inline] - #[unstable(feature = "cell_update", issue = "0")] // TODO: issue + #[unstable(feature = "cell_update", issue = "0")] // FIXME: issue pub fn update(&self, f: F) -> T where F: FnOnce(T) -> T, -- cgit 1.4.1-3-g733a5 From 587098abf943b08cbed79063b5bad30b4864ffe8 Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Tue, 3 Apr 2018 15:03:41 -0400 Subject: Consistently default operator Rhs/RHS to Self Operator traits seem to be inconsistent regarding the right hand side generic. Most default Rhs/RHS to Self, but a few omit this. This patch modifies them all to default to Self. This should not have any backwards compatibility issues because we are only enabling code that previously wouldn't compile. --- src/libcore/ops/bit.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/bit.rs b/src/libcore/ops/bit.rs index a0ecd6cf75c..8785cbee633 100644 --- a/src/libcore/ops/bit.rs +++ b/src/libcore/ops/bit.rs @@ -370,7 +370,7 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} << {RHS}`", label="no implementation for `{Self} << {RHS}`")] -pub trait Shl { +pub trait Shl { /// The resulting type after applying the `<<` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; @@ -472,7 +472,7 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} >> {RHS}`", label="no implementation for `{Self} >> {RHS}`")] -pub trait Shr { +pub trait Shr { /// The resulting type after applying the `>>` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; @@ -728,7 +728,7 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} <<= {Rhs}`", label="no implementation for `{Self} <<= {Rhs}`")] -pub trait ShlAssign { +pub trait ShlAssign { /// Performs the `<<=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] fn shl_assign(&mut self, rhs: Rhs); -- cgit 1.4.1-3-g733a5 From 5dcce519469690d09704b82d53417b67915adb94 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 6 Apr 2018 22:45:31 +0200 Subject: Fix the failing tests --- src/libcore/cell.rs | 2 ++ src/libcore/tests/lib.rs | 1 + 2 files changed, 3 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index c0f7183b06c..e4a52d9c4a4 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -262,6 +262,8 @@ impl Cell { /// # Examples /// /// ``` + /// #![feature(cell_update)] + /// /// use std::cell::Cell; /// /// let c = Cell::new(5); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index de7211e718c..13c53f47b69 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -12,6 +12,7 @@ #![feature(ascii_ctype)] #![feature(box_syntax)] +#![feature(cell_update)] #![feature(core_float)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] -- cgit 1.4.1-3-g733a5 From 8b8091d370fa31844d6ed55f4ccdd32e5dbd20f9 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 6 Apr 2018 00:34:45 -0700 Subject: Rewrite docs for `std::ptr` - Add links to the GNU libc docs for `memmove`, `memcpy`, and `memset`, as well as internally linking to other functions in `std::ptr` - List sources of UB for all functions. - Add example to `ptr::drop_in_place` and compares it to `ptr::read`. - Add examples which more closely mirror real world uses for the functions in `std::ptr`. Also, move the reimplementation of `mem::swap` to the examples of `ptr::read` and use a more interesting example for `copy_nonoverlapping`. - Change module level description --- src/libcore/intrinsics.rs | 177 +++++++++++++++---- src/libcore/ptr.rs | 421 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 496 insertions(+), 102 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 83274682250..d6bd2b86855 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -959,59 +959,134 @@ extern "rust-intrinsic" { /// value is not necessarily valid to be used to actually access memory. pub fn arith_offset(dst: *const T, offset: isize) -> *const T; - /// Copies `count * size_of` bytes from `src` to `dst`. The source - /// and destination may *not* overlap. + /// Copies `count * size_of::()` bytes from `src` to `dst`. The source + /// and destination must *not* overlap. /// - /// `copy_nonoverlapping` is semantically equivalent to C's `memcpy`. + /// For regions of memory which might overlap, use [`copy`] instead. + /// + /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`]. + /// + /// [`copy`]: ./fn.copy.html + /// [`memcpy`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memcpy /// /// # Safety /// - /// Beyond requiring that the program must be allowed to access both regions - /// of memory, it is Undefined Behavior for source and destination to - /// overlap. Care must also be taken with the ownership of `src` and - /// `dst`. This method semantically moves the values of `src` into `dst`. - /// However it does not drop the contents of `dst`, or prevent the contents - /// of `src` from being dropped or used. + /// `copy_nonoverlapping` is unsafe because it dereferences a raw pointer. + /// The caller must ensure that `src` points to a valid sequence of type + /// `T`. + /// + /// # [Undefined Behavior] + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * The region of memory which begins at `src` and has a length of + /// `count * size_of::()` bytes must be *both* valid and initialized. + /// + /// * The region of memory which begins at `dst` and has a length of + /// `count * size_of::()` bytes must be valid (but may or may not be + /// initialized). + /// + /// * `src` must be properly aligned. + /// + /// * `dst` must be properly aligned. + /// + /// * The two regions of memory must *not* overlap. + /// + /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy), only the region at `src` *or* the + /// region at `dst` can be used or dropped after calling + /// `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise copies of + /// `T`, regardless of whether `T: Copy`, which can result in undefined + /// behavior if both copies are used. + /// + /// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// - /// A safe swap function: + /// Manually implement [`Vec::append`]: /// /// ``` - /// use std::mem; /// use std::ptr; /// - /// # #[allow(dead_code)] - /// fn swap(x: &mut T, y: &mut T) { + /// /// Moves all the elements of `src` into `dst`, leaving `src` empty. + /// fn append(dst: &mut Vec, src: &mut Vec) { + /// let src_len = src.len(); + /// let dst_len = dst.len(); + /// + /// // Ensure that `dst` has enough capacity to hold all of `src`. + /// dst.reserve(src_len); + /// /// unsafe { - /// // Give ourselves some scratch space to work with - /// let mut t: T = mem::uninitialized(); + /// // The call to offset is always safe because `Vec` will never + /// // allocate more than `isize::MAX` bytes. + /// let dst = dst.as_mut_ptr().offset(dst_len as isize); + /// let src = src.as_ptr(); + /// + /// // The two regions cannot overlap becuase mutable references do + /// // not alias, and two different vectors cannot own the same + /// // memory. + /// ptr::copy_nonoverlapping(src, dst, src_len); + /// } /// - /// // Perform the swap, `&mut` pointers never alias - /// ptr::copy_nonoverlapping(x, &mut t, 1); - /// ptr::copy_nonoverlapping(y, x, 1); - /// ptr::copy_nonoverlapping(&t, y, 1); + /// unsafe { + /// // Truncate `src` without dropping its contents. + /// src.set_len(0); /// - /// // y and t now point to the same thing, but we need to completely forget `t` - /// // because it's no longer relevant. - /// mem::forget(t); + /// // Notify `dst` that it now holds the contents of `src`. + /// dst.set_len(dst_len + src_len); /// } /// } + /// + /// let mut a = vec!['r']; + /// let mut b = vec!['u', 's', 't']; + /// + /// append(&mut a, &mut b); + /// + /// assert_eq!(a, &['r', 'u', 's', 't']); + /// assert!(b.is_empty()); /// ``` + /// + /// [`Vec::append()`]: ../vec/struct.Vec.html#method.append #[stable(feature = "rust1", since = "1.0.0")] pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); - /// Copies `count * size_of` bytes from `src` to `dst`. The source + /// Copies `count * size_of::()` bytes from `src` to `dst`. The source /// and destination may overlap. /// - /// `copy` is semantically equivalent to C's `memmove`. + /// If the source and destination will *never* overlap, + /// [`copy_nonoverlapping`] can be used instead. + /// + /// `copy` is semantically equivalent to C's [`memmove`]. + /// + /// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html + /// [`memmove`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memmove /// /// # Safety /// - /// Care must be taken with the ownership of `src` and `dst`. - /// This method semantically moves the values of `src` into `dst`. - /// However it does not drop the contents of `dst`, or prevent the contents of `src` - /// from being dropped or used. + /// `copy` is unsafe because it dereferences a raw pointer. The caller must + /// ensure that `src` points to a valid sequence of type `T`. + /// + /// # [Undefined Behavior] + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * The region of memory which begins at `src` and has a length of + /// `count * size_of::()` bytes must be *both* valid and initialized. + /// + /// * The region of memory which begins at `dst` and has a length of + /// `count * size_of::()` bytes must be valid (but may or may not be + /// initialized). + /// + /// * `src` must be properly aligned. + /// + /// * `dst` must be properly aligned. + /// + /// Additionally, if `T` is not [`Copy`], only the region at `src` *or* the + /// region at `dst` can be used or dropped after calling `copy`. `copy` + /// creates bitwise copies of `T`, regardless of whether `T: Copy`, which + /// can result in undefined behavior if both copies are used. + /// + /// [`Copy`]: ../marker/trait.Copy.html + /// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -1028,15 +1103,39 @@ extern "rust-intrinsic" { /// dst /// } /// ``` - /// #[stable(feature = "rust1", since = "1.0.0")] pub fn copy(src: *const T, dst: *mut T, count: usize); - /// Invokes memset on the specified pointer, setting `count * size_of::()` - /// bytes of memory starting at `dst` to `val`. + /// Sets `count * size_of::()` bytes of memory starting at `dst` to + /// `val`. + /// + /// `write_bytes` is semantically equivalent to C's [`memset`]. + /// + /// [`memset`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memset + /// + /// # Safety + /// + /// `write_bytes` is unsafe because it dereferences a raw pointer. The + /// caller must ensure that the poiinter points to a valid value of type `T`. + /// + /// # [Undefined Behavior] + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * The region of memory which begins at `dst` and has a length of + /// `count` bytes must be valid. + /// + /// * `dst` must be properly aligned. + /// + /// Additionally, the caller must ensure that writing `count` bytes to the + /// given region of memory results in a valid value of `T`. Creating an + /// invalid value of `T` can result in undefined behavior. An example is + /// provided below. /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::ptr; /// @@ -1047,6 +1146,22 @@ extern "rust-intrinsic" { /// } /// assert_eq!(vec, [b'a', b'a', 0, 0]); /// ``` + /// + /// Creating an invalid value: + /// + /// ```ignore + /// use std::{mem, ptr}; + /// + /// let mut v = Box::new(0i32); + /// + /// unsafe { + /// // Leaks the previously held value by overwriting the `Box` with + /// // a null pointer. + /// ptr::write_bytes(&mut v, 0, mem::size_of::>()); + /// } + /// + /// // At this point, using or dropping `v` results in undefined behavior. + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn write_bytes(dst: *mut T, val: u8, count: usize); diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 5a54de06b5e..98d5030477b 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -10,7 +10,7 @@ // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory -//! Raw, unsafe pointers, `*const T`, and `*mut T`. +//! Manually manage memory through raw, unsafe pointers. //! //! *[See also the pointer primitive types](../../std/primitive.pointer.html).* @@ -38,21 +38,68 @@ pub use intrinsics::write_bytes; /// Executes the destructor (if any) of the pointed-to value. /// -/// This has two use cases: +/// This is semantically equivalent to calling [`ptr::read`] and discarding +/// the result, but has the following advantages: /// /// * It is *required* to use `drop_in_place` to drop unsized types like /// trait objects, because they can't be read out onto the stack and /// dropped normally. /// -/// * It is friendlier to the optimizer to do this over `ptr::read` when +/// * It is friendlier to the optimizer to do this over [`ptr::read`] when /// dropping manually allocated memory (e.g. when writing Box/Rc/Vec), /// as the compiler doesn't need to prove that it's sound to elide the /// copy. /// +/// [`ptr::read`]: ./fn.read.html +/// /// # Safety /// -/// This has all the same safety problems as `ptr::read` with respect to -/// invalid pointers, types, and double drops. +/// `drop_in_place` is unsafe because it dereferences a raw pointer. The caller +/// must ensure that the pointer points to a valid value of type `T`. +/// +/// # [Undefined Behavior] +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `to_drop` must point to valid memory. +/// +/// * `to_drop` must be properly aligned. +/// +/// Additionally, if `T` is not [`Copy`], using the pointed-to value after +/// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop = +/// foo` counts as a use because it will cause the the value to be dropped +/// again. [`write`] can be used to overwrite data without causing it to be +/// dropped. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`write`]: ./fn.write.html +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html +/// +/// # Examples +/// +/// Manually remove the last item from a vector: +/// +/// ``` +/// use std::ptr; +/// use std::rc::Rc; +/// +/// let last = Rc::new(1); +/// let weak = Rc::downgrade(&last); +/// +/// let mut v = vec![Rc::new(0), last]; +/// +/// unsafe { +/// // Without a call `drop_in_place`, the last item would never be dropped, +/// // and the memory it manages would be leaked. +/// ptr::drop_in_place(&mut v[1]); +/// v.set_len(1); +/// } +/// +/// assert_eq!(v, &[0.into()]); +/// +/// // Ensure that the last item was dropped. +/// assert!(weak.upgrade().is_none()); +/// ``` #[stable(feature = "drop_in_place", since = "1.8.0")] #[lang = "drop_in_place"] #[allow(unconditional_recursion)] @@ -93,17 +140,32 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// Swaps the values at two mutable locations of the same type, without /// deinitializing either. /// -/// The values pointed at by `x` and `y` may overlap, unlike `mem::swap` which -/// is otherwise equivalent. If the values do overlap, then the overlapping -/// region of memory from `x` will be used. This is demonstrated in the -/// examples section below. +/// But for the following two exceptions, this function is semantically +/// equivalent to [`mem::swap`]: +/// +/// * It operates on raw pointers instead of references. When references are +/// available, [`mem::swap`] should be preferred. +/// +/// * The two pointed-to values may overlap. If the values do overlap, then the +/// overlapping region of memory from `x` will be used. This is demonstrated +/// in the examples below. +/// +/// [`mem::swap`]: ../mem/fn.swap.html /// /// # Safety /// -/// This function copies the memory through the raw pointers passed to it -/// as arguments. +/// `swap` is unsafe because it dereferences a raw pointer. The caller must +/// ensure that both pointers point to valid values of type `T`. +/// +/// # [Undefined Behavior] +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `x` and `y` must point to valid, initialized memory. /// -/// Ensure that these pointers are valid before calling `swap`. +/// * `x` and `y` must be properly aligned. +/// +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -241,13 +303,46 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { } } -/// Replaces the value at `dest` with `src`, returning the old -/// value, without dropping either. +/// Replaces the value at `dest` with `src`, returning the old value, without +/// dropping either. +/// +/// This function is semantically equivalent to [`mem::replace`] except that it +/// operates on raw pointers instead of references. When references are +/// available, [`mem::replace`] should be preferred. /// /// # Safety /// -/// This is only unsafe because it accepts a raw pointer. -/// Otherwise, this operation is identical to `mem::replace`. +/// `replace` is unsafe because it dereferences a raw pointer. The caller +/// must ensure that the pointer points to a valid value of type `T`. +/// +/// [`mem::replace`]: ../mem/fn.replace.html +/// +/// # [Undefined Behavior] +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `dest` must point to valid, initialized memory. +/// +/// * `dest` must be properly aligned. +/// +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html +/// +/// # Examples +/// +/// ``` +/// use std::ptr; +/// +/// let mut rust = vec!['b', 'u', 's', 't']; +/// +/// // `mem::replace` would have the same effect without requiring the unsafe +/// // block. +/// let b = unsafe { +/// ptr::replace(&mut a[0], 'r') +/// }; +/// +/// assert_eq!(b, 'b'); +/// assert_eq!(rust, &['r', 'u', 's', 't']); +/// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn replace(dest: *mut T, mut src: T) -> T { @@ -260,14 +355,29 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// /// # Safety /// -/// Beyond accepting a raw pointer, this is unsafe because it semantically -/// moves the value out of `src` without preventing further usage of `src`. -/// If `T` is not `Copy`, then care must be taken to ensure that the value at -/// `src` is not used before the data is overwritten again (e.g. with `write`, -/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use -/// because it will attempt to drop the value previously at `*src`. +/// `read` is unsafe because it dereferences a raw pointer. The caller +/// must ensure that the pointer points to a valid value of type `T`. +/// +/// # [Undefined Behavior] /// -/// The pointer must be aligned; use `read_unaligned` if that is not the case. +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must point to valid, initialized memory. +/// +/// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the +/// case. +/// +/// Additionally, if `T` is not [`Copy`], only the returned value *or* the +/// pointed-to value can be used or dropped after calling `read`. `read` creates +/// a bitwise copy of `T`, regardless of whether `T: Copy`, which can result +/// in undefined behavior if both copies are used. Note that `*src = foo` counts +/// as a use because it will attempt to drop the value previously at `*src`. +/// [`write`] can be used to overwrite data without causing it to be dropped. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`read_unaligned`]: ./fn.read_unaligned.html +/// [`write`]: ./fn.write.html +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -281,6 +391,44 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// assert_eq!(std::ptr::read(y), 12); /// } /// ``` +/// +/// Manually implement [`mem::swap`]: +/// +/// ``` +/// use std::ptr; +/// +/// fn swap(a: &mut T, b: &mut T) { +/// unsafe { +/// // Create a bitwise copy of the value at `a` in `tmp`. +/// let tmp = ptr::read(a); +/// +/// // Exiting at this point (either by explicitly returning or by +/// // calling a function which panics) would cause the value in `tmp` to +/// // be dropped while the same value is still referenced by `a`. This +/// // could trigger undefined behavior if `T` is not `Copy`. +/// +/// // Create a bitwise copy of the value at `b` in `a`. +/// // This is safe because mutable references cannot alias. +/// ptr::copy_nonoverlapping(b, a, 1); +/// +/// // As above, exiting here could trigger undefined behavior because +/// // the same value is referenced by `a` and `b`. +/// +/// // Move `tmp` into `b`. +/// ptr::write(b, tmp); +/// } +/// } +/// +/// let mut foo = "foo".to_owned(); +/// let mut bar = "bar".to_owned(); +/// +/// swap(&mut foo, &mut bar); +/// +/// assert_eq!(foo, "bar"); +/// assert_eq!(bar, "foo"); +/// ``` +/// +/// [`mem::swap`]: ../mem/fn.swap.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn read(src: *const T) -> T { @@ -292,28 +440,66 @@ pub unsafe fn read(src: *const T) -> T { /// Reads the value from `src` without moving it. This leaves the /// memory in `src` unchanged. /// -/// Unlike `read`, the pointer may be unaligned. +/// Unlike [`read`], `read_unaligned` works with unaligned pointers. /// -/// # Safety +/// [`read`]: ./fn.read.html +/// +/// `read_unaligned` is unsafe because it dereferences a raw pointer. The caller +/// must ensure that the pointer points to a valid value of type `T`. +/// +/// # [Undefined Behavior] +/// +/// Behavior is undefined if any of the following conditions are violated: /// -/// Beyond accepting a raw pointer, this is unsafe because it semantically -/// moves the value out of `src` without preventing further usage of `src`. -/// If `T` is not `Copy`, then care must be taken to ensure that the value at -/// `src` is not used before the data is overwritten again (e.g. with `write`, -/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use -/// because it will attempt to drop the value previously at `*src`. +/// * `src` must point to valid, initialized memory. +/// +/// Additionally, if `T` is not [`Copy`], only the returned value *or* the +/// pointed-to value can be used or dropped after calling `read_unaligned`. +/// `read_unaligned` creates a bitwise copy of `T`, regardless of whether `T: +/// Copy`, and this can result in undefined behavior if both copies are used. +/// Note that `*src = foo` counts as a use because it will attempt to drop the +/// value previously at `*src`. [`write_unaligned`] can be used to overwrite +/// data without causing it to be dropped. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`write_unaligned`]: ./fn.write_unaligned.html +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// -/// Basic usage: +/// Access members of a packed struct by reference: /// /// ``` -/// let x = 12; -/// let y = &x as *const i32; +/// use std::ptr; /// -/// unsafe { -/// assert_eq!(std::ptr::read_unaligned(y), 12); +/// #[repr(packed, C)] +/// #[derive(Default)] +/// struct Packed { +/// _padding: u8, +/// unaligned: u32, /// } +/// +/// let x = Packed { +/// _padding: 0x00, +/// unaligned: 0x01020304, +/// }; +/// +/// let v = unsafe { +/// // Take a reference to a 32-bit integer which is not aligned. +/// let unaligned = &x.unaligned; +/// +/// // Dereferencing normally will emit an unaligned load instruction, +/// // causing undefined behavior. +/// // let v = *unaligned; // ERROR +/// +/// // Instead, use `read_unaligned` to read improperly aligned values. +/// let v = ptr::read_unaligned(unaligned); +/// +/// v +/// }; +/// +/// // Accessing unaligned values directly is safe. +/// assert!(x.unaligned == v); /// ``` #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] @@ -328,11 +514,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// Overwrites a memory location with the given value without reading or /// dropping the old value. /// -/// # Safety -/// -/// This operation is marked unsafe because it accepts a raw pointer. -/// -/// It does not drop the contents of `dst`. This is safe, but it could leak +/// `write` does not drop the contents of `dst`. This is safe, but it could leak /// allocations or resources, so care must be taken not to overwrite an object /// that should be dropped. /// @@ -340,9 +522,26 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// location pointed to by `dst`. /// /// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been `read` from. +/// memory that has previously been [`read`] from. +/// +/// [`read`]: ./fn.read.html +/// +/// # Safety +/// +/// `write` is unsafe because it dereferences a raw pointer. +/// +/// # [Undefined Behavior] +/// +/// `write` can trigger undefined behavior if any of the following conditions +/// are violated: /// -/// The pointer must be aligned; use `write_unaligned` if that is not the case. +/// * `dst` must point to valid memory. +/// +/// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the +/// case. +/// +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html +/// [`write_unaligned`]: ./fn.write_unaligned.html /// /// # Examples /// @@ -358,6 +557,30 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// assert_eq!(std::ptr::read(y), 12); /// } /// ``` +/// +/// Manually implement [`mem::swap`]: +/// +/// ``` +/// use std::ptr; +/// +/// fn swap(a: &mut T, b: &mut T) { +/// unsafe { +/// let tmp = ptr::read(a); +/// ptr::copy_nonoverlapping(b, a, 1); +/// ptr::write(b, tmp); +/// } +/// } +/// +/// let mut foo = "foo".to_owned(); +/// let mut bar = "bar".to_owned(); +/// +/// swap(&mut foo, &mut bar); +/// +/// assert_eq!(foo, "bar"); +/// assert_eq!(bar, "foo"); +/// ``` +/// +/// [`mem::swap`]: ../mem/fn.swap.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn write(dst: *mut T, src: T) { @@ -367,36 +590,65 @@ pub unsafe fn write(dst: *mut T, src: T) { /// Overwrites a memory location with the given value without reading or /// dropping the old value. /// -/// Unlike `write`, the pointer may be unaligned. +/// Unlike [`write`], the pointer may be unaligned. /// -/// # Safety -/// -/// This operation is marked unsafe because it accepts a raw pointer. -/// -/// It does not drop the contents of `dst`. This is safe, but it could leak -/// allocations or resources, so care must be taken not to overwrite an object -/// that should be dropped. +/// `write_unaligned` does not drop the contents of `dst`. This is safe, but it +/// could leak allocations or resources, so care must be taken not to overwrite +/// an object that should be dropped. /// /// Additionally, it does not drop `src`. Semantically, `src` is moved into the /// location pointed to by `dst`. /// /// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been `read` from. +/// memory that has previously been [`read`] from. +/// +/// [`write`]: ./fn.write.html +/// [`read_unaligned`]: ./fn.read_unaligned.html +/// +/// # Safety +/// +/// `write_unaligned` is unsafe because it dereferences a raw pointer. +/// +/// # [Undefined Behavior] +/// +/// `write_unaligned` can trigger undefined behavior if any of the following +/// conditions are violated: +/// +/// * `dst` must point to valid memory. +/// +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// -/// Basic usage: +/// Access fields in a packed struct: /// /// ``` -/// let mut x = 0; -/// let y = &mut x as *mut i32; -/// let z = 12; +/// use std::{mem, ptr}; +/// +/// #[repr(packed, C)] +/// #[derive(Default)] +/// struct Packed { +/// _padding: u8, +/// unaligned: u32, +/// } +/// +/// let v = 0x01020304; +/// let mut x: Packed = unsafe { mem::zeroed() }; /// /// unsafe { -/// std::ptr::write_unaligned(y, z); -/// assert_eq!(std::ptr::read_unaligned(y), 12); +/// // Take a reference to a 32-bit integer which is not aligned. +/// let unaligned = &mut x.unaligned; +/// +/// // Dereferencing normally will emit an unaligned store instruction, +/// // causing undefined behavior. +/// // *unaligned = v; // ERROR +/// +/// // Instead, use `write_unaligned` to write improperly aligned values. +/// ptr::write_unaligned(unaligned, v); /// } -/// ``` +/// +/// // Accessing unaligned values directly is safe. +/// assert!(x.unaligned == v); #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] pub unsafe fn write_unaligned(dst: *mut T, src: T) { @@ -429,12 +681,28 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// # Safety /// -/// Beyond accepting a raw pointer, this is unsafe because it semantically -/// moves the value out of `src` without preventing further usage of `src`. -/// If `T` is not `Copy`, then care must be taken to ensure that the value at -/// `src` is not used before the data is overwritten again (e.g. with `write`, -/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use -/// because it will attempt to drop the value previously at `*src`. +/// `read_volatile` is unsafe because it dereferences a raw pointer. The caller +/// must ensure that the pointer points to a valid value of type `T`. +/// +/// # [Undefined Behavior] +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must point to valid, initialized memory. +/// +/// * `src` must be properly aligned. +/// +/// Additionally, if `T` is not [`Copy`], only the returned value *or* the +/// pointed-to value can be used or dropped after calling `read_volatile`. +/// `read_volatile` creates a bitwise copy of `T`, regardless of whether `T: +/// Copy`, which can result in undefined behavior if both copies are used. +/// Note that `*src = foo` counts as a use because it will attempt to drop the +/// value previously at `*src`. [`write_volatile`] can be used to overwrite +/// data without causing it to be dropped. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`write_volatile`]: ./fn.write_volatile.html +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -461,6 +729,13 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// to not be elided or reordered by the compiler across other volatile /// operations. /// +/// `write_volatile` does not drop the contents of `dst`. This is safe, but it +/// could leak allocations or resources, so care must be taken not to overwrite +/// an object that should be dropped. +/// +/// Additionally, it does not drop `src`. Semantically, `src` is moved into the +/// location pointed to by `dst`. +/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model, @@ -477,14 +752,18 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// # Safety /// -/// This operation is marked unsafe because it accepts a raw pointer. +/// `write_volatile` is unsafe because it dereferences a raw pointer. /// -/// It does not drop the contents of `dst`. This is safe, but it could leak -/// allocations or resources, so care must be taken not to overwrite an object -/// that should be dropped. +/// # [Undefined Behavior] /// -/// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been `read` from. +/// `write_volatile` can trigger undefined behavior if any of the following +/// conditions are violated: +/// +/// * `dst` must point to valid memory. +/// +/// * `dst` must be properly aligned. +/// +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From f5a367c7bb50f74d82c3909d5c961baac879242e Mon Sep 17 00:00:00 2001 From: Steven Malis Date: Sat, 7 Apr 2018 15:47:18 -0700 Subject: Update based on RangeBounds trait being moved to libcore. --- src/libcore/ops/range.rs | 75 ++++++++++++++++++---- src/librustc_errors/emitter.rs | 4 +- .../borrow_check/nll/universal_regions.rs | 8 +-- 3 files changed, 69 insertions(+), 18 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 3f667407125..210a0e118d5 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -109,8 +109,12 @@ impl> Range { /// assert!(!(3..2).contains(3)); /// ``` #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] - pub fn contains(&self, item: Idx) -> bool { - (self.start <= item) && (item < self.end) + pub fn contains(&self, item: &U) -> bool + where + Idx: PartialOrd, + U: ?Sized, + { + >::contains(self, item) } /// Returns `true` if the range contains no items. @@ -179,7 +183,6 @@ impl fmt::Debug for RangeFrom { } } -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> RangeFrom { /// Returns `true` if `item` is contained in the range. /// @@ -192,8 +195,13 @@ impl> RangeFrom { /// assert!( (3..).contains(3)); /// assert!( (3..).contains(1_000_000_000)); /// ``` - pub fn contains(&self, item: Idx) -> bool { - (self.start <= item) + #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] + pub fn contains(&self, item: &U) -> bool + where + Idx: PartialOrd, + U: ?Sized, + { + >::contains(self, item) } } @@ -250,7 +258,6 @@ impl fmt::Debug for RangeTo { } } -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> RangeTo { /// Returns `true` if `item` is contained in the range. /// @@ -263,8 +270,13 @@ impl> RangeTo { /// assert!( (..5).contains(4)); /// assert!(!(..5).contains(5)); /// ``` - pub fn contains(&self, item: Idx) -> bool { - (item < self.end) + #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] + pub fn contains(&self, item: &U) -> bool + where + Idx: PartialOrd, + U: ?Sized, + { + >::contains(self, item) } } @@ -328,8 +340,12 @@ impl> RangeInclusive { /// assert!(!(3..=2).contains(3)); /// ``` #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] - pub fn contains(&self, item: Idx) -> bool { - self.start <= item && item <= self.end + pub fn contains(&self, item: &U) -> bool + where + Idx: PartialOrd, + U: ?Sized, + { + >::contains(self, item) } /// Returns `true` if the range contains no items. @@ -435,8 +451,13 @@ impl> RangeToInclusive { /// assert!( (..=5).contains(5)); /// assert!(!(..=5).contains(6)); /// ``` - pub fn contains(&self, item: Idx) -> bool { - (item <= self.end) + #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] + pub fn contains(&self, item: &U) -> bool + where + Idx: PartialOrd, + U: ?Sized, + { + >::contains(self, item) } } @@ -537,6 +558,36 @@ pub trait RangeBounds { /// # } /// ``` fn end(&self) -> Bound<&T>; + + /// Returns `true` if `item` is contained in the range. + #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] + fn contains(&self, item: &U) -> bool + where + T: PartialOrd, + U: ?Sized, + { + match self.start() { + Included(ref start) => if *start > item { + return false; + }, + Excluded(ref start) => if *start >= item { + return false; + }, + Unbounded => (), + }; + + match self.end() { + Included(ref end) => if *end < item { + return false; + }, + Excluded(ref end) => if *end <= item { + return false; + }, + Unbounded => (), + } + + true + } } use self::Bound::{Excluded, Included, Unbounded}; diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index ca5d3f55a0f..91075ddcfa4 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -1389,8 +1389,8 @@ fn num_overlap(a_start: usize, a_end: usize, b_start: usize, b_end:usize, inclus } else { 0 }; - (b_start..b_end + extra).contains(a_start) || - (a_start..a_end + extra).contains(b_start) + (b_start..b_end + extra).contains(&a_start) || + (a_start..a_end + extra).contains(&b_start) } fn overlaps(a1: &Annotation, a2: &Annotation, padding: usize) -> bool { num_overlap(a1.start_col, a1.end_col + padding, a2.start_col, a2.end_col, false) diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index 39dc29ba18b..0fe6265345d 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -259,18 +259,18 @@ impl<'tcx> UniversalRegions<'tcx> { /// True if `r` is a member of this set of universal regions. pub fn is_universal_region(&self, r: RegionVid) -> bool { - (FIRST_GLOBAL_INDEX..self.num_universals).contains(r.index()) + (FIRST_GLOBAL_INDEX..self.num_universals).contains(&r.index()) } /// Classifies `r` as a universal region, returning `None` if this /// is not a member of this set of universal regions. pub fn region_classification(&self, r: RegionVid) -> Option { let index = r.index(); - if (FIRST_GLOBAL_INDEX..self.first_extern_index).contains(index) { + if (FIRST_GLOBAL_INDEX..self.first_extern_index).contains(&index) { Some(RegionClassification::Global) - } else if (self.first_extern_index..self.first_local_index).contains(index) { + } else if (self.first_extern_index..self.first_local_index).contains(&index) { Some(RegionClassification::External) - } else if (self.first_local_index..self.num_universals).contains(index) { + } else if (self.first_local_index..self.num_universals).contains(&index) { Some(RegionClassification::Local) } else { None -- cgit 1.4.1-3-g733a5 From ee259e4dd340f9532511b7249e4eb961f111b63f Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 7 Apr 2018 15:51:25 -0700 Subject: Change `write_bytes` test causing UB to `no_run` This also fixes improper text wrapping. --- src/libcore/intrinsics.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index d6bd2b86855..8e3180cd2a6 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -992,11 +992,11 @@ extern "rust-intrinsic" { /// /// * The two regions of memory must *not* overlap. /// - /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy), only the region at `src` *or* the - /// region at `dst` can be used or dropped after calling - /// `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise copies of - /// `T`, regardless of whether `T: Copy`, which can result in undefined - /// behavior if both copies are used. + /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy), only the + /// region at `src` *or* the region at `dst` can be used or dropped after + /// calling `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise + /// copies of `T`, regardless of whether `T: Copy`, which can result in + /// undefined behavior if both copies are used. /// /// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// @@ -1149,7 +1149,7 @@ extern "rust-intrinsic" { /// /// Creating an invalid value: /// - /// ```ignore + /// ```no_run /// use std::{mem, ptr}; /// /// let mut v = Box::new(0i32); @@ -1161,6 +1161,7 @@ extern "rust-intrinsic" { /// } /// /// // At this point, using or dropping `v` results in undefined behavior. + /// // v = Box::new(0i32); // ERROR /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn write_bytes(dst: *mut T, val: u8, count: usize); -- cgit 1.4.1-3-g733a5 From b564c4a0ee96acb0a68b8421b6cecac47e2a2e8b Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 7 Apr 2018 17:20:20 -0700 Subject: Fix example for `ptr::replace` --- src/libcore/ptr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 98d5030477b..9069feab06c 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -337,7 +337,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// // `mem::replace` would have the same effect without requiring the unsafe /// // block. /// let b = unsafe { -/// ptr::replace(&mut a[0], 'r') +/// ptr::replace(&mut rust[0], 'r') /// }; /// /// assert_eq!(b, 'b'); -- cgit 1.4.1-3-g733a5 From 6eceb94d09636d272f8448d0eb26e072b891cb45 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 7 Apr 2018 17:22:27 -0700 Subject: Don't link "Undefined Behavior" heading The rendered version does not make clear that this is a link to another page, and it breaks the anchor link. --- src/libcore/intrinsics.rs | 9 +++------ src/libcore/ptr.rs | 31 +++++++++---------------------- 2 files changed, 12 insertions(+), 28 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 8e3180cd2a6..daa43337fd7 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -975,7 +975,7 @@ extern "rust-intrinsic" { /// The caller must ensure that `src` points to a valid sequence of type /// `T`. /// - /// # [Undefined Behavior] + /// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -998,8 +998,6 @@ extern "rust-intrinsic" { /// copies of `T`, regardless of whether `T: Copy`, which can result in /// undefined behavior if both copies are used. /// - /// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html - /// /// # Examples /// /// Manually implement [`Vec::append`]: @@ -1065,7 +1063,7 @@ extern "rust-intrinsic" { /// `copy` is unsafe because it dereferences a raw pointer. The caller must /// ensure that `src` points to a valid sequence of type `T`. /// - /// # [Undefined Behavior] + /// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -1086,7 +1084,6 @@ extern "rust-intrinsic" { /// can result in undefined behavior if both copies are used. /// /// [`Copy`]: ../marker/trait.Copy.html - /// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -1118,7 +1115,7 @@ extern "rust-intrinsic" { /// `write_bytes` is unsafe because it dereferences a raw pointer. The /// caller must ensure that the poiinter points to a valid value of type `T`. /// - /// # [Undefined Behavior] + /// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 9069feab06c..4cb9c655441 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -57,7 +57,7 @@ pub use intrinsics::write_bytes; /// `drop_in_place` is unsafe because it dereferences a raw pointer. The caller /// must ensure that the pointer points to a valid value of type `T`. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -73,7 +73,6 @@ pub use intrinsics::write_bytes; /// /// [`Copy`]: ../marker/trait.Copy.html /// [`write`]: ./fn.write.html -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -157,7 +156,7 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// `swap` is unsafe because it dereferences a raw pointer. The caller must /// ensure that both pointers point to valid values of type `T`. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -165,8 +164,6 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// /// * `x` and `y` must be properly aligned. /// -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html -/// /// # Examples /// /// Swapping two non-overlapping regions: @@ -317,7 +314,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// [`mem::replace`]: ../mem/fn.replace.html /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -325,8 +322,6 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// * `dest` must be properly aligned. /// -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html -/// /// # Examples /// /// ``` @@ -358,7 +353,7 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// `read` is unsafe because it dereferences a raw pointer. The caller /// must ensure that the pointer points to a valid value of type `T`. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -377,7 +372,6 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// [`Copy`]: ../marker/trait.Copy.html /// [`read_unaligned`]: ./fn.read_unaligned.html /// [`write`]: ./fn.write.html -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -447,7 +441,7 @@ pub unsafe fn read(src: *const T) -> T { /// `read_unaligned` is unsafe because it dereferences a raw pointer. The caller /// must ensure that the pointer points to a valid value of type `T`. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -463,7 +457,6 @@ pub unsafe fn read(src: *const T) -> T { /// /// [`Copy`]: ../marker/trait.Copy.html /// [`write_unaligned`]: ./fn.write_unaligned.html -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -530,7 +523,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// /// `write` is unsafe because it dereferences a raw pointer. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// `write` can trigger undefined behavior if any of the following conditions /// are violated: @@ -540,7 +533,6 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the /// case. /// -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// [`write_unaligned`]: ./fn.write_unaligned.html /// /// # Examples @@ -609,15 +601,13 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// `write_unaligned` is unsafe because it dereferences a raw pointer. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// `write_unaligned` can trigger undefined behavior if any of the following /// conditions are violated: /// /// * `dst` must point to valid memory. /// -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html -/// /// # Examples /// /// Access fields in a packed struct: @@ -684,7 +674,7 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// `read_volatile` is unsafe because it dereferences a raw pointer. The caller /// must ensure that the pointer points to a valid value of type `T`. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -702,7 +692,6 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// [`Copy`]: ../marker/trait.Copy.html /// [`write_volatile`]: ./fn.write_volatile.html -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -754,7 +743,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// `write_volatile` is unsafe because it dereferences a raw pointer. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// `write_volatile` can trigger undefined behavior if any of the following /// conditions are violated: @@ -763,8 +752,6 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// * `dst` must be properly aligned. /// -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html -/// /// # Examples /// /// Basic usage: -- cgit 1.4.1-3-g733a5 From 422b6164e505bc240948dc6e420a82c89ead0711 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 7 Apr 2018 17:28:10 -0700 Subject: Fix broken link in `write_unaligned` docs --- src/libcore/ptr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 4cb9c655441..c679a1a2456 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -592,7 +592,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// location pointed to by `dst`. /// /// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been [`read`] from. +/// memory that has previously been read with [`read_unaligned`]. /// /// [`write`]: ./fn.write.html /// [`read_unaligned`]: ./fn.read_unaligned.html -- cgit 1.4.1-3-g733a5 From 16f30c2da2a92ff9264935ac309b3e94bbd83ddf Mon Sep 17 00:00:00 2001 From: Steven Malis Date: Sat, 7 Apr 2018 18:34:12 -0700 Subject: fix tests --- src/libcore/ops/range.rs | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 210a0e118d5..97b476fa5b6 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -100,13 +100,13 @@ impl> Range { /// ``` /// #![feature(range_contains)] /// - /// assert!(!(3..5).contains(2)); - /// assert!( (3..5).contains(3)); - /// assert!( (3..5).contains(4)); - /// assert!(!(3..5).contains(5)); + /// assert!(!(3..5).contains(&2)); + /// assert!( (3..5).contains(&3)); + /// assert!( (3..5).contains(&4)); + /// assert!(!(3..5).contains(&5)); /// - /// assert!(!(3..3).contains(3)); - /// assert!(!(3..2).contains(3)); + /// assert!(!(3..3).contains(&3)); + /// assert!(!(3..2).contains(&3)); /// ``` #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: &U) -> bool @@ -191,9 +191,9 @@ impl> RangeFrom { /// ``` /// #![feature(range_contains)] /// - /// assert!(!(3..).contains(2)); - /// assert!( (3..).contains(3)); - /// assert!( (3..).contains(1_000_000_000)); + /// assert!(!(3..).contains(&2)); + /// assert!( (3..).contains(&3)); + /// assert!( (3..).contains(&1_000_000_000)); /// ``` #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: &U) -> bool @@ -266,9 +266,9 @@ impl> RangeTo { /// ``` /// #![feature(range_contains)] /// - /// assert!( (..5).contains(-1_000_000_000)); - /// assert!( (..5).contains(4)); - /// assert!(!(..5).contains(5)); + /// assert!( (..5).contains(&-1_000_000_000)); + /// assert!( (..5).contains(&4)); + /// assert!(!(..5).contains(&5)); /// ``` #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: &U) -> bool @@ -330,14 +330,14 @@ impl> RangeInclusive { /// ``` /// #![feature(range_contains)] /// - /// assert!(!(3..=5).contains(2)); - /// assert!( (3..=5).contains(3)); - /// assert!( (3..=5).contains(4)); - /// assert!( (3..=5).contains(5)); - /// assert!(!(3..=5).contains(6)); + /// assert!(!(3..=5).contains(&2)); + /// assert!( (3..=5).contains(&3)); + /// assert!( (3..=5).contains(&4)); + /// assert!( (3..=5).contains(&5)); + /// assert!(!(3..=5).contains(&6)); /// - /// assert!( (3..=3).contains(3)); - /// assert!(!(3..=2).contains(3)); + /// assert!( (3..=3).contains(&3)); + /// assert!(!(3..=2).contains(&3)); /// ``` #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: &U) -> bool @@ -447,9 +447,9 @@ impl> RangeToInclusive { /// ``` /// #![feature(range_contains)] /// - /// assert!( (..=5).contains(-1_000_000_000)); - /// assert!( (..=5).contains(5)); - /// assert!(!(..=5).contains(6)); + /// assert!( (..=5).contains(&-1_000_000_000)); + /// assert!( (..=5).contains(&5)); + /// assert!(!(..=5).contains(&6)); /// ``` #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: &U) -> bool -- cgit 1.4.1-3-g733a5 From d7ce9a213c11f825b8b47f7d9fd970cfb97033bd Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 7 Apr 2018 20:45:16 -0700 Subject: Fix broken relative links --- src/libcore/intrinsics.rs | 12 ++++++------ src/libcore/ptr.rs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index daa43337fd7..8c510842c2a 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -992,11 +992,11 @@ extern "rust-intrinsic" { /// /// * The two regions of memory must *not* overlap. /// - /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy), only the - /// region at `src` *or* the region at `dst` can be used or dropped after - /// calling `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise - /// copies of `T`, regardless of whether `T: Copy`, which can result in - /// undefined behavior if both copies are used. + /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy.html), only + /// the region at `src` *or* the region at `dst` can be used or dropped + /// after calling `copy_nonoverlapping`. `copy_nonoverlapping` creates + /// bitwise copies of `T`, regardless of whether `T: Copy`, which can result + /// in undefined behavior if both copies are used. /// /// # Examples /// @@ -1043,7 +1043,7 @@ extern "rust-intrinsic" { /// assert!(b.is_empty()); /// ``` /// - /// [`Vec::append()`]: ../vec/struct.Vec.html#method.append + /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append #[stable(feature = "rust1", since = "1.0.0")] pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index c679a1a2456..962fb0f31a4 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -50,7 +50,7 @@ pub use intrinsics::write_bytes; /// as the compiler doesn't need to prove that it's sound to elide the /// copy. /// -/// [`ptr::read`]: ./fn.read.html +/// [`ptr::read`]: ../ptr/fn.read.html /// /// # Safety /// @@ -72,7 +72,7 @@ pub use intrinsics::write_bytes; /// dropped. /// /// [`Copy`]: ../marker/trait.Copy.html -/// [`write`]: ./fn.write.html +/// [`write`]: ../ptr/fn.write.html /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 249dc9e5cd5abaea710345fcabca815e5e59eec6 Mon Sep 17 00:00:00 2001 From: Steven Malis Date: Sat, 7 Apr 2018 21:09:26 -0700 Subject: Add float NaN tests. --- src/libcore/ops/range.rs | 80 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 21 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 97b476fa5b6..868308cafd1 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -100,6 +100,8 @@ impl> Range { /// ``` /// #![feature(range_contains)] /// + /// use std::f32; + /// /// assert!(!(3..5).contains(&2)); /// assert!( (3..5).contains(&3)); /// assert!( (3..5).contains(&4)); @@ -107,6 +109,11 @@ impl> Range { /// /// assert!(!(3..3).contains(&3)); /// assert!(!(3..2).contains(&3)); + /// + /// assert!( (0.0..1.0).contains(&0.5)); + /// assert!(!(0.0..1.0).contains(&f32::NAN)); + /// assert!(!(0.0..f32::NAN).contains(&0.5)); + /// assert!(!(f32::NAN..1.0).contains(&0.5)); /// ``` #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: &U) -> bool @@ -191,9 +198,15 @@ impl> RangeFrom { /// ``` /// #![feature(range_contains)] /// + /// use std::f32; + /// /// assert!(!(3..).contains(&2)); /// assert!( (3..).contains(&3)); /// assert!( (3..).contains(&1_000_000_000)); + /// + /// assert!( (0.0..).contains(&0.5)); + /// assert!(!(0.0..).contains(&f32::NAN)); + /// assert!(!(f32::NAN..).contains(&0.5)); /// ``` #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: &U) -> bool @@ -266,9 +279,15 @@ impl> RangeTo { /// ``` /// #![feature(range_contains)] /// + /// use std::f32; + /// /// assert!( (..5).contains(&-1_000_000_000)); /// assert!( (..5).contains(&4)); /// assert!(!(..5).contains(&5)); + /// + /// assert!( (..1.0).contains(&0.5)); + /// assert!(!(..1.0).contains(&f32::NAN)); + /// assert!(!(..f32::NAN).contains(&0.5)); /// ``` #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: &U) -> bool @@ -330,6 +349,8 @@ impl> RangeInclusive { /// ``` /// #![feature(range_contains)] /// + /// use std::f32; + /// /// assert!(!(3..=5).contains(&2)); /// assert!( (3..=5).contains(&3)); /// assert!( (3..=5).contains(&4)); @@ -338,6 +359,11 @@ impl> RangeInclusive { /// /// assert!( (3..=3).contains(&3)); /// assert!(!(3..=2).contains(&3)); + /// + /// assert!( (0.0..=1.0).contains(&1.0)); + /// assert!(!(0.0..=1.0).contains(&f32::NAN)); + /// assert!(!(0.0..=f32::NAN).contains(&0.0)); + /// assert!(!(f32::NAN..=1.0).contains(&1.0)); /// ``` #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: &U) -> bool @@ -447,9 +473,15 @@ impl> RangeToInclusive { /// ``` /// #![feature(range_contains)] /// + /// use std::f32; + /// /// assert!( (..=5).contains(&-1_000_000_000)); /// assert!( (..=5).contains(&5)); /// assert!(!(..=5).contains(&6)); + /// + /// assert!( (..=1.0).contains(&1.0)); + /// assert!(!(..=1.0).contains(&f32::NAN)); + /// assert!(!(..=f32::NAN).contains(&0.5)); /// ``` #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: &U) -> bool @@ -559,34 +591,40 @@ pub trait RangeBounds { /// ``` fn end(&self) -> Bound<&T>; + /// Returns `true` if `item` is contained in the range. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_contains)] + /// + /// use std::f32; + /// + /// assert!( (3..5).contains(&4)); + /// assert!(!(3..5).contains(&2)); + /// + /// assert!( (0.0..1.0).contains(&0.5)); + /// assert!(!(0.0..1.0).contains(&f32::NAN)); + /// assert!(!(0.0..f32::NAN).contains(&0.5)); + /// assert!(!(f32::NAN..1.0).contains(&0.5)); #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] fn contains(&self, item: &U) -> bool where T: PartialOrd, U: ?Sized, { - match self.start() { - Included(ref start) => if *start > item { - return false; - }, - Excluded(ref start) => if *start >= item { - return false; - }, - Unbounded => (), - }; - - match self.end() { - Included(ref end) => if *end < item { - return false; - }, - Excluded(ref end) => if *end <= item { - return false; - }, - Unbounded => (), - } - - true + (match self.start() { + Included(ref start) => *start <= item, + Excluded(ref start) => *start < item, + Unbounded => true, + }) + && + (match self.end() { + Included(ref end) => *end >= item, + Excluded(ref end) => *end > item, + Unbounded => true, + }) } } -- cgit 1.4.1-3-g733a5 From c115cc655c8bb3077ff349e4ddd704a2239438a6 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sun, 1 Apr 2018 09:35:53 -0600 Subject: Move deny(warnings) into rustbuild This permits easier iteration without having to worry about warnings being denied. Fixes #49517 --- config.toml.example | 3 +++ src/bootstrap/bin/rustc.rs | 4 ++++ src/bootstrap/builder.rs | 5 +++++ src/bootstrap/config.rs | 8 ++++++++ src/bootstrap/flags.rs | 6 ++++++ src/build_helper/lib.rs | 1 - src/liballoc/benches/lib.rs | 2 -- src/liballoc/lib.rs | 1 - src/liballoc/tests/lib.rs | 2 -- src/liballoc_jemalloc/lib.rs | 1 - src/liballoc_system/lib.rs | 1 - src/libarena/lib.rs | 1 - src/libcore/benches/lib.rs | 2 -- src/libcore/lib.rs | 1 - src/libcore/tests/lib.rs | 2 -- src/libfmt_macros/lib.rs | 1 - src/libgraphviz/lib.rs | 1 - src/libpanic_abort/lib.rs | 1 - src/libpanic_unwind/lib.rs | 1 - src/libproc_macro/lib.rs | 1 - src/librustc/benches/lib.rs | 2 -- src/librustc/lib.rs | 1 - src/librustc_allocator/lib.rs | 2 -- src/librustc_apfloat/lib.rs | 1 - src/librustc_back/lib.rs | 1 - src/librustc_borrowck/lib.rs | 1 - src/librustc_const_math/lib.rs | 1 - src/librustc_data_structures/lib.rs | 1 - src/librustc_driver/lib.rs | 1 - src/librustc_errors/lib.rs | 1 - src/librustc_incremental/lib.rs | 1 - src/librustc_lint/lib.rs | 1 - src/librustc_llvm/lib.rs | 1 - src/librustc_metadata/lib.rs | 1 - src/librustc_mir/lib.rs | 2 -- src/librustc_passes/lib.rs | 1 - src/librustc_platform_intrinsics/lib.rs | 1 - src/librustc_plugin/lib.rs | 1 - src/librustc_privacy/lib.rs | 1 - src/librustc_resolve/lib.rs | 1 - src/librustc_save_analysis/lib.rs | 1 - src/librustc_traits/lib.rs | 2 -- src/librustc_trans/lib.rs | 1 - src/librustc_trans_utils/lib.rs | 1 - src/librustc_typeck/lib.rs | 1 - src/librustdoc/lib.rs | 1 - src/libserialize/lib.rs | 1 - src/libstd/lib.rs | 4 ---- src/libstd_unicode/lib.rs | 1 - src/libsyntax/lib.rs | 1 - src/libsyntax_ext/lib.rs | 1 - src/libsyntax_pos/lib.rs | 1 - src/libterm/lib.rs | 1 - src/libtest/lib.rs | 1 - src/libunwind/lib.rs | 1 - src/tools/tidy/src/lib.rs | 2 -- 56 files changed, 26 insertions(+), 63 deletions(-) (limited to 'src/libcore') diff --git a/config.toml.example b/config.toml.example index 9dd3002506e..68bc7dfe720 100644 --- a/config.toml.example +++ b/config.toml.example @@ -339,6 +339,9 @@ # rustc to execute. #lld = false +# Whether to deny warnings in crates +#deny-warnings = true + # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 6701f58ba8e..3dd9b684059 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -279,6 +279,10 @@ fn main() { cmd.arg("--color=always"); } + if env::var_os("RUSTC_DENY_WARNINGS").is_some() { + cmd.arg("-Dwarnings"); + } + if verbose > 1 { eprintln!("rustc command: {:?}", cmd); eprintln!("sysroot: {:?}", sysroot); diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 3f5ec4933d0..7ff64af9196 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -698,6 +698,11 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity)); + // in std, we want to avoid denying warnings for stage 0 as that makes cfg's painful. + if self.config.deny_warnings && !(mode == Mode::Libstd && stage == 0) { + cargo.env("RUSTC_DENY_WARNINGS", "1"); + } + // Throughout the build Cargo can execute a number of build scripts // compiling C/C++ code and we need to pass compilers, archivers, flags, etc // obtained previously to those build scripts. diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 95baf4f8cca..239316d45c4 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -71,6 +71,8 @@ pub struct Config { pub incremental: bool, pub dry_run: bool, + pub deny_warnings: bool, + // llvm codegen options pub llvm_enabled: bool, pub llvm_assertions: bool, @@ -301,6 +303,7 @@ struct Rust { codegen_backends_dir: Option, wasm_syscall: Option, lld: Option, + deny_warnings: Option, } /// TOML representation of how each build target is configured. @@ -340,6 +343,7 @@ impl Config { config.test_miri = false; config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")]; config.rust_codegen_backends_dir = "codegen-backends".to_owned(); + config.deny_warnings = true; // set by bootstrap.py config.src = env::var_os("SRC").map(PathBuf::from).expect("'SRC' to be set"); @@ -366,6 +370,9 @@ impl Config { config.incremental = flags.incremental; config.dry_run = flags.dry_run; config.keep_stage = flags.keep_stage; + if let Some(value) = flags.warnings { + config.deny_warnings = value; + } if config.dry_run { let dir = config.out.join("tmp-dry-run"); @@ -511,6 +518,7 @@ impl Config { config.rustc_default_linker = rust.default_linker.clone(); config.musl_root = rust.musl_root.clone().map(PathBuf::from); config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from); + set(&mut config.deny_warnings, rust.deny_warnings.or(flags.warnings)); if let Some(ref backends) = rust.codegen_backends { config.rust_codegen_backends = backends.iter() diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index ef902c68d12..3eb9dca2aa8 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -42,6 +42,9 @@ pub struct Flags { pub exclude: Vec, pub rustc_error_format: Option, pub dry_run: bool, + + // true => deny + pub warnings: Option, } pub enum Subcommand { @@ -118,6 +121,8 @@ To learn more about a subcommand, run `./x.py -h`"); opts.optopt("", "src", "path to the root of the rust checkout", "DIR"); opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); opts.optflag("h", "help", "print this help message"); + opts.optopt("", "warnings", "if value is deny, will deny warnings, otherwise use default", + "VALUE"); opts.optopt("", "error-format", "rustc error format", "FORMAT"); // fn usage() @@ -374,6 +379,7 @@ Arguments: incremental: matches.opt_present("incremental"), exclude: split(matches.opt_strs("exclude")) .into_iter().map(|p| p.into()).collect::>(), + warnings: matches.opt_str("warnings").map(|v| v == "deny"), } } } diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index 5a12afd03e1..e5c85ddb3a9 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] use std::fs::File; use std::path::{Path, PathBuf}; diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index 4d92fc67b2a..4f69aa6670b 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(rand)] #![feature(repr_simd)] #![feature(slice_sort_by_cached_key)] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index da26e7c852c..b08bd66b47c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -72,7 +72,6 @@ test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] #![no_std] #![needs_allocator] -#![deny(warnings)] #![deny(missing_debug_implementations)] #![cfg_attr(test, allow(deprecated))] // rand diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index a173ef10a81..17f1d0464a5 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(allocator_api)] #![feature(alloc_system)] #![feature(attr_literals)] diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 7a8d01e4ef8..df7e3f61f5f 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -14,7 +14,6 @@ reason = "this library is unlikely to be stabilized in its current \ form or name", issue = "27783")] -#![deny(warnings)] #![feature(alloc_system)] #![feature(libc)] #![feature(linkage)] diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index d4404e564e0..cdcb732f635 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -10,7 +10,6 @@ #![no_std] #![allow(unused_attributes)] -#![deny(warnings)] #![unstable(feature = "alloc_system", reason = "this library is unlikely to be stabilized in its current \ form or name", diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 7eaf67e6ea6..b319f333342 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -22,7 +22,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", test(no_crate_inject, attr(deny(warnings))))] -#![deny(warnings)] #![feature(alloc)] #![feature(core_intrinsics)] diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs index c947b003ccb..ced77d77918 100644 --- a/src/libcore/benches/lib.rs +++ b/src/libcore/benches/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(flt2dec)] #![feature(test)] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index cf9abb26d3e..e194b173aa7 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -63,7 +63,6 @@ #![no_core] #![deny(missing_docs)] #![deny(missing_debug_implementations)] -#![deny(warnings)] #![feature(allow_internal_unstable)] #![feature(asm)] diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 971759dcdd0..c3162899bbd 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(ascii_ctype)] #![feature(box_syntax)] #![feature(core_float)] diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 0f45f965104..a551b1b770a 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -19,7 +19,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))] -#![deny(warnings)] pub use self::Piece::*; pub use self::Position::*; diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index d8c366d2413..158d0101515 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -287,7 +287,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(allow(unused_variables), deny(warnings))))] -#![deny(warnings)] #![feature(str_escape)] diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index 5f768ef4399..43c5bbbc618 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -19,7 +19,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] -#![deny(warnings)] #![panic_runtime] #![allow(unused_features)] diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index a5c227cb401..9321d6917d1 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -28,7 +28,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] -#![deny(warnings)] #![feature(alloc)] #![feature(core_intrinsics)] diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 6aa5572721d..dafdacfdd72 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -24,7 +24,6 @@ //! See [the book](../book/first-edition/procedural-macros.html) for more. #![stable(feature = "proc_macro_lib", since = "1.15.0")] -#![deny(warnings)] #![deny(missing_docs)] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", diff --git a/src/librustc/benches/lib.rs b/src/librustc/benches/lib.rs index 278e0f9a26e..5496df1342f 100644 --- a/src/librustc/benches/lib.rs +++ b/src/librustc/benches/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(test)] extern crate test; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 7da664e6d02..b54699901fa 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -39,7 +39,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index e17fce5a2ec..0c7a9a91711 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(rustc_private)] extern crate rustc; diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 276f6cd09bf..0f051ea5981 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -43,7 +43,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![forbid(unsafe_code)] // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 9baee267709..027a9c45555 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -24,7 +24,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_syntax)] #![feature(const_fn)] diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index 6fe2ac2b0ca..52a357e1a1d 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![allow(non_camel_case_types)] diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index c4c5886d465..499c330be1d 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] extern crate rustc_apfloat; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 1e1628936d5..ba1d73dc268 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -19,7 +19,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://www.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(collections_range)] #![feature(nonzero)] diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6f88b0aecb6..f6903d26e70 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_syntax)] #![cfg_attr(unix, feature(libc))] diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index a723e455222..8d5f9ac93f0 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(custom_attribute)] #![allow(unused_attributes)] diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 9e72ede309d..a5e07bcec24 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -13,7 +13,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(fs_read_write)] #![feature(specialization)] diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index c915181213d..16e8600f2d8 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -22,7 +22,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![cfg_attr(test, feature(test))] #![feature(box_patterns)] diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 16bee5b987e..bf8a087ab55 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -16,7 +16,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_syntax)] #![feature(concat_idents)] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index e89b5a7fc1b..f02a34c65a9 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_patterns)] #![feature(fs_read_write)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 8762e7550cd..51256c4d96f 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -14,8 +14,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! */ -#![deny(warnings)] - #![feature(slice_patterns)] #![feature(from_ref)] #![feature(box_patterns)] diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 1f6cc1f71fc..e65c9de8df1 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs index 4cc65ee28e8..b57debdd994 100644 --- a/src/librustc_platform_intrinsics/lib.rs +++ b/src/librustc_platform_intrinsics/lib.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] #![allow(bad_style)] pub struct Intrinsic { diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs index c0f830f1fbe..622d8e51a6c 100644 --- a/src/librustc_plugin/lib.rs +++ b/src/librustc_plugin/lib.rs @@ -63,7 +63,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(rustc_diagnostic_macros)] #![feature(staged_api)] diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index d951a7f1cc1..ef710ff7a7e 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2bf17cd1317..61ff326b2af 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 4f46fb3545b..fefedd4e1c8 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(custom_attribute)] #![feature(macro_lifetime_matcher)] #![allow(unused_attributes)] diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index cfa3b6912f2..8136f6857a5 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -11,8 +11,6 @@ //! New recursive solver modeled on Chalk's recursive solver. Most of //! the guts are broken up into modules; see the comments in those modules. -#![deny(warnings)] - #![feature(crate_visibility_modifier)] #[macro_use] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 344f959c141..b9fa5b1353c 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index cf47d9b62a9..b297fd99865 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -15,7 +15,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 6f71db998bd..eb9a26855c6 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -68,7 +68,6 @@ This API is completely unstable and subject to change. #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![allow(non_camel_case_types)] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 42e87f88fd4..730f61e0aa6 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -12,7 +12,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/")] -#![deny(warnings)] #![feature(ascii_ctype)] #![feature(rustc_private)] diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index f78eed30694..22d27b6697a 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -19,7 +19,6 @@ Core encoding and decoding interfaces. html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/", test(attr(allow(unused_variables), deny(warnings))))] -#![deny(warnings)] #![feature(box_syntax)] #![feature(core_intrinsics)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3227aa9acff..672723341eb 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -227,10 +227,6 @@ // Tell the compiler to link to either panic_abort or panic_unwind #![needs_panic_runtime] -// Turn warnings into errors, but only after stage0, where it can be useful for -// code to emit warnings during language transitions -#![cfg_attr(not(stage0), deny(warnings))] - // std may use features in a platform-specific way #![allow(unused_features)] diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index c22ea1671fa..cf8c101a2f9 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -27,7 +27,6 @@ html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] -#![deny(warnings)] #![deny(missing_debug_implementations)] #![no_std] diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index c456dc45d21..b2976f71d49 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -18,7 +18,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![deny(warnings)] #![feature(unicode)] #![feature(rustc_diagnostic_macros)] diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 249a64b353f..97e34c554d1 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -13,7 +13,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(proc_macro_internals)] #![feature(decl_macro)] diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 33428eb271a..9a7d1fd8ee6 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(const_fn)] #![feature(custom_attribute)] diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index ad0e582b1c3..a012f4e776f 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -46,7 +46,6 @@ html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))] #![deny(missing_docs)] -#![deny(warnings)] #![cfg_attr(windows, feature(libc))] // Handle rustfmt skips diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index b8be1aeff17..9291eaa910b 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -31,7 +31,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![deny(warnings)] #![feature(asm)] #![feature(fnbox)] #![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc))] diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs index 5347c781218..2b3c19c067e 100644 --- a/src/libunwind/lib.rs +++ b/src/libunwind/lib.rs @@ -10,7 +10,6 @@ #![no_std] #![unstable(feature = "panic_unwind", issue = "32837")] -#![deny(warnings)] #![feature(cfg_target_vendor)] #![feature(link_cfg)] diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 06eb055f68e..fa227436640 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -13,8 +13,6 @@ //! This library contains the tidy lints and exposes it //! to be used by tools. -#![deny(warnings)] - extern crate serde; extern crate serde_json; #[macro_use] -- cgit 1.4.1-3-g733a5 From 69c3830c4487ce50017ab323d0ce4cbc0b6a4700 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 9 Apr 2018 11:40:53 -0700 Subject: std: Be sure to modify atomics in tests See #49775 for some more information but it looks like this is working around an LLVM bug for the time being. Closes #49775 --- src/libcore/tests/atomic.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/tests/atomic.rs b/src/libcore/tests/atomic.rs index f634fabe503..a3667b3f3fe 100644 --- a/src/libcore/tests/atomic.rs +++ b/src/libcore/tests/atomic.rs @@ -104,8 +104,10 @@ static S_UINT: AtomicUsize = AtomicUsize::new(0); #[test] fn static_init() { - assert!(!S_FALSE.load(SeqCst)); - assert!(S_TRUE.load(SeqCst)); - assert!(S_INT.load(SeqCst) == 0); - assert!(S_UINT.load(SeqCst) == 0); + // Note that we're not really testing the mutability here but it's important + // on Android at the moment (#49775) + assert!(!S_FALSE.swap(true, SeqCst)); + assert!(S_TRUE.swap(false, SeqCst)); + assert!(S_INT.fetch_add(1, SeqCst) == 0); + assert!(S_UINT.fetch_add(1, SeqCst) == 0); } -- cgit 1.4.1-3-g733a5 From d7209d5babae4e1e428771287eaca6165e43972c Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 9 Apr 2018 14:23:08 -0700 Subject: Fix various nits from PR review - Remove redundant "unsafe" from module description. - Add a missing `Safety` heading to `read_unaligned`. - Remove weasel words in `Undefined Behavior` description for `write{,_unaligned,_bytes}`. --- src/libcore/ptr.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 962fb0f31a4..3d15e4b1658 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -10,7 +10,7 @@ // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory -//! Manually manage memory through raw, unsafe pointers. +//! Manually manage memory through raw pointers. //! //! *[See also the pointer primitive types](../../std/primitive.pointer.html).* @@ -438,6 +438,8 @@ pub unsafe fn read(src: *const T) -> T { /// /// [`read`]: ./fn.read.html /// +/// # Safety +/// /// `read_unaligned` is unsafe because it dereferences a raw pointer. The caller /// must ensure that the pointer points to a valid value of type `T`. /// @@ -525,8 +527,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// /// # Undefined Behavior /// -/// `write` can trigger undefined behavior if any of the following conditions -/// are violated: +/// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. /// @@ -603,8 +604,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// # Undefined Behavior /// -/// `write_unaligned` can trigger undefined behavior if any of the following -/// conditions are violated: +/// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. /// @@ -745,8 +745,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// # Undefined Behavior /// -/// `write_volatile` can trigger undefined behavior if any of the following -/// conditions are violated: +/// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. /// -- cgit 1.4.1-3-g733a5 From f817d1960a4d495a20689bc7ed22847561afd216 Mon Sep 17 00:00:00 2001 From: Daiki Mizukami Date: Tue, 10 Apr 2018 17:13:32 +0900 Subject: std: Mark `ptr::Unique` with `#[doc(hidden)]` --- src/libcore/ptr.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libcore') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 5a54de06b5e..a1307a6d599 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2511,6 +2511,7 @@ impl PartialOrd for *mut T { reason = "use NonNull instead and consider PhantomData \ (if you also use #[may_dangle]), Send, and/or Sync")] #[allow(deprecated)] +#[doc(hidden)] pub struct Unique { pointer: NonZero<*const T>, // NOTE: this marker has no consequences for variance, but is necessary -- cgit 1.4.1-3-g733a5 From 51f24ec7f01b6a636750baff5ab5a12ec6bfe6cd Mon Sep 17 00:00:00 2001 From: Steven Malis Date: Tue, 10 Apr 2018 19:26:25 -0700 Subject: Add symmetric requirement of PartialOrd. --- src/libcore/ops/range.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 868308cafd1..6f3e3b50885 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -119,7 +119,7 @@ impl> Range { pub fn contains(&self, item: &U) -> bool where Idx: PartialOrd, - U: ?Sized, + U: ?Sized + PartialOrd, { >::contains(self, item) } @@ -212,7 +212,7 @@ impl> RangeFrom { pub fn contains(&self, item: &U) -> bool where Idx: PartialOrd, - U: ?Sized, + U: ?Sized + PartialOrd, { >::contains(self, item) } @@ -293,7 +293,7 @@ impl> RangeTo { pub fn contains(&self, item: &U) -> bool where Idx: PartialOrd, - U: ?Sized, + U: ?Sized + PartialOrd, { >::contains(self, item) } @@ -369,7 +369,7 @@ impl> RangeInclusive { pub fn contains(&self, item: &U) -> bool where Idx: PartialOrd, - U: ?Sized, + U: ?Sized + PartialOrd, { >::contains(self, item) } @@ -487,7 +487,7 @@ impl> RangeToInclusive { pub fn contains(&self, item: &U) -> bool where Idx: PartialOrd, - U: ?Sized, + U: ?Sized + PartialOrd, { >::contains(self, item) } @@ -612,7 +612,7 @@ pub trait RangeBounds { fn contains(&self, item: &U) -> bool where T: PartialOrd, - U: ?Sized, + U: ?Sized + PartialOrd, { (match self.start() { Included(ref start) => *start <= item, @@ -621,8 +621,8 @@ pub trait RangeBounds { }) && (match self.end() { - Included(ref end) => *end >= item, - Excluded(ref end) => *end > item, + Included(ref end) => item <= *end, + Excluded(ref end) => item < *end, Unbounded => true, }) } -- cgit 1.4.1-3-g733a5 From ae6adf335c88cad4e4a1805a805ac49dd1350174 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 5 Apr 2018 15:45:33 +0200 Subject: Move char::REPLACEMENT_CHARACTER to libcore --- src/libcore/char.rs | 8 ++++++++ src/libstd_unicode/char.rs | 10 ++-------- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 718c6b893ed..b5554a59db5 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -77,6 +77,14 @@ const MAX_THREE_B: u32 = 0x10000; #[stable(feature = "rust1", since = "1.0.0")] pub const MAX: char = '\u{10ffff}'; +/// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a +/// decoding error. +/// +/// It can occur, for example, when giving ill-formed UTF-8 bytes to +/// [`String::from_utf8_lossy`](../../std/string/struct.String.html#method.from_utf8_lossy). +#[stable(feature = "decode_utf16", since = "1.9.0")] +pub const REPLACEMENT_CHARACTER: char = '\u{FFFD}'; + /// Converts a `u32` to a `char`. /// /// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index 33e47ade8cb..460f83d875a 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -38,6 +38,8 @@ use tables::{conversions, derived_property, general_category, property}; pub use core::char::{MAX, from_digit, from_u32, from_u32_unchecked}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::char::{EscapeDebug, EscapeDefault, EscapeUnicode}; +#[stable(feature = "decode_utf16", since = "1.9.0")] +pub use core::char::REPLACEMENT_CHARACTER; #[stable(feature = "char_from_str", since = "1.20.0")] pub use core::char::ParseCharError; @@ -1581,11 +1583,3 @@ impl fmt::Display for DecodeUtf16Error { write!(f, "unpaired surrogate found: {:x}", self.code) } } - -/// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a -/// decoding error. -/// -/// It can occur, for example, when giving ill-formed UTF-8 bytes to -/// [`String::from_utf8_lossy`](../../std/string/struct.String.html#method.from_utf8_lossy). -#[stable(feature = "decode_utf16", since = "1.9.0")] -pub const REPLACEMENT_CHARACTER: char = '\u{FFFD}'; -- cgit 1.4.1-3-g733a5 From f87d4a15a82a76e7510629173c366d084f2c02ca Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 5 Apr 2018 15:55:28 +0200 Subject: Move Utf8Lossy decoder to libcore --- src/liballoc/string.rs | 2 +- src/libcore/str/lossy.rs | 212 +++++++++++++++++++++++++++++++++++ src/libcore/str/mod.rs | 4 + src/libcore/tests/lib.rs | 2 + src/libcore/tests/str_lossy.rs | 91 +++++++++++++++ src/libstd/sys/redox/os_str.rs | 2 +- src/libstd/sys/unix/os_str.rs | 2 +- src/libstd/sys/wasm/os_str.rs | 2 +- src/libstd/sys_common/bytestring.rs | 2 +- src/libstd_unicode/Cargo.toml | 4 - src/libstd_unicode/lib.rs | 1 - src/libstd_unicode/lossy.rs | 213 ------------------------------------ src/libstd_unicode/tests/lib.rs | 15 --- src/libstd_unicode/tests/lossy.rs | 91 --------------- 14 files changed, 314 insertions(+), 329 deletions(-) create mode 100644 src/libcore/str/lossy.rs create mode 100644 src/libcore/tests/str_lossy.rs delete mode 100644 src/libstd_unicode/lossy.rs delete mode 100644 src/libstd_unicode/tests/lib.rs delete mode 100644 src/libstd_unicode/tests/lossy.rs (limited to 'src/libcore') diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index b95aae02894..5f90e28cb3c 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -63,7 +63,7 @@ use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds}; use core::ptr; use core::str::pattern::Pattern; -use std_unicode::lossy; +use core::str::lossy; use std_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; use borrow::{Cow, ToOwned}; diff --git a/src/libcore/str/lossy.rs b/src/libcore/str/lossy.rs new file mode 100644 index 00000000000..30b7267da7c --- /dev/null +++ b/src/libcore/str/lossy.rs @@ -0,0 +1,212 @@ +// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use char; +use str as core_str; +use fmt; +use fmt::Write; +use mem; + +/// Lossy UTF-8 string. +#[unstable(feature = "str_internals", issue = "0")] +pub struct Utf8Lossy { + bytes: [u8] +} + +impl Utf8Lossy { + pub fn from_str(s: &str) -> &Utf8Lossy { + Utf8Lossy::from_bytes(s.as_bytes()) + } + + pub fn from_bytes(bytes: &[u8]) -> &Utf8Lossy { + unsafe { mem::transmute(bytes) } + } + + pub fn chunks(&self) -> Utf8LossyChunksIter { + Utf8LossyChunksIter { source: &self.bytes } + } +} + + +/// Iterator over lossy UTF-8 string +#[unstable(feature = "str_internals", issue = "0")] +#[allow(missing_debug_implementations)] +pub struct Utf8LossyChunksIter<'a> { + source: &'a [u8], +} + +#[unstable(feature = "str_internals", issue = "0")] +#[derive(PartialEq, Eq, Debug)] +pub struct Utf8LossyChunk<'a> { + /// Sequence of valid chars. + /// Can be empty between broken UTF-8 chars. + pub valid: &'a str, + /// Single broken char, empty if none. + /// Empty iff iterator item is last. + pub broken: &'a [u8], +} + +impl<'a> Iterator for Utf8LossyChunksIter<'a> { + type Item = Utf8LossyChunk<'a>; + + fn next(&mut self) -> Option> { + if self.source.len() == 0 { + return None; + } + + const TAG_CONT_U8: u8 = 128; + fn unsafe_get(xs: &[u8], i: usize) -> u8 { + unsafe { *xs.get_unchecked(i) } + } + fn safe_get(xs: &[u8], i: usize) -> u8 { + if i >= xs.len() { 0 } else { unsafe_get(xs, i) } + } + + let mut i = 0; + while i < self.source.len() { + let i_ = i; + + let byte = unsafe_get(self.source, i); + i += 1; + + if byte < 128 { + + } else { + let w = core_str::utf8_char_width(byte); + + macro_rules! error { () => ({ + unsafe { + let r = Utf8LossyChunk { + valid: core_str::from_utf8_unchecked(&self.source[0..i_]), + broken: &self.source[i_..i], + }; + self.source = &self.source[i..]; + return Some(r); + } + })} + + match w { + 2 => { + if safe_get(self.source, i) & 192 != TAG_CONT_U8 { + error!(); + } + i += 1; + } + 3 => { + match (byte, safe_get(self.source, i)) { + (0xE0, 0xA0 ... 0xBF) => (), + (0xE1 ... 0xEC, 0x80 ... 0xBF) => (), + (0xED, 0x80 ... 0x9F) => (), + (0xEE ... 0xEF, 0x80 ... 0xBF) => (), + _ => { + error!(); + } + } + i += 1; + if safe_get(self.source, i) & 192 != TAG_CONT_U8 { + error!(); + } + i += 1; + } + 4 => { + match (byte, safe_get(self.source, i)) { + (0xF0, 0x90 ... 0xBF) => (), + (0xF1 ... 0xF3, 0x80 ... 0xBF) => (), + (0xF4, 0x80 ... 0x8F) => (), + _ => { + error!(); + } + } + i += 1; + if safe_get(self.source, i) & 192 != TAG_CONT_U8 { + error!(); + } + i += 1; + if safe_get(self.source, i) & 192 != TAG_CONT_U8 { + error!(); + } + i += 1; + } + _ => { + error!(); + } + } + } + } + + let r = Utf8LossyChunk { + valid: unsafe { core_str::from_utf8_unchecked(self.source) }, + broken: &[], + }; + self.source = &[]; + return Some(r); + } +} + + +impl fmt::Display for Utf8Lossy { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // If we're the empty string then our iterator won't actually yield + // anything, so perform the formatting manually + if self.bytes.len() == 0 { + return "".fmt(f) + } + + for Utf8LossyChunk { valid, broken } in self.chunks() { + // If we successfully decoded the whole chunk as a valid string then + // we can return a direct formatting of the string which will also + // respect various formatting flags if possible. + if valid.len() == self.bytes.len() { + assert!(broken.is_empty()); + return valid.fmt(f) + } + + f.write_str(valid)?; + if !broken.is_empty() { + f.write_char(char::REPLACEMENT_CHARACTER)?; + } + } + Ok(()) + } +} + +impl fmt::Debug for Utf8Lossy { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_char('"')?; + + for Utf8LossyChunk { valid, broken } in self.chunks() { + + // Valid part. + // Here we partially parse UTF-8 again which is suboptimal. + { + let mut from = 0; + for (i, c) in valid.char_indices() { + let esc = c.escape_debug(); + // If char needs escaping, flush backlog so far and write, else skip + if esc.len() != 1 { + f.write_str(&valid[from..i])?; + for c in esc { + f.write_char(c)?; + } + from = i + c.len_utf8(); + } + } + f.write_str(&valid[from..])?; + } + + // Broken parts of string as hex escape. + for &b in broken { + write!(f, "\\x{:02x}", b)?; + } + } + + f.write_char('"') + } +} diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 1185b7acaae..7a97d89dcf9 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -26,6 +26,10 @@ use mem; pub mod pattern; +#[unstable(feature = "str_internals", issue = "0")] +#[allow(missing_docs)] +pub mod lossy; + /// A trait to abstract the idea of creating a new instance of a type from a /// string. /// diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index c3162899bbd..149269263dc 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -33,6 +33,7 @@ #![feature(sort_internals)] #![feature(specialization)] #![feature(step_trait)] +#![feature(str_internals)] #![feature(test)] #![feature(trusted_len)] #![feature(try_trait)] @@ -68,4 +69,5 @@ mod ptr; mod result; mod slice; mod str; +mod str_lossy; mod tuple; diff --git a/src/libcore/tests/str_lossy.rs b/src/libcore/tests/str_lossy.rs new file mode 100644 index 00000000000..69e28256da9 --- /dev/null +++ b/src/libcore/tests/str_lossy.rs @@ -0,0 +1,91 @@ +// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::str::lossy::*; + +#[test] +fn chunks() { + let mut iter = Utf8Lossy::from_bytes(b"hello").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "hello", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes("ศไทย中华Việt Nam".as_bytes()).chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "ศไทย中华Việt Nam", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"Hello\xC2 There\xFF Goodbye").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC2", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xFF", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC0", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xE6\x83", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"\xF5foo\xF5\x80bar").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF5", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF5", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"\xF1foo\xF1\x80bar\xF1\x80\x80baz").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF1", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF1\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF1\x80\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"\xF4foo\xF4\x80bar\xF4\xBFbaz").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF4", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF4\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF4", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF0", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "foo\u{10000}bar", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + // surrogates + let mut iter = Utf8Lossy::from_bytes(b"\xED\xA0\x80foo\xED\xBF\xBFbar").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xED", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xA0", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xED", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); +} + +#[test] +fn display() { + assert_eq!( + "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", + &format!("{}", Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye"))); +} + +#[test] +fn debug() { + assert_eq!( + "\"Hello\\xc0\\x80 There\\xe6\\x83 Goodbye\\u{10d4ea}\"", + &format!("{:?}", Utf8Lossy::from_bytes( + b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa"))); +} diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs index da27787babb..eb3a1ead58c 100644 --- a/src/libstd/sys/redox/os_str.rs +++ b/src/libstd/sys/redox/os_str.rs @@ -19,7 +19,7 @@ use rc::Rc; use sync::Arc; use sys_common::{AsInner, IntoInner}; use sys_common::bytestring::debug_fmt_bytestring; -use std_unicode::lossy::Utf8Lossy; +use core::str::lossy::Utf8Lossy; #[derive(Clone, Hash)] pub struct Buf { diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs index e43bc6da5f1..01c0fb830aa 100644 --- a/src/libstd/sys/unix/os_str.rs +++ b/src/libstd/sys/unix/os_str.rs @@ -19,7 +19,7 @@ use rc::Rc; use sync::Arc; use sys_common::{AsInner, IntoInner}; use sys_common::bytestring::debug_fmt_bytestring; -use std_unicode::lossy::Utf8Lossy; +use core::str::lossy::Utf8Lossy; #[derive(Clone, Hash)] pub struct Buf { diff --git a/src/libstd/sys/wasm/os_str.rs b/src/libstd/sys/wasm/os_str.rs index 84f560af69b..e0da5bdf36c 100644 --- a/src/libstd/sys/wasm/os_str.rs +++ b/src/libstd/sys/wasm/os_str.rs @@ -19,7 +19,7 @@ use rc::Rc; use sync::Arc; use sys_common::{AsInner, IntoInner}; use sys_common::bytestring::debug_fmt_bytestring; -use std_unicode::lossy::Utf8Lossy; +use core::str::lossy::Utf8Lossy; #[derive(Clone, Hash)] pub struct Buf { diff --git a/src/libstd/sys_common/bytestring.rs b/src/libstd/sys_common/bytestring.rs index eb9cad09915..971b83938c1 100644 --- a/src/libstd/sys_common/bytestring.rs +++ b/src/libstd/sys_common/bytestring.rs @@ -11,7 +11,7 @@ #![allow(dead_code)] use fmt::{Formatter, Result, Write}; -use std_unicode::lossy::{Utf8Lossy, Utf8LossyChunk}; +use core::str::lossy::{Utf8Lossy, Utf8LossyChunk}; pub fn debug_fmt_bytestring(slice: &[u8], f: &mut Formatter) -> Result { // Writes out a valid unicode string with the correct escape sequences diff --git a/src/libstd_unicode/Cargo.toml b/src/libstd_unicode/Cargo.toml index 283070a0e2c..b1c55c2e4b6 100644 --- a/src/libstd_unicode/Cargo.toml +++ b/src/libstd_unicode/Cargo.toml @@ -9,10 +9,6 @@ path = "lib.rs" test = false bench = false -[[test]] -name = "std_unicode_tests" -path = "tests/lib.rs" - [dependencies] core = { path = "../libcore" } compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index cf8c101a2f9..106a2c0f0c5 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -45,7 +45,6 @@ mod tables; mod u_str; mod version; pub mod char; -pub mod lossy; #[allow(deprecated)] pub mod str { diff --git a/src/libstd_unicode/lossy.rs b/src/libstd_unicode/lossy.rs deleted file mode 100644 index cc8e93308a5..00000000000 --- a/src/libstd_unicode/lossy.rs +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use core::str as core_str; -use core::fmt; -use core::fmt::Write; -use char; -use core::mem; - - -/// Lossy UTF-8 string. -#[unstable(feature = "str_internals", issue = "0")] -pub struct Utf8Lossy { - bytes: [u8] -} - -impl Utf8Lossy { - pub fn from_str(s: &str) -> &Utf8Lossy { - Utf8Lossy::from_bytes(s.as_bytes()) - } - - pub fn from_bytes(bytes: &[u8]) -> &Utf8Lossy { - unsafe { mem::transmute(bytes) } - } - - pub fn chunks(&self) -> Utf8LossyChunksIter { - Utf8LossyChunksIter { source: &self.bytes } - } -} - - -/// Iterator over lossy UTF-8 string -#[unstable(feature = "str_internals", issue = "0")] -#[allow(missing_debug_implementations)] -pub struct Utf8LossyChunksIter<'a> { - source: &'a [u8], -} - -#[unstable(feature = "str_internals", issue = "0")] -#[derive(PartialEq, Eq, Debug)] -pub struct Utf8LossyChunk<'a> { - /// Sequence of valid chars. - /// Can be empty between broken UTF-8 chars. - pub valid: &'a str, - /// Single broken char, empty if none. - /// Empty iff iterator item is last. - pub broken: &'a [u8], -} - -impl<'a> Iterator for Utf8LossyChunksIter<'a> { - type Item = Utf8LossyChunk<'a>; - - fn next(&mut self) -> Option> { - if self.source.len() == 0 { - return None; - } - - const TAG_CONT_U8: u8 = 128; - fn unsafe_get(xs: &[u8], i: usize) -> u8 { - unsafe { *xs.get_unchecked(i) } - } - fn safe_get(xs: &[u8], i: usize) -> u8 { - if i >= xs.len() { 0 } else { unsafe_get(xs, i) } - } - - let mut i = 0; - while i < self.source.len() { - let i_ = i; - - let byte = unsafe_get(self.source, i); - i += 1; - - if byte < 128 { - - } else { - let w = core_str::utf8_char_width(byte); - - macro_rules! error { () => ({ - unsafe { - let r = Utf8LossyChunk { - valid: core_str::from_utf8_unchecked(&self.source[0..i_]), - broken: &self.source[i_..i], - }; - self.source = &self.source[i..]; - return Some(r); - } - })} - - match w { - 2 => { - if safe_get(self.source, i) & 192 != TAG_CONT_U8 { - error!(); - } - i += 1; - } - 3 => { - match (byte, safe_get(self.source, i)) { - (0xE0, 0xA0 ... 0xBF) => (), - (0xE1 ... 0xEC, 0x80 ... 0xBF) => (), - (0xED, 0x80 ... 0x9F) => (), - (0xEE ... 0xEF, 0x80 ... 0xBF) => (), - _ => { - error!(); - } - } - i += 1; - if safe_get(self.source, i) & 192 != TAG_CONT_U8 { - error!(); - } - i += 1; - } - 4 => { - match (byte, safe_get(self.source, i)) { - (0xF0, 0x90 ... 0xBF) => (), - (0xF1 ... 0xF3, 0x80 ... 0xBF) => (), - (0xF4, 0x80 ... 0x8F) => (), - _ => { - error!(); - } - } - i += 1; - if safe_get(self.source, i) & 192 != TAG_CONT_U8 { - error!(); - } - i += 1; - if safe_get(self.source, i) & 192 != TAG_CONT_U8 { - error!(); - } - i += 1; - } - _ => { - error!(); - } - } - } - } - - let r = Utf8LossyChunk { - valid: unsafe { core_str::from_utf8_unchecked(self.source) }, - broken: &[], - }; - self.source = &[]; - return Some(r); - } -} - - -impl fmt::Display for Utf8Lossy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // If we're the empty string then our iterator won't actually yield - // anything, so perform the formatting manually - if self.bytes.len() == 0 { - return "".fmt(f) - } - - for Utf8LossyChunk { valid, broken } in self.chunks() { - // If we successfully decoded the whole chunk as a valid string then - // we can return a direct formatting of the string which will also - // respect various formatting flags if possible. - if valid.len() == self.bytes.len() { - assert!(broken.is_empty()); - return valid.fmt(f) - } - - f.write_str(valid)?; - if !broken.is_empty() { - f.write_char(char::REPLACEMENT_CHARACTER)?; - } - } - Ok(()) - } -} - -impl fmt::Debug for Utf8Lossy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_char('"')?; - - for Utf8LossyChunk { valid, broken } in self.chunks() { - - // Valid part. - // Here we partially parse UTF-8 again which is suboptimal. - { - let mut from = 0; - for (i, c) in valid.char_indices() { - let esc = c.escape_debug(); - // If char needs escaping, flush backlog so far and write, else skip - if esc.len() != 1 { - f.write_str(&valid[from..i])?; - for c in esc { - f.write_char(c)?; - } - from = i + c.len_utf8(); - } - } - f.write_str(&valid[from..])?; - } - - // Broken parts of string as hex escape. - for &b in broken { - write!(f, "\\x{:02x}", b)?; - } - } - - f.write_char('"') - } -} diff --git a/src/libstd_unicode/tests/lib.rs b/src/libstd_unicode/tests/lib.rs deleted file mode 100644 index 9535ec18763..00000000000 --- a/src/libstd_unicode/tests/lib.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(str_internals, unicode)] - -extern crate std_unicode; - -mod lossy; diff --git a/src/libstd_unicode/tests/lossy.rs b/src/libstd_unicode/tests/lossy.rs deleted file mode 100644 index e05d0668556..00000000000 --- a/src/libstd_unicode/tests/lossy.rs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std_unicode::lossy::*; - -#[test] -fn chunks() { - let mut iter = Utf8Lossy::from_bytes(b"hello").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "hello", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes("ศไทย中华Việt Nam".as_bytes()).chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "ศไทย中华Việt Nam", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"Hello\xC2 There\xFF Goodbye").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC2", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xFF", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC0", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xE6\x83", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"\xF5foo\xF5\x80bar").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF5", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF5", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"\xF1foo\xF1\x80bar\xF1\x80\x80baz").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF1", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF1\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF1\x80\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"\xF4foo\xF4\x80bar\xF4\xBFbaz").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF4", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF4\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF4", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF0", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo\u{10000}bar", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); - - // surrogates - let mut iter = Utf8Lossy::from_bytes(b"\xED\xA0\x80foo\xED\xBF\xBFbar").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xED", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xA0", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xED", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); -} - -#[test] -fn display() { - assert_eq!( - "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", - &format!("{}", Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye"))); -} - -#[test] -fn debug() { - assert_eq!( - "\"Hello\\xc0\\x80 There\\xe6\\x83 Goodbye\\u{10d4ea}\"", - &format!("{:?}", Utf8Lossy::from_bytes( - b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa"))); -} -- cgit 1.4.1-3-g733a5 From 5807be7ccb2c14df9db87a54038221bbf5ae00fa Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 5 Apr 2018 17:09:28 +0200 Subject: Move contents of libstd_unicode into libcore --- src/libcore/lib.rs | 2 + src/libcore/unicode/bool_trie.rs | 76 + src/libcore/unicode/char.rs | 1585 +++++++++++++ src/libcore/unicode/mod.rs | 29 + src/libcore/unicode/str.rs | 189 ++ src/libcore/unicode/tables.rs | 2375 +++++++++++++++++++ src/libcore/unicode/unicode.py | 501 +++++ src/libcore/unicode/version.rs | 27 + src/libstd_unicode/bool_trie.rs | 76 - src/libstd_unicode/char.rs | 1585 ------------- src/libstd_unicode/lib.rs | 32 +- src/libstd_unicode/tables.rs | 2378 -------------------- src/libstd_unicode/u_str.rs | 189 -- src/libstd_unicode/unicode.py | 504 ----- src/libstd_unicode/version.rs | 27 - .../compile-fail/single-primitive-inherent-impl.rs | 8 +- 16 files changed, 4790 insertions(+), 4793 deletions(-) create mode 100644 src/libcore/unicode/bool_trie.rs create mode 100644 src/libcore/unicode/char.rs create mode 100644 src/libcore/unicode/mod.rs create mode 100644 src/libcore/unicode/str.rs create mode 100644 src/libcore/unicode/tables.rs create mode 100755 src/libcore/unicode/unicode.py create mode 100644 src/libcore/unicode/version.rs delete mode 100644 src/libstd_unicode/bool_trie.rs delete mode 100644 src/libstd_unicode/char.rs delete mode 100644 src/libstd_unicode/tables.rs delete mode 100644 src/libstd_unicode/u_str.rs delete mode 100755 src/libstd_unicode/unicode.py delete mode 100644 src/libstd_unicode/version.rs (limited to 'src/libcore') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index e194b173aa7..7cb635a299a 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -180,6 +180,8 @@ pub mod hash; pub mod fmt; pub mod time; +pub mod unicode; + /* Heap memory allocator trait */ #[allow(missing_docs)] pub mod heap; diff --git a/src/libcore/unicode/bool_trie.rs b/src/libcore/unicode/bool_trie.rs new file mode 100644 index 00000000000..3e45b08f399 --- /dev/null +++ b/src/libcore/unicode/bool_trie.rs @@ -0,0 +1,76 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// BoolTrie is a trie for representing a set of Unicode codepoints. It is +/// implemented with postfix compression (sharing of identical child nodes), +/// which gives both compact size and fast lookup. +/// +/// The space of Unicode codepoints is divided into 3 subareas, each +/// represented by a trie with different depth. In the first (0..0x800), there +/// is no trie structure at all; each u64 entry corresponds to a bitvector +/// effectively holding 64 bool values. +/// +/// In the second (0x800..0x10000), each child of the root node represents a +/// 64-wide subrange, but instead of storing the full 64-bit value of the leaf, +/// the trie stores an 8-bit index into a shared table of leaf values. This +/// exploits the fact that in reasonable sets, many such leaves can be shared. +/// +/// In the third (0x10000..0x110000), each child of the root node represents a +/// 4096-wide subrange, and the trie stores an 8-bit index into a 64-byte slice +/// of a child tree. Each of these 64 bytes represents an index into the table +/// of shared 64-bit leaf values. This exploits the sparse structure in the +/// non-BMP range of most Unicode sets. +pub struct BoolTrie { + // 0..0x800 (corresponding to 1 and 2 byte utf-8 sequences) + pub r1: [u64; 32], // leaves + + // 0x800..0x10000 (corresponding to 3 byte utf-8 sequences) + pub r2: [u8; 992], // first level + pub r3: &'static [u64], // leaves + + // 0x10000..0x110000 (corresponding to 4 byte utf-8 sequences) + pub r4: [u8; 256], // first level + pub r5: &'static [u8], // second level + pub r6: &'static [u64], // leaves +} +impl BoolTrie { + pub fn lookup(&self, c: char) -> bool { + let c = c as usize; + if c < 0x800 { + trie_range_leaf(c, self.r1[c >> 6]) + } else if c < 0x10000 { + let child = self.r2[(c >> 6) - 0x20]; + trie_range_leaf(c, self.r3[child as usize]) + } else { + let child = self.r4[(c >> 12) - 0x10]; + let leaf = self.r5[((child as usize) << 6) + ((c >> 6) & 0x3f)]; + trie_range_leaf(c, self.r6[leaf as usize]) + } + } +} + +pub struct SmallBoolTrie { + pub(crate) r1: &'static [u8], // first level + pub(crate) r2: &'static [u64], // leaves +} + +impl SmallBoolTrie { + pub fn lookup(&self, c: char) -> bool { + let c = c as usize; + match self.r1.get(c >> 6) { + Some(&child) => trie_range_leaf(c, self.r2[child as usize]), + None => false, + } + } +} + +fn trie_range_leaf(c: usize, bitmap_chunk: u64) -> bool { + ((bitmap_chunk >> (c & 63)) & 1) != 0 +} diff --git a/src/libcore/unicode/char.rs b/src/libcore/unicode/char.rs new file mode 100644 index 00000000000..0e8b09f621a --- /dev/null +++ b/src/libcore/unicode/char.rs @@ -0,0 +1,1585 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A character type. +//! +//! The `char` type represents a single character. More specifically, since +//! 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode +//! scalar value]', which is similar to, but not the same as, a '[Unicode code +//! point]'. +//! +//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value +//! [Unicode code point]: http://www.unicode.org/glossary/#code_point +//! +//! This module exists for technical reasons, the primary documentation for +//! `char` is directly on [the `char` primitive type](../../std/primitive.char.html) +//! itself. +//! +//! This module is the home of the iterator implementations for the iterators +//! implemented on `char`, as well as some useful constants and conversion +//! functions that convert various types to `char`. + +#![stable(feature = "rust1", since = "1.0.0")] + +use char::CharExt as C; +use iter::FusedIterator; +use fmt::{self, Write}; +use unicode::tables::{conversions, derived_property, general_category, property}; + +// stable re-exports +#[stable(feature = "rust1", since = "1.0.0")] +pub use char::{MAX, from_digit, from_u32, from_u32_unchecked}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use char::{EscapeDebug, EscapeDefault, EscapeUnicode}; +#[stable(feature = "decode_utf16", since = "1.9.0")] +pub use char::REPLACEMENT_CHARACTER; +#[stable(feature = "char_from_str", since = "1.20.0")] +pub use char::ParseCharError; + +// unstable re-exports +#[stable(feature = "try_from", since = "1.26.0")] +pub use char::CharTryFromError; +#[unstable(feature = "decode_utf8", issue = "33906")] +pub use char::{DecodeUtf8, decode_utf8}; +#[unstable(feature = "unicode", issue = "27783")] +pub use unicode::tables::{UNICODE_VERSION}; +#[unstable(feature = "unicode", issue = "27783")] +pub use unicode::version::UnicodeVersion; + +/// Returns an iterator that yields the lowercase equivalent of a `char`. +/// +/// This `struct` is created by the [`to_lowercase`] method on [`char`]. See +/// its documentation for more. +/// +/// [`to_lowercase`]: ../../std/primitive.char.html#method.to_lowercase +/// [`char`]: ../../std/primitive.char.html +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug, Clone)] +pub struct ToLowercase(CaseMappingIter); + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for ToLowercase { + type Item = char; + fn next(&mut self) -> Option { + self.0.next() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for ToLowercase {} + +/// Returns an iterator that yields the uppercase equivalent of a `char`. +/// +/// This `struct` is created by the [`to_uppercase`] method on [`char`]. See +/// its documentation for more. +/// +/// [`to_uppercase`]: ../../std/primitive.char.html#method.to_uppercase +/// [`char`]: ../../std/primitive.char.html +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug, Clone)] +pub struct ToUppercase(CaseMappingIter); + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for ToUppercase { + type Item = char; + fn next(&mut self) -> Option { + self.0.next() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for ToUppercase {} + +#[derive(Debug, Clone)] +enum CaseMappingIter { + Three(char, char, char), + Two(char, char), + One(char), + Zero, +} + +impl CaseMappingIter { + fn new(chars: [char; 3]) -> CaseMappingIter { + if chars[2] == '\0' { + if chars[1] == '\0' { + CaseMappingIter::One(chars[0]) // Including if chars[0] == '\0' + } else { + CaseMappingIter::Two(chars[0], chars[1]) + } + } else { + CaseMappingIter::Three(chars[0], chars[1], chars[2]) + } + } +} + +impl Iterator for CaseMappingIter { + type Item = char; + fn next(&mut self) -> Option { + match *self { + CaseMappingIter::Three(a, b, c) => { + *self = CaseMappingIter::Two(b, c); + Some(a) + } + CaseMappingIter::Two(b, c) => { + *self = CaseMappingIter::One(c); + Some(b) + } + CaseMappingIter::One(c) => { + *self = CaseMappingIter::Zero; + Some(c) + } + CaseMappingIter::Zero => None, + } + } +} + +impl fmt::Display for CaseMappingIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + CaseMappingIter::Three(a, b, c) => { + f.write_char(a)?; + f.write_char(b)?; + f.write_char(c) + } + CaseMappingIter::Two(b, c) => { + f.write_char(b)?; + f.write_char(c) + } + CaseMappingIter::One(c) => { + f.write_char(c) + } + CaseMappingIter::Zero => Ok(()), + } + } +} + +#[stable(feature = "char_struct_display", since = "1.16.0")] +impl fmt::Display for ToLowercase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +#[stable(feature = "char_struct_display", since = "1.16.0")] +impl fmt::Display for ToUppercase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +#[lang = "char"] +impl char { + /// Checks if a `char` is a digit in the given radix. + /// + /// A 'radix' here is sometimes also called a 'base'. A radix of two + /// indicates a binary number, a radix of ten, decimal, and a radix of + /// sixteen, hexadecimal, to give some common values. Arbitrary + /// radices are supported. + /// + /// Compared to `is_numeric()`, this function only recognizes the characters + /// `0-9`, `a-z` and `A-Z`. + /// + /// 'Digit' is defined to be only the following characters: + /// + /// * `0-9` + /// * `a-z` + /// * `A-Z` + /// + /// For a more comprehensive understanding of 'digit', see [`is_numeric`][is_numeric]. + /// + /// [is_numeric]: #method.is_numeric + /// + /// # Panics + /// + /// Panics if given a radix larger than 36. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert!('1'.is_digit(10)); + /// assert!('f'.is_digit(16)); + /// assert!(!'f'.is_digit(10)); + /// ``` + /// + /// Passing a large radix, causing a panic: + /// + /// ``` + /// use std::thread; + /// + /// let result = thread::spawn(|| { + /// // this panics + /// '1'.is_digit(37); + /// }).join(); + /// + /// assert!(result.is_err()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_digit(self, radix: u32) -> bool { + C::is_digit(self, radix) + } + + /// Converts a `char` to a digit in the given radix. + /// + /// A 'radix' here is sometimes also called a 'base'. A radix of two + /// indicates a binary number, a radix of ten, decimal, and a radix of + /// sixteen, hexadecimal, to give some common values. Arbitrary + /// radices are supported. + /// + /// 'Digit' is defined to be only the following characters: + /// + /// * `0-9` + /// * `a-z` + /// * `A-Z` + /// + /// # Errors + /// + /// Returns `None` if the `char` does not refer to a digit in the given radix. + /// + /// # Panics + /// + /// Panics if given a radix larger than 36. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert_eq!('1'.to_digit(10), Some(1)); + /// assert_eq!('f'.to_digit(16), Some(15)); + /// ``` + /// + /// Passing a non-digit results in failure: + /// + /// ``` + /// assert_eq!('f'.to_digit(10), None); + /// assert_eq!('z'.to_digit(16), None); + /// ``` + /// + /// Passing a large radix, causing a panic: + /// + /// ``` + /// use std::thread; + /// + /// let result = thread::spawn(|| { + /// '1'.to_digit(37); + /// }).join(); + /// + /// assert!(result.is_err()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_digit(self, radix: u32) -> Option { + C::to_digit(self, radix) + } + + /// Returns an iterator that yields the hexadecimal Unicode escape of a + /// character as `char`s. + /// + /// This will escape characters with the Rust syntax of the form + /// `\u{NNNNNN}` where `NNNNNN` is a hexadecimal representation. + /// + /// # Examples + /// + /// As an iterator: + /// + /// ``` + /// for c in '❤'.escape_unicode() { + /// print!("{}", c); + /// } + /// println!(); + /// ``` + /// + /// Using `println!` directly: + /// + /// ``` + /// println!("{}", '❤'.escape_unicode()); + /// ``` + /// + /// Both are equivalent to: + /// + /// ``` + /// println!("\\u{{2764}}"); + /// ``` + /// + /// Using `to_string`: + /// + /// ``` + /// assert_eq!('❤'.escape_unicode().to_string(), "\\u{2764}"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn escape_unicode(self) -> EscapeUnicode { + C::escape_unicode(self) + } + + /// Returns an iterator that yields the literal escape code of a character + /// as `char`s. + /// + /// This will escape the characters similar to the `Debug` implementations + /// of `str` or `char`. + /// + /// # Examples + /// + /// As an iterator: + /// + /// ``` + /// for c in '\n'.escape_debug() { + /// print!("{}", c); + /// } + /// println!(); + /// ``` + /// + /// Using `println!` directly: + /// + /// ``` + /// println!("{}", '\n'.escape_debug()); + /// ``` + /// + /// Both are equivalent to: + /// + /// ``` + /// println!("\\n"); + /// ``` + /// + /// Using `to_string`: + /// + /// ``` + /// assert_eq!('\n'.escape_debug().to_string(), "\\n"); + /// ``` + #[stable(feature = "char_escape_debug", since = "1.20.0")] + #[inline] + pub fn escape_debug(self) -> EscapeDebug { + C::escape_debug(self) + } + + /// Returns an iterator that yields the literal escape code of a character + /// as `char`s. + /// + /// The default is chosen with a bias toward producing literals that are + /// legal in a variety of languages, including C++11 and similar C-family + /// languages. The exact rules are: + /// + /// * Tab is escaped as `\t`. + /// * Carriage return is escaped as `\r`. + /// * Line feed is escaped as `\n`. + /// * Single quote is escaped as `\'`. + /// * Double quote is escaped as `\"`. + /// * Backslash is escaped as `\\`. + /// * Any character in the 'printable ASCII' range `0x20` .. `0x7e` + /// inclusive is not escaped. + /// * All other characters are given hexadecimal Unicode escapes; see + /// [`escape_unicode`][escape_unicode]. + /// + /// [escape_unicode]: #method.escape_unicode + /// + /// # Examples + /// + /// As an iterator: + /// + /// ``` + /// for c in '"'.escape_default() { + /// print!("{}", c); + /// } + /// println!(); + /// ``` + /// + /// Using `println!` directly: + /// + /// ``` + /// println!("{}", '"'.escape_default()); + /// ``` + /// + /// + /// Both are equivalent to: + /// + /// ``` + /// println!("\\\""); + /// ``` + /// + /// Using `to_string`: + /// + /// ``` + /// assert_eq!('"'.escape_default().to_string(), "\\\""); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn escape_default(self) -> EscapeDefault { + C::escape_default(self) + } + + /// Returns the number of bytes this `char` would need if encoded in UTF-8. + /// + /// That number of bytes is always between 1 and 4, inclusive. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let len = 'A'.len_utf8(); + /// assert_eq!(len, 1); + /// + /// let len = 'ß'.len_utf8(); + /// assert_eq!(len, 2); + /// + /// let len = 'ℝ'.len_utf8(); + /// assert_eq!(len, 3); + /// + /// let len = '💣'.len_utf8(); + /// assert_eq!(len, 4); + /// ``` + /// + /// The `&str` type guarantees that its contents are UTF-8, and so we can compare the length it + /// would take if each code point was represented as a `char` vs in the `&str` itself: + /// + /// ``` + /// // as chars + /// let eastern = '東'; + /// let capitol = '京'; + /// + /// // both can be represented as three bytes + /// assert_eq!(3, eastern.len_utf8()); + /// assert_eq!(3, capitol.len_utf8()); + /// + /// // as a &str, these two are encoded in UTF-8 + /// let tokyo = "東京"; + /// + /// let len = eastern.len_utf8() + capitol.len_utf8(); + /// + /// // we can see that they take six bytes total... + /// assert_eq!(6, tokyo.len()); + /// + /// // ... just like the &str + /// assert_eq!(len, tokyo.len()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn len_utf8(self) -> usize { + C::len_utf8(self) + } + + /// Returns the number of 16-bit code units this `char` would need if + /// encoded in UTF-16. + /// + /// See the documentation for [`len_utf8`] for more explanation of this + /// concept. This function is a mirror, but for UTF-16 instead of UTF-8. + /// + /// [`len_utf8`]: #method.len_utf8 + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let n = 'ß'.len_utf16(); + /// assert_eq!(n, 1); + /// + /// let len = '💣'.len_utf16(); + /// assert_eq!(len, 2); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn len_utf16(self) -> usize { + C::len_utf16(self) + } + + /// Encodes this character as UTF-8 into the provided byte buffer, + /// and then returns the subslice of the buffer that contains the encoded character. + /// + /// # Panics + /// + /// Panics if the buffer is not large enough. + /// A buffer of length four is large enough to encode any `char`. + /// + /// # Examples + /// + /// In both of these examples, 'ß' takes two bytes to encode. + /// + /// ``` + /// let mut b = [0; 2]; + /// + /// let result = 'ß'.encode_utf8(&mut b); + /// + /// assert_eq!(result, "ß"); + /// + /// assert_eq!(result.len(), 2); + /// ``` + /// + /// A buffer that's too small: + /// + /// ``` + /// use std::thread; + /// + /// let result = thread::spawn(|| { + /// let mut b = [0; 1]; + /// + /// // this panics + /// 'ß'.encode_utf8(&mut b); + /// }).join(); + /// + /// assert!(result.is_err()); + /// ``` + #[stable(feature = "unicode_encode_char", since = "1.15.0")] + #[inline] + pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str { + C::encode_utf8(self, dst) + } + + /// Encodes this character as UTF-16 into the provided `u16` buffer, + /// and then returns the subslice of the buffer that contains the encoded character. + /// + /// # Panics + /// + /// Panics if the buffer is not large enough. + /// A buffer of length 2 is large enough to encode any `char`. + /// + /// # Examples + /// + /// In both of these examples, '𝕊' takes two `u16`s to encode. + /// + /// ``` + /// let mut b = [0; 2]; + /// + /// let result = '𝕊'.encode_utf16(&mut b); + /// + /// assert_eq!(result.len(), 2); + /// ``` + /// + /// A buffer that's too small: + /// + /// ``` + /// use std::thread; + /// + /// let result = thread::spawn(|| { + /// let mut b = [0; 1]; + /// + /// // this panics + /// '𝕊'.encode_utf16(&mut b); + /// }).join(); + /// + /// assert!(result.is_err()); + /// ``` + #[stable(feature = "unicode_encode_char", since = "1.15.0")] + #[inline] + pub fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { + C::encode_utf16(self, dst) + } + + /// Returns true if this `char` is an alphabetic code point, and false if not. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert!('a'.is_alphabetic()); + /// assert!('京'.is_alphabetic()); + /// + /// let c = '💝'; + /// // love is many things, but it is not alphabetic + /// assert!(!c.is_alphabetic()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_alphabetic(self) -> bool { + match self { + 'a'...'z' | 'A'...'Z' => true, + c if c > '\x7f' => derived_property::Alphabetic(c), + _ => false, + } + } + + /// Returns true if this `char` satisfies the 'XID_Start' Unicode property, and false + /// otherwise. + /// + /// 'XID_Start' is a Unicode Derived Property specified in + /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), + /// mostly similar to `ID_Start` but modified for closure under `NFKx`. + #[unstable(feature = "rustc_private", + reason = "mainly needed for compiler internals", + issue = "27812")] + #[inline] + pub fn is_xid_start(self) -> bool { + derived_property::XID_Start(self) + } + + /// Returns true if this `char` satisfies the 'XID_Continue' Unicode property, and false + /// otherwise. + /// + /// 'XID_Continue' is a Unicode Derived Property specified in + /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), + /// mostly similar to 'ID_Continue' but modified for closure under NFKx. + #[unstable(feature = "rustc_private", + reason = "mainly needed for compiler internals", + issue = "27812")] + #[inline] + pub fn is_xid_continue(self) -> bool { + derived_property::XID_Continue(self) + } + + /// Returns true if this `char` is lowercase, and false otherwise. + /// + /// 'Lowercase' is defined according to the terms of the Unicode Derived Core + /// Property `Lowercase`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert!('a'.is_lowercase()); + /// assert!('δ'.is_lowercase()); + /// assert!(!'A'.is_lowercase()); + /// assert!(!'Δ'.is_lowercase()); + /// + /// // The various Chinese scripts do not have case, and so: + /// assert!(!'中'.is_lowercase()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_lowercase(self) -> bool { + match self { + 'a'...'z' => true, + c if c > '\x7f' => derived_property::Lowercase(c), + _ => false, + } + } + + /// Returns true if this `char` is uppercase, and false otherwise. + /// + /// 'Uppercase' is defined according to the terms of the Unicode Derived Core + /// Property `Uppercase`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert!(!'a'.is_uppercase()); + /// assert!(!'δ'.is_uppercase()); + /// assert!('A'.is_uppercase()); + /// assert!('Δ'.is_uppercase()); + /// + /// // The various Chinese scripts do not have case, and so: + /// assert!(!'中'.is_uppercase()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_uppercase(self) -> bool { + match self { + 'A'...'Z' => true, + c if c > '\x7f' => derived_property::Uppercase(c), + _ => false, + } + } + + /// Returns true if this `char` is whitespace, and false otherwise. + /// + /// 'Whitespace' is defined according to the terms of the Unicode Derived Core + /// Property `White_Space`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert!(' '.is_whitespace()); + /// + /// // a non-breaking space + /// assert!('\u{A0}'.is_whitespace()); + /// + /// assert!(!'越'.is_whitespace()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_whitespace(self) -> bool { + match self { + ' ' | '\x09'...'\x0d' => true, + c if c > '\x7f' => property::White_Space(c), + _ => false, + } + } + + /// Returns true if this `char` is alphanumeric, and false otherwise. + /// + /// 'Alphanumeric'-ness is defined in terms of the Unicode General Categories + /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert!('٣'.is_alphanumeric()); + /// assert!('7'.is_alphanumeric()); + /// assert!('৬'.is_alphanumeric()); + /// assert!('K'.is_alphanumeric()); + /// assert!('و'.is_alphanumeric()); + /// assert!('藏'.is_alphanumeric()); + /// assert!(!'¾'.is_alphanumeric()); + /// assert!(!'①'.is_alphanumeric()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_alphanumeric(self) -> bool { + self.is_alphabetic() || self.is_numeric() + } + + /// Returns true if this `char` is a control code point, and false otherwise. + /// + /// 'Control code point' is defined in terms of the Unicode General + /// Category `Cc`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // U+009C, STRING TERMINATOR + /// assert!('œ'.is_control()); + /// assert!(!'q'.is_control()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_control(self) -> bool { + general_category::Cc(self) + } + + /// Returns true if this `char` is numeric, and false otherwise. + /// + /// 'Numeric'-ness is defined in terms of the Unicode General Categories + /// 'Nd', 'Nl', 'No'. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert!('٣'.is_numeric()); + /// assert!('7'.is_numeric()); + /// assert!('৬'.is_numeric()); + /// assert!(!'K'.is_numeric()); + /// assert!(!'و'.is_numeric()); + /// assert!(!'藏'.is_numeric()); + /// assert!(!'¾'.is_numeric()); + /// assert!(!'①'.is_numeric()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_numeric(self) -> bool { + match self { + '0'...'9' => true, + c if c > '\x7f' => general_category::N(c), + _ => false, + } + } + + /// Returns an iterator that yields the lowercase equivalent of a `char` + /// as one or more `char`s. + /// + /// If a character does not have a lowercase equivalent, the same character + /// will be returned back by the iterator. + /// + /// This performs complex unconditional mappings with no tailoring: it maps + /// one Unicode character to its lowercase equivalent according to the + /// [Unicode database] and the additional complex mappings + /// [`SpecialCasing.txt`]. Conditional mappings (based on context or + /// language) are not considered here. + /// + /// For a full reference, see [here][reference]. + /// + /// [Unicode database]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt + /// + /// [`SpecialCasing.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt + /// + /// [reference]: http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 + /// + /// # Examples + /// + /// As an iterator: + /// + /// ``` + /// for c in 'İ'.to_lowercase() { + /// print!("{}", c); + /// } + /// println!(); + /// ``` + /// + /// Using `println!` directly: + /// + /// ``` + /// println!("{}", 'İ'.to_lowercase()); + /// ``` + /// + /// Both are equivalent to: + /// + /// ``` + /// println!("i\u{307}"); + /// ``` + /// + /// Using `to_string`: + /// + /// ``` + /// assert_eq!('C'.to_lowercase().to_string(), "c"); + /// + /// // Sometimes the result is more than one character: + /// assert_eq!('İ'.to_lowercase().to_string(), "i\u{307}"); + /// + /// // Characters that do not have both uppercase and lowercase + /// // convert into themselves. + /// assert_eq!('山'.to_lowercase().to_string(), "山"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_lowercase(self) -> ToLowercase { + ToLowercase(CaseMappingIter::new(conversions::to_lower(self))) + } + + /// Returns an iterator that yields the uppercase equivalent of a `char` + /// as one or more `char`s. + /// + /// If a character does not have an uppercase equivalent, the same character + /// will be returned back by the iterator. + /// + /// This performs complex unconditional mappings with no tailoring: it maps + /// one Unicode character to its uppercase equivalent according to the + /// [Unicode database] and the additional complex mappings + /// [`SpecialCasing.txt`]. Conditional mappings (based on context or + /// language) are not considered here. + /// + /// For a full reference, see [here][reference]. + /// + /// [Unicode database]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt + /// + /// [`SpecialCasing.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt + /// + /// [reference]: http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 + /// + /// # Examples + /// + /// As an iterator: + /// + /// ``` + /// for c in 'ß'.to_uppercase() { + /// print!("{}", c); + /// } + /// println!(); + /// ``` + /// + /// Using `println!` directly: + /// + /// ``` + /// println!("{}", 'ß'.to_uppercase()); + /// ``` + /// + /// Both are equivalent to: + /// + /// ``` + /// println!("SS"); + /// ``` + /// + /// Using `to_string`: + /// + /// ``` + /// assert_eq!('c'.to_uppercase().to_string(), "C"); + /// + /// // Sometimes the result is more than one character: + /// assert_eq!('ß'.to_uppercase().to_string(), "SS"); + /// + /// // Characters that do not have both uppercase and lowercase + /// // convert into themselves. + /// assert_eq!('山'.to_uppercase().to_string(), "山"); + /// ``` + /// + /// # Note on locale + /// + /// In Turkish, the equivalent of 'i' in Latin has five forms instead of two: + /// + /// * 'Dotless': I / ı, sometimes written ï + /// * 'Dotted': İ / i + /// + /// Note that the lowercase dotted 'i' is the same as the Latin. Therefore: + /// + /// ``` + /// let upper_i = 'i'.to_uppercase().to_string(); + /// ``` + /// + /// The value of `upper_i` here relies on the language of the text: if we're + /// in `en-US`, it should be `"I"`, but if we're in `tr_TR`, it should + /// be `"İ"`. `to_uppercase()` does not take this into account, and so: + /// + /// ``` + /// let upper_i = 'i'.to_uppercase().to_string(); + /// + /// assert_eq!(upper_i, "I"); + /// ``` + /// + /// holds across languages. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_uppercase(self) -> ToUppercase { + ToUppercase(CaseMappingIter::new(conversions::to_upper(self))) + } + + /// Checks if the value is within the ASCII range. + /// + /// # Examples + /// + /// ``` + /// let ascii = 'a'; + /// let non_ascii = '❤'; + /// + /// assert!(ascii.is_ascii()); + /// assert!(!non_ascii.is_ascii()); + /// ``` + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn is_ascii(&self) -> bool { + *self as u32 <= 0x7F + } + + /// Makes a copy of the value in its ASCII upper case equivalent. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To uppercase the value in-place, use [`make_ascii_uppercase`]. + /// + /// To uppercase ASCII characters in addition to non-ASCII characters, use + /// [`to_uppercase`]. + /// + /// # Examples + /// + /// ``` + /// let ascii = 'a'; + /// let non_ascii = '❤'; + /// + /// assert_eq!('A', ascii.to_ascii_uppercase()); + /// assert_eq!('❤', non_ascii.to_ascii_uppercase()); + /// ``` + /// + /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase + /// [`to_uppercase`]: #method.to_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn to_ascii_uppercase(&self) -> char { + if self.is_ascii() { + (*self as u8).to_ascii_uppercase() as char + } else { + *self + } + } + + /// Makes a copy of the value in its ASCII lower case equivalent. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To lowercase the value in-place, use [`make_ascii_lowercase`]. + /// + /// To lowercase ASCII characters in addition to non-ASCII characters, use + /// [`to_lowercase`]. + /// + /// # Examples + /// + /// ``` + /// let ascii = 'A'; + /// let non_ascii = '❤'; + /// + /// assert_eq!('a', ascii.to_ascii_lowercase()); + /// assert_eq!('❤', non_ascii.to_ascii_lowercase()); + /// ``` + /// + /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase + /// [`to_lowercase`]: #method.to_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn to_ascii_lowercase(&self) -> char { + if self.is_ascii() { + (*self as u8).to_ascii_lowercase() as char + } else { + *self + } + } + + /// Checks that two values are an ASCII case-insensitive match. + /// + /// Equivalent to `to_ascii_lowercase(a) == to_ascii_lowercase(b)`. + /// + /// # Examples + /// + /// ``` + /// let upper_a = 'A'; + /// let lower_a = 'a'; + /// let lower_z = 'z'; + /// + /// assert!(upper_a.eq_ignore_ascii_case(&lower_a)); + /// assert!(upper_a.eq_ignore_ascii_case(&upper_a)); + /// assert!(!upper_a.eq_ignore_ascii_case(&lower_z)); + /// ``` + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn eq_ignore_ascii_case(&self, other: &char) -> bool { + self.to_ascii_lowercase() == other.to_ascii_lowercase() + } + + /// Converts this type to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`to_ascii_uppercase`]. + /// + /// # Examples + /// + /// ``` + /// let mut ascii = 'a'; + /// + /// ascii.make_ascii_uppercase(); + /// + /// assert_eq!('A', ascii); + /// ``` + /// + /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn make_ascii_uppercase(&mut self) { + *self = self.to_ascii_uppercase(); + } + + /// Converts this type to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`to_ascii_lowercase`]. + /// + /// # Examples + /// + /// ``` + /// let mut ascii = 'A'; + /// + /// ascii.make_ascii_lowercase(); + /// + /// assert_eq!('a', ascii); + /// ``` + /// + /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn make_ascii_lowercase(&mut self) { + *self = self.to_ascii_lowercase(); + } + + /// Checks if the value is an ASCII alphabetic character: + /// + /// - U+0041 'A' ... U+005A 'Z', or + /// - U+0061 'a' ... U+007A 'z'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(uppercase_a.is_ascii_alphabetic()); + /// assert!(uppercase_g.is_ascii_alphabetic()); + /// assert!(a.is_ascii_alphabetic()); + /// assert!(g.is_ascii_alphabetic()); + /// assert!(!zero.is_ascii_alphabetic()); + /// assert!(!percent.is_ascii_alphabetic()); + /// assert!(!space.is_ascii_alphabetic()); + /// assert!(!lf.is_ascii_alphabetic()); + /// assert!(!esc.is_ascii_alphabetic()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_alphabetic(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_alphabetic() + } + + /// Checks if the value is an ASCII uppercase character: + /// U+0041 'A' ... U+005A 'Z'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(uppercase_a.is_ascii_uppercase()); + /// assert!(uppercase_g.is_ascii_uppercase()); + /// assert!(!a.is_ascii_uppercase()); + /// assert!(!g.is_ascii_uppercase()); + /// assert!(!zero.is_ascii_uppercase()); + /// assert!(!percent.is_ascii_uppercase()); + /// assert!(!space.is_ascii_uppercase()); + /// assert!(!lf.is_ascii_uppercase()); + /// assert!(!esc.is_ascii_uppercase()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_uppercase(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_uppercase() + } + + /// Checks if the value is an ASCII lowercase character: + /// U+0061 'a' ... U+007A 'z'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(!uppercase_a.is_ascii_lowercase()); + /// assert!(!uppercase_g.is_ascii_lowercase()); + /// assert!(a.is_ascii_lowercase()); + /// assert!(g.is_ascii_lowercase()); + /// assert!(!zero.is_ascii_lowercase()); + /// assert!(!percent.is_ascii_lowercase()); + /// assert!(!space.is_ascii_lowercase()); + /// assert!(!lf.is_ascii_lowercase()); + /// assert!(!esc.is_ascii_lowercase()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_lowercase(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_lowercase() + } + + /// Checks if the value is an ASCII alphanumeric character: + /// + /// - U+0041 'A' ... U+005A 'Z', or + /// - U+0061 'a' ... U+007A 'z', or + /// - U+0030 '0' ... U+0039 '9'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(uppercase_a.is_ascii_alphanumeric()); + /// assert!(uppercase_g.is_ascii_alphanumeric()); + /// assert!(a.is_ascii_alphanumeric()); + /// assert!(g.is_ascii_alphanumeric()); + /// assert!(zero.is_ascii_alphanumeric()); + /// assert!(!percent.is_ascii_alphanumeric()); + /// assert!(!space.is_ascii_alphanumeric()); + /// assert!(!lf.is_ascii_alphanumeric()); + /// assert!(!esc.is_ascii_alphanumeric()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_alphanumeric(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_alphanumeric() + } + + /// Checks if the value is an ASCII decimal digit: + /// U+0030 '0' ... U+0039 '9'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(!uppercase_a.is_ascii_digit()); + /// assert!(!uppercase_g.is_ascii_digit()); + /// assert!(!a.is_ascii_digit()); + /// assert!(!g.is_ascii_digit()); + /// assert!(zero.is_ascii_digit()); + /// assert!(!percent.is_ascii_digit()); + /// assert!(!space.is_ascii_digit()); + /// assert!(!lf.is_ascii_digit()); + /// assert!(!esc.is_ascii_digit()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_digit(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_digit() + } + + /// Checks if the value is an ASCII hexadecimal digit: + /// + /// - U+0030 '0' ... U+0039 '9', or + /// - U+0041 'A' ... U+0046 'F', or + /// - U+0061 'a' ... U+0066 'f'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(uppercase_a.is_ascii_hexdigit()); + /// assert!(!uppercase_g.is_ascii_hexdigit()); + /// assert!(a.is_ascii_hexdigit()); + /// assert!(!g.is_ascii_hexdigit()); + /// assert!(zero.is_ascii_hexdigit()); + /// assert!(!percent.is_ascii_hexdigit()); + /// assert!(!space.is_ascii_hexdigit()); + /// assert!(!lf.is_ascii_hexdigit()); + /// assert!(!esc.is_ascii_hexdigit()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_hexdigit(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_hexdigit() + } + + /// Checks if the value is an ASCII punctuation character: + /// + /// - U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`, or + /// - U+003A ... U+0040 `: ; < = > ? @`, or + /// - U+005B ... U+0060 ``[ \ ] ^ _ ` ``, or + /// - U+007B ... U+007E `{ | } ~` + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(!uppercase_a.is_ascii_punctuation()); + /// assert!(!uppercase_g.is_ascii_punctuation()); + /// assert!(!a.is_ascii_punctuation()); + /// assert!(!g.is_ascii_punctuation()); + /// assert!(!zero.is_ascii_punctuation()); + /// assert!(percent.is_ascii_punctuation()); + /// assert!(!space.is_ascii_punctuation()); + /// assert!(!lf.is_ascii_punctuation()); + /// assert!(!esc.is_ascii_punctuation()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_punctuation(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_punctuation() + } + + /// Checks if the value is an ASCII graphic character: + /// U+0021 '!' ... U+007E '~'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(uppercase_a.is_ascii_graphic()); + /// assert!(uppercase_g.is_ascii_graphic()); + /// assert!(a.is_ascii_graphic()); + /// assert!(g.is_ascii_graphic()); + /// assert!(zero.is_ascii_graphic()); + /// assert!(percent.is_ascii_graphic()); + /// assert!(!space.is_ascii_graphic()); + /// assert!(!lf.is_ascii_graphic()); + /// assert!(!esc.is_ascii_graphic()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_graphic(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_graphic() + } + + /// Checks if the value is an ASCII whitespace character: + /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED, + /// U+000C FORM FEED, or U+000D CARRIAGE RETURN. + /// + /// Rust uses the WhatWG Infra Standard's [definition of ASCII + /// whitespace][infra-aw]. There are several other definitions in + /// wide use. For instance, [the POSIX locale][pct] includes + /// U+000B VERTICAL TAB as well as all the above characters, + /// but—from the very same specification—[the default rule for + /// "field splitting" in the Bourne shell][bfs] considers *only* + /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace. + /// + /// If you are writing a program that will process an existing + /// file format, check what that format's definition of whitespace is + /// before using this function. + /// + /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace + /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 + /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(!uppercase_a.is_ascii_whitespace()); + /// assert!(!uppercase_g.is_ascii_whitespace()); + /// assert!(!a.is_ascii_whitespace()); + /// assert!(!g.is_ascii_whitespace()); + /// assert!(!zero.is_ascii_whitespace()); + /// assert!(!percent.is_ascii_whitespace()); + /// assert!(space.is_ascii_whitespace()); + /// assert!(lf.is_ascii_whitespace()); + /// assert!(!esc.is_ascii_whitespace()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_whitespace(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_whitespace() + } + + /// Checks if the value is an ASCII control character: + /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE. + /// Note that most ASCII whitespace characters are control + /// characters, but SPACE is not. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(!uppercase_a.is_ascii_control()); + /// assert!(!uppercase_g.is_ascii_control()); + /// assert!(!a.is_ascii_control()); + /// assert!(!g.is_ascii_control()); + /// assert!(!zero.is_ascii_control()); + /// assert!(!percent.is_ascii_control()); + /// assert!(!space.is_ascii_control()); + /// assert!(lf.is_ascii_control()); + /// assert!(esc.is_ascii_control()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_control(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_control() + } +} + +/// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s. +#[stable(feature = "decode_utf16", since = "1.9.0")] +#[derive(Clone, Debug)] +pub struct DecodeUtf16 + where I: Iterator +{ + iter: I, + buf: Option, +} + +/// An error that can be returned when decoding UTF-16 code points. +#[stable(feature = "decode_utf16", since = "1.9.0")] +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct DecodeUtf16Error { + code: u16, +} + +/// Create an iterator over the UTF-16 encoded code points in `iter`, +/// returning unpaired surrogates as `Err`s. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::char::decode_utf16; +/// +/// fn main() { +/// // 𝄞music +/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075, +/// 0x0073, 0xDD1E, 0x0069, 0x0063, +/// 0xD834]; +/// +/// assert_eq!(decode_utf16(v.iter().cloned()) +/// .map(|r| r.map_err(|e| e.unpaired_surrogate())) +/// .collect::>(), +/// vec![Ok('𝄞'), +/// Ok('m'), Ok('u'), Ok('s'), +/// Err(0xDD1E), +/// Ok('i'), Ok('c'), +/// Err(0xD834)]); +/// } +/// ``` +/// +/// A lossy decoder can be obtained by replacing `Err` results with the replacement character: +/// +/// ``` +/// use std::char::{decode_utf16, REPLACEMENT_CHARACTER}; +/// +/// fn main() { +/// // 𝄞music +/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075, +/// 0x0073, 0xDD1E, 0x0069, 0x0063, +/// 0xD834]; +/// +/// assert_eq!(decode_utf16(v.iter().cloned()) +/// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) +/// .collect::(), +/// "𝄞mus�ic�"); +/// } +/// ``` +#[stable(feature = "decode_utf16", since = "1.9.0")] +#[inline] +pub fn decode_utf16>(iter: I) -> DecodeUtf16 { + DecodeUtf16 { + iter: iter.into_iter(), + buf: None, + } +} + +#[stable(feature = "decode_utf16", since = "1.9.0")] +impl> Iterator for DecodeUtf16 { + type Item = Result; + + fn next(&mut self) -> Option> { + let u = match self.buf.take() { + Some(buf) => buf, + None => self.iter.next()? + }; + + if u < 0xD800 || 0xDFFF < u { + // not a surrogate + Some(Ok(unsafe { from_u32_unchecked(u as u32) })) + } else if u >= 0xDC00 { + // a trailing surrogate + Some(Err(DecodeUtf16Error { code: u })) + } else { + let u2 = match self.iter.next() { + Some(u2) => u2, + // eof + None => return Some(Err(DecodeUtf16Error { code: u })), + }; + if u2 < 0xDC00 || u2 > 0xDFFF { + // not a trailing surrogate so we're not a valid + // surrogate pair, so rewind to redecode u2 next time. + self.buf = Some(u2); + return Some(Err(DecodeUtf16Error { code: u })); + } + + // all ok, so lets decode it. + let c = (((u - 0xD800) as u32) << 10 | (u2 - 0xDC00) as u32) + 0x1_0000; + Some(Ok(unsafe { from_u32_unchecked(c) })) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (low, high) = self.iter.size_hint(); + // we could be entirely valid surrogates (2 elements per + // char), or entirely non-surrogates (1 element per char) + (low / 2, high) + } +} + +impl DecodeUtf16Error { + /// Returns the unpaired surrogate which caused this error. + #[stable(feature = "decode_utf16", since = "1.9.0")] + pub fn unpaired_surrogate(&self) -> u16 { + self.code + } +} + +#[stable(feature = "decode_utf16", since = "1.9.0")] +impl fmt::Display for DecodeUtf16Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "unpaired surrogate found: {:x}", self.code) + } +} diff --git a/src/libcore/unicode/mod.rs b/src/libcore/unicode/mod.rs new file mode 100644 index 00000000000..aaf8081799f --- /dev/null +++ b/src/libcore/unicode/mod.rs @@ -0,0 +1,29 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "unicode", issue = "27783")] +#![allow(missing_docs)] + +mod bool_trie; +mod tables; +mod version; + +pub mod str; +pub mod char; + +// For use in liballoc, not re-exported in libstd. +pub mod derived_property { + pub use unicode::tables::derived_property::{Case_Ignorable, Cased}; +} + +// For use in libsyntax +pub mod property { + pub use unicode::tables::property::Pattern_White_Space; +} diff --git a/src/libcore/unicode/str.rs b/src/libcore/unicode/str.rs new file mode 100644 index 00000000000..18581bf4d58 --- /dev/null +++ b/src/libcore/unicode/str.rs @@ -0,0 +1,189 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Unicode-intensive string manipulations. +//! +//! This module provides functionality to `str` that requires the Unicode +//! methods provided by the unicode parts of the CharExt trait. + +use char; +use iter::{Filter, FusedIterator}; +use str::Split; + +/// An iterator over the non-whitespace substrings of a string, +/// separated by any amount of whitespace. +/// +/// This struct is created by the [`split_whitespace`] method on [`str`]. +/// See its documentation for more. +/// +/// [`split_whitespace`]: ../../std/primitive.str.html#method.split_whitespace +/// [`str`]: ../../std/primitive.str.html +#[stable(feature = "split_whitespace", since = "1.1.0")] +#[derive(Clone, Debug)] +pub struct SplitWhitespace<'a> { + inner: Filter, IsNotEmpty>, +} + +/// Methods for Unicode string slices +#[allow(missing_docs)] // docs in liballoc +pub trait UnicodeStr { + fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>; + fn is_whitespace(&self) -> bool; + fn is_alphanumeric(&self) -> bool; + fn trim(&self) -> &str; + fn trim_left(&self) -> &str; + fn trim_right(&self) -> &str; +} + +impl UnicodeStr for str { + #[inline] + fn split_whitespace(&self) -> SplitWhitespace { + SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } + } + + #[inline] + fn is_whitespace(&self) -> bool { + self.chars().all(|c| c.is_whitespace()) + } + + #[inline] + fn is_alphanumeric(&self) -> bool { + self.chars().all(|c| c.is_alphanumeric()) + } + + #[inline] + fn trim(&self) -> &str { + self.trim_matches(|c: char| c.is_whitespace()) + } + + #[inline] + fn trim_left(&self) -> &str { + self.trim_left_matches(|c: char| c.is_whitespace()) + } + + #[inline] + fn trim_right(&self) -> &str { + self.trim_right_matches(|c: char| c.is_whitespace()) + } +} + +/// Iterator adaptor for encoding `char`s to UTF-16. +#[derive(Clone)] +#[allow(missing_debug_implementations)] +pub struct Utf16Encoder { + chars: I, + extra: u16, +} + +impl Utf16Encoder { + /// Create a UTF-16 encoder from any `char` iterator. + pub fn new(chars: I) -> Utf16Encoder + where I: Iterator + { + Utf16Encoder { + chars, + extra: 0, + } + } +} + +impl Iterator for Utf16Encoder + where I: Iterator +{ + type Item = u16; + + #[inline] + fn next(&mut self) -> Option { + if self.extra != 0 { + let tmp = self.extra; + self.extra = 0; + return Some(tmp); + } + + let mut buf = [0; 2]; + self.chars.next().map(|ch| { + let n = CharExt::encode_utf16(ch, &mut buf).len(); + if n == 2 { + self.extra = buf[1]; + } + buf[0] + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (low, high) = self.chars.size_hint(); + // every char gets either one u16 or two u16, + // so this iterator is between 1 or 2 times as + // long as the underlying iterator. + (low, high.and_then(|n| n.checked_mul(2))) + } +} + +impl FusedIterator for Utf16Encoder + where I: FusedIterator {} + +#[derive(Clone)] +struct IsWhitespace; + +impl FnOnce<(char, )> for IsWhitespace { + type Output = bool; + + #[inline] + extern "rust-call" fn call_once(mut self, arg: (char, )) -> bool { + self.call_mut(arg) + } +} + +impl FnMut<(char, )> for IsWhitespace { + #[inline] + extern "rust-call" fn call_mut(&mut self, arg: (char, )) -> bool { + arg.0.is_whitespace() + } +} + +#[derive(Clone)] +struct IsNotEmpty; + +impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty { + type Output = bool; + + #[inline] + extern "rust-call" fn call_once(mut self, arg: (&&str, )) -> bool { + self.call_mut(arg) + } +} + +impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty { + #[inline] + extern "rust-call" fn call_mut(&mut self, arg: (&&str, )) -> bool { + !arg.0.is_empty() + } +} + + +#[stable(feature = "split_whitespace", since = "1.1.0")] +impl<'a> Iterator for SplitWhitespace<'a> { + type Item = &'a str; + + fn next(&mut self) -> Option<&'a str> { + self.inner.next() + } +} + +#[stable(feature = "split_whitespace", since = "1.1.0")] +impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { + fn next_back(&mut self) -> Option<&'a str> { + self.inner.next_back() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a> FusedIterator for SplitWhitespace<'a> {} diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs new file mode 100644 index 00000000000..7e8e925bda3 --- /dev/null +++ b/src/libcore/unicode/tables.rs @@ -0,0 +1,2375 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "./unicode.py", do not edit directly + +#![allow(missing_docs, non_upper_case_globals, non_snake_case)] + +use unicode::version::UnicodeVersion; +use unicode::bool_trie::{BoolTrie, SmallBoolTrie}; + +/// The version of [Unicode](http://www.unicode.org/) that the Unicode parts of +/// `CharExt` and `UnicodeStrPrelude` traits are based on. +pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { + major: 10, + minor: 0, + micro: 0, + _priv: (), +}; +pub mod general_category { + pub const Cc_table: &super::SmallBoolTrie = &super::SmallBoolTrie { + r1: &[ + 0, 1, 0 + ], + r2: &[ + 0x00000000ffffffff, 0x8000000000000000 + ], + }; + + pub fn Cc(c: char) -> bool { + Cc_table.lookup(c) + } + + pub const N_table: &super::BoolTrie = &super::BoolTrie { + r1: [ + 0x03ff000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x000003ff00000000, 0x0000000000000000, 0x03ff000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x00000000000003ff + ], + r2: [ + 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 3, + 0, 0, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 0, 0, 0, 3, 2, 0, 0, 0, 0, 6, 0, 2, 0, 0, 7, 0, 0, 2, 8, 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 2, 4, 0, 0, 12, 0, 2, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0 + ], + r3: &[ + 0x0000000000000000, 0x0000ffc000000000, 0x0000000003ff0000, 0x000003ff00000000, + 0x00000000000003ff, 0x0001c00000000000, 0x000000000000ffc0, 0x0000000003ff03ff, + 0x03ff000000000000, 0xffffffff00000000, 0x00000000000001e7, 0x070003fe00000080, + 0x03ff000003ff0000 + ], + r4: [ + 0, 1, 2, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 5, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 + ], + r5: &[ + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 7, 0, 0, 8, 0, 0, 0, 6, 0, 0, 0, 0, 0, 8, 0, 8, 0, 0, 0, + 0, 0, 8, 0, 9, 6, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, + 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ], + r6: &[ + 0x0000000000000000, 0x001fffffffffffff, 0x0000000000000402, 0x00000000003e0000, + 0x000003ff00000000, 0x0000ffc000000000, 0x03ff000000000000, 0xffc0000000000000, + 0x0000000003ff0000, 0x00000000000003ff, 0xffffffffffffffff, 0x00007fffffffffff, + 0xffffffffffffc000 + ], + }; + + pub fn N(c: char) -> bool { + N_table.lookup(c) + } + +} + +pub mod derived_property { + pub const Alphabetic_table: &super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, + 0x0000000000000000, 0xbcdf000000000020, 0xfffffffbffffd740, 0xffbfffffffffffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, + 0xfffeffffffffffff, 0xfffffffe027fffff, 0xbfff0000000000ff, 0x000707ffffff00b6, + 0xffffffff07ff0000, 0xffffc000feffffff, 0xffffffffffffffff, 0x9c00e1fe1fefffff, + 0xffffffffffff0000, 0xffffffffffffe000, 0x0003ffffffffffff, 0x043007fffffffc00 + ], + r2: [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 36, 36, 36, 36, 36, 36, 36, 36, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 31, 63, 64, 65, 66, 55, 67, 68, 69, 36, 36, 36, 70, 36, 36, + 36, 36, 71, 72, 73, 74, 31, 75, 76, 31, 77, 78, 68, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 79, 80, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 81, 82, 36, 83, 84, 85, 86, 87, 88, 31, 31, 31, + 31, 31, 31, 31, 89, 44, 90, 91, 92, 36, 93, 94, 31, 31, 31, 31, 31, 31, 31, 31, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 55, 31, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 95, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 96, 97, 36, 36, 36, 36, 98, 99, 36, 100, 101, 36, 102, + 103, 104, 105, 36, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 36, 95, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 117, 118, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 36, 36, 36, 36, 36, 119, 36, 120, 121, 122, 123, 124, 36, 36, 36, 36, 125, 126, 127, + 128, 31, 129, 36, 130, 131, 132, 113, 133 + ], + r3: &[ + 0x00001ffffcffffff, 0x000007ff01ffffff, 0x3fdfffff00000000, 0xffff03f8fff00000, + 0xefffffffffffffff, 0xfffe000fffe1dfff, 0xe3c5fdfffff99fef, 0x1003000fb080599f, + 0xc36dfdfffff987ee, 0x003f00005e021987, 0xe3edfdfffffbbfee, 0x1e00000f00011bbf, + 0xe3edfdfffff99fee, 0x0002000fb0c0199f, 0xc3ffc718d63dc7ec, 0x0000000000811dc7, + 0xe3fffdfffffddfef, 0x0000000f07601ddf, 0xe3effdfffffddfef, 0x0006000f40601ddf, + 0xe7fffffffffddfef, 0xfc00000f80f05ddf, 0x2ffbfffffc7fffec, 0x000c0000ff5f807f, + 0x07fffffffffffffe, 0x000000000000207f, 0x3bffecaefef02596, 0x00000000f000205f, + 0x0000000000000001, 0xfffe1ffffffffeff, 0x1ffffffffeffff03, 0x0000000000000000, + 0xf97fffffffffffff, 0xffffc1e7ffff0000, 0xffffffff3000407f, 0xf7ffffffffff20bf, + 0xffffffffffffffff, 0xffffffff3d7f3dff, 0x7f3dffffffff3dff, 0xffffffffff7fff3d, + 0xffffffffff3dffff, 0x0000000087ffffff, 0xffffffff0000ffff, 0x3f3fffffffffffff, + 0xfffffffffffffffe, 0xffff9fffffffffff, 0xffffffff07fffffe, 0x01ffc7ffffffffff, + 0x000fffff000fdfff, 0x000ddfff000fffff, 0xffcfffffffffffff, 0x00000000108001ff, + 0xffffffff00000000, 0x00ffffffffffffff, 0xffff07ffffffffff, 0x003fffffffffffff, + 0x01ff0fff7fffffff, 0x001f3fffffff0000, 0xffff0fffffffffff, 0x00000000000003ff, + 0xffffffff0fffffff, 0x001ffffe7fffffff, 0x0000008000000000, 0xffefffffffffffff, + 0x0000000000000fef, 0xfc00f3ffffffffff, 0x0003ffbfffffffff, 0x3ffffffffc00e000, + 0x00000000000001ff, 0x006fde0000000000, 0x001fff8000000000, 0xffffffff3f3fffff, + 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8002000000000000, + 0x000000001fff0000, 0xf3ffbd503e2ffc84, 0xffffffff000043e0, 0xffc0000000000000, + 0x000003ffffffffff, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, + 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, + 0x0000800000000000, 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, + 0xfffe7fffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, + 0x0000000000001fff, 0x3fffffffffff0000, 0x00000c00ffff1fff, 0x8ff07fffffffffff, + 0x0000ffffffffffff, 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000, + 0x000000fffffff7bb, 0x000fffffffffffff, 0x28fc00000000002f, 0xffff07fffffffc00, + 0x1fffffff0007ffff, 0xfff7ffffffffffff, 0x7c00ffdf00008000, 0x007fffffffffffff, + 0xc47fffff00003fff, 0x7fffffffffffffff, 0x003cffff38000005, 0xffff7f7f007e7e7e, + 0xffff003ff7ffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, 0xffff3fffffffffff, + 0x0000000003ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb, 0x0003ffffffffffff, + 0xfffffffffff80000, 0x3fffffffffffffff, 0xffffffffffff0000, 0xfffffffffffcffff, + 0x0fff0000000000ff, 0xffdf000000000000, 0x1fffffffffffffff, 0x07fffffe00000000, + 0xffffffc007fffffe, 0x000000001cfcfcfc + ], + r4: [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 13, 14, + 15, 7, 16, 17, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + ], + r5: &[ + 0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 13, 14, 15, 4, 4, 2, 2, 2, + 2, 16, 17, 4, 4, 18, 19, 20, 21, 22, 4, 23, 4, 24, 25, 26, 27, 28, 29, 30, 4, 2, 31, 32, + 32, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 33, 34, 35, 32, 36, 2, 37, 38, 4, 39, 40, 41, + 42, 4, 4, 2, 43, 2, 44, 4, 4, 45, 46, 47, 48, 28, 4, 49, 4, 4, 4, 4, 4, 50, 51, 4, 4, 4, + 4, 52, 53, 54, 55, 4, 4, 4, 4, 56, 57, 58, 4, 59, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 61, 4, 2, 62, 2, 2, 2, 63, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 62, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, + 2, 2, 2, 2, 2, 2, 55, 20, 4, 65, 16, 66, 67, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, + 68, 69, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 71, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 72, 2, 2, 2, 2, 2, 73, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 2, 74, 75, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 76, 77, 78, 79, 80, 2, 2, 2, 2, 81, 82, 83, 84, 85, 86, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 87, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 2, 2, 2, 88, 2, 89, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 90, 91, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 72, 93, 94, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 95, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 96, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 98, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 + ], + r6: &[ + 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, + 0x0000000000000000, 0x001fffffffffffff, 0xffffffff1fffffff, 0x000000000001ffff, + 0xffffe000ffffffff, 0x07ffffffffff07ff, 0xffffffff3fffffff, 0x00000000003eff0f, + 0xffff00003fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, 0x0000000fffffffff, + 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, + 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, 0xc0ffffffffffffff, + 0x000ffffffeeff06f, 0x1fffffff00000000, 0x000000001fffffff, 0x0000001ffffffeff, + 0x003fffffffffffff, 0x0007ffff003fffff, 0x000000000003ffff, 0x00000000000001ff, + 0x0007ffffffffffff, 0x000000000000003f, 0x01fffffffffffffc, 0x000001ffffff0000, + 0x0047ffffffff0000, 0x000000001400001e, 0x409ffffffffbffff, 0xffff01ffbfffbd7f, + 0x000001ffffffffff, 0xe3edfdfffff99fef, 0x0000000fe081199f, 0x00000000000007bb, + 0x00000000000000b3, 0x7f3fffffffffffff, 0x000000003f000000, 0x7fffffffffffffff, + 0x0000000000000011, 0x000007ffe3ffffff, 0xffffffff00000000, 0x80000000ffffffff, + 0x7fe7ffffffffffff, 0xffffffffffff0000, 0x0000000000ffffcf, 0x01ffffffffffffff, + 0x7f7ffffffffffdff, 0xfffc000000000001, 0x007ffefffffcffff, 0xb47ffffffffffb7f, + 0x00000000000000cb, 0x0000000003ffffff, 0x00007fffffffffff, 0x000000000000000f, + 0x000000000000007f, 0x00003fffffff0000, 0xe0fffff80000000f, 0x000000000000ffff, + 0x7fffffffffff001f, 0x00000000fff80000, 0x0000000300000000, 0x00001fffffffffff, + 0xffff000000000000, 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000043ff01ff, + 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, + 0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, + 0xffff7fffffff7fff, 0xfffffdfffffffdff, 0x0000000000000ff7, 0x000007dbf9ffff7f, + 0x000000000000001f, 0x000000000000008f, 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, + 0x0ffffbee0ffffbff, 0xffff03ffffff03ff, 0x00000000000003ff, 0x00000000007fffff, + 0xffff0003ffffffff, 0x00000001ffffffff, 0x000000003fffffff + ], + }; + + pub fn Alphabetic(c: char) -> bool { + Alphabetic_table.lookup(c) + } + + pub const Case_Ignorable_table: &super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0400408000000000, 0x0000000140000000, 0x0190a10000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0xffff000000000000, 0xffffffffffffffff, + 0xffffffffffffffff, 0x0430ffffffffffff, 0x00000000000000b0, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x00000000000003f8, 0x0000000000000000, + 0x0000000000000000, 0x0000000002000000, 0xbffffffffffe0000, 0x00100000000000b6, + 0x0000000017ff003f, 0x00010000fffff801, 0x0000000000000000, 0x00003dffbfc00000, + 0xffff000000028000, 0x00000000000007ff, 0x0001ffc000000000, 0x043ff80000000000 + ], + r2: [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 15, 16, 11, 17, 18, 7, 2, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 34, 35, 36, 37, 38, 39, 2, 40, 2, 2, 2, 41, 42, 43, 2, + 44, 45, 46, 47, 48, 49, 2, 50, 51, 52, 53, 54, 2, 2, 2, 2, 2, 2, 55, 56, 57, 58, 59, 60, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 61, 2, 62, 2, 63, 2, 64, 65, 2, 2, 2, 2, + 2, 2, 2, 66, 2, 67, 68, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 49, 2, 2, 2, 2, 70, 71, 72, 73, 74, 75, 76, 77, 78, 2, 2, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 2, 88, 2, 89, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 90, 2, 91, 92, 2, 2, 2, 2, 2, 2, 2, 2, 93, 94, 2, 95, + 96, 97, 98, 99 + ], + r3: &[ + 0x00003fffffc00000, 0x000000000e000000, 0x0000000000000000, 0xfffffffffff00000, + 0x1400000000000007, 0x0002000c00fe21fe, 0x1000000000000002, 0x0000000c0000201e, + 0x1000000000000006, 0x0023000000023986, 0xfc00000c000021be, 0x9000000000000002, + 0x0000000c0040201e, 0x0000000000000004, 0x0000000000002001, 0xc000000000000001, + 0x0000000c00603dc1, 0x0000000c00003040, 0x1800000000000003, 0x00000000005c0400, + 0x07f2000000000000, 0x0000000000007fc0, 0x1bf2000000000000, 0x0000000000003f40, + 0x02a0000003000000, 0x7ffe000000000000, 0x1ffffffffeffe0df, 0x0000000000000040, + 0x66fde00000000000, 0x001e0001c3000000, 0x0000000020002064, 0x1000000000000000, + 0x00000000e0000000, 0x001c0000001c0000, 0x000c0000000c0000, 0x3fb0000000000000, + 0x00000000208ffe40, 0x0000000000007800, 0x0000000000000008, 0x0000020000000060, + 0x0e04018700000000, 0x0000000009800000, 0x9ff81fe57f400000, 0x7fff008000000000, + 0x17d000000000000f, 0x000ff80000000004, 0x00003b3c00000003, 0x0003a34000000000, + 0x00cff00000000000, 0x3f00000000000000, 0x031021fdfff70000, 0xfffff00000000000, + 0x010007ffffffffff, 0xfffffffff8000000, 0xfbffffffffffffff, 0xa000000000000000, + 0x6000e000e000e003, 0x00007c900300f800, 0x8002ffdf00000000, 0x000000001fff0000, + 0x0001ffffffff0000, 0x3000000000000000, 0x0003800000000000, 0x8000800000000000, + 0xffffffff00000000, 0x0000800000000000, 0x083e3c0000000020, 0x000000007e000000, + 0x7000000000000000, 0x0000000000200000, 0x0000000000001000, 0xbff7800000000000, + 0x00000000f0000000, 0x0003000000000000, 0x00000003ffffffff, 0x0001000000000000, + 0x0000000000000700, 0x0300000000000000, 0x0000006000000844, 0x0003ffff00000030, + 0x00003fc000000000, 0x000000000003ff80, 0x13c8000000000007, 0x0000006000008000, + 0x00667e0000000000, 0x1001000000001008, 0xc19d000000000000, 0x0058300020000002, + 0x00000000f8000000, 0x0000212000000000, 0x0000000040000000, 0xfffc000000000000, + 0x0000000000000003, 0x0000ffff0008ffff, 0x0000000000240000, 0x8000000000000000, + 0x4000000004004080, 0x0001000000000001, 0x00000000c0000000, 0x0e00000800000000 + ], + r4: [ + 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 4, 2, 5, 6, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + ], + r5: &[ + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 7, 8, 0, 9, 10, 11, 12, 13, 0, 0, 14, 15, 16, 0, 0, 17, 18, 19, 20, + 0, 0, 21, 22, 23, 24, 25, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 0, 0, 0, + 0, 0, 30, 0, 31, 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 48, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 50, 51, 0, 0, 51, 51, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + ], + r6: &[ + 0x0000000000000000, 0x2000000000000000, 0x0000000100000000, 0x07c0000000000000, + 0x870000000000f06e, 0x0000006000000000, 0xff00000000000002, 0x800000000000007f, + 0x2678000000000003, 0x001fef8000000007, 0x0008000000000000, 0x7fc0000000000003, + 0x0000000000001c00, 0x40d3800000000000, 0x000007f880000000, 0x1000000000000003, + 0x001f1fc000000001, 0xff00000000000000, 0x000000000000005c, 0x85f8000000000000, + 0x000000000000000d, 0xb03c000000000000, 0x0000000030000001, 0xa7f8000000000000, + 0x0000000000000001, 0x00bf280000000000, 0x00000fbce0000000, 0x79f800000000067e, + 0x000000000e7e0080, 0x00000000037ffc00, 0xbf7f000000000000, 0x006dfcfffffc0000, + 0xb47e000000000000, 0x00000000000000bf, 0x001f000000000000, 0x007f000000000000, + 0x000000000000000f, 0x00000000ffff8000, 0x0000000300000000, 0x0000000f60000000, + 0xfff8038000000000, 0x00003c0000000fe7, 0x000000000000001c, 0xf87fffffffffffff, + 0x00201fffffffffff, 0x0000fffef8000010, 0x000007dbf9ffff7f, 0x00000000007f0000, + 0x00000000000007f0, 0xf800000000000000, 0xffffffff00000002, 0xffffffffffffffff, + 0x0000ffffffffffff + ], + }; + + pub fn Case_Ignorable(c: char) -> bool { + Case_Ignorable_table.lookup(c) + } + + pub const Cased_table: &super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xf7ffffffffffffff, 0xfffffffffffffff0, + 0xffffffffffffffff, 0xffffffffffffffff, 0x01ffffffffefffff, 0x0000001f00000003, + 0x0000000000000000, 0xbccf000000000020, 0xfffffffbffffd740, 0xffbfffffffffffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, + 0xfffeffffffffffff, 0xfffffffe007fffff, 0x00000000000000ff, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 + ], + r2: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 5, 5, 5, + 0, 5, 5, 5, 5, 6, 7, 8, 9, 0, 10, 11, 0, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 15, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 18, 5, 19, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22, + 0, 23, 5, 24, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 27, 5, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 29, 30, 0, 0 + ], + r3: &[ + 0x0000000000000000, 0xffffffff00000000, 0x00000000000020bf, 0x3f3fffffffffffff, + 0x00000000000001ff, 0xffffffffffffffff, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, + 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8002000000000000, 0x000000001fff0000, + 0xf21fbd503e2ffc84, 0xffffffff000043e0, 0x0000000000000018, 0xffc0000000000000, + 0x000003ffffffffff, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, + 0x000020bfffffffff, 0x00003fffffffffff, 0x000000003fffffff, 0xfffffffc00000000, + 0x00ff7fffffff78ff, 0x0700000000000000, 0xffff000000000000, 0xffff003ff7ffffff, + 0x0000000000f8007f, 0x07fffffe00000000, 0x0000000007fffffe + ], + r4: [ + 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + ], + r5: &[ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 8, 9, 10, 11, 12, 1, 1, 1, 1, 13, 14, 15, 16, 17, 18, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 20, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ], + r6: &[ + 0x0000000000000000, 0xffffffffffffffff, 0x000000000000ffff, 0xffff000000000000, + 0x0fffffffff0fffff, 0x0007ffffffffffff, 0xffffffff00000000, 0x00000000ffffffff, + 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, + 0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, + 0xffff7fffffff7fff, 0xfffffdfffffffdff, 0x0000000000000ff7, 0x000000000000000f, + 0xffff03ffffff03ff, 0x00000000000003ff + ], + }; + + pub fn Cased(c: char) -> bool { + Cased_table.lookup(c) + } + + pub const Lowercase_table: &super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0000000000000000, 0x07fffffe00000000, 0x0420040000000000, 0xff7fffff80000000, + 0x55aaaaaaaaaaaaaa, 0xd4aaaaaaaaaaab55, 0xe6512d2a4e243129, 0xaa29aaaab5555240, + 0x93faaaaaaaaaaaaa, 0xffffffffffffaa85, 0x01ffffffffefffff, 0x0000001f00000003, + 0x0000000000000000, 0x3c8a000000000020, 0xfffff00000010000, 0x192faaaaaae37fff, + 0xffff000000000000, 0xaaaaaaaaffffffff, 0xaaaaaaaaaaaaa802, 0xaaaaaaaaaaaad554, + 0x0000aaaaaaaaaaaa, 0xfffffffe00000000, 0x00000000000000ff, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 + ], + r2: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 3, 3, + 0, 4, 4, 5, 4, 6, 7, 8, 9, 0, 10, 11, 0, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16, 17, 4, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 0, + 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 26, 3, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 28, 0, 0 + ], + r3: &[ + 0x0000000000000000, 0x3f00000000000000, 0x00000000000001ff, 0xffffffffffffffff, + 0xaaaaaaaaaaaaaaaa, 0xaaaaaaaabfeaaaaa, 0x00ff00ff003f00ff, 0x3fff00ff00ff003f, + 0x40df00ff00ff00ff, 0x00dc00ff00cf00dc, 0x8002000000000000, 0x000000001fff0000, + 0x321080000008c400, 0xffff0000000043c0, 0x0000000000000010, 0x000003ffffff0000, + 0xffff000000000000, 0x3fda15627fffffff, 0x0008501aaaaaaaaa, 0x000020bfffffffff, + 0x00002aaaaaaaaaaa, 0x000000003aaaaaaa, 0xaaabaaa800000000, 0x95ffaaaaaaaaaaaa, + 0x00a002aaaaba50aa, 0x0700000000000000, 0xffff003ff7ffffff, 0x0000000000f8007f, + 0x0000000007fffffe + ], + r4: [ + 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + ], + r5: &[ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 + ], + r6: &[ + 0x0000000000000000, 0xffffff0000000000, 0x000000000000ffff, 0x0fffffffff000000, + 0x0007ffffffffffff, 0x00000000ffffffff, 0x000ffffffc000000, 0x000000ffffdfc000, + 0xebc000000ffffffc, 0xfffffc000000ffef, 0x00ffffffc000000f, 0x00000ffffffc0000, + 0xfc000000ffffffc0, 0xffffc000000fffff, 0x0ffffffc000000ff, 0x0000ffffffc00000, + 0x0000003ffffffc00, 0xf0000003f7fffffc, 0xffc000000fdfffff, 0xffff0000003f7fff, + 0xfffffc000000fdff, 0x0000000000000bf7, 0xfffffffc00000000, 0x000000000000000f + ], + }; + + pub fn Lowercase(c: char) -> bool { + Lowercase_table.lookup(c) + } + + pub const Uppercase_table: &super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0000000000000000, 0x0000000007fffffe, 0x0000000000000000, 0x000000007f7fffff, + 0xaa55555555555555, 0x2b555555555554aa, 0x11aed2d5b1dbced6, 0x55d255554aaaa490, + 0x6c05555555555555, 0x000000000000557a, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x8045000000000000, 0x00000ffbfffed740, 0xe6905555551c8000, + 0x0000ffffffffffff, 0x5555555500000000, 0x5555555555555401, 0x5555555555552aab, + 0xfffe555555555555, 0x00000000007fffff, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 + ], + r2: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4, 4, 5, 4, 6, 7, 8, 9, 0, 0, 0, 0, 10, 11, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, + 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 15, 16, 4, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 19, 0, + 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 23, 0, 0, 0 + ], + r3: &[ + 0x0000000000000000, 0xffffffff00000000, 0x00000000000020bf, 0x003fffffffffffff, + 0x5555555555555555, 0x5555555540155555, 0xff00ff003f00ff00, 0x0000ff00aa003f00, + 0x0f00000000000000, 0x0f001f000f000f00, 0xc00f3d503e273884, 0x0000ffff00000020, + 0x0000000000000008, 0xffc0000000000000, 0x000000000000ffff, 0x00007fffffffffff, + 0xc025ea9d00000000, 0x0004280555555555, 0x0000155555555555, 0x0000000005555555, + 0x5554555400000000, 0x6a00555555555555, 0x005f7d5555452855, 0x07fffffe00000000 + ], + r4: [ + 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + ], + r5: &[ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ], + r6: &[ + 0x0000000000000000, 0x000000ffffffffff, 0xffff000000000000, 0x00000000000fffff, + 0x0007ffffffffffff, 0xffffffff00000000, 0xfff0000003ffffff, 0xffffff0000003fff, + 0x003fde64d0000003, 0x000003ffffff0000, 0x7b0000001fdfe7b0, 0xfffff0000001fc5f, + 0x03ffffff0000003f, 0x00003ffffff00000, 0xf0000003ffffff00, 0xffff0000003fffff, + 0xffffff00000003ff, 0x07fffffc00000001, 0x001ffffff0000000, 0x00007fffffc00000, + 0x000001ffffff0000, 0x0000000000000400, 0x00000003ffffffff, 0xffff03ffffff03ff, + 0x00000000000003ff + ], + }; + + pub fn Uppercase(c: char) -> bool { + Uppercase_table.lookup(c) + } + + pub const XID_Continue_table: &super::BoolTrie = &super::BoolTrie { + r1: [ + 0x03ff000000000000, 0x07fffffe87fffffe, 0x04a0040000000000, 0xff7fffffff7fffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, + 0xffffffffffffffff, 0xb8dfffffffffffff, 0xfffffffbffffd7c0, 0xffbfffffffffffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffcfb, 0xffffffffffffffff, + 0xfffeffffffffffff, 0xfffffffe027fffff, 0xbffffffffffe00ff, 0x000707ffffff00b6, + 0xffffffff07ff0000, 0xffffc3ffffffffff, 0xffffffffffffffff, 0x9ffffdff9fefffff, + 0xffffffffffff0000, 0xffffffffffffe7ff, 0x0003ffffffffffff, 0x043fffffffffffff + ], + r2: [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 4, 32, 33, 34, 4, 4, 4, 4, 4, 35, 36, 37, 38, 39, 40, + 41, 42, 4, 4, 4, 4, 4, 4, 4, 4, 43, 44, 45, 46, 47, 4, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 4, 61, 4, 62, 50, 63, 64, 65, 4, 4, 4, 66, 4, 4, 4, 4, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 64, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 77, 78, 4, 79, 80, 81, 82, 83, 60, 60, 60, 60, 60, 60, 60, 60, 84, + 42, 85, 86, 87, 4, 88, 89, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 52, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 90, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 91, 92, 4, 4, 4, 4, 93, 94, 4, 95, 96, 4, 97, 98, 99, 62, 4, 100, 101, + 102, 4, 103, 104, 105, 4, 106, 107, 108, 4, 109, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 110, 111, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 101, 4, 112, + 113, 114, 95, 115, 4, 116, 4, 4, 117, 118, 119, 120, 121, 122, 4, 123, 124, 125, 126, + 127 + ], + r3: &[ + 0x00003fffffffffff, 0x000007ff0fffffff, 0x3fdfffff00000000, 0xfffffffbfff00000, + 0xffffffffffffffff, 0xfffeffcfffffffff, 0xf3c5fdfffff99fef, 0x1003ffcfb080799f, + 0xd36dfdfffff987ee, 0x003fffc05e023987, 0xf3edfdfffffbbfee, 0xfe00ffcf00013bbf, + 0xf3edfdfffff99fee, 0x0002ffcfb0c0399f, 0xc3ffc718d63dc7ec, 0x0000ffc000813dc7, + 0xe3fffdfffffddfef, 0x0000ffcf07603ddf, 0xf3effdfffffddfef, 0x0006ffcf40603ddf, + 0xfffffffffffddfef, 0xfc00ffcf80f07ddf, 0x2ffbfffffc7fffec, 0x000cffc0ff5f847f, + 0x07fffffffffffffe, 0x0000000003ff7fff, 0x3bffecaefef02596, 0x00000000f3ff3f5f, + 0xc2a003ff03000001, 0xfffe1ffffffffeff, 0x1ffffffffeffffdf, 0x0000000000000040, + 0xffffffffffff03ff, 0xffffffff3fffffff, 0xf7ffffffffff20bf, 0xffffffff3d7f3dff, + 0x7f3dffffffff3dff, 0xffffffffff7fff3d, 0xffffffffff3dffff, 0x0003fe00e7ffffff, + 0xffffffff0000ffff, 0x3f3fffffffffffff, 0xfffffffffffffffe, 0xffff9fffffffffff, + 0xffffffff07fffffe, 0x01ffc7ffffffffff, 0x001fffff001fdfff, 0x000ddfff000fffff, + 0x000003ff308fffff, 0xffffffff03ff3800, 0x00ffffffffffffff, 0xffff07ffffffffff, + 0x003fffffffffffff, 0x0fff0fff7fffffff, 0x001f3fffffffffc0, 0xffff0fffffffffff, + 0x0000000007ff03ff, 0xffffffff0fffffff, 0x9fffffff7fffffff, 0x3fff008003ff03ff, + 0x0000000000000000, 0x000ff80003ff0fff, 0x000fffffffffffff, 0x3fffffffffffe3ff, + 0x00000000000001ff, 0x03fffffffff70000, 0xfbffffffffffffff, 0xffffffff3f3fffff, + 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8000000000000000, + 0x8002000000100001, 0x000000001fff0000, 0x0001ffe21fff0000, 0xf3fffd503f2ffc84, + 0xffffffff000043e0, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000ff81fffffffff, + 0xffff20bfffffffff, 0x800080ffffffffff, 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, + 0x1f3efffe000000e0, 0xfffffffee67fffff, 0xf7ffffffffffffff, 0xfffe7fffffffffe0, + 0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, 0x0000000000001fff, + 0x3fffffffffff0000, 0x00000fffffff1fff, 0xbff0ffffffffffff, 0x0003ffffffffffff, + 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000, 0x000000ffffffffff, + 0x28ffffff03ff003f, 0xffff3fffffffffff, 0x1fffffff000fffff, 0x7fffffff03ff8001, + 0x007fffffffffffff, 0xfc7fffff03ff3fff, 0x007cffff38000007, 0xffff7f7f007e7e7e, + 0xffff003ff7ffffff, 0x03ff37ffffffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, + 0x0000000003ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb, 0xfffffffffff80000, + 0xfffffff03fffffff, 0x3fffffffffffffff, 0xffffffffffff0000, 0xfffffffffffcffff, + 0x03ff0000000000ff, 0x0018ffff0000ffff, 0xaa8a00000000e000, 0x1fffffffffffffff, + 0x87fffffe03ff0000, 0xffffffc007fffffe, 0x7fffffffffffffff, 0x000000001cfcfcfc + ], + r4: [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 13, + 14, 7, 15, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 17, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + ], + r5: &[ + 0, 1, 2, 3, 4, 5, 4, 6, 4, 4, 7, 8, 9, 10, 11, 12, 2, 2, 13, 14, 15, 16, 4, 4, 2, 2, 2, + 2, 17, 18, 4, 4, 19, 20, 21, 22, 23, 4, 24, 4, 25, 26, 27, 28, 29, 30, 31, 4, 2, 32, 33, + 33, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 34, 3, 35, 36, 37, 2, 38, 39, 4, 40, 41, 42, + 43, 4, 4, 2, 44, 2, 45, 4, 4, 46, 47, 2, 48, 49, 50, 51, 4, 4, 4, 4, 4, 52, 53, 4, 4, 4, + 4, 54, 55, 56, 57, 4, 4, 4, 4, 58, 59, 60, 4, 61, 62, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 63, 4, 2, 64, 2, 2, 2, 65, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 66, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, + 2, 2, 2, 2, 2, 2, 57, 67, 4, 68, 17, 69, 70, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, + 71, 72, 73, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 21, 75, 2, 2, 2, 2, 2, 76, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 2, 77, 78, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 79, 80, 4, 4, 81, 4, 4, 4, 4, 4, 4, 2, 82, 83, 84, 85, 86, 2, 2, 2, 2, 87, 88, 89, 90, + 91, 92, 4, 4, 4, 4, 4, 4, 4, 4, 93, 94, 95, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 96, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 97, 2, 44, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 98, 99, 100, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 101, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 102, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 103, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 104, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 105, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 + ], + r6: &[ + 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, + 0x0000000000000000, 0x001fffffffffffff, 0x2000000000000000, 0xffffffff1fffffff, + 0x000000010001ffff, 0xffffe000ffffffff, 0x07ffffffffff07ff, 0xffffffff3fffffff, + 0x00000000003eff0f, 0xffff03ff3fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, + 0x0000000fffffffff, 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, + 0x007fffff003fffff, 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, + 0xc0ffffffffffffff, 0x870ffffffeeff06f, 0x1fffffff00000000, 0x000000001fffffff, + 0x0000007ffffffeff, 0x003fffffffffffff, 0x0007ffff003fffff, 0x000000000003ffff, + 0x00000000000001ff, 0x0007ffffffffffff, 0x8000ffc00000007f, 0x03ff01ffffff0000, + 0xffdfffffffffffff, 0x004fffffffff0000, 0x0000000017ff1c1f, 0x40fffffffffbffff, + 0xffff01ffbfffbd7f, 0x03ff07ffffffffff, 0xf3edfdfffff99fef, 0x001f1fcfe081399f, + 0x0000000003ff07ff, 0x0000000003ff00bf, 0xff3fffffffffffff, 0x000000003f000001, + 0x0000000003ff0011, 0x00ffffffffffffff, 0x00000000000003ff, 0x03ff0fffe3ffffff, + 0xffffffff00000000, 0x800003ffffffffff, 0x7fffffffffffffff, 0xffffffffffff0080, + 0x0000000003ffffcf, 0x01ffffffffffffff, 0xff7ffffffffffdff, 0xfffc000003ff0001, + 0x007ffefffffcffff, 0xb47ffffffffffb7f, 0x0000000003ff00ff, 0x0000000003ffffff, + 0x00007fffffffffff, 0x000000000000000f, 0x000000000000007f, 0x000003ff7fffffff, + 0x001f3fffffff0000, 0xe0fffff803ff000f, 0x000000000000ffff, 0x7fffffffffff001f, + 0x00000000ffff8000, 0x0000000300000000, 0x00001fffffffffff, 0xffff000000000000, + 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000063ff01ff, 0xf807e3e000000000, + 0x00003c0000000fe7, 0x000000000000001c, 0xffffffffffdfffff, 0xebffde64dfffffff, + 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffff3fffffffff, + 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, 0xfffffdfffffffdff, + 0xffffffffffffcff7, 0xf87fffffffffffff, 0x00201fffffffffff, 0x0000fffef8000010, + 0x000007dbf9ffff7f, 0x00000000007f001f, 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, + 0x0ffffbee0ffffbff, 0x00000000007fffff, 0xffff0003ffffffff, 0x00000001ffffffff, + 0x000000003fffffff, 0x0000ffffffffffff + ], + }; + + pub fn XID_Continue(c: char) -> bool { + XID_Continue_table.lookup(c) + } + + pub const XID_Start_table: &super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, + 0x0000000000000000, 0xb8df000000000000, 0xfffffffbffffd740, 0xffbfffffffffffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, + 0xfffeffffffffffff, 0xfffffffe027fffff, 0x00000000000000ff, 0x000707ffffff0000, + 0xffffffff00000000, 0xfffec000000007ff, 0xffffffffffffffff, 0x9c00c060002fffff, + 0x0000fffffffd0000, 0xffffffffffffe000, 0x0002003fffffffff, 0x043007fffffffc00 + ], + r2: [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 23, 25, 26, 27, 28, 29, 3, 30, 31, 32, 33, 34, 34, 34, 34, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 34, 34, 34, 34, 34, 34, 34, 34, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 3, 61, 62, 63, 64, 65, 66, 67, 68, 34, 34, 34, 3, 34, 34, + 34, 34, 69, 70, 71, 72, 3, 73, 74, 3, 75, 76, 67, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 77, + 78, 34, 79, 80, 81, 82, 83, 3, 3, 3, 3, 3, 3, 3, 3, 84, 42, 85, 86, 87, 34, 88, 89, 3, + 3, 3, 3, 3, 3, 3, 3, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 53, 3, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 90, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 91, 92, 34, 34, 34, 34, 93, + 94, 95, 96, 97, 34, 98, 99, 100, 48, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 34, 113, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 114, 115, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 34, 34, 34, 34, 34, + 116, 34, 117, 118, 119, 120, 121, 34, 122, 34, 34, 123, 124, 125, 126, 3, 127, 34, 128, + 129, 130, 131, 132 + ], + r3: &[ + 0x00000110043fffff, 0x000007ff01ffffff, 0x3fdfffff00000000, 0x0000000000000000, + 0x23fffffffffffff0, 0xfffe0003ff010000, 0x23c5fdfffff99fe1, 0x10030003b0004000, + 0x036dfdfffff987e0, 0x001c00005e000000, 0x23edfdfffffbbfe0, 0x0200000300010000, + 0x23edfdfffff99fe0, 0x00020003b0000000, 0x03ffc718d63dc7e8, 0x0000000000010000, + 0x23fffdfffffddfe0, 0x0000000307000000, 0x23effdfffffddfe1, 0x0006000340000000, + 0x27fffffffffddfe0, 0xfc00000380704000, 0x2ffbfffffc7fffe0, 0x000000000000007f, + 0x0005fffffffffffe, 0x2005ecaefef02596, 0x00000000f000005f, 0x0000000000000001, + 0x00001ffffffffeff, 0x0000000000001f00, 0x800007ffffffffff, 0xffe1c0623c3f0000, + 0xffffffff00004003, 0xf7ffffffffff20bf, 0xffffffffffffffff, 0xffffffff3d7f3dff, + 0x7f3dffffffff3dff, 0xffffffffff7fff3d, 0xffffffffff3dffff, 0x0000000007ffffff, + 0xffffffff0000ffff, 0x3f3fffffffffffff, 0xfffffffffffffffe, 0xffff9fffffffffff, + 0xffffffff07fffffe, 0x01ffc7ffffffffff, 0x0003ffff0003dfff, 0x0001dfff0003ffff, + 0x000fffffffffffff, 0x0000000010800000, 0xffffffff00000000, 0x00ffffffffffffff, + 0xffff05ffffffffff, 0x003fffffffffffff, 0x000000007fffffff, 0x001f3fffffff0000, + 0xffff0fffffffffff, 0x00000000000003ff, 0xffffffff007fffff, 0x00000000001fffff, + 0x0000008000000000, 0x000fffffffffffe0, 0x0000000000000fe0, 0xfc00c001fffffff8, + 0x0000003fffffffff, 0x0000000fffffffff, 0x3ffffffffc00e000, 0x00000000000001ff, + 0x0063de0000000000, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, + 0x1fdc1fff0fcf1fdc, 0x8002000000000000, 0x000000001fff0000, 0xf3fffd503f2ffc84, + 0xffffffff000043e0, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, + 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, 0x000000007f7f7f7f, + 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, 0xfffe7fffffffffe0, + 0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, 0x0000000000001fff, + 0x3fffffffffff0000, 0x00000c00ffff1fff, 0x80007fffffffffff, 0xffffffff3fffffff, + 0x0000ffffffffffff, 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000, + 0x00000007fffff7bb, 0x000ffffffffffffc, 0x28fc000000000000, 0xffff003ffffffc00, + 0x1fffffff0000007f, 0x0007fffffffffff0, 0x7c00ffdf00008000, 0x000001ffffffffff, + 0xc47fffff00000ff7, 0x3e62ffffffffffff, 0x001c07ff38000005, 0xffff7f7f007e7e7e, + 0xffff003ff7ffffff, 0x00000007ffffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, + 0xffff3fffffffffff, 0x0000000003ffffff, 0x5f7ffdffa0f8007f, 0xffffffffffffffdb, + 0x0003ffffffffffff, 0xfffffffffff80000, 0xfffffff03fffffff, 0x3fffffffffffffff, + 0xffffffffffff0000, 0xfffffffffffcffff, 0x03ff0000000000ff, 0xaa8a000000000000, + 0x1fffffffffffffff, 0x07fffffe00000000, 0xffffffc007fffffe, 0x7fffffff3fffffff, + 0x000000001cfcfcfc + ], + r4: [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 13, + 14, 7, 15, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + ], + r5: &[ + 0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 13, 14, 15, 4, 4, 2, 2, 2, + 2, 16, 17, 4, 4, 18, 19, 20, 21, 22, 4, 23, 4, 24, 25, 26, 27, 28, 29, 30, 4, 2, 31, 32, + 32, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 33, 4, 34, 35, 36, 37, 38, 39, 40, 4, 41, 20, + 42, 43, 4, 4, 5, 44, 45, 46, 4, 4, 47, 48, 45, 49, 50, 4, 51, 4, 4, 4, 4, 4, 52, 53, 4, + 4, 4, 4, 54, 55, 56, 57, 4, 4, 4, 4, 58, 59, 60, 4, 61, 62, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 51, 4, 2, 47, 2, 2, 2, 63, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 47, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 57, 20, 4, 65, 45, 66, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 2, 67, 68, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 71, 2, 2, 2, 2, 2, + 72, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 2, 73, 74, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 75, 76, 77, 78, 79, 2, 2, 2, 2, 80, 81, 82, 83, 84, + 85, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 86, 2, 63, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 87, 88, 89, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 91, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 93, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 + ], + r6: &[ + 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, + 0x0000000000000000, 0x001fffffffffffff, 0xffffffff1fffffff, 0x000000000001ffff, + 0xffffe000ffffffff, 0x003fffffffff07ff, 0xffffffff3fffffff, 0x00000000003eff0f, + 0xffff00003fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, 0x0000000fffffffff, + 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, + 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, 0xc0ffffffffffffff, + 0x000ffffffeef0001, 0x1fffffff00000000, 0x000000001fffffff, 0x0000001ffffffeff, + 0x003fffffffffffff, 0x0007ffff003fffff, 0x000000000003ffff, 0x00000000000001ff, + 0x0007ffffffffffff, 0x00fffffffffffff8, 0x0000fffffffffff8, 0x000001ffffff0000, + 0x0000007ffffffff8, 0x0047ffffffff0000, 0x0007fffffffffff8, 0x000000001400001e, + 0x00000ffffffbffff, 0xffff01ffbfffbd7f, 0x23edfdfffff99fe0, 0x00000003e0010000, + 0x0000000000000780, 0x0000ffffffffffff, 0x00000000000000b0, 0x00007fffffffffff, + 0x000000000f000000, 0x0000000000000010, 0x000007ffffffffff, 0x0000000003ffffff, + 0xffffffff00000000, 0x80000000ffffffff, 0x0407fffffffff801, 0xfffffffff0010000, + 0x00000000000003cf, 0x01ffffffffffffff, 0x00007ffffffffdff, 0xfffc000000000001, + 0x000000000000ffff, 0x0001fffffffffb7f, 0x0000000000000040, 0x000000000000000f, + 0x000000000000007f, 0x00003fffffff0000, 0xe0fffff80000000f, 0x000000000001001f, + 0x00000000fff80000, 0x0000000300000000, 0x00001fffffffffff, 0xffff000000000000, + 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000003ff01ff, 0xffffffffffdfffff, + 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, + 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, + 0xfffffdfffffffdff, 0x0000000000000ff7, 0x000000000000001f, 0x0af7fe96ffffffef, + 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0x00000000007fffff, 0xffff0003ffffffff, + 0x00000001ffffffff, 0x000000003fffffff + ], + }; + + pub fn XID_Start(c: char) -> bool { + XID_Start_table.lookup(c) + } + +} + +pub mod property { + pub const Pattern_White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie { + r1: &[ + 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 + ], + r2: &[ + 0x0000000100003e00, 0x0000000000000000, 0x0000000000000020, 0x000003000000c000 + ], + }; + + pub fn Pattern_White_Space(c: char) -> bool { + Pattern_White_Space_table.lookup(c) + } + + pub const White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie { + r1: &[ + 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 + ], + r2: &[ + 0x0000000100003e00, 0x0000000000000000, 0x0000000100000020, 0x0000000000000001, + 0x00008300000007ff, 0x0000000080000000 + ], + }; + + pub fn White_Space(c: char) -> bool { + White_Space_table.lookup(c) + } + +} + +pub mod conversions { + pub fn to_lower(c: char) -> [char; 3] { + match bsearch_case_table(c, to_lowercase_table) { + None => [c, '\0', '\0'], + Some(index) => to_lowercase_table[index].1, + } + } + + pub fn to_upper(c: char) -> [char; 3] { + match bsearch_case_table(c, to_uppercase_table) { + None => [c, '\0', '\0'], + Some(index) => to_uppercase_table[index].1, + } + } + + fn bsearch_case_table(c: char, table: &[(char, [char; 3])]) -> Option { + table.binary_search_by(|&(key, _)| key.cmp(&c)).ok() + } + + const to_lowercase_table: &[(char, [char; 3])] = &[ + ('\u{41}', ['\u{61}', '\0', '\0']), ('\u{42}', ['\u{62}', '\0', '\0']), ('\u{43}', + ['\u{63}', '\0', '\0']), ('\u{44}', ['\u{64}', '\0', '\0']), ('\u{45}', ['\u{65}', '\0', + '\0']), ('\u{46}', ['\u{66}', '\0', '\0']), ('\u{47}', ['\u{67}', '\0', '\0']), ('\u{48}', + ['\u{68}', '\0', '\0']), ('\u{49}', ['\u{69}', '\0', '\0']), ('\u{4a}', ['\u{6a}', '\0', + '\0']), ('\u{4b}', ['\u{6b}', '\0', '\0']), ('\u{4c}', ['\u{6c}', '\0', '\0']), ('\u{4d}', + ['\u{6d}', '\0', '\0']), ('\u{4e}', ['\u{6e}', '\0', '\0']), ('\u{4f}', ['\u{6f}', '\0', + '\0']), ('\u{50}', ['\u{70}', '\0', '\0']), ('\u{51}', ['\u{71}', '\0', '\0']), ('\u{52}', + ['\u{72}', '\0', '\0']), ('\u{53}', ['\u{73}', '\0', '\0']), ('\u{54}', ['\u{74}', '\0', + '\0']), ('\u{55}', ['\u{75}', '\0', '\0']), ('\u{56}', ['\u{76}', '\0', '\0']), ('\u{57}', + ['\u{77}', '\0', '\0']), ('\u{58}', ['\u{78}', '\0', '\0']), ('\u{59}', ['\u{79}', '\0', + '\0']), ('\u{5a}', ['\u{7a}', '\0', '\0']), ('\u{c0}', ['\u{e0}', '\0', '\0']), ('\u{c1}', + ['\u{e1}', '\0', '\0']), ('\u{c2}', ['\u{e2}', '\0', '\0']), ('\u{c3}', ['\u{e3}', '\0', + '\0']), ('\u{c4}', ['\u{e4}', '\0', '\0']), ('\u{c5}', ['\u{e5}', '\0', '\0']), ('\u{c6}', + ['\u{e6}', '\0', '\0']), ('\u{c7}', ['\u{e7}', '\0', '\0']), ('\u{c8}', ['\u{e8}', '\0', + '\0']), ('\u{c9}', ['\u{e9}', '\0', '\0']), ('\u{ca}', ['\u{ea}', '\0', '\0']), ('\u{cb}', + ['\u{eb}', '\0', '\0']), ('\u{cc}', ['\u{ec}', '\0', '\0']), ('\u{cd}', ['\u{ed}', '\0', + '\0']), ('\u{ce}', ['\u{ee}', '\0', '\0']), ('\u{cf}', ['\u{ef}', '\0', '\0']), ('\u{d0}', + ['\u{f0}', '\0', '\0']), ('\u{d1}', ['\u{f1}', '\0', '\0']), ('\u{d2}', ['\u{f2}', '\0', + '\0']), ('\u{d3}', ['\u{f3}', '\0', '\0']), ('\u{d4}', ['\u{f4}', '\0', '\0']), ('\u{d5}', + ['\u{f5}', '\0', '\0']), ('\u{d6}', ['\u{f6}', '\0', '\0']), ('\u{d8}', ['\u{f8}', '\0', + '\0']), ('\u{d9}', ['\u{f9}', '\0', '\0']), ('\u{da}', ['\u{fa}', '\0', '\0']), ('\u{db}', + ['\u{fb}', '\0', '\0']), ('\u{dc}', ['\u{fc}', '\0', '\0']), ('\u{dd}', ['\u{fd}', '\0', + '\0']), ('\u{de}', ['\u{fe}', '\0', '\0']), ('\u{100}', ['\u{101}', '\0', '\0']), + ('\u{102}', ['\u{103}', '\0', '\0']), ('\u{104}', ['\u{105}', '\0', '\0']), ('\u{106}', + ['\u{107}', '\0', '\0']), ('\u{108}', ['\u{109}', '\0', '\0']), ('\u{10a}', ['\u{10b}', + '\0', '\0']), ('\u{10c}', ['\u{10d}', '\0', '\0']), ('\u{10e}', ['\u{10f}', '\0', '\0']), + ('\u{110}', ['\u{111}', '\0', '\0']), ('\u{112}', ['\u{113}', '\0', '\0']), ('\u{114}', + ['\u{115}', '\0', '\0']), ('\u{116}', ['\u{117}', '\0', '\0']), ('\u{118}', ['\u{119}', + '\0', '\0']), ('\u{11a}', ['\u{11b}', '\0', '\0']), ('\u{11c}', ['\u{11d}', '\0', '\0']), + ('\u{11e}', ['\u{11f}', '\0', '\0']), ('\u{120}', ['\u{121}', '\0', '\0']), ('\u{122}', + ['\u{123}', '\0', '\0']), ('\u{124}', ['\u{125}', '\0', '\0']), ('\u{126}', ['\u{127}', + '\0', '\0']), ('\u{128}', ['\u{129}', '\0', '\0']), ('\u{12a}', ['\u{12b}', '\0', '\0']), + ('\u{12c}', ['\u{12d}', '\0', '\0']), ('\u{12e}', ['\u{12f}', '\0', '\0']), ('\u{130}', + ['\u{69}', '\u{307}', '\0']), ('\u{132}', ['\u{133}', '\0', '\0']), ('\u{134}', ['\u{135}', + '\0', '\0']), ('\u{136}', ['\u{137}', '\0', '\0']), ('\u{139}', ['\u{13a}', '\0', '\0']), + ('\u{13b}', ['\u{13c}', '\0', '\0']), ('\u{13d}', ['\u{13e}', '\0', '\0']), ('\u{13f}', + ['\u{140}', '\0', '\0']), ('\u{141}', ['\u{142}', '\0', '\0']), ('\u{143}', ['\u{144}', + '\0', '\0']), ('\u{145}', ['\u{146}', '\0', '\0']), ('\u{147}', ['\u{148}', '\0', '\0']), + ('\u{14a}', ['\u{14b}', '\0', '\0']), ('\u{14c}', ['\u{14d}', '\0', '\0']), ('\u{14e}', + ['\u{14f}', '\0', '\0']), ('\u{150}', ['\u{151}', '\0', '\0']), ('\u{152}', ['\u{153}', + '\0', '\0']), ('\u{154}', ['\u{155}', '\0', '\0']), ('\u{156}', ['\u{157}', '\0', '\0']), + ('\u{158}', ['\u{159}', '\0', '\0']), ('\u{15a}', ['\u{15b}', '\0', '\0']), ('\u{15c}', + ['\u{15d}', '\0', '\0']), ('\u{15e}', ['\u{15f}', '\0', '\0']), ('\u{160}', ['\u{161}', + '\0', '\0']), ('\u{162}', ['\u{163}', '\0', '\0']), ('\u{164}', ['\u{165}', '\0', '\0']), + ('\u{166}', ['\u{167}', '\0', '\0']), ('\u{168}', ['\u{169}', '\0', '\0']), ('\u{16a}', + ['\u{16b}', '\0', '\0']), ('\u{16c}', ['\u{16d}', '\0', '\0']), ('\u{16e}', ['\u{16f}', + '\0', '\0']), ('\u{170}', ['\u{171}', '\0', '\0']), ('\u{172}', ['\u{173}', '\0', '\0']), + ('\u{174}', ['\u{175}', '\0', '\0']), ('\u{176}', ['\u{177}', '\0', '\0']), ('\u{178}', + ['\u{ff}', '\0', '\0']), ('\u{179}', ['\u{17a}', '\0', '\0']), ('\u{17b}', ['\u{17c}', '\0', + '\0']), ('\u{17d}', ['\u{17e}', '\0', '\0']), ('\u{181}', ['\u{253}', '\0', '\0']), + ('\u{182}', ['\u{183}', '\0', '\0']), ('\u{184}', ['\u{185}', '\0', '\0']), ('\u{186}', + ['\u{254}', '\0', '\0']), ('\u{187}', ['\u{188}', '\0', '\0']), ('\u{189}', ['\u{256}', + '\0', '\0']), ('\u{18a}', ['\u{257}', '\0', '\0']), ('\u{18b}', ['\u{18c}', '\0', '\0']), + ('\u{18e}', ['\u{1dd}', '\0', '\0']), ('\u{18f}', ['\u{259}', '\0', '\0']), ('\u{190}', + ['\u{25b}', '\0', '\0']), ('\u{191}', ['\u{192}', '\0', '\0']), ('\u{193}', ['\u{260}', + '\0', '\0']), ('\u{194}', ['\u{263}', '\0', '\0']), ('\u{196}', ['\u{269}', '\0', '\0']), + ('\u{197}', ['\u{268}', '\0', '\0']), ('\u{198}', ['\u{199}', '\0', '\0']), ('\u{19c}', + ['\u{26f}', '\0', '\0']), ('\u{19d}', ['\u{272}', '\0', '\0']), ('\u{19f}', ['\u{275}', + '\0', '\0']), ('\u{1a0}', ['\u{1a1}', '\0', '\0']), ('\u{1a2}', ['\u{1a3}', '\0', '\0']), + ('\u{1a4}', ['\u{1a5}', '\0', '\0']), ('\u{1a6}', ['\u{280}', '\0', '\0']), ('\u{1a7}', + ['\u{1a8}', '\0', '\0']), ('\u{1a9}', ['\u{283}', '\0', '\0']), ('\u{1ac}', ['\u{1ad}', + '\0', '\0']), ('\u{1ae}', ['\u{288}', '\0', '\0']), ('\u{1af}', ['\u{1b0}', '\0', '\0']), + ('\u{1b1}', ['\u{28a}', '\0', '\0']), ('\u{1b2}', ['\u{28b}', '\0', '\0']), ('\u{1b3}', + ['\u{1b4}', '\0', '\0']), ('\u{1b5}', ['\u{1b6}', '\0', '\0']), ('\u{1b7}', ['\u{292}', + '\0', '\0']), ('\u{1b8}', ['\u{1b9}', '\0', '\0']), ('\u{1bc}', ['\u{1bd}', '\0', '\0']), + ('\u{1c4}', ['\u{1c6}', '\0', '\0']), ('\u{1c5}', ['\u{1c6}', '\0', '\0']), ('\u{1c7}', + ['\u{1c9}', '\0', '\0']), ('\u{1c8}', ['\u{1c9}', '\0', '\0']), ('\u{1ca}', ['\u{1cc}', + '\0', '\0']), ('\u{1cb}', ['\u{1cc}', '\0', '\0']), ('\u{1cd}', ['\u{1ce}', '\0', '\0']), + ('\u{1cf}', ['\u{1d0}', '\0', '\0']), ('\u{1d1}', ['\u{1d2}', '\0', '\0']), ('\u{1d3}', + ['\u{1d4}', '\0', '\0']), ('\u{1d5}', ['\u{1d6}', '\0', '\0']), ('\u{1d7}', ['\u{1d8}', + '\0', '\0']), ('\u{1d9}', ['\u{1da}', '\0', '\0']), ('\u{1db}', ['\u{1dc}', '\0', '\0']), + ('\u{1de}', ['\u{1df}', '\0', '\0']), ('\u{1e0}', ['\u{1e1}', '\0', '\0']), ('\u{1e2}', + ['\u{1e3}', '\0', '\0']), ('\u{1e4}', ['\u{1e5}', '\0', '\0']), ('\u{1e6}', ['\u{1e7}', + '\0', '\0']), ('\u{1e8}', ['\u{1e9}', '\0', '\0']), ('\u{1ea}', ['\u{1eb}', '\0', '\0']), + ('\u{1ec}', ['\u{1ed}', '\0', '\0']), ('\u{1ee}', ['\u{1ef}', '\0', '\0']), ('\u{1f1}', + ['\u{1f3}', '\0', '\0']), ('\u{1f2}', ['\u{1f3}', '\0', '\0']), ('\u{1f4}', ['\u{1f5}', + '\0', '\0']), ('\u{1f6}', ['\u{195}', '\0', '\0']), ('\u{1f7}', ['\u{1bf}', '\0', '\0']), + ('\u{1f8}', ['\u{1f9}', '\0', '\0']), ('\u{1fa}', ['\u{1fb}', '\0', '\0']), ('\u{1fc}', + ['\u{1fd}', '\0', '\0']), ('\u{1fe}', ['\u{1ff}', '\0', '\0']), ('\u{200}', ['\u{201}', + '\0', '\0']), ('\u{202}', ['\u{203}', '\0', '\0']), ('\u{204}', ['\u{205}', '\0', '\0']), + ('\u{206}', ['\u{207}', '\0', '\0']), ('\u{208}', ['\u{209}', '\0', '\0']), ('\u{20a}', + ['\u{20b}', '\0', '\0']), ('\u{20c}', ['\u{20d}', '\0', '\0']), ('\u{20e}', ['\u{20f}', + '\0', '\0']), ('\u{210}', ['\u{211}', '\0', '\0']), ('\u{212}', ['\u{213}', '\0', '\0']), + ('\u{214}', ['\u{215}', '\0', '\0']), ('\u{216}', ['\u{217}', '\0', '\0']), ('\u{218}', + ['\u{219}', '\0', '\0']), ('\u{21a}', ['\u{21b}', '\0', '\0']), ('\u{21c}', ['\u{21d}', + '\0', '\0']), ('\u{21e}', ['\u{21f}', '\0', '\0']), ('\u{220}', ['\u{19e}', '\0', '\0']), + ('\u{222}', ['\u{223}', '\0', '\0']), ('\u{224}', ['\u{225}', '\0', '\0']), ('\u{226}', + ['\u{227}', '\0', '\0']), ('\u{228}', ['\u{229}', '\0', '\0']), ('\u{22a}', ['\u{22b}', + '\0', '\0']), ('\u{22c}', ['\u{22d}', '\0', '\0']), ('\u{22e}', ['\u{22f}', '\0', '\0']), + ('\u{230}', ['\u{231}', '\0', '\0']), ('\u{232}', ['\u{233}', '\0', '\0']), ('\u{23a}', + ['\u{2c65}', '\0', '\0']), ('\u{23b}', ['\u{23c}', '\0', '\0']), ('\u{23d}', ['\u{19a}', + '\0', '\0']), ('\u{23e}', ['\u{2c66}', '\0', '\0']), ('\u{241}', ['\u{242}', '\0', '\0']), + ('\u{243}', ['\u{180}', '\0', '\0']), ('\u{244}', ['\u{289}', '\0', '\0']), ('\u{245}', + ['\u{28c}', '\0', '\0']), ('\u{246}', ['\u{247}', '\0', '\0']), ('\u{248}', ['\u{249}', + '\0', '\0']), ('\u{24a}', ['\u{24b}', '\0', '\0']), ('\u{24c}', ['\u{24d}', '\0', '\0']), + ('\u{24e}', ['\u{24f}', '\0', '\0']), ('\u{370}', ['\u{371}', '\0', '\0']), ('\u{372}', + ['\u{373}', '\0', '\0']), ('\u{376}', ['\u{377}', '\0', '\0']), ('\u{37f}', ['\u{3f3}', + '\0', '\0']), ('\u{386}', ['\u{3ac}', '\0', '\0']), ('\u{388}', ['\u{3ad}', '\0', '\0']), + ('\u{389}', ['\u{3ae}', '\0', '\0']), ('\u{38a}', ['\u{3af}', '\0', '\0']), ('\u{38c}', + ['\u{3cc}', '\0', '\0']), ('\u{38e}', ['\u{3cd}', '\0', '\0']), ('\u{38f}', ['\u{3ce}', + '\0', '\0']), ('\u{391}', ['\u{3b1}', '\0', '\0']), ('\u{392}', ['\u{3b2}', '\0', '\0']), + ('\u{393}', ['\u{3b3}', '\0', '\0']), ('\u{394}', ['\u{3b4}', '\0', '\0']), ('\u{395}', + ['\u{3b5}', '\0', '\0']), ('\u{396}', ['\u{3b6}', '\0', '\0']), ('\u{397}', ['\u{3b7}', + '\0', '\0']), ('\u{398}', ['\u{3b8}', '\0', '\0']), ('\u{399}', ['\u{3b9}', '\0', '\0']), + ('\u{39a}', ['\u{3ba}', '\0', '\0']), ('\u{39b}', ['\u{3bb}', '\0', '\0']), ('\u{39c}', + ['\u{3bc}', '\0', '\0']), ('\u{39d}', ['\u{3bd}', '\0', '\0']), ('\u{39e}', ['\u{3be}', + '\0', '\0']), ('\u{39f}', ['\u{3bf}', '\0', '\0']), ('\u{3a0}', ['\u{3c0}', '\0', '\0']), + ('\u{3a1}', ['\u{3c1}', '\0', '\0']), ('\u{3a3}', ['\u{3c3}', '\0', '\0']), ('\u{3a4}', + ['\u{3c4}', '\0', '\0']), ('\u{3a5}', ['\u{3c5}', '\0', '\0']), ('\u{3a6}', ['\u{3c6}', + '\0', '\0']), ('\u{3a7}', ['\u{3c7}', '\0', '\0']), ('\u{3a8}', ['\u{3c8}', '\0', '\0']), + ('\u{3a9}', ['\u{3c9}', '\0', '\0']), ('\u{3aa}', ['\u{3ca}', '\0', '\0']), ('\u{3ab}', + ['\u{3cb}', '\0', '\0']), ('\u{3cf}', ['\u{3d7}', '\0', '\0']), ('\u{3d8}', ['\u{3d9}', + '\0', '\0']), ('\u{3da}', ['\u{3db}', '\0', '\0']), ('\u{3dc}', ['\u{3dd}', '\0', '\0']), + ('\u{3de}', ['\u{3df}', '\0', '\0']), ('\u{3e0}', ['\u{3e1}', '\0', '\0']), ('\u{3e2}', + ['\u{3e3}', '\0', '\0']), ('\u{3e4}', ['\u{3e5}', '\0', '\0']), ('\u{3e6}', ['\u{3e7}', + '\0', '\0']), ('\u{3e8}', ['\u{3e9}', '\0', '\0']), ('\u{3ea}', ['\u{3eb}', '\0', '\0']), + ('\u{3ec}', ['\u{3ed}', '\0', '\0']), ('\u{3ee}', ['\u{3ef}', '\0', '\0']), ('\u{3f4}', + ['\u{3b8}', '\0', '\0']), ('\u{3f7}', ['\u{3f8}', '\0', '\0']), ('\u{3f9}', ['\u{3f2}', + '\0', '\0']), ('\u{3fa}', ['\u{3fb}', '\0', '\0']), ('\u{3fd}', ['\u{37b}', '\0', '\0']), + ('\u{3fe}', ['\u{37c}', '\0', '\0']), ('\u{3ff}', ['\u{37d}', '\0', '\0']), ('\u{400}', + ['\u{450}', '\0', '\0']), ('\u{401}', ['\u{451}', '\0', '\0']), ('\u{402}', ['\u{452}', + '\0', '\0']), ('\u{403}', ['\u{453}', '\0', '\0']), ('\u{404}', ['\u{454}', '\0', '\0']), + ('\u{405}', ['\u{455}', '\0', '\0']), ('\u{406}', ['\u{456}', '\0', '\0']), ('\u{407}', + ['\u{457}', '\0', '\0']), ('\u{408}', ['\u{458}', '\0', '\0']), ('\u{409}', ['\u{459}', + '\0', '\0']), ('\u{40a}', ['\u{45a}', '\0', '\0']), ('\u{40b}', ['\u{45b}', '\0', '\0']), + ('\u{40c}', ['\u{45c}', '\0', '\0']), ('\u{40d}', ['\u{45d}', '\0', '\0']), ('\u{40e}', + ['\u{45e}', '\0', '\0']), ('\u{40f}', ['\u{45f}', '\0', '\0']), ('\u{410}', ['\u{430}', + '\0', '\0']), ('\u{411}', ['\u{431}', '\0', '\0']), ('\u{412}', ['\u{432}', '\0', '\0']), + ('\u{413}', ['\u{433}', '\0', '\0']), ('\u{414}', ['\u{434}', '\0', '\0']), ('\u{415}', + ['\u{435}', '\0', '\0']), ('\u{416}', ['\u{436}', '\0', '\0']), ('\u{417}', ['\u{437}', + '\0', '\0']), ('\u{418}', ['\u{438}', '\0', '\0']), ('\u{419}', ['\u{439}', '\0', '\0']), + ('\u{41a}', ['\u{43a}', '\0', '\0']), ('\u{41b}', ['\u{43b}', '\0', '\0']), ('\u{41c}', + ['\u{43c}', '\0', '\0']), ('\u{41d}', ['\u{43d}', '\0', '\0']), ('\u{41e}', ['\u{43e}', + '\0', '\0']), ('\u{41f}', ['\u{43f}', '\0', '\0']), ('\u{420}', ['\u{440}', '\0', '\0']), + ('\u{421}', ['\u{441}', '\0', '\0']), ('\u{422}', ['\u{442}', '\0', '\0']), ('\u{423}', + ['\u{443}', '\0', '\0']), ('\u{424}', ['\u{444}', '\0', '\0']), ('\u{425}', ['\u{445}', + '\0', '\0']), ('\u{426}', ['\u{446}', '\0', '\0']), ('\u{427}', ['\u{447}', '\0', '\0']), + ('\u{428}', ['\u{448}', '\0', '\0']), ('\u{429}', ['\u{449}', '\0', '\0']), ('\u{42a}', + ['\u{44a}', '\0', '\0']), ('\u{42b}', ['\u{44b}', '\0', '\0']), ('\u{42c}', ['\u{44c}', + '\0', '\0']), ('\u{42d}', ['\u{44d}', '\0', '\0']), ('\u{42e}', ['\u{44e}', '\0', '\0']), + ('\u{42f}', ['\u{44f}', '\0', '\0']), ('\u{460}', ['\u{461}', '\0', '\0']), ('\u{462}', + ['\u{463}', '\0', '\0']), ('\u{464}', ['\u{465}', '\0', '\0']), ('\u{466}', ['\u{467}', + '\0', '\0']), ('\u{468}', ['\u{469}', '\0', '\0']), ('\u{46a}', ['\u{46b}', '\0', '\0']), + ('\u{46c}', ['\u{46d}', '\0', '\0']), ('\u{46e}', ['\u{46f}', '\0', '\0']), ('\u{470}', + ['\u{471}', '\0', '\0']), ('\u{472}', ['\u{473}', '\0', '\0']), ('\u{474}', ['\u{475}', + '\0', '\0']), ('\u{476}', ['\u{477}', '\0', '\0']), ('\u{478}', ['\u{479}', '\0', '\0']), + ('\u{47a}', ['\u{47b}', '\0', '\0']), ('\u{47c}', ['\u{47d}', '\0', '\0']), ('\u{47e}', + ['\u{47f}', '\0', '\0']), ('\u{480}', ['\u{481}', '\0', '\0']), ('\u{48a}', ['\u{48b}', + '\0', '\0']), ('\u{48c}', ['\u{48d}', '\0', '\0']), ('\u{48e}', ['\u{48f}', '\0', '\0']), + ('\u{490}', ['\u{491}', '\0', '\0']), ('\u{492}', ['\u{493}', '\0', '\0']), ('\u{494}', + ['\u{495}', '\0', '\0']), ('\u{496}', ['\u{497}', '\0', '\0']), ('\u{498}', ['\u{499}', + '\0', '\0']), ('\u{49a}', ['\u{49b}', '\0', '\0']), ('\u{49c}', ['\u{49d}', '\0', '\0']), + ('\u{49e}', ['\u{49f}', '\0', '\0']), ('\u{4a0}', ['\u{4a1}', '\0', '\0']), ('\u{4a2}', + ['\u{4a3}', '\0', '\0']), ('\u{4a4}', ['\u{4a5}', '\0', '\0']), ('\u{4a6}', ['\u{4a7}', + '\0', '\0']), ('\u{4a8}', ['\u{4a9}', '\0', '\0']), ('\u{4aa}', ['\u{4ab}', '\0', '\0']), + ('\u{4ac}', ['\u{4ad}', '\0', '\0']), ('\u{4ae}', ['\u{4af}', '\0', '\0']), ('\u{4b0}', + ['\u{4b1}', '\0', '\0']), ('\u{4b2}', ['\u{4b3}', '\0', '\0']), ('\u{4b4}', ['\u{4b5}', + '\0', '\0']), ('\u{4b6}', ['\u{4b7}', '\0', '\0']), ('\u{4b8}', ['\u{4b9}', '\0', '\0']), + ('\u{4ba}', ['\u{4bb}', '\0', '\0']), ('\u{4bc}', ['\u{4bd}', '\0', '\0']), ('\u{4be}', + ['\u{4bf}', '\0', '\0']), ('\u{4c0}', ['\u{4cf}', '\0', '\0']), ('\u{4c1}', ['\u{4c2}', + '\0', '\0']), ('\u{4c3}', ['\u{4c4}', '\0', '\0']), ('\u{4c5}', ['\u{4c6}', '\0', '\0']), + ('\u{4c7}', ['\u{4c8}', '\0', '\0']), ('\u{4c9}', ['\u{4ca}', '\0', '\0']), ('\u{4cb}', + ['\u{4cc}', '\0', '\0']), ('\u{4cd}', ['\u{4ce}', '\0', '\0']), ('\u{4d0}', ['\u{4d1}', + '\0', '\0']), ('\u{4d2}', ['\u{4d3}', '\0', '\0']), ('\u{4d4}', ['\u{4d5}', '\0', '\0']), + ('\u{4d6}', ['\u{4d7}', '\0', '\0']), ('\u{4d8}', ['\u{4d9}', '\0', '\0']), ('\u{4da}', + ['\u{4db}', '\0', '\0']), ('\u{4dc}', ['\u{4dd}', '\0', '\0']), ('\u{4de}', ['\u{4df}', + '\0', '\0']), ('\u{4e0}', ['\u{4e1}', '\0', '\0']), ('\u{4e2}', ['\u{4e3}', '\0', '\0']), + ('\u{4e4}', ['\u{4e5}', '\0', '\0']), ('\u{4e6}', ['\u{4e7}', '\0', '\0']), ('\u{4e8}', + ['\u{4e9}', '\0', '\0']), ('\u{4ea}', ['\u{4eb}', '\0', '\0']), ('\u{4ec}', ['\u{4ed}', + '\0', '\0']), ('\u{4ee}', ['\u{4ef}', '\0', '\0']), ('\u{4f0}', ['\u{4f1}', '\0', '\0']), + ('\u{4f2}', ['\u{4f3}', '\0', '\0']), ('\u{4f4}', ['\u{4f5}', '\0', '\0']), ('\u{4f6}', + ['\u{4f7}', '\0', '\0']), ('\u{4f8}', ['\u{4f9}', '\0', '\0']), ('\u{4fa}', ['\u{4fb}', + '\0', '\0']), ('\u{4fc}', ['\u{4fd}', '\0', '\0']), ('\u{4fe}', ['\u{4ff}', '\0', '\0']), + ('\u{500}', ['\u{501}', '\0', '\0']), ('\u{502}', ['\u{503}', '\0', '\0']), ('\u{504}', + ['\u{505}', '\0', '\0']), ('\u{506}', ['\u{507}', '\0', '\0']), ('\u{508}', ['\u{509}', + '\0', '\0']), ('\u{50a}', ['\u{50b}', '\0', '\0']), ('\u{50c}', ['\u{50d}', '\0', '\0']), + ('\u{50e}', ['\u{50f}', '\0', '\0']), ('\u{510}', ['\u{511}', '\0', '\0']), ('\u{512}', + ['\u{513}', '\0', '\0']), ('\u{514}', ['\u{515}', '\0', '\0']), ('\u{516}', ['\u{517}', + '\0', '\0']), ('\u{518}', ['\u{519}', '\0', '\0']), ('\u{51a}', ['\u{51b}', '\0', '\0']), + ('\u{51c}', ['\u{51d}', '\0', '\0']), ('\u{51e}', ['\u{51f}', '\0', '\0']), ('\u{520}', + ['\u{521}', '\0', '\0']), ('\u{522}', ['\u{523}', '\0', '\0']), ('\u{524}', ['\u{525}', + '\0', '\0']), ('\u{526}', ['\u{527}', '\0', '\0']), ('\u{528}', ['\u{529}', '\0', '\0']), + ('\u{52a}', ['\u{52b}', '\0', '\0']), ('\u{52c}', ['\u{52d}', '\0', '\0']), ('\u{52e}', + ['\u{52f}', '\0', '\0']), ('\u{531}', ['\u{561}', '\0', '\0']), ('\u{532}', ['\u{562}', + '\0', '\0']), ('\u{533}', ['\u{563}', '\0', '\0']), ('\u{534}', ['\u{564}', '\0', '\0']), + ('\u{535}', ['\u{565}', '\0', '\0']), ('\u{536}', ['\u{566}', '\0', '\0']), ('\u{537}', + ['\u{567}', '\0', '\0']), ('\u{538}', ['\u{568}', '\0', '\0']), ('\u{539}', ['\u{569}', + '\0', '\0']), ('\u{53a}', ['\u{56a}', '\0', '\0']), ('\u{53b}', ['\u{56b}', '\0', '\0']), + ('\u{53c}', ['\u{56c}', '\0', '\0']), ('\u{53d}', ['\u{56d}', '\0', '\0']), ('\u{53e}', + ['\u{56e}', '\0', '\0']), ('\u{53f}', ['\u{56f}', '\0', '\0']), ('\u{540}', ['\u{570}', + '\0', '\0']), ('\u{541}', ['\u{571}', '\0', '\0']), ('\u{542}', ['\u{572}', '\0', '\0']), + ('\u{543}', ['\u{573}', '\0', '\0']), ('\u{544}', ['\u{574}', '\0', '\0']), ('\u{545}', + ['\u{575}', '\0', '\0']), ('\u{546}', ['\u{576}', '\0', '\0']), ('\u{547}', ['\u{577}', + '\0', '\0']), ('\u{548}', ['\u{578}', '\0', '\0']), ('\u{549}', ['\u{579}', '\0', '\0']), + ('\u{54a}', ['\u{57a}', '\0', '\0']), ('\u{54b}', ['\u{57b}', '\0', '\0']), ('\u{54c}', + ['\u{57c}', '\0', '\0']), ('\u{54d}', ['\u{57d}', '\0', '\0']), ('\u{54e}', ['\u{57e}', + '\0', '\0']), ('\u{54f}', ['\u{57f}', '\0', '\0']), ('\u{550}', ['\u{580}', '\0', '\0']), + ('\u{551}', ['\u{581}', '\0', '\0']), ('\u{552}', ['\u{582}', '\0', '\0']), ('\u{553}', + ['\u{583}', '\0', '\0']), ('\u{554}', ['\u{584}', '\0', '\0']), ('\u{555}', ['\u{585}', + '\0', '\0']), ('\u{556}', ['\u{586}', '\0', '\0']), ('\u{10a0}', ['\u{2d00}', '\0', '\0']), + ('\u{10a1}', ['\u{2d01}', '\0', '\0']), ('\u{10a2}', ['\u{2d02}', '\0', '\0']), ('\u{10a3}', + ['\u{2d03}', '\0', '\0']), ('\u{10a4}', ['\u{2d04}', '\0', '\0']), ('\u{10a5}', ['\u{2d05}', + '\0', '\0']), ('\u{10a6}', ['\u{2d06}', '\0', '\0']), ('\u{10a7}', ['\u{2d07}', '\0', + '\0']), ('\u{10a8}', ['\u{2d08}', '\0', '\0']), ('\u{10a9}', ['\u{2d09}', '\0', '\0']), + ('\u{10aa}', ['\u{2d0a}', '\0', '\0']), ('\u{10ab}', ['\u{2d0b}', '\0', '\0']), ('\u{10ac}', + ['\u{2d0c}', '\0', '\0']), ('\u{10ad}', ['\u{2d0d}', '\0', '\0']), ('\u{10ae}', ['\u{2d0e}', + '\0', '\0']), ('\u{10af}', ['\u{2d0f}', '\0', '\0']), ('\u{10b0}', ['\u{2d10}', '\0', + '\0']), ('\u{10b1}', ['\u{2d11}', '\0', '\0']), ('\u{10b2}', ['\u{2d12}', '\0', '\0']), + ('\u{10b3}', ['\u{2d13}', '\0', '\0']), ('\u{10b4}', ['\u{2d14}', '\0', '\0']), ('\u{10b5}', + ['\u{2d15}', '\0', '\0']), ('\u{10b6}', ['\u{2d16}', '\0', '\0']), ('\u{10b7}', ['\u{2d17}', + '\0', '\0']), ('\u{10b8}', ['\u{2d18}', '\0', '\0']), ('\u{10b9}', ['\u{2d19}', '\0', + '\0']), ('\u{10ba}', ['\u{2d1a}', '\0', '\0']), ('\u{10bb}', ['\u{2d1b}', '\0', '\0']), + ('\u{10bc}', ['\u{2d1c}', '\0', '\0']), ('\u{10bd}', ['\u{2d1d}', '\0', '\0']), ('\u{10be}', + ['\u{2d1e}', '\0', '\0']), ('\u{10bf}', ['\u{2d1f}', '\0', '\0']), ('\u{10c0}', ['\u{2d20}', + '\0', '\0']), ('\u{10c1}', ['\u{2d21}', '\0', '\0']), ('\u{10c2}', ['\u{2d22}', '\0', + '\0']), ('\u{10c3}', ['\u{2d23}', '\0', '\0']), ('\u{10c4}', ['\u{2d24}', '\0', '\0']), + ('\u{10c5}', ['\u{2d25}', '\0', '\0']), ('\u{10c7}', ['\u{2d27}', '\0', '\0']), ('\u{10cd}', + ['\u{2d2d}', '\0', '\0']), ('\u{13a0}', ['\u{ab70}', '\0', '\0']), ('\u{13a1}', ['\u{ab71}', + '\0', '\0']), ('\u{13a2}', ['\u{ab72}', '\0', '\0']), ('\u{13a3}', ['\u{ab73}', '\0', + '\0']), ('\u{13a4}', ['\u{ab74}', '\0', '\0']), ('\u{13a5}', ['\u{ab75}', '\0', '\0']), + ('\u{13a6}', ['\u{ab76}', '\0', '\0']), ('\u{13a7}', ['\u{ab77}', '\0', '\0']), ('\u{13a8}', + ['\u{ab78}', '\0', '\0']), ('\u{13a9}', ['\u{ab79}', '\0', '\0']), ('\u{13aa}', ['\u{ab7a}', + '\0', '\0']), ('\u{13ab}', ['\u{ab7b}', '\0', '\0']), ('\u{13ac}', ['\u{ab7c}', '\0', + '\0']), ('\u{13ad}', ['\u{ab7d}', '\0', '\0']), ('\u{13ae}', ['\u{ab7e}', '\0', '\0']), + ('\u{13af}', ['\u{ab7f}', '\0', '\0']), ('\u{13b0}', ['\u{ab80}', '\0', '\0']), ('\u{13b1}', + ['\u{ab81}', '\0', '\0']), ('\u{13b2}', ['\u{ab82}', '\0', '\0']), ('\u{13b3}', ['\u{ab83}', + '\0', '\0']), ('\u{13b4}', ['\u{ab84}', '\0', '\0']), ('\u{13b5}', ['\u{ab85}', '\0', + '\0']), ('\u{13b6}', ['\u{ab86}', '\0', '\0']), ('\u{13b7}', ['\u{ab87}', '\0', '\0']), + ('\u{13b8}', ['\u{ab88}', '\0', '\0']), ('\u{13b9}', ['\u{ab89}', '\0', '\0']), ('\u{13ba}', + ['\u{ab8a}', '\0', '\0']), ('\u{13bb}', ['\u{ab8b}', '\0', '\0']), ('\u{13bc}', ['\u{ab8c}', + '\0', '\0']), ('\u{13bd}', ['\u{ab8d}', '\0', '\0']), ('\u{13be}', ['\u{ab8e}', '\0', + '\0']), ('\u{13bf}', ['\u{ab8f}', '\0', '\0']), ('\u{13c0}', ['\u{ab90}', '\0', '\0']), + ('\u{13c1}', ['\u{ab91}', '\0', '\0']), ('\u{13c2}', ['\u{ab92}', '\0', '\0']), ('\u{13c3}', + ['\u{ab93}', '\0', '\0']), ('\u{13c4}', ['\u{ab94}', '\0', '\0']), ('\u{13c5}', ['\u{ab95}', + '\0', '\0']), ('\u{13c6}', ['\u{ab96}', '\0', '\0']), ('\u{13c7}', ['\u{ab97}', '\0', + '\0']), ('\u{13c8}', ['\u{ab98}', '\0', '\0']), ('\u{13c9}', ['\u{ab99}', '\0', '\0']), + ('\u{13ca}', ['\u{ab9a}', '\0', '\0']), ('\u{13cb}', ['\u{ab9b}', '\0', '\0']), ('\u{13cc}', + ['\u{ab9c}', '\0', '\0']), ('\u{13cd}', ['\u{ab9d}', '\0', '\0']), ('\u{13ce}', ['\u{ab9e}', + '\0', '\0']), ('\u{13cf}', ['\u{ab9f}', '\0', '\0']), ('\u{13d0}', ['\u{aba0}', '\0', + '\0']), ('\u{13d1}', ['\u{aba1}', '\0', '\0']), ('\u{13d2}', ['\u{aba2}', '\0', '\0']), + ('\u{13d3}', ['\u{aba3}', '\0', '\0']), ('\u{13d4}', ['\u{aba4}', '\0', '\0']), ('\u{13d5}', + ['\u{aba5}', '\0', '\0']), ('\u{13d6}', ['\u{aba6}', '\0', '\0']), ('\u{13d7}', ['\u{aba7}', + '\0', '\0']), ('\u{13d8}', ['\u{aba8}', '\0', '\0']), ('\u{13d9}', ['\u{aba9}', '\0', + '\0']), ('\u{13da}', ['\u{abaa}', '\0', '\0']), ('\u{13db}', ['\u{abab}', '\0', '\0']), + ('\u{13dc}', ['\u{abac}', '\0', '\0']), ('\u{13dd}', ['\u{abad}', '\0', '\0']), ('\u{13de}', + ['\u{abae}', '\0', '\0']), ('\u{13df}', ['\u{abaf}', '\0', '\0']), ('\u{13e0}', ['\u{abb0}', + '\0', '\0']), ('\u{13e1}', ['\u{abb1}', '\0', '\0']), ('\u{13e2}', ['\u{abb2}', '\0', + '\0']), ('\u{13e3}', ['\u{abb3}', '\0', '\0']), ('\u{13e4}', ['\u{abb4}', '\0', '\0']), + ('\u{13e5}', ['\u{abb5}', '\0', '\0']), ('\u{13e6}', ['\u{abb6}', '\0', '\0']), ('\u{13e7}', + ['\u{abb7}', '\0', '\0']), ('\u{13e8}', ['\u{abb8}', '\0', '\0']), ('\u{13e9}', ['\u{abb9}', + '\0', '\0']), ('\u{13ea}', ['\u{abba}', '\0', '\0']), ('\u{13eb}', ['\u{abbb}', '\0', + '\0']), ('\u{13ec}', ['\u{abbc}', '\0', '\0']), ('\u{13ed}', ['\u{abbd}', '\0', '\0']), + ('\u{13ee}', ['\u{abbe}', '\0', '\0']), ('\u{13ef}', ['\u{abbf}', '\0', '\0']), ('\u{13f0}', + ['\u{13f8}', '\0', '\0']), ('\u{13f1}', ['\u{13f9}', '\0', '\0']), ('\u{13f2}', ['\u{13fa}', + '\0', '\0']), ('\u{13f3}', ['\u{13fb}', '\0', '\0']), ('\u{13f4}', ['\u{13fc}', '\0', + '\0']), ('\u{13f5}', ['\u{13fd}', '\0', '\0']), ('\u{1e00}', ['\u{1e01}', '\0', '\0']), + ('\u{1e02}', ['\u{1e03}', '\0', '\0']), ('\u{1e04}', ['\u{1e05}', '\0', '\0']), ('\u{1e06}', + ['\u{1e07}', '\0', '\0']), ('\u{1e08}', ['\u{1e09}', '\0', '\0']), ('\u{1e0a}', ['\u{1e0b}', + '\0', '\0']), ('\u{1e0c}', ['\u{1e0d}', '\0', '\0']), ('\u{1e0e}', ['\u{1e0f}', '\0', + '\0']), ('\u{1e10}', ['\u{1e11}', '\0', '\0']), ('\u{1e12}', ['\u{1e13}', '\0', '\0']), + ('\u{1e14}', ['\u{1e15}', '\0', '\0']), ('\u{1e16}', ['\u{1e17}', '\0', '\0']), ('\u{1e18}', + ['\u{1e19}', '\0', '\0']), ('\u{1e1a}', ['\u{1e1b}', '\0', '\0']), ('\u{1e1c}', ['\u{1e1d}', + '\0', '\0']), ('\u{1e1e}', ['\u{1e1f}', '\0', '\0']), ('\u{1e20}', ['\u{1e21}', '\0', + '\0']), ('\u{1e22}', ['\u{1e23}', '\0', '\0']), ('\u{1e24}', ['\u{1e25}', '\0', '\0']), + ('\u{1e26}', ['\u{1e27}', '\0', '\0']), ('\u{1e28}', ['\u{1e29}', '\0', '\0']), ('\u{1e2a}', + ['\u{1e2b}', '\0', '\0']), ('\u{1e2c}', ['\u{1e2d}', '\0', '\0']), ('\u{1e2e}', ['\u{1e2f}', + '\0', '\0']), ('\u{1e30}', ['\u{1e31}', '\0', '\0']), ('\u{1e32}', ['\u{1e33}', '\0', + '\0']), ('\u{1e34}', ['\u{1e35}', '\0', '\0']), ('\u{1e36}', ['\u{1e37}', '\0', '\0']), + ('\u{1e38}', ['\u{1e39}', '\0', '\0']), ('\u{1e3a}', ['\u{1e3b}', '\0', '\0']), ('\u{1e3c}', + ['\u{1e3d}', '\0', '\0']), ('\u{1e3e}', ['\u{1e3f}', '\0', '\0']), ('\u{1e40}', ['\u{1e41}', + '\0', '\0']), ('\u{1e42}', ['\u{1e43}', '\0', '\0']), ('\u{1e44}', ['\u{1e45}', '\0', + '\0']), ('\u{1e46}', ['\u{1e47}', '\0', '\0']), ('\u{1e48}', ['\u{1e49}', '\0', '\0']), + ('\u{1e4a}', ['\u{1e4b}', '\0', '\0']), ('\u{1e4c}', ['\u{1e4d}', '\0', '\0']), ('\u{1e4e}', + ['\u{1e4f}', '\0', '\0']), ('\u{1e50}', ['\u{1e51}', '\0', '\0']), ('\u{1e52}', ['\u{1e53}', + '\0', '\0']), ('\u{1e54}', ['\u{1e55}', '\0', '\0']), ('\u{1e56}', ['\u{1e57}', '\0', + '\0']), ('\u{1e58}', ['\u{1e59}', '\0', '\0']), ('\u{1e5a}', ['\u{1e5b}', '\0', '\0']), + ('\u{1e5c}', ['\u{1e5d}', '\0', '\0']), ('\u{1e5e}', ['\u{1e5f}', '\0', '\0']), ('\u{1e60}', + ['\u{1e61}', '\0', '\0']), ('\u{1e62}', ['\u{1e63}', '\0', '\0']), ('\u{1e64}', ['\u{1e65}', + '\0', '\0']), ('\u{1e66}', ['\u{1e67}', '\0', '\0']), ('\u{1e68}', ['\u{1e69}', '\0', + '\0']), ('\u{1e6a}', ['\u{1e6b}', '\0', '\0']), ('\u{1e6c}', ['\u{1e6d}', '\0', '\0']), + ('\u{1e6e}', ['\u{1e6f}', '\0', '\0']), ('\u{1e70}', ['\u{1e71}', '\0', '\0']), ('\u{1e72}', + ['\u{1e73}', '\0', '\0']), ('\u{1e74}', ['\u{1e75}', '\0', '\0']), ('\u{1e76}', ['\u{1e77}', + '\0', '\0']), ('\u{1e78}', ['\u{1e79}', '\0', '\0']), ('\u{1e7a}', ['\u{1e7b}', '\0', + '\0']), ('\u{1e7c}', ['\u{1e7d}', '\0', '\0']), ('\u{1e7e}', ['\u{1e7f}', '\0', '\0']), + ('\u{1e80}', ['\u{1e81}', '\0', '\0']), ('\u{1e82}', ['\u{1e83}', '\0', '\0']), ('\u{1e84}', + ['\u{1e85}', '\0', '\0']), ('\u{1e86}', ['\u{1e87}', '\0', '\0']), ('\u{1e88}', ['\u{1e89}', + '\0', '\0']), ('\u{1e8a}', ['\u{1e8b}', '\0', '\0']), ('\u{1e8c}', ['\u{1e8d}', '\0', + '\0']), ('\u{1e8e}', ['\u{1e8f}', '\0', '\0']), ('\u{1e90}', ['\u{1e91}', '\0', '\0']), + ('\u{1e92}', ['\u{1e93}', '\0', '\0']), ('\u{1e94}', ['\u{1e95}', '\0', '\0']), ('\u{1e9e}', + ['\u{df}', '\0', '\0']), ('\u{1ea0}', ['\u{1ea1}', '\0', '\0']), ('\u{1ea2}', ['\u{1ea3}', + '\0', '\0']), ('\u{1ea4}', ['\u{1ea5}', '\0', '\0']), ('\u{1ea6}', ['\u{1ea7}', '\0', + '\0']), ('\u{1ea8}', ['\u{1ea9}', '\0', '\0']), ('\u{1eaa}', ['\u{1eab}', '\0', '\0']), + ('\u{1eac}', ['\u{1ead}', '\0', '\0']), ('\u{1eae}', ['\u{1eaf}', '\0', '\0']), ('\u{1eb0}', + ['\u{1eb1}', '\0', '\0']), ('\u{1eb2}', ['\u{1eb3}', '\0', '\0']), ('\u{1eb4}', ['\u{1eb5}', + '\0', '\0']), ('\u{1eb6}', ['\u{1eb7}', '\0', '\0']), ('\u{1eb8}', ['\u{1eb9}', '\0', + '\0']), ('\u{1eba}', ['\u{1ebb}', '\0', '\0']), ('\u{1ebc}', ['\u{1ebd}', '\0', '\0']), + ('\u{1ebe}', ['\u{1ebf}', '\0', '\0']), ('\u{1ec0}', ['\u{1ec1}', '\0', '\0']), ('\u{1ec2}', + ['\u{1ec3}', '\0', '\0']), ('\u{1ec4}', ['\u{1ec5}', '\0', '\0']), ('\u{1ec6}', ['\u{1ec7}', + '\0', '\0']), ('\u{1ec8}', ['\u{1ec9}', '\0', '\0']), ('\u{1eca}', ['\u{1ecb}', '\0', + '\0']), ('\u{1ecc}', ['\u{1ecd}', '\0', '\0']), ('\u{1ece}', ['\u{1ecf}', '\0', '\0']), + ('\u{1ed0}', ['\u{1ed1}', '\0', '\0']), ('\u{1ed2}', ['\u{1ed3}', '\0', '\0']), ('\u{1ed4}', + ['\u{1ed5}', '\0', '\0']), ('\u{1ed6}', ['\u{1ed7}', '\0', '\0']), ('\u{1ed8}', ['\u{1ed9}', + '\0', '\0']), ('\u{1eda}', ['\u{1edb}', '\0', '\0']), ('\u{1edc}', ['\u{1edd}', '\0', + '\0']), ('\u{1ede}', ['\u{1edf}', '\0', '\0']), ('\u{1ee0}', ['\u{1ee1}', '\0', '\0']), + ('\u{1ee2}', ['\u{1ee3}', '\0', '\0']), ('\u{1ee4}', ['\u{1ee5}', '\0', '\0']), ('\u{1ee6}', + ['\u{1ee7}', '\0', '\0']), ('\u{1ee8}', ['\u{1ee9}', '\0', '\0']), ('\u{1eea}', ['\u{1eeb}', + '\0', '\0']), ('\u{1eec}', ['\u{1eed}', '\0', '\0']), ('\u{1eee}', ['\u{1eef}', '\0', + '\0']), ('\u{1ef0}', ['\u{1ef1}', '\0', '\0']), ('\u{1ef2}', ['\u{1ef3}', '\0', '\0']), + ('\u{1ef4}', ['\u{1ef5}', '\0', '\0']), ('\u{1ef6}', ['\u{1ef7}', '\0', '\0']), ('\u{1ef8}', + ['\u{1ef9}', '\0', '\0']), ('\u{1efa}', ['\u{1efb}', '\0', '\0']), ('\u{1efc}', ['\u{1efd}', + '\0', '\0']), ('\u{1efe}', ['\u{1eff}', '\0', '\0']), ('\u{1f08}', ['\u{1f00}', '\0', + '\0']), ('\u{1f09}', ['\u{1f01}', '\0', '\0']), ('\u{1f0a}', ['\u{1f02}', '\0', '\0']), + ('\u{1f0b}', ['\u{1f03}', '\0', '\0']), ('\u{1f0c}', ['\u{1f04}', '\0', '\0']), ('\u{1f0d}', + ['\u{1f05}', '\0', '\0']), ('\u{1f0e}', ['\u{1f06}', '\0', '\0']), ('\u{1f0f}', ['\u{1f07}', + '\0', '\0']), ('\u{1f18}', ['\u{1f10}', '\0', '\0']), ('\u{1f19}', ['\u{1f11}', '\0', + '\0']), ('\u{1f1a}', ['\u{1f12}', '\0', '\0']), ('\u{1f1b}', ['\u{1f13}', '\0', '\0']), + ('\u{1f1c}', ['\u{1f14}', '\0', '\0']), ('\u{1f1d}', ['\u{1f15}', '\0', '\0']), ('\u{1f28}', + ['\u{1f20}', '\0', '\0']), ('\u{1f29}', ['\u{1f21}', '\0', '\0']), ('\u{1f2a}', ['\u{1f22}', + '\0', '\0']), ('\u{1f2b}', ['\u{1f23}', '\0', '\0']), ('\u{1f2c}', ['\u{1f24}', '\0', + '\0']), ('\u{1f2d}', ['\u{1f25}', '\0', '\0']), ('\u{1f2e}', ['\u{1f26}', '\0', '\0']), + ('\u{1f2f}', ['\u{1f27}', '\0', '\0']), ('\u{1f38}', ['\u{1f30}', '\0', '\0']), ('\u{1f39}', + ['\u{1f31}', '\0', '\0']), ('\u{1f3a}', ['\u{1f32}', '\0', '\0']), ('\u{1f3b}', ['\u{1f33}', + '\0', '\0']), ('\u{1f3c}', ['\u{1f34}', '\0', '\0']), ('\u{1f3d}', ['\u{1f35}', '\0', + '\0']), ('\u{1f3e}', ['\u{1f36}', '\0', '\0']), ('\u{1f3f}', ['\u{1f37}', '\0', '\0']), + ('\u{1f48}', ['\u{1f40}', '\0', '\0']), ('\u{1f49}', ['\u{1f41}', '\0', '\0']), ('\u{1f4a}', + ['\u{1f42}', '\0', '\0']), ('\u{1f4b}', ['\u{1f43}', '\0', '\0']), ('\u{1f4c}', ['\u{1f44}', + '\0', '\0']), ('\u{1f4d}', ['\u{1f45}', '\0', '\0']), ('\u{1f59}', ['\u{1f51}', '\0', + '\0']), ('\u{1f5b}', ['\u{1f53}', '\0', '\0']), ('\u{1f5d}', ['\u{1f55}', '\0', '\0']), + ('\u{1f5f}', ['\u{1f57}', '\0', '\0']), ('\u{1f68}', ['\u{1f60}', '\0', '\0']), ('\u{1f69}', + ['\u{1f61}', '\0', '\0']), ('\u{1f6a}', ['\u{1f62}', '\0', '\0']), ('\u{1f6b}', ['\u{1f63}', + '\0', '\0']), ('\u{1f6c}', ['\u{1f64}', '\0', '\0']), ('\u{1f6d}', ['\u{1f65}', '\0', + '\0']), ('\u{1f6e}', ['\u{1f66}', '\0', '\0']), ('\u{1f6f}', ['\u{1f67}', '\0', '\0']), + ('\u{1f88}', ['\u{1f80}', '\0', '\0']), ('\u{1f89}', ['\u{1f81}', '\0', '\0']), ('\u{1f8a}', + ['\u{1f82}', '\0', '\0']), ('\u{1f8b}', ['\u{1f83}', '\0', '\0']), ('\u{1f8c}', ['\u{1f84}', + '\0', '\0']), ('\u{1f8d}', ['\u{1f85}', '\0', '\0']), ('\u{1f8e}', ['\u{1f86}', '\0', + '\0']), ('\u{1f8f}', ['\u{1f87}', '\0', '\0']), ('\u{1f98}', ['\u{1f90}', '\0', '\0']), + ('\u{1f99}', ['\u{1f91}', '\0', '\0']), ('\u{1f9a}', ['\u{1f92}', '\0', '\0']), ('\u{1f9b}', + ['\u{1f93}', '\0', '\0']), ('\u{1f9c}', ['\u{1f94}', '\0', '\0']), ('\u{1f9d}', ['\u{1f95}', + '\0', '\0']), ('\u{1f9e}', ['\u{1f96}', '\0', '\0']), ('\u{1f9f}', ['\u{1f97}', '\0', + '\0']), ('\u{1fa8}', ['\u{1fa0}', '\0', '\0']), ('\u{1fa9}', ['\u{1fa1}', '\0', '\0']), + ('\u{1faa}', ['\u{1fa2}', '\0', '\0']), ('\u{1fab}', ['\u{1fa3}', '\0', '\0']), ('\u{1fac}', + ['\u{1fa4}', '\0', '\0']), ('\u{1fad}', ['\u{1fa5}', '\0', '\0']), ('\u{1fae}', ['\u{1fa6}', + '\0', '\0']), ('\u{1faf}', ['\u{1fa7}', '\0', '\0']), ('\u{1fb8}', ['\u{1fb0}', '\0', + '\0']), ('\u{1fb9}', ['\u{1fb1}', '\0', '\0']), ('\u{1fba}', ['\u{1f70}', '\0', '\0']), + ('\u{1fbb}', ['\u{1f71}', '\0', '\0']), ('\u{1fbc}', ['\u{1fb3}', '\0', '\0']), ('\u{1fc8}', + ['\u{1f72}', '\0', '\0']), ('\u{1fc9}', ['\u{1f73}', '\0', '\0']), ('\u{1fca}', ['\u{1f74}', + '\0', '\0']), ('\u{1fcb}', ['\u{1f75}', '\0', '\0']), ('\u{1fcc}', ['\u{1fc3}', '\0', + '\0']), ('\u{1fd8}', ['\u{1fd0}', '\0', '\0']), ('\u{1fd9}', ['\u{1fd1}', '\0', '\0']), + ('\u{1fda}', ['\u{1f76}', '\0', '\0']), ('\u{1fdb}', ['\u{1f77}', '\0', '\0']), ('\u{1fe8}', + ['\u{1fe0}', '\0', '\0']), ('\u{1fe9}', ['\u{1fe1}', '\0', '\0']), ('\u{1fea}', ['\u{1f7a}', + '\0', '\0']), ('\u{1feb}', ['\u{1f7b}', '\0', '\0']), ('\u{1fec}', ['\u{1fe5}', '\0', + '\0']), ('\u{1ff8}', ['\u{1f78}', '\0', '\0']), ('\u{1ff9}', ['\u{1f79}', '\0', '\0']), + ('\u{1ffa}', ['\u{1f7c}', '\0', '\0']), ('\u{1ffb}', ['\u{1f7d}', '\0', '\0']), ('\u{1ffc}', + ['\u{1ff3}', '\0', '\0']), ('\u{2126}', ['\u{3c9}', '\0', '\0']), ('\u{212a}', ['\u{6b}', + '\0', '\0']), ('\u{212b}', ['\u{e5}', '\0', '\0']), ('\u{2132}', ['\u{214e}', '\0', '\0']), + ('\u{2160}', ['\u{2170}', '\0', '\0']), ('\u{2161}', ['\u{2171}', '\0', '\0']), ('\u{2162}', + ['\u{2172}', '\0', '\0']), ('\u{2163}', ['\u{2173}', '\0', '\0']), ('\u{2164}', ['\u{2174}', + '\0', '\0']), ('\u{2165}', ['\u{2175}', '\0', '\0']), ('\u{2166}', ['\u{2176}', '\0', + '\0']), ('\u{2167}', ['\u{2177}', '\0', '\0']), ('\u{2168}', ['\u{2178}', '\0', '\0']), + ('\u{2169}', ['\u{2179}', '\0', '\0']), ('\u{216a}', ['\u{217a}', '\0', '\0']), ('\u{216b}', + ['\u{217b}', '\0', '\0']), ('\u{216c}', ['\u{217c}', '\0', '\0']), ('\u{216d}', ['\u{217d}', + '\0', '\0']), ('\u{216e}', ['\u{217e}', '\0', '\0']), ('\u{216f}', ['\u{217f}', '\0', + '\0']), ('\u{2183}', ['\u{2184}', '\0', '\0']), ('\u{24b6}', ['\u{24d0}', '\0', '\0']), + ('\u{24b7}', ['\u{24d1}', '\0', '\0']), ('\u{24b8}', ['\u{24d2}', '\0', '\0']), ('\u{24b9}', + ['\u{24d3}', '\0', '\0']), ('\u{24ba}', ['\u{24d4}', '\0', '\0']), ('\u{24bb}', ['\u{24d5}', + '\0', '\0']), ('\u{24bc}', ['\u{24d6}', '\0', '\0']), ('\u{24bd}', ['\u{24d7}', '\0', + '\0']), ('\u{24be}', ['\u{24d8}', '\0', '\0']), ('\u{24bf}', ['\u{24d9}', '\0', '\0']), + ('\u{24c0}', ['\u{24da}', '\0', '\0']), ('\u{24c1}', ['\u{24db}', '\0', '\0']), ('\u{24c2}', + ['\u{24dc}', '\0', '\0']), ('\u{24c3}', ['\u{24dd}', '\0', '\0']), ('\u{24c4}', ['\u{24de}', + '\0', '\0']), ('\u{24c5}', ['\u{24df}', '\0', '\0']), ('\u{24c6}', ['\u{24e0}', '\0', + '\0']), ('\u{24c7}', ['\u{24e1}', '\0', '\0']), ('\u{24c8}', ['\u{24e2}', '\0', '\0']), + ('\u{24c9}', ['\u{24e3}', '\0', '\0']), ('\u{24ca}', ['\u{24e4}', '\0', '\0']), ('\u{24cb}', + ['\u{24e5}', '\0', '\0']), ('\u{24cc}', ['\u{24e6}', '\0', '\0']), ('\u{24cd}', ['\u{24e7}', + '\0', '\0']), ('\u{24ce}', ['\u{24e8}', '\0', '\0']), ('\u{24cf}', ['\u{24e9}', '\0', + '\0']), ('\u{2c00}', ['\u{2c30}', '\0', '\0']), ('\u{2c01}', ['\u{2c31}', '\0', '\0']), + ('\u{2c02}', ['\u{2c32}', '\0', '\0']), ('\u{2c03}', ['\u{2c33}', '\0', '\0']), ('\u{2c04}', + ['\u{2c34}', '\0', '\0']), ('\u{2c05}', ['\u{2c35}', '\0', '\0']), ('\u{2c06}', ['\u{2c36}', + '\0', '\0']), ('\u{2c07}', ['\u{2c37}', '\0', '\0']), ('\u{2c08}', ['\u{2c38}', '\0', + '\0']), ('\u{2c09}', ['\u{2c39}', '\0', '\0']), ('\u{2c0a}', ['\u{2c3a}', '\0', '\0']), + ('\u{2c0b}', ['\u{2c3b}', '\0', '\0']), ('\u{2c0c}', ['\u{2c3c}', '\0', '\0']), ('\u{2c0d}', + ['\u{2c3d}', '\0', '\0']), ('\u{2c0e}', ['\u{2c3e}', '\0', '\0']), ('\u{2c0f}', ['\u{2c3f}', + '\0', '\0']), ('\u{2c10}', ['\u{2c40}', '\0', '\0']), ('\u{2c11}', ['\u{2c41}', '\0', + '\0']), ('\u{2c12}', ['\u{2c42}', '\0', '\0']), ('\u{2c13}', ['\u{2c43}', '\0', '\0']), + ('\u{2c14}', ['\u{2c44}', '\0', '\0']), ('\u{2c15}', ['\u{2c45}', '\0', '\0']), ('\u{2c16}', + ['\u{2c46}', '\0', '\0']), ('\u{2c17}', ['\u{2c47}', '\0', '\0']), ('\u{2c18}', ['\u{2c48}', + '\0', '\0']), ('\u{2c19}', ['\u{2c49}', '\0', '\0']), ('\u{2c1a}', ['\u{2c4a}', '\0', + '\0']), ('\u{2c1b}', ['\u{2c4b}', '\0', '\0']), ('\u{2c1c}', ['\u{2c4c}', '\0', '\0']), + ('\u{2c1d}', ['\u{2c4d}', '\0', '\0']), ('\u{2c1e}', ['\u{2c4e}', '\0', '\0']), ('\u{2c1f}', + ['\u{2c4f}', '\0', '\0']), ('\u{2c20}', ['\u{2c50}', '\0', '\0']), ('\u{2c21}', ['\u{2c51}', + '\0', '\0']), ('\u{2c22}', ['\u{2c52}', '\0', '\0']), ('\u{2c23}', ['\u{2c53}', '\0', + '\0']), ('\u{2c24}', ['\u{2c54}', '\0', '\0']), ('\u{2c25}', ['\u{2c55}', '\0', '\0']), + ('\u{2c26}', ['\u{2c56}', '\0', '\0']), ('\u{2c27}', ['\u{2c57}', '\0', '\0']), ('\u{2c28}', + ['\u{2c58}', '\0', '\0']), ('\u{2c29}', ['\u{2c59}', '\0', '\0']), ('\u{2c2a}', ['\u{2c5a}', + '\0', '\0']), ('\u{2c2b}', ['\u{2c5b}', '\0', '\0']), ('\u{2c2c}', ['\u{2c5c}', '\0', + '\0']), ('\u{2c2d}', ['\u{2c5d}', '\0', '\0']), ('\u{2c2e}', ['\u{2c5e}', '\0', '\0']), + ('\u{2c60}', ['\u{2c61}', '\0', '\0']), ('\u{2c62}', ['\u{26b}', '\0', '\0']), ('\u{2c63}', + ['\u{1d7d}', '\0', '\0']), ('\u{2c64}', ['\u{27d}', '\0', '\0']), ('\u{2c67}', ['\u{2c68}', + '\0', '\0']), ('\u{2c69}', ['\u{2c6a}', '\0', '\0']), ('\u{2c6b}', ['\u{2c6c}', '\0', + '\0']), ('\u{2c6d}', ['\u{251}', '\0', '\0']), ('\u{2c6e}', ['\u{271}', '\0', '\0']), + ('\u{2c6f}', ['\u{250}', '\0', '\0']), ('\u{2c70}', ['\u{252}', '\0', '\0']), ('\u{2c72}', + ['\u{2c73}', '\0', '\0']), ('\u{2c75}', ['\u{2c76}', '\0', '\0']), ('\u{2c7e}', ['\u{23f}', + '\0', '\0']), ('\u{2c7f}', ['\u{240}', '\0', '\0']), ('\u{2c80}', ['\u{2c81}', '\0', '\0']), + ('\u{2c82}', ['\u{2c83}', '\0', '\0']), ('\u{2c84}', ['\u{2c85}', '\0', '\0']), ('\u{2c86}', + ['\u{2c87}', '\0', '\0']), ('\u{2c88}', ['\u{2c89}', '\0', '\0']), ('\u{2c8a}', ['\u{2c8b}', + '\0', '\0']), ('\u{2c8c}', ['\u{2c8d}', '\0', '\0']), ('\u{2c8e}', ['\u{2c8f}', '\0', + '\0']), ('\u{2c90}', ['\u{2c91}', '\0', '\0']), ('\u{2c92}', ['\u{2c93}', '\0', '\0']), + ('\u{2c94}', ['\u{2c95}', '\0', '\0']), ('\u{2c96}', ['\u{2c97}', '\0', '\0']), ('\u{2c98}', + ['\u{2c99}', '\0', '\0']), ('\u{2c9a}', ['\u{2c9b}', '\0', '\0']), ('\u{2c9c}', ['\u{2c9d}', + '\0', '\0']), ('\u{2c9e}', ['\u{2c9f}', '\0', '\0']), ('\u{2ca0}', ['\u{2ca1}', '\0', + '\0']), ('\u{2ca2}', ['\u{2ca3}', '\0', '\0']), ('\u{2ca4}', ['\u{2ca5}', '\0', '\0']), + ('\u{2ca6}', ['\u{2ca7}', '\0', '\0']), ('\u{2ca8}', ['\u{2ca9}', '\0', '\0']), ('\u{2caa}', + ['\u{2cab}', '\0', '\0']), ('\u{2cac}', ['\u{2cad}', '\0', '\0']), ('\u{2cae}', ['\u{2caf}', + '\0', '\0']), ('\u{2cb0}', ['\u{2cb1}', '\0', '\0']), ('\u{2cb2}', ['\u{2cb3}', '\0', + '\0']), ('\u{2cb4}', ['\u{2cb5}', '\0', '\0']), ('\u{2cb6}', ['\u{2cb7}', '\0', '\0']), + ('\u{2cb8}', ['\u{2cb9}', '\0', '\0']), ('\u{2cba}', ['\u{2cbb}', '\0', '\0']), ('\u{2cbc}', + ['\u{2cbd}', '\0', '\0']), ('\u{2cbe}', ['\u{2cbf}', '\0', '\0']), ('\u{2cc0}', ['\u{2cc1}', + '\0', '\0']), ('\u{2cc2}', ['\u{2cc3}', '\0', '\0']), ('\u{2cc4}', ['\u{2cc5}', '\0', + '\0']), ('\u{2cc6}', ['\u{2cc7}', '\0', '\0']), ('\u{2cc8}', ['\u{2cc9}', '\0', '\0']), + ('\u{2cca}', ['\u{2ccb}', '\0', '\0']), ('\u{2ccc}', ['\u{2ccd}', '\0', '\0']), ('\u{2cce}', + ['\u{2ccf}', '\0', '\0']), ('\u{2cd0}', ['\u{2cd1}', '\0', '\0']), ('\u{2cd2}', ['\u{2cd3}', + '\0', '\0']), ('\u{2cd4}', ['\u{2cd5}', '\0', '\0']), ('\u{2cd6}', ['\u{2cd7}', '\0', + '\0']), ('\u{2cd8}', ['\u{2cd9}', '\0', '\0']), ('\u{2cda}', ['\u{2cdb}', '\0', '\0']), + ('\u{2cdc}', ['\u{2cdd}', '\0', '\0']), ('\u{2cde}', ['\u{2cdf}', '\0', '\0']), ('\u{2ce0}', + ['\u{2ce1}', '\0', '\0']), ('\u{2ce2}', ['\u{2ce3}', '\0', '\0']), ('\u{2ceb}', ['\u{2cec}', + '\0', '\0']), ('\u{2ced}', ['\u{2cee}', '\0', '\0']), ('\u{2cf2}', ['\u{2cf3}', '\0', + '\0']), ('\u{a640}', ['\u{a641}', '\0', '\0']), ('\u{a642}', ['\u{a643}', '\0', '\0']), + ('\u{a644}', ['\u{a645}', '\0', '\0']), ('\u{a646}', ['\u{a647}', '\0', '\0']), ('\u{a648}', + ['\u{a649}', '\0', '\0']), ('\u{a64a}', ['\u{a64b}', '\0', '\0']), ('\u{a64c}', ['\u{a64d}', + '\0', '\0']), ('\u{a64e}', ['\u{a64f}', '\0', '\0']), ('\u{a650}', ['\u{a651}', '\0', + '\0']), ('\u{a652}', ['\u{a653}', '\0', '\0']), ('\u{a654}', ['\u{a655}', '\0', '\0']), + ('\u{a656}', ['\u{a657}', '\0', '\0']), ('\u{a658}', ['\u{a659}', '\0', '\0']), ('\u{a65a}', + ['\u{a65b}', '\0', '\0']), ('\u{a65c}', ['\u{a65d}', '\0', '\0']), ('\u{a65e}', ['\u{a65f}', + '\0', '\0']), ('\u{a660}', ['\u{a661}', '\0', '\0']), ('\u{a662}', ['\u{a663}', '\0', + '\0']), ('\u{a664}', ['\u{a665}', '\0', '\0']), ('\u{a666}', ['\u{a667}', '\0', '\0']), + ('\u{a668}', ['\u{a669}', '\0', '\0']), ('\u{a66a}', ['\u{a66b}', '\0', '\0']), ('\u{a66c}', + ['\u{a66d}', '\0', '\0']), ('\u{a680}', ['\u{a681}', '\0', '\0']), ('\u{a682}', ['\u{a683}', + '\0', '\0']), ('\u{a684}', ['\u{a685}', '\0', '\0']), ('\u{a686}', ['\u{a687}', '\0', + '\0']), ('\u{a688}', ['\u{a689}', '\0', '\0']), ('\u{a68a}', ['\u{a68b}', '\0', '\0']), + ('\u{a68c}', ['\u{a68d}', '\0', '\0']), ('\u{a68e}', ['\u{a68f}', '\0', '\0']), ('\u{a690}', + ['\u{a691}', '\0', '\0']), ('\u{a692}', ['\u{a693}', '\0', '\0']), ('\u{a694}', ['\u{a695}', + '\0', '\0']), ('\u{a696}', ['\u{a697}', '\0', '\0']), ('\u{a698}', ['\u{a699}', '\0', + '\0']), ('\u{a69a}', ['\u{a69b}', '\0', '\0']), ('\u{a722}', ['\u{a723}', '\0', '\0']), + ('\u{a724}', ['\u{a725}', '\0', '\0']), ('\u{a726}', ['\u{a727}', '\0', '\0']), ('\u{a728}', + ['\u{a729}', '\0', '\0']), ('\u{a72a}', ['\u{a72b}', '\0', '\0']), ('\u{a72c}', ['\u{a72d}', + '\0', '\0']), ('\u{a72e}', ['\u{a72f}', '\0', '\0']), ('\u{a732}', ['\u{a733}', '\0', + '\0']), ('\u{a734}', ['\u{a735}', '\0', '\0']), ('\u{a736}', ['\u{a737}', '\0', '\0']), + ('\u{a738}', ['\u{a739}', '\0', '\0']), ('\u{a73a}', ['\u{a73b}', '\0', '\0']), ('\u{a73c}', + ['\u{a73d}', '\0', '\0']), ('\u{a73e}', ['\u{a73f}', '\0', '\0']), ('\u{a740}', ['\u{a741}', + '\0', '\0']), ('\u{a742}', ['\u{a743}', '\0', '\0']), ('\u{a744}', ['\u{a745}', '\0', + '\0']), ('\u{a746}', ['\u{a747}', '\0', '\0']), ('\u{a748}', ['\u{a749}', '\0', '\0']), + ('\u{a74a}', ['\u{a74b}', '\0', '\0']), ('\u{a74c}', ['\u{a74d}', '\0', '\0']), ('\u{a74e}', + ['\u{a74f}', '\0', '\0']), ('\u{a750}', ['\u{a751}', '\0', '\0']), ('\u{a752}', ['\u{a753}', + '\0', '\0']), ('\u{a754}', ['\u{a755}', '\0', '\0']), ('\u{a756}', ['\u{a757}', '\0', + '\0']), ('\u{a758}', ['\u{a759}', '\0', '\0']), ('\u{a75a}', ['\u{a75b}', '\0', '\0']), + ('\u{a75c}', ['\u{a75d}', '\0', '\0']), ('\u{a75e}', ['\u{a75f}', '\0', '\0']), ('\u{a760}', + ['\u{a761}', '\0', '\0']), ('\u{a762}', ['\u{a763}', '\0', '\0']), ('\u{a764}', ['\u{a765}', + '\0', '\0']), ('\u{a766}', ['\u{a767}', '\0', '\0']), ('\u{a768}', ['\u{a769}', '\0', + '\0']), ('\u{a76a}', ['\u{a76b}', '\0', '\0']), ('\u{a76c}', ['\u{a76d}', '\0', '\0']), + ('\u{a76e}', ['\u{a76f}', '\0', '\0']), ('\u{a779}', ['\u{a77a}', '\0', '\0']), ('\u{a77b}', + ['\u{a77c}', '\0', '\0']), ('\u{a77d}', ['\u{1d79}', '\0', '\0']), ('\u{a77e}', ['\u{a77f}', + '\0', '\0']), ('\u{a780}', ['\u{a781}', '\0', '\0']), ('\u{a782}', ['\u{a783}', '\0', + '\0']), ('\u{a784}', ['\u{a785}', '\0', '\0']), ('\u{a786}', ['\u{a787}', '\0', '\0']), + ('\u{a78b}', ['\u{a78c}', '\0', '\0']), ('\u{a78d}', ['\u{265}', '\0', '\0']), ('\u{a790}', + ['\u{a791}', '\0', '\0']), ('\u{a792}', ['\u{a793}', '\0', '\0']), ('\u{a796}', ['\u{a797}', + '\0', '\0']), ('\u{a798}', ['\u{a799}', '\0', '\0']), ('\u{a79a}', ['\u{a79b}', '\0', + '\0']), ('\u{a79c}', ['\u{a79d}', '\0', '\0']), ('\u{a79e}', ['\u{a79f}', '\0', '\0']), + ('\u{a7a0}', ['\u{a7a1}', '\0', '\0']), ('\u{a7a2}', ['\u{a7a3}', '\0', '\0']), ('\u{a7a4}', + ['\u{a7a5}', '\0', '\0']), ('\u{a7a6}', ['\u{a7a7}', '\0', '\0']), ('\u{a7a8}', ['\u{a7a9}', + '\0', '\0']), ('\u{a7aa}', ['\u{266}', '\0', '\0']), ('\u{a7ab}', ['\u{25c}', '\0', '\0']), + ('\u{a7ac}', ['\u{261}', '\0', '\0']), ('\u{a7ad}', ['\u{26c}', '\0', '\0']), ('\u{a7ae}', + ['\u{26a}', '\0', '\0']), ('\u{a7b0}', ['\u{29e}', '\0', '\0']), ('\u{a7b1}', ['\u{287}', + '\0', '\0']), ('\u{a7b2}', ['\u{29d}', '\0', '\0']), ('\u{a7b3}', ['\u{ab53}', '\0', '\0']), + ('\u{a7b4}', ['\u{a7b5}', '\0', '\0']), ('\u{a7b6}', ['\u{a7b7}', '\0', '\0']), ('\u{ff21}', + ['\u{ff41}', '\0', '\0']), ('\u{ff22}', ['\u{ff42}', '\0', '\0']), ('\u{ff23}', ['\u{ff43}', + '\0', '\0']), ('\u{ff24}', ['\u{ff44}', '\0', '\0']), ('\u{ff25}', ['\u{ff45}', '\0', + '\0']), ('\u{ff26}', ['\u{ff46}', '\0', '\0']), ('\u{ff27}', ['\u{ff47}', '\0', '\0']), + ('\u{ff28}', ['\u{ff48}', '\0', '\0']), ('\u{ff29}', ['\u{ff49}', '\0', '\0']), ('\u{ff2a}', + ['\u{ff4a}', '\0', '\0']), ('\u{ff2b}', ['\u{ff4b}', '\0', '\0']), ('\u{ff2c}', ['\u{ff4c}', + '\0', '\0']), ('\u{ff2d}', ['\u{ff4d}', '\0', '\0']), ('\u{ff2e}', ['\u{ff4e}', '\0', + '\0']), ('\u{ff2f}', ['\u{ff4f}', '\0', '\0']), ('\u{ff30}', ['\u{ff50}', '\0', '\0']), + ('\u{ff31}', ['\u{ff51}', '\0', '\0']), ('\u{ff32}', ['\u{ff52}', '\0', '\0']), ('\u{ff33}', + ['\u{ff53}', '\0', '\0']), ('\u{ff34}', ['\u{ff54}', '\0', '\0']), ('\u{ff35}', ['\u{ff55}', + '\0', '\0']), ('\u{ff36}', ['\u{ff56}', '\0', '\0']), ('\u{ff37}', ['\u{ff57}', '\0', + '\0']), ('\u{ff38}', ['\u{ff58}', '\0', '\0']), ('\u{ff39}', ['\u{ff59}', '\0', '\0']), + ('\u{ff3a}', ['\u{ff5a}', '\0', '\0']), ('\u{10400}', ['\u{10428}', '\0', '\0']), + ('\u{10401}', ['\u{10429}', '\0', '\0']), ('\u{10402}', ['\u{1042a}', '\0', '\0']), + ('\u{10403}', ['\u{1042b}', '\0', '\0']), ('\u{10404}', ['\u{1042c}', '\0', '\0']), + ('\u{10405}', ['\u{1042d}', '\0', '\0']), ('\u{10406}', ['\u{1042e}', '\0', '\0']), + ('\u{10407}', ['\u{1042f}', '\0', '\0']), ('\u{10408}', ['\u{10430}', '\0', '\0']), + ('\u{10409}', ['\u{10431}', '\0', '\0']), ('\u{1040a}', ['\u{10432}', '\0', '\0']), + ('\u{1040b}', ['\u{10433}', '\0', '\0']), ('\u{1040c}', ['\u{10434}', '\0', '\0']), + ('\u{1040d}', ['\u{10435}', '\0', '\0']), ('\u{1040e}', ['\u{10436}', '\0', '\0']), + ('\u{1040f}', ['\u{10437}', '\0', '\0']), ('\u{10410}', ['\u{10438}', '\0', '\0']), + ('\u{10411}', ['\u{10439}', '\0', '\0']), ('\u{10412}', ['\u{1043a}', '\0', '\0']), + ('\u{10413}', ['\u{1043b}', '\0', '\0']), ('\u{10414}', ['\u{1043c}', '\0', '\0']), + ('\u{10415}', ['\u{1043d}', '\0', '\0']), ('\u{10416}', ['\u{1043e}', '\0', '\0']), + ('\u{10417}', ['\u{1043f}', '\0', '\0']), ('\u{10418}', ['\u{10440}', '\0', '\0']), + ('\u{10419}', ['\u{10441}', '\0', '\0']), ('\u{1041a}', ['\u{10442}', '\0', '\0']), + ('\u{1041b}', ['\u{10443}', '\0', '\0']), ('\u{1041c}', ['\u{10444}', '\0', '\0']), + ('\u{1041d}', ['\u{10445}', '\0', '\0']), ('\u{1041e}', ['\u{10446}', '\0', '\0']), + ('\u{1041f}', ['\u{10447}', '\0', '\0']), ('\u{10420}', ['\u{10448}', '\0', '\0']), + ('\u{10421}', ['\u{10449}', '\0', '\0']), ('\u{10422}', ['\u{1044a}', '\0', '\0']), + ('\u{10423}', ['\u{1044b}', '\0', '\0']), ('\u{10424}', ['\u{1044c}', '\0', '\0']), + ('\u{10425}', ['\u{1044d}', '\0', '\0']), ('\u{10426}', ['\u{1044e}', '\0', '\0']), + ('\u{10427}', ['\u{1044f}', '\0', '\0']), ('\u{104b0}', ['\u{104d8}', '\0', '\0']), + ('\u{104b1}', ['\u{104d9}', '\0', '\0']), ('\u{104b2}', ['\u{104da}', '\0', '\0']), + ('\u{104b3}', ['\u{104db}', '\0', '\0']), ('\u{104b4}', ['\u{104dc}', '\0', '\0']), + ('\u{104b5}', ['\u{104dd}', '\0', '\0']), ('\u{104b6}', ['\u{104de}', '\0', '\0']), + ('\u{104b7}', ['\u{104df}', '\0', '\0']), ('\u{104b8}', ['\u{104e0}', '\0', '\0']), + ('\u{104b9}', ['\u{104e1}', '\0', '\0']), ('\u{104ba}', ['\u{104e2}', '\0', '\0']), + ('\u{104bb}', ['\u{104e3}', '\0', '\0']), ('\u{104bc}', ['\u{104e4}', '\0', '\0']), + ('\u{104bd}', ['\u{104e5}', '\0', '\0']), ('\u{104be}', ['\u{104e6}', '\0', '\0']), + ('\u{104bf}', ['\u{104e7}', '\0', '\0']), ('\u{104c0}', ['\u{104e8}', '\0', '\0']), + ('\u{104c1}', ['\u{104e9}', '\0', '\0']), ('\u{104c2}', ['\u{104ea}', '\0', '\0']), + ('\u{104c3}', ['\u{104eb}', '\0', '\0']), ('\u{104c4}', ['\u{104ec}', '\0', '\0']), + ('\u{104c5}', ['\u{104ed}', '\0', '\0']), ('\u{104c6}', ['\u{104ee}', '\0', '\0']), + ('\u{104c7}', ['\u{104ef}', '\0', '\0']), ('\u{104c8}', ['\u{104f0}', '\0', '\0']), + ('\u{104c9}', ['\u{104f1}', '\0', '\0']), ('\u{104ca}', ['\u{104f2}', '\0', '\0']), + ('\u{104cb}', ['\u{104f3}', '\0', '\0']), ('\u{104cc}', ['\u{104f4}', '\0', '\0']), + ('\u{104cd}', ['\u{104f5}', '\0', '\0']), ('\u{104ce}', ['\u{104f6}', '\0', '\0']), + ('\u{104cf}', ['\u{104f7}', '\0', '\0']), ('\u{104d0}', ['\u{104f8}', '\0', '\0']), + ('\u{104d1}', ['\u{104f9}', '\0', '\0']), ('\u{104d2}', ['\u{104fa}', '\0', '\0']), + ('\u{104d3}', ['\u{104fb}', '\0', '\0']), ('\u{10c80}', ['\u{10cc0}', '\0', '\0']), + ('\u{10c81}', ['\u{10cc1}', '\0', '\0']), ('\u{10c82}', ['\u{10cc2}', '\0', '\0']), + ('\u{10c83}', ['\u{10cc3}', '\0', '\0']), ('\u{10c84}', ['\u{10cc4}', '\0', '\0']), + ('\u{10c85}', ['\u{10cc5}', '\0', '\0']), ('\u{10c86}', ['\u{10cc6}', '\0', '\0']), + ('\u{10c87}', ['\u{10cc7}', '\0', '\0']), ('\u{10c88}', ['\u{10cc8}', '\0', '\0']), + ('\u{10c89}', ['\u{10cc9}', '\0', '\0']), ('\u{10c8a}', ['\u{10cca}', '\0', '\0']), + ('\u{10c8b}', ['\u{10ccb}', '\0', '\0']), ('\u{10c8c}', ['\u{10ccc}', '\0', '\0']), + ('\u{10c8d}', ['\u{10ccd}', '\0', '\0']), ('\u{10c8e}', ['\u{10cce}', '\0', '\0']), + ('\u{10c8f}', ['\u{10ccf}', '\0', '\0']), ('\u{10c90}', ['\u{10cd0}', '\0', '\0']), + ('\u{10c91}', ['\u{10cd1}', '\0', '\0']), ('\u{10c92}', ['\u{10cd2}', '\0', '\0']), + ('\u{10c93}', ['\u{10cd3}', '\0', '\0']), ('\u{10c94}', ['\u{10cd4}', '\0', '\0']), + ('\u{10c95}', ['\u{10cd5}', '\0', '\0']), ('\u{10c96}', ['\u{10cd6}', '\0', '\0']), + ('\u{10c97}', ['\u{10cd7}', '\0', '\0']), ('\u{10c98}', ['\u{10cd8}', '\0', '\0']), + ('\u{10c99}', ['\u{10cd9}', '\0', '\0']), ('\u{10c9a}', ['\u{10cda}', '\0', '\0']), + ('\u{10c9b}', ['\u{10cdb}', '\0', '\0']), ('\u{10c9c}', ['\u{10cdc}', '\0', '\0']), + ('\u{10c9d}', ['\u{10cdd}', '\0', '\0']), ('\u{10c9e}', ['\u{10cde}', '\0', '\0']), + ('\u{10c9f}', ['\u{10cdf}', '\0', '\0']), ('\u{10ca0}', ['\u{10ce0}', '\0', '\0']), + ('\u{10ca1}', ['\u{10ce1}', '\0', '\0']), ('\u{10ca2}', ['\u{10ce2}', '\0', '\0']), + ('\u{10ca3}', ['\u{10ce3}', '\0', '\0']), ('\u{10ca4}', ['\u{10ce4}', '\0', '\0']), + ('\u{10ca5}', ['\u{10ce5}', '\0', '\0']), ('\u{10ca6}', ['\u{10ce6}', '\0', '\0']), + ('\u{10ca7}', ['\u{10ce7}', '\0', '\0']), ('\u{10ca8}', ['\u{10ce8}', '\0', '\0']), + ('\u{10ca9}', ['\u{10ce9}', '\0', '\0']), ('\u{10caa}', ['\u{10cea}', '\0', '\0']), + ('\u{10cab}', ['\u{10ceb}', '\0', '\0']), ('\u{10cac}', ['\u{10cec}', '\0', '\0']), + ('\u{10cad}', ['\u{10ced}', '\0', '\0']), ('\u{10cae}', ['\u{10cee}', '\0', '\0']), + ('\u{10caf}', ['\u{10cef}', '\0', '\0']), ('\u{10cb0}', ['\u{10cf0}', '\0', '\0']), + ('\u{10cb1}', ['\u{10cf1}', '\0', '\0']), ('\u{10cb2}', ['\u{10cf2}', '\0', '\0']), + ('\u{118a0}', ['\u{118c0}', '\0', '\0']), ('\u{118a1}', ['\u{118c1}', '\0', '\0']), + ('\u{118a2}', ['\u{118c2}', '\0', '\0']), ('\u{118a3}', ['\u{118c3}', '\0', '\0']), + ('\u{118a4}', ['\u{118c4}', '\0', '\0']), ('\u{118a5}', ['\u{118c5}', '\0', '\0']), + ('\u{118a6}', ['\u{118c6}', '\0', '\0']), ('\u{118a7}', ['\u{118c7}', '\0', '\0']), + ('\u{118a8}', ['\u{118c8}', '\0', '\0']), ('\u{118a9}', ['\u{118c9}', '\0', '\0']), + ('\u{118aa}', ['\u{118ca}', '\0', '\0']), ('\u{118ab}', ['\u{118cb}', '\0', '\0']), + ('\u{118ac}', ['\u{118cc}', '\0', '\0']), ('\u{118ad}', ['\u{118cd}', '\0', '\0']), + ('\u{118ae}', ['\u{118ce}', '\0', '\0']), ('\u{118af}', ['\u{118cf}', '\0', '\0']), + ('\u{118b0}', ['\u{118d0}', '\0', '\0']), ('\u{118b1}', ['\u{118d1}', '\0', '\0']), + ('\u{118b2}', ['\u{118d2}', '\0', '\0']), ('\u{118b3}', ['\u{118d3}', '\0', '\0']), + ('\u{118b4}', ['\u{118d4}', '\0', '\0']), ('\u{118b5}', ['\u{118d5}', '\0', '\0']), + ('\u{118b6}', ['\u{118d6}', '\0', '\0']), ('\u{118b7}', ['\u{118d7}', '\0', '\0']), + ('\u{118b8}', ['\u{118d8}', '\0', '\0']), ('\u{118b9}', ['\u{118d9}', '\0', '\0']), + ('\u{118ba}', ['\u{118da}', '\0', '\0']), ('\u{118bb}', ['\u{118db}', '\0', '\0']), + ('\u{118bc}', ['\u{118dc}', '\0', '\0']), ('\u{118bd}', ['\u{118dd}', '\0', '\0']), + ('\u{118be}', ['\u{118de}', '\0', '\0']), ('\u{118bf}', ['\u{118df}', '\0', '\0']), + ('\u{1e900}', ['\u{1e922}', '\0', '\0']), ('\u{1e901}', ['\u{1e923}', '\0', '\0']), + ('\u{1e902}', ['\u{1e924}', '\0', '\0']), ('\u{1e903}', ['\u{1e925}', '\0', '\0']), + ('\u{1e904}', ['\u{1e926}', '\0', '\0']), ('\u{1e905}', ['\u{1e927}', '\0', '\0']), + ('\u{1e906}', ['\u{1e928}', '\0', '\0']), ('\u{1e907}', ['\u{1e929}', '\0', '\0']), + ('\u{1e908}', ['\u{1e92a}', '\0', '\0']), ('\u{1e909}', ['\u{1e92b}', '\0', '\0']), + ('\u{1e90a}', ['\u{1e92c}', '\0', '\0']), ('\u{1e90b}', ['\u{1e92d}', '\0', '\0']), + ('\u{1e90c}', ['\u{1e92e}', '\0', '\0']), ('\u{1e90d}', ['\u{1e92f}', '\0', '\0']), + ('\u{1e90e}', ['\u{1e930}', '\0', '\0']), ('\u{1e90f}', ['\u{1e931}', '\0', '\0']), + ('\u{1e910}', ['\u{1e932}', '\0', '\0']), ('\u{1e911}', ['\u{1e933}', '\0', '\0']), + ('\u{1e912}', ['\u{1e934}', '\0', '\0']), ('\u{1e913}', ['\u{1e935}', '\0', '\0']), + ('\u{1e914}', ['\u{1e936}', '\0', '\0']), ('\u{1e915}', ['\u{1e937}', '\0', '\0']), + ('\u{1e916}', ['\u{1e938}', '\0', '\0']), ('\u{1e917}', ['\u{1e939}', '\0', '\0']), + ('\u{1e918}', ['\u{1e93a}', '\0', '\0']), ('\u{1e919}', ['\u{1e93b}', '\0', '\0']), + ('\u{1e91a}', ['\u{1e93c}', '\0', '\0']), ('\u{1e91b}', ['\u{1e93d}', '\0', '\0']), + ('\u{1e91c}', ['\u{1e93e}', '\0', '\0']), ('\u{1e91d}', ['\u{1e93f}', '\0', '\0']), + ('\u{1e91e}', ['\u{1e940}', '\0', '\0']), ('\u{1e91f}', ['\u{1e941}', '\0', '\0']), + ('\u{1e920}', ['\u{1e942}', '\0', '\0']), ('\u{1e921}', ['\u{1e943}', '\0', '\0']) + ]; + + const to_uppercase_table: &[(char, [char; 3])] = &[ + ('\u{61}', ['\u{41}', '\0', '\0']), ('\u{62}', ['\u{42}', '\0', '\0']), ('\u{63}', + ['\u{43}', '\0', '\0']), ('\u{64}', ['\u{44}', '\0', '\0']), ('\u{65}', ['\u{45}', '\0', + '\0']), ('\u{66}', ['\u{46}', '\0', '\0']), ('\u{67}', ['\u{47}', '\0', '\0']), ('\u{68}', + ['\u{48}', '\0', '\0']), ('\u{69}', ['\u{49}', '\0', '\0']), ('\u{6a}', ['\u{4a}', '\0', + '\0']), ('\u{6b}', ['\u{4b}', '\0', '\0']), ('\u{6c}', ['\u{4c}', '\0', '\0']), ('\u{6d}', + ['\u{4d}', '\0', '\0']), ('\u{6e}', ['\u{4e}', '\0', '\0']), ('\u{6f}', ['\u{4f}', '\0', + '\0']), ('\u{70}', ['\u{50}', '\0', '\0']), ('\u{71}', ['\u{51}', '\0', '\0']), ('\u{72}', + ['\u{52}', '\0', '\0']), ('\u{73}', ['\u{53}', '\0', '\0']), ('\u{74}', ['\u{54}', '\0', + '\0']), ('\u{75}', ['\u{55}', '\0', '\0']), ('\u{76}', ['\u{56}', '\0', '\0']), ('\u{77}', + ['\u{57}', '\0', '\0']), ('\u{78}', ['\u{58}', '\0', '\0']), ('\u{79}', ['\u{59}', '\0', + '\0']), ('\u{7a}', ['\u{5a}', '\0', '\0']), ('\u{b5}', ['\u{39c}', '\0', '\0']), ('\u{df}', + ['\u{53}', '\u{53}', '\0']), ('\u{e0}', ['\u{c0}', '\0', '\0']), ('\u{e1}', ['\u{c1}', '\0', + '\0']), ('\u{e2}', ['\u{c2}', '\0', '\0']), ('\u{e3}', ['\u{c3}', '\0', '\0']), ('\u{e4}', + ['\u{c4}', '\0', '\0']), ('\u{e5}', ['\u{c5}', '\0', '\0']), ('\u{e6}', ['\u{c6}', '\0', + '\0']), ('\u{e7}', ['\u{c7}', '\0', '\0']), ('\u{e8}', ['\u{c8}', '\0', '\0']), ('\u{e9}', + ['\u{c9}', '\0', '\0']), ('\u{ea}', ['\u{ca}', '\0', '\0']), ('\u{eb}', ['\u{cb}', '\0', + '\0']), ('\u{ec}', ['\u{cc}', '\0', '\0']), ('\u{ed}', ['\u{cd}', '\0', '\0']), ('\u{ee}', + ['\u{ce}', '\0', '\0']), ('\u{ef}', ['\u{cf}', '\0', '\0']), ('\u{f0}', ['\u{d0}', '\0', + '\0']), ('\u{f1}', ['\u{d1}', '\0', '\0']), ('\u{f2}', ['\u{d2}', '\0', '\0']), ('\u{f3}', + ['\u{d3}', '\0', '\0']), ('\u{f4}', ['\u{d4}', '\0', '\0']), ('\u{f5}', ['\u{d5}', '\0', + '\0']), ('\u{f6}', ['\u{d6}', '\0', '\0']), ('\u{f8}', ['\u{d8}', '\0', '\0']), ('\u{f9}', + ['\u{d9}', '\0', '\0']), ('\u{fa}', ['\u{da}', '\0', '\0']), ('\u{fb}', ['\u{db}', '\0', + '\0']), ('\u{fc}', ['\u{dc}', '\0', '\0']), ('\u{fd}', ['\u{dd}', '\0', '\0']), ('\u{fe}', + ['\u{de}', '\0', '\0']), ('\u{ff}', ['\u{178}', '\0', '\0']), ('\u{101}', ['\u{100}', '\0', + '\0']), ('\u{103}', ['\u{102}', '\0', '\0']), ('\u{105}', ['\u{104}', '\0', '\0']), + ('\u{107}', ['\u{106}', '\0', '\0']), ('\u{109}', ['\u{108}', '\0', '\0']), ('\u{10b}', + ['\u{10a}', '\0', '\0']), ('\u{10d}', ['\u{10c}', '\0', '\0']), ('\u{10f}', ['\u{10e}', + '\0', '\0']), ('\u{111}', ['\u{110}', '\0', '\0']), ('\u{113}', ['\u{112}', '\0', '\0']), + ('\u{115}', ['\u{114}', '\0', '\0']), ('\u{117}', ['\u{116}', '\0', '\0']), ('\u{119}', + ['\u{118}', '\0', '\0']), ('\u{11b}', ['\u{11a}', '\0', '\0']), ('\u{11d}', ['\u{11c}', + '\0', '\0']), ('\u{11f}', ['\u{11e}', '\0', '\0']), ('\u{121}', ['\u{120}', '\0', '\0']), + ('\u{123}', ['\u{122}', '\0', '\0']), ('\u{125}', ['\u{124}', '\0', '\0']), ('\u{127}', + ['\u{126}', '\0', '\0']), ('\u{129}', ['\u{128}', '\0', '\0']), ('\u{12b}', ['\u{12a}', + '\0', '\0']), ('\u{12d}', ['\u{12c}', '\0', '\0']), ('\u{12f}', ['\u{12e}', '\0', '\0']), + ('\u{131}', ['\u{49}', '\0', '\0']), ('\u{133}', ['\u{132}', '\0', '\0']), ('\u{135}', + ['\u{134}', '\0', '\0']), ('\u{137}', ['\u{136}', '\0', '\0']), ('\u{13a}', ['\u{139}', + '\0', '\0']), ('\u{13c}', ['\u{13b}', '\0', '\0']), ('\u{13e}', ['\u{13d}', '\0', '\0']), + ('\u{140}', ['\u{13f}', '\0', '\0']), ('\u{142}', ['\u{141}', '\0', '\0']), ('\u{144}', + ['\u{143}', '\0', '\0']), ('\u{146}', ['\u{145}', '\0', '\0']), ('\u{148}', ['\u{147}', + '\0', '\0']), ('\u{149}', ['\u{2bc}', '\u{4e}', '\0']), ('\u{14b}', ['\u{14a}', '\0', + '\0']), ('\u{14d}', ['\u{14c}', '\0', '\0']), ('\u{14f}', ['\u{14e}', '\0', '\0']), + ('\u{151}', ['\u{150}', '\0', '\0']), ('\u{153}', ['\u{152}', '\0', '\0']), ('\u{155}', + ['\u{154}', '\0', '\0']), ('\u{157}', ['\u{156}', '\0', '\0']), ('\u{159}', ['\u{158}', + '\0', '\0']), ('\u{15b}', ['\u{15a}', '\0', '\0']), ('\u{15d}', ['\u{15c}', '\0', '\0']), + ('\u{15f}', ['\u{15e}', '\0', '\0']), ('\u{161}', ['\u{160}', '\0', '\0']), ('\u{163}', + ['\u{162}', '\0', '\0']), ('\u{165}', ['\u{164}', '\0', '\0']), ('\u{167}', ['\u{166}', + '\0', '\0']), ('\u{169}', ['\u{168}', '\0', '\0']), ('\u{16b}', ['\u{16a}', '\0', '\0']), + ('\u{16d}', ['\u{16c}', '\0', '\0']), ('\u{16f}', ['\u{16e}', '\0', '\0']), ('\u{171}', + ['\u{170}', '\0', '\0']), ('\u{173}', ['\u{172}', '\0', '\0']), ('\u{175}', ['\u{174}', + '\0', '\0']), ('\u{177}', ['\u{176}', '\0', '\0']), ('\u{17a}', ['\u{179}', '\0', '\0']), + ('\u{17c}', ['\u{17b}', '\0', '\0']), ('\u{17e}', ['\u{17d}', '\0', '\0']), ('\u{17f}', + ['\u{53}', '\0', '\0']), ('\u{180}', ['\u{243}', '\0', '\0']), ('\u{183}', ['\u{182}', '\0', + '\0']), ('\u{185}', ['\u{184}', '\0', '\0']), ('\u{188}', ['\u{187}', '\0', '\0']), + ('\u{18c}', ['\u{18b}', '\0', '\0']), ('\u{192}', ['\u{191}', '\0', '\0']), ('\u{195}', + ['\u{1f6}', '\0', '\0']), ('\u{199}', ['\u{198}', '\0', '\0']), ('\u{19a}', ['\u{23d}', + '\0', '\0']), ('\u{19e}', ['\u{220}', '\0', '\0']), ('\u{1a1}', ['\u{1a0}', '\0', '\0']), + ('\u{1a3}', ['\u{1a2}', '\0', '\0']), ('\u{1a5}', ['\u{1a4}', '\0', '\0']), ('\u{1a8}', + ['\u{1a7}', '\0', '\0']), ('\u{1ad}', ['\u{1ac}', '\0', '\0']), ('\u{1b0}', ['\u{1af}', + '\0', '\0']), ('\u{1b4}', ['\u{1b3}', '\0', '\0']), ('\u{1b6}', ['\u{1b5}', '\0', '\0']), + ('\u{1b9}', ['\u{1b8}', '\0', '\0']), ('\u{1bd}', ['\u{1bc}', '\0', '\0']), ('\u{1bf}', + ['\u{1f7}', '\0', '\0']), ('\u{1c5}', ['\u{1c4}', '\0', '\0']), ('\u{1c6}', ['\u{1c4}', + '\0', '\0']), ('\u{1c8}', ['\u{1c7}', '\0', '\0']), ('\u{1c9}', ['\u{1c7}', '\0', '\0']), + ('\u{1cb}', ['\u{1ca}', '\0', '\0']), ('\u{1cc}', ['\u{1ca}', '\0', '\0']), ('\u{1ce}', + ['\u{1cd}', '\0', '\0']), ('\u{1d0}', ['\u{1cf}', '\0', '\0']), ('\u{1d2}', ['\u{1d1}', + '\0', '\0']), ('\u{1d4}', ['\u{1d3}', '\0', '\0']), ('\u{1d6}', ['\u{1d5}', '\0', '\0']), + ('\u{1d8}', ['\u{1d7}', '\0', '\0']), ('\u{1da}', ['\u{1d9}', '\0', '\0']), ('\u{1dc}', + ['\u{1db}', '\0', '\0']), ('\u{1dd}', ['\u{18e}', '\0', '\0']), ('\u{1df}', ['\u{1de}', + '\0', '\0']), ('\u{1e1}', ['\u{1e0}', '\0', '\0']), ('\u{1e3}', ['\u{1e2}', '\0', '\0']), + ('\u{1e5}', ['\u{1e4}', '\0', '\0']), ('\u{1e7}', ['\u{1e6}', '\0', '\0']), ('\u{1e9}', + ['\u{1e8}', '\0', '\0']), ('\u{1eb}', ['\u{1ea}', '\0', '\0']), ('\u{1ed}', ['\u{1ec}', + '\0', '\0']), ('\u{1ef}', ['\u{1ee}', '\0', '\0']), ('\u{1f0}', ['\u{4a}', '\u{30c}', + '\0']), ('\u{1f2}', ['\u{1f1}', '\0', '\0']), ('\u{1f3}', ['\u{1f1}', '\0', '\0']), + ('\u{1f5}', ['\u{1f4}', '\0', '\0']), ('\u{1f9}', ['\u{1f8}', '\0', '\0']), ('\u{1fb}', + ['\u{1fa}', '\0', '\0']), ('\u{1fd}', ['\u{1fc}', '\0', '\0']), ('\u{1ff}', ['\u{1fe}', + '\0', '\0']), ('\u{201}', ['\u{200}', '\0', '\0']), ('\u{203}', ['\u{202}', '\0', '\0']), + ('\u{205}', ['\u{204}', '\0', '\0']), ('\u{207}', ['\u{206}', '\0', '\0']), ('\u{209}', + ['\u{208}', '\0', '\0']), ('\u{20b}', ['\u{20a}', '\0', '\0']), ('\u{20d}', ['\u{20c}', + '\0', '\0']), ('\u{20f}', ['\u{20e}', '\0', '\0']), ('\u{211}', ['\u{210}', '\0', '\0']), + ('\u{213}', ['\u{212}', '\0', '\0']), ('\u{215}', ['\u{214}', '\0', '\0']), ('\u{217}', + ['\u{216}', '\0', '\0']), ('\u{219}', ['\u{218}', '\0', '\0']), ('\u{21b}', ['\u{21a}', + '\0', '\0']), ('\u{21d}', ['\u{21c}', '\0', '\0']), ('\u{21f}', ['\u{21e}', '\0', '\0']), + ('\u{223}', ['\u{222}', '\0', '\0']), ('\u{225}', ['\u{224}', '\0', '\0']), ('\u{227}', + ['\u{226}', '\0', '\0']), ('\u{229}', ['\u{228}', '\0', '\0']), ('\u{22b}', ['\u{22a}', + '\0', '\0']), ('\u{22d}', ['\u{22c}', '\0', '\0']), ('\u{22f}', ['\u{22e}', '\0', '\0']), + ('\u{231}', ['\u{230}', '\0', '\0']), ('\u{233}', ['\u{232}', '\0', '\0']), ('\u{23c}', + ['\u{23b}', '\0', '\0']), ('\u{23f}', ['\u{2c7e}', '\0', '\0']), ('\u{240}', ['\u{2c7f}', + '\0', '\0']), ('\u{242}', ['\u{241}', '\0', '\0']), ('\u{247}', ['\u{246}', '\0', '\0']), + ('\u{249}', ['\u{248}', '\0', '\0']), ('\u{24b}', ['\u{24a}', '\0', '\0']), ('\u{24d}', + ['\u{24c}', '\0', '\0']), ('\u{24f}', ['\u{24e}', '\0', '\0']), ('\u{250}', ['\u{2c6f}', + '\0', '\0']), ('\u{251}', ['\u{2c6d}', '\0', '\0']), ('\u{252}', ['\u{2c70}', '\0', '\0']), + ('\u{253}', ['\u{181}', '\0', '\0']), ('\u{254}', ['\u{186}', '\0', '\0']), ('\u{256}', + ['\u{189}', '\0', '\0']), ('\u{257}', ['\u{18a}', '\0', '\0']), ('\u{259}', ['\u{18f}', + '\0', '\0']), ('\u{25b}', ['\u{190}', '\0', '\0']), ('\u{25c}', ['\u{a7ab}', '\0', '\0']), + ('\u{260}', ['\u{193}', '\0', '\0']), ('\u{261}', ['\u{a7ac}', '\0', '\0']), ('\u{263}', + ['\u{194}', '\0', '\0']), ('\u{265}', ['\u{a78d}', '\0', '\0']), ('\u{266}', ['\u{a7aa}', + '\0', '\0']), ('\u{268}', ['\u{197}', '\0', '\0']), ('\u{269}', ['\u{196}', '\0', '\0']), + ('\u{26a}', ['\u{a7ae}', '\0', '\0']), ('\u{26b}', ['\u{2c62}', '\0', '\0']), ('\u{26c}', + ['\u{a7ad}', '\0', '\0']), ('\u{26f}', ['\u{19c}', '\0', '\0']), ('\u{271}', ['\u{2c6e}', + '\0', '\0']), ('\u{272}', ['\u{19d}', '\0', '\0']), ('\u{275}', ['\u{19f}', '\0', '\0']), + ('\u{27d}', ['\u{2c64}', '\0', '\0']), ('\u{280}', ['\u{1a6}', '\0', '\0']), ('\u{283}', + ['\u{1a9}', '\0', '\0']), ('\u{287}', ['\u{a7b1}', '\0', '\0']), ('\u{288}', ['\u{1ae}', + '\0', '\0']), ('\u{289}', ['\u{244}', '\0', '\0']), ('\u{28a}', ['\u{1b1}', '\0', '\0']), + ('\u{28b}', ['\u{1b2}', '\0', '\0']), ('\u{28c}', ['\u{245}', '\0', '\0']), ('\u{292}', + ['\u{1b7}', '\0', '\0']), ('\u{29d}', ['\u{a7b2}', '\0', '\0']), ('\u{29e}', ['\u{a7b0}', + '\0', '\0']), ('\u{345}', ['\u{399}', '\0', '\0']), ('\u{371}', ['\u{370}', '\0', '\0']), + ('\u{373}', ['\u{372}', '\0', '\0']), ('\u{377}', ['\u{376}', '\0', '\0']), ('\u{37b}', + ['\u{3fd}', '\0', '\0']), ('\u{37c}', ['\u{3fe}', '\0', '\0']), ('\u{37d}', ['\u{3ff}', + '\0', '\0']), ('\u{390}', ['\u{399}', '\u{308}', '\u{301}']), ('\u{3ac}', ['\u{386}', '\0', + '\0']), ('\u{3ad}', ['\u{388}', '\0', '\0']), ('\u{3ae}', ['\u{389}', '\0', '\0']), + ('\u{3af}', ['\u{38a}', '\0', '\0']), ('\u{3b0}', ['\u{3a5}', '\u{308}', '\u{301}']), + ('\u{3b1}', ['\u{391}', '\0', '\0']), ('\u{3b2}', ['\u{392}', '\0', '\0']), ('\u{3b3}', + ['\u{393}', '\0', '\0']), ('\u{3b4}', ['\u{394}', '\0', '\0']), ('\u{3b5}', ['\u{395}', + '\0', '\0']), ('\u{3b6}', ['\u{396}', '\0', '\0']), ('\u{3b7}', ['\u{397}', '\0', '\0']), + ('\u{3b8}', ['\u{398}', '\0', '\0']), ('\u{3b9}', ['\u{399}', '\0', '\0']), ('\u{3ba}', + ['\u{39a}', '\0', '\0']), ('\u{3bb}', ['\u{39b}', '\0', '\0']), ('\u{3bc}', ['\u{39c}', + '\0', '\0']), ('\u{3bd}', ['\u{39d}', '\0', '\0']), ('\u{3be}', ['\u{39e}', '\0', '\0']), + ('\u{3bf}', ['\u{39f}', '\0', '\0']), ('\u{3c0}', ['\u{3a0}', '\0', '\0']), ('\u{3c1}', + ['\u{3a1}', '\0', '\0']), ('\u{3c2}', ['\u{3a3}', '\0', '\0']), ('\u{3c3}', ['\u{3a3}', + '\0', '\0']), ('\u{3c4}', ['\u{3a4}', '\0', '\0']), ('\u{3c5}', ['\u{3a5}', '\0', '\0']), + ('\u{3c6}', ['\u{3a6}', '\0', '\0']), ('\u{3c7}', ['\u{3a7}', '\0', '\0']), ('\u{3c8}', + ['\u{3a8}', '\0', '\0']), ('\u{3c9}', ['\u{3a9}', '\0', '\0']), ('\u{3ca}', ['\u{3aa}', + '\0', '\0']), ('\u{3cb}', ['\u{3ab}', '\0', '\0']), ('\u{3cc}', ['\u{38c}', '\0', '\0']), + ('\u{3cd}', ['\u{38e}', '\0', '\0']), ('\u{3ce}', ['\u{38f}', '\0', '\0']), ('\u{3d0}', + ['\u{392}', '\0', '\0']), ('\u{3d1}', ['\u{398}', '\0', '\0']), ('\u{3d5}', ['\u{3a6}', + '\0', '\0']), ('\u{3d6}', ['\u{3a0}', '\0', '\0']), ('\u{3d7}', ['\u{3cf}', '\0', '\0']), + ('\u{3d9}', ['\u{3d8}', '\0', '\0']), ('\u{3db}', ['\u{3da}', '\0', '\0']), ('\u{3dd}', + ['\u{3dc}', '\0', '\0']), ('\u{3df}', ['\u{3de}', '\0', '\0']), ('\u{3e1}', ['\u{3e0}', + '\0', '\0']), ('\u{3e3}', ['\u{3e2}', '\0', '\0']), ('\u{3e5}', ['\u{3e4}', '\0', '\0']), + ('\u{3e7}', ['\u{3e6}', '\0', '\0']), ('\u{3e9}', ['\u{3e8}', '\0', '\0']), ('\u{3eb}', + ['\u{3ea}', '\0', '\0']), ('\u{3ed}', ['\u{3ec}', '\0', '\0']), ('\u{3ef}', ['\u{3ee}', + '\0', '\0']), ('\u{3f0}', ['\u{39a}', '\0', '\0']), ('\u{3f1}', ['\u{3a1}', '\0', '\0']), + ('\u{3f2}', ['\u{3f9}', '\0', '\0']), ('\u{3f3}', ['\u{37f}', '\0', '\0']), ('\u{3f5}', + ['\u{395}', '\0', '\0']), ('\u{3f8}', ['\u{3f7}', '\0', '\0']), ('\u{3fb}', ['\u{3fa}', + '\0', '\0']), ('\u{430}', ['\u{410}', '\0', '\0']), ('\u{431}', ['\u{411}', '\0', '\0']), + ('\u{432}', ['\u{412}', '\0', '\0']), ('\u{433}', ['\u{413}', '\0', '\0']), ('\u{434}', + ['\u{414}', '\0', '\0']), ('\u{435}', ['\u{415}', '\0', '\0']), ('\u{436}', ['\u{416}', + '\0', '\0']), ('\u{437}', ['\u{417}', '\0', '\0']), ('\u{438}', ['\u{418}', '\0', '\0']), + ('\u{439}', ['\u{419}', '\0', '\0']), ('\u{43a}', ['\u{41a}', '\0', '\0']), ('\u{43b}', + ['\u{41b}', '\0', '\0']), ('\u{43c}', ['\u{41c}', '\0', '\0']), ('\u{43d}', ['\u{41d}', + '\0', '\0']), ('\u{43e}', ['\u{41e}', '\0', '\0']), ('\u{43f}', ['\u{41f}', '\0', '\0']), + ('\u{440}', ['\u{420}', '\0', '\0']), ('\u{441}', ['\u{421}', '\0', '\0']), ('\u{442}', + ['\u{422}', '\0', '\0']), ('\u{443}', ['\u{423}', '\0', '\0']), ('\u{444}', ['\u{424}', + '\0', '\0']), ('\u{445}', ['\u{425}', '\0', '\0']), ('\u{446}', ['\u{426}', '\0', '\0']), + ('\u{447}', ['\u{427}', '\0', '\0']), ('\u{448}', ['\u{428}', '\0', '\0']), ('\u{449}', + ['\u{429}', '\0', '\0']), ('\u{44a}', ['\u{42a}', '\0', '\0']), ('\u{44b}', ['\u{42b}', + '\0', '\0']), ('\u{44c}', ['\u{42c}', '\0', '\0']), ('\u{44d}', ['\u{42d}', '\0', '\0']), + ('\u{44e}', ['\u{42e}', '\0', '\0']), ('\u{44f}', ['\u{42f}', '\0', '\0']), ('\u{450}', + ['\u{400}', '\0', '\0']), ('\u{451}', ['\u{401}', '\0', '\0']), ('\u{452}', ['\u{402}', + '\0', '\0']), ('\u{453}', ['\u{403}', '\0', '\0']), ('\u{454}', ['\u{404}', '\0', '\0']), + ('\u{455}', ['\u{405}', '\0', '\0']), ('\u{456}', ['\u{406}', '\0', '\0']), ('\u{457}', + ['\u{407}', '\0', '\0']), ('\u{458}', ['\u{408}', '\0', '\0']), ('\u{459}', ['\u{409}', + '\0', '\0']), ('\u{45a}', ['\u{40a}', '\0', '\0']), ('\u{45b}', ['\u{40b}', '\0', '\0']), + ('\u{45c}', ['\u{40c}', '\0', '\0']), ('\u{45d}', ['\u{40d}', '\0', '\0']), ('\u{45e}', + ['\u{40e}', '\0', '\0']), ('\u{45f}', ['\u{40f}', '\0', '\0']), ('\u{461}', ['\u{460}', + '\0', '\0']), ('\u{463}', ['\u{462}', '\0', '\0']), ('\u{465}', ['\u{464}', '\0', '\0']), + ('\u{467}', ['\u{466}', '\0', '\0']), ('\u{469}', ['\u{468}', '\0', '\0']), ('\u{46b}', + ['\u{46a}', '\0', '\0']), ('\u{46d}', ['\u{46c}', '\0', '\0']), ('\u{46f}', ['\u{46e}', + '\0', '\0']), ('\u{471}', ['\u{470}', '\0', '\0']), ('\u{473}', ['\u{472}', '\0', '\0']), + ('\u{475}', ['\u{474}', '\0', '\0']), ('\u{477}', ['\u{476}', '\0', '\0']), ('\u{479}', + ['\u{478}', '\0', '\0']), ('\u{47b}', ['\u{47a}', '\0', '\0']), ('\u{47d}', ['\u{47c}', + '\0', '\0']), ('\u{47f}', ['\u{47e}', '\0', '\0']), ('\u{481}', ['\u{480}', '\0', '\0']), + ('\u{48b}', ['\u{48a}', '\0', '\0']), ('\u{48d}', ['\u{48c}', '\0', '\0']), ('\u{48f}', + ['\u{48e}', '\0', '\0']), ('\u{491}', ['\u{490}', '\0', '\0']), ('\u{493}', ['\u{492}', + '\0', '\0']), ('\u{495}', ['\u{494}', '\0', '\0']), ('\u{497}', ['\u{496}', '\0', '\0']), + ('\u{499}', ['\u{498}', '\0', '\0']), ('\u{49b}', ['\u{49a}', '\0', '\0']), ('\u{49d}', + ['\u{49c}', '\0', '\0']), ('\u{49f}', ['\u{49e}', '\0', '\0']), ('\u{4a1}', ['\u{4a0}', + '\0', '\0']), ('\u{4a3}', ['\u{4a2}', '\0', '\0']), ('\u{4a5}', ['\u{4a4}', '\0', '\0']), + ('\u{4a7}', ['\u{4a6}', '\0', '\0']), ('\u{4a9}', ['\u{4a8}', '\0', '\0']), ('\u{4ab}', + ['\u{4aa}', '\0', '\0']), ('\u{4ad}', ['\u{4ac}', '\0', '\0']), ('\u{4af}', ['\u{4ae}', + '\0', '\0']), ('\u{4b1}', ['\u{4b0}', '\0', '\0']), ('\u{4b3}', ['\u{4b2}', '\0', '\0']), + ('\u{4b5}', ['\u{4b4}', '\0', '\0']), ('\u{4b7}', ['\u{4b6}', '\0', '\0']), ('\u{4b9}', + ['\u{4b8}', '\0', '\0']), ('\u{4bb}', ['\u{4ba}', '\0', '\0']), ('\u{4bd}', ['\u{4bc}', + '\0', '\0']), ('\u{4bf}', ['\u{4be}', '\0', '\0']), ('\u{4c2}', ['\u{4c1}', '\0', '\0']), + ('\u{4c4}', ['\u{4c3}', '\0', '\0']), ('\u{4c6}', ['\u{4c5}', '\0', '\0']), ('\u{4c8}', + ['\u{4c7}', '\0', '\0']), ('\u{4ca}', ['\u{4c9}', '\0', '\0']), ('\u{4cc}', ['\u{4cb}', + '\0', '\0']), ('\u{4ce}', ['\u{4cd}', '\0', '\0']), ('\u{4cf}', ['\u{4c0}', '\0', '\0']), + ('\u{4d1}', ['\u{4d0}', '\0', '\0']), ('\u{4d3}', ['\u{4d2}', '\0', '\0']), ('\u{4d5}', + ['\u{4d4}', '\0', '\0']), ('\u{4d7}', ['\u{4d6}', '\0', '\0']), ('\u{4d9}', ['\u{4d8}', + '\0', '\0']), ('\u{4db}', ['\u{4da}', '\0', '\0']), ('\u{4dd}', ['\u{4dc}', '\0', '\0']), + ('\u{4df}', ['\u{4de}', '\0', '\0']), ('\u{4e1}', ['\u{4e0}', '\0', '\0']), ('\u{4e3}', + ['\u{4e2}', '\0', '\0']), ('\u{4e5}', ['\u{4e4}', '\0', '\0']), ('\u{4e7}', ['\u{4e6}', + '\0', '\0']), ('\u{4e9}', ['\u{4e8}', '\0', '\0']), ('\u{4eb}', ['\u{4ea}', '\0', '\0']), + ('\u{4ed}', ['\u{4ec}', '\0', '\0']), ('\u{4ef}', ['\u{4ee}', '\0', '\0']), ('\u{4f1}', + ['\u{4f0}', '\0', '\0']), ('\u{4f3}', ['\u{4f2}', '\0', '\0']), ('\u{4f5}', ['\u{4f4}', + '\0', '\0']), ('\u{4f7}', ['\u{4f6}', '\0', '\0']), ('\u{4f9}', ['\u{4f8}', '\0', '\0']), + ('\u{4fb}', ['\u{4fa}', '\0', '\0']), ('\u{4fd}', ['\u{4fc}', '\0', '\0']), ('\u{4ff}', + ['\u{4fe}', '\0', '\0']), ('\u{501}', ['\u{500}', '\0', '\0']), ('\u{503}', ['\u{502}', + '\0', '\0']), ('\u{505}', ['\u{504}', '\0', '\0']), ('\u{507}', ['\u{506}', '\0', '\0']), + ('\u{509}', ['\u{508}', '\0', '\0']), ('\u{50b}', ['\u{50a}', '\0', '\0']), ('\u{50d}', + ['\u{50c}', '\0', '\0']), ('\u{50f}', ['\u{50e}', '\0', '\0']), ('\u{511}', ['\u{510}', + '\0', '\0']), ('\u{513}', ['\u{512}', '\0', '\0']), ('\u{515}', ['\u{514}', '\0', '\0']), + ('\u{517}', ['\u{516}', '\0', '\0']), ('\u{519}', ['\u{518}', '\0', '\0']), ('\u{51b}', + ['\u{51a}', '\0', '\0']), ('\u{51d}', ['\u{51c}', '\0', '\0']), ('\u{51f}', ['\u{51e}', + '\0', '\0']), ('\u{521}', ['\u{520}', '\0', '\0']), ('\u{523}', ['\u{522}', '\0', '\0']), + ('\u{525}', ['\u{524}', '\0', '\0']), ('\u{527}', ['\u{526}', '\0', '\0']), ('\u{529}', + ['\u{528}', '\0', '\0']), ('\u{52b}', ['\u{52a}', '\0', '\0']), ('\u{52d}', ['\u{52c}', + '\0', '\0']), ('\u{52f}', ['\u{52e}', '\0', '\0']), ('\u{561}', ['\u{531}', '\0', '\0']), + ('\u{562}', ['\u{532}', '\0', '\0']), ('\u{563}', ['\u{533}', '\0', '\0']), ('\u{564}', + ['\u{534}', '\0', '\0']), ('\u{565}', ['\u{535}', '\0', '\0']), ('\u{566}', ['\u{536}', + '\0', '\0']), ('\u{567}', ['\u{537}', '\0', '\0']), ('\u{568}', ['\u{538}', '\0', '\0']), + ('\u{569}', ['\u{539}', '\0', '\0']), ('\u{56a}', ['\u{53a}', '\0', '\0']), ('\u{56b}', + ['\u{53b}', '\0', '\0']), ('\u{56c}', ['\u{53c}', '\0', '\0']), ('\u{56d}', ['\u{53d}', + '\0', '\0']), ('\u{56e}', ['\u{53e}', '\0', '\0']), ('\u{56f}', ['\u{53f}', '\0', '\0']), + ('\u{570}', ['\u{540}', '\0', '\0']), ('\u{571}', ['\u{541}', '\0', '\0']), ('\u{572}', + ['\u{542}', '\0', '\0']), ('\u{573}', ['\u{543}', '\0', '\0']), ('\u{574}', ['\u{544}', + '\0', '\0']), ('\u{575}', ['\u{545}', '\0', '\0']), ('\u{576}', ['\u{546}', '\0', '\0']), + ('\u{577}', ['\u{547}', '\0', '\0']), ('\u{578}', ['\u{548}', '\0', '\0']), ('\u{579}', + ['\u{549}', '\0', '\0']), ('\u{57a}', ['\u{54a}', '\0', '\0']), ('\u{57b}', ['\u{54b}', + '\0', '\0']), ('\u{57c}', ['\u{54c}', '\0', '\0']), ('\u{57d}', ['\u{54d}', '\0', '\0']), + ('\u{57e}', ['\u{54e}', '\0', '\0']), ('\u{57f}', ['\u{54f}', '\0', '\0']), ('\u{580}', + ['\u{550}', '\0', '\0']), ('\u{581}', ['\u{551}', '\0', '\0']), ('\u{582}', ['\u{552}', + '\0', '\0']), ('\u{583}', ['\u{553}', '\0', '\0']), ('\u{584}', ['\u{554}', '\0', '\0']), + ('\u{585}', ['\u{555}', '\0', '\0']), ('\u{586}', ['\u{556}', '\0', '\0']), ('\u{587}', + ['\u{535}', '\u{552}', '\0']), ('\u{13f8}', ['\u{13f0}', '\0', '\0']), ('\u{13f9}', + ['\u{13f1}', '\0', '\0']), ('\u{13fa}', ['\u{13f2}', '\0', '\0']), ('\u{13fb}', ['\u{13f3}', + '\0', '\0']), ('\u{13fc}', ['\u{13f4}', '\0', '\0']), ('\u{13fd}', ['\u{13f5}', '\0', + '\0']), ('\u{1c80}', ['\u{412}', '\0', '\0']), ('\u{1c81}', ['\u{414}', '\0', '\0']), + ('\u{1c82}', ['\u{41e}', '\0', '\0']), ('\u{1c83}', ['\u{421}', '\0', '\0']), ('\u{1c84}', + ['\u{422}', '\0', '\0']), ('\u{1c85}', ['\u{422}', '\0', '\0']), ('\u{1c86}', ['\u{42a}', + '\0', '\0']), ('\u{1c87}', ['\u{462}', '\0', '\0']), ('\u{1c88}', ['\u{a64a}', '\0', '\0']), + ('\u{1d79}', ['\u{a77d}', '\0', '\0']), ('\u{1d7d}', ['\u{2c63}', '\0', '\0']), ('\u{1e01}', + ['\u{1e00}', '\0', '\0']), ('\u{1e03}', ['\u{1e02}', '\0', '\0']), ('\u{1e05}', ['\u{1e04}', + '\0', '\0']), ('\u{1e07}', ['\u{1e06}', '\0', '\0']), ('\u{1e09}', ['\u{1e08}', '\0', + '\0']), ('\u{1e0b}', ['\u{1e0a}', '\0', '\0']), ('\u{1e0d}', ['\u{1e0c}', '\0', '\0']), + ('\u{1e0f}', ['\u{1e0e}', '\0', '\0']), ('\u{1e11}', ['\u{1e10}', '\0', '\0']), ('\u{1e13}', + ['\u{1e12}', '\0', '\0']), ('\u{1e15}', ['\u{1e14}', '\0', '\0']), ('\u{1e17}', ['\u{1e16}', + '\0', '\0']), ('\u{1e19}', ['\u{1e18}', '\0', '\0']), ('\u{1e1b}', ['\u{1e1a}', '\0', + '\0']), ('\u{1e1d}', ['\u{1e1c}', '\0', '\0']), ('\u{1e1f}', ['\u{1e1e}', '\0', '\0']), + ('\u{1e21}', ['\u{1e20}', '\0', '\0']), ('\u{1e23}', ['\u{1e22}', '\0', '\0']), ('\u{1e25}', + ['\u{1e24}', '\0', '\0']), ('\u{1e27}', ['\u{1e26}', '\0', '\0']), ('\u{1e29}', ['\u{1e28}', + '\0', '\0']), ('\u{1e2b}', ['\u{1e2a}', '\0', '\0']), ('\u{1e2d}', ['\u{1e2c}', '\0', + '\0']), ('\u{1e2f}', ['\u{1e2e}', '\0', '\0']), ('\u{1e31}', ['\u{1e30}', '\0', '\0']), + ('\u{1e33}', ['\u{1e32}', '\0', '\0']), ('\u{1e35}', ['\u{1e34}', '\0', '\0']), ('\u{1e37}', + ['\u{1e36}', '\0', '\0']), ('\u{1e39}', ['\u{1e38}', '\0', '\0']), ('\u{1e3b}', ['\u{1e3a}', + '\0', '\0']), ('\u{1e3d}', ['\u{1e3c}', '\0', '\0']), ('\u{1e3f}', ['\u{1e3e}', '\0', + '\0']), ('\u{1e41}', ['\u{1e40}', '\0', '\0']), ('\u{1e43}', ['\u{1e42}', '\0', '\0']), + ('\u{1e45}', ['\u{1e44}', '\0', '\0']), ('\u{1e47}', ['\u{1e46}', '\0', '\0']), ('\u{1e49}', + ['\u{1e48}', '\0', '\0']), ('\u{1e4b}', ['\u{1e4a}', '\0', '\0']), ('\u{1e4d}', ['\u{1e4c}', + '\0', '\0']), ('\u{1e4f}', ['\u{1e4e}', '\0', '\0']), ('\u{1e51}', ['\u{1e50}', '\0', + '\0']), ('\u{1e53}', ['\u{1e52}', '\0', '\0']), ('\u{1e55}', ['\u{1e54}', '\0', '\0']), + ('\u{1e57}', ['\u{1e56}', '\0', '\0']), ('\u{1e59}', ['\u{1e58}', '\0', '\0']), ('\u{1e5b}', + ['\u{1e5a}', '\0', '\0']), ('\u{1e5d}', ['\u{1e5c}', '\0', '\0']), ('\u{1e5f}', ['\u{1e5e}', + '\0', '\0']), ('\u{1e61}', ['\u{1e60}', '\0', '\0']), ('\u{1e63}', ['\u{1e62}', '\0', + '\0']), ('\u{1e65}', ['\u{1e64}', '\0', '\0']), ('\u{1e67}', ['\u{1e66}', '\0', '\0']), + ('\u{1e69}', ['\u{1e68}', '\0', '\0']), ('\u{1e6b}', ['\u{1e6a}', '\0', '\0']), ('\u{1e6d}', + ['\u{1e6c}', '\0', '\0']), ('\u{1e6f}', ['\u{1e6e}', '\0', '\0']), ('\u{1e71}', ['\u{1e70}', + '\0', '\0']), ('\u{1e73}', ['\u{1e72}', '\0', '\0']), ('\u{1e75}', ['\u{1e74}', '\0', + '\0']), ('\u{1e77}', ['\u{1e76}', '\0', '\0']), ('\u{1e79}', ['\u{1e78}', '\0', '\0']), + ('\u{1e7b}', ['\u{1e7a}', '\0', '\0']), ('\u{1e7d}', ['\u{1e7c}', '\0', '\0']), ('\u{1e7f}', + ['\u{1e7e}', '\0', '\0']), ('\u{1e81}', ['\u{1e80}', '\0', '\0']), ('\u{1e83}', ['\u{1e82}', + '\0', '\0']), ('\u{1e85}', ['\u{1e84}', '\0', '\0']), ('\u{1e87}', ['\u{1e86}', '\0', + '\0']), ('\u{1e89}', ['\u{1e88}', '\0', '\0']), ('\u{1e8b}', ['\u{1e8a}', '\0', '\0']), + ('\u{1e8d}', ['\u{1e8c}', '\0', '\0']), ('\u{1e8f}', ['\u{1e8e}', '\0', '\0']), ('\u{1e91}', + ['\u{1e90}', '\0', '\0']), ('\u{1e93}', ['\u{1e92}', '\0', '\0']), ('\u{1e95}', ['\u{1e94}', + '\0', '\0']), ('\u{1e96}', ['\u{48}', '\u{331}', '\0']), ('\u{1e97}', ['\u{54}', '\u{308}', + '\0']), ('\u{1e98}', ['\u{57}', '\u{30a}', '\0']), ('\u{1e99}', ['\u{59}', '\u{30a}', + '\0']), ('\u{1e9a}', ['\u{41}', '\u{2be}', '\0']), ('\u{1e9b}', ['\u{1e60}', '\0', '\0']), + ('\u{1ea1}', ['\u{1ea0}', '\0', '\0']), ('\u{1ea3}', ['\u{1ea2}', '\0', '\0']), ('\u{1ea5}', + ['\u{1ea4}', '\0', '\0']), ('\u{1ea7}', ['\u{1ea6}', '\0', '\0']), ('\u{1ea9}', ['\u{1ea8}', + '\0', '\0']), ('\u{1eab}', ['\u{1eaa}', '\0', '\0']), ('\u{1ead}', ['\u{1eac}', '\0', + '\0']), ('\u{1eaf}', ['\u{1eae}', '\0', '\0']), ('\u{1eb1}', ['\u{1eb0}', '\0', '\0']), + ('\u{1eb3}', ['\u{1eb2}', '\0', '\0']), ('\u{1eb5}', ['\u{1eb4}', '\0', '\0']), ('\u{1eb7}', + ['\u{1eb6}', '\0', '\0']), ('\u{1eb9}', ['\u{1eb8}', '\0', '\0']), ('\u{1ebb}', ['\u{1eba}', + '\0', '\0']), ('\u{1ebd}', ['\u{1ebc}', '\0', '\0']), ('\u{1ebf}', ['\u{1ebe}', '\0', + '\0']), ('\u{1ec1}', ['\u{1ec0}', '\0', '\0']), ('\u{1ec3}', ['\u{1ec2}', '\0', '\0']), + ('\u{1ec5}', ['\u{1ec4}', '\0', '\0']), ('\u{1ec7}', ['\u{1ec6}', '\0', '\0']), ('\u{1ec9}', + ['\u{1ec8}', '\0', '\0']), ('\u{1ecb}', ['\u{1eca}', '\0', '\0']), ('\u{1ecd}', ['\u{1ecc}', + '\0', '\0']), ('\u{1ecf}', ['\u{1ece}', '\0', '\0']), ('\u{1ed1}', ['\u{1ed0}', '\0', + '\0']), ('\u{1ed3}', ['\u{1ed2}', '\0', '\0']), ('\u{1ed5}', ['\u{1ed4}', '\0', '\0']), + ('\u{1ed7}', ['\u{1ed6}', '\0', '\0']), ('\u{1ed9}', ['\u{1ed8}', '\0', '\0']), ('\u{1edb}', + ['\u{1eda}', '\0', '\0']), ('\u{1edd}', ['\u{1edc}', '\0', '\0']), ('\u{1edf}', ['\u{1ede}', + '\0', '\0']), ('\u{1ee1}', ['\u{1ee0}', '\0', '\0']), ('\u{1ee3}', ['\u{1ee2}', '\0', + '\0']), ('\u{1ee5}', ['\u{1ee4}', '\0', '\0']), ('\u{1ee7}', ['\u{1ee6}', '\0', '\0']), + ('\u{1ee9}', ['\u{1ee8}', '\0', '\0']), ('\u{1eeb}', ['\u{1eea}', '\0', '\0']), ('\u{1eed}', + ['\u{1eec}', '\0', '\0']), ('\u{1eef}', ['\u{1eee}', '\0', '\0']), ('\u{1ef1}', ['\u{1ef0}', + '\0', '\0']), ('\u{1ef3}', ['\u{1ef2}', '\0', '\0']), ('\u{1ef5}', ['\u{1ef4}', '\0', + '\0']), ('\u{1ef7}', ['\u{1ef6}', '\0', '\0']), ('\u{1ef9}', ['\u{1ef8}', '\0', '\0']), + ('\u{1efb}', ['\u{1efa}', '\0', '\0']), ('\u{1efd}', ['\u{1efc}', '\0', '\0']), ('\u{1eff}', + ['\u{1efe}', '\0', '\0']), ('\u{1f00}', ['\u{1f08}', '\0', '\0']), ('\u{1f01}', ['\u{1f09}', + '\0', '\0']), ('\u{1f02}', ['\u{1f0a}', '\0', '\0']), ('\u{1f03}', ['\u{1f0b}', '\0', + '\0']), ('\u{1f04}', ['\u{1f0c}', '\0', '\0']), ('\u{1f05}', ['\u{1f0d}', '\0', '\0']), + ('\u{1f06}', ['\u{1f0e}', '\0', '\0']), ('\u{1f07}', ['\u{1f0f}', '\0', '\0']), ('\u{1f10}', + ['\u{1f18}', '\0', '\0']), ('\u{1f11}', ['\u{1f19}', '\0', '\0']), ('\u{1f12}', ['\u{1f1a}', + '\0', '\0']), ('\u{1f13}', ['\u{1f1b}', '\0', '\0']), ('\u{1f14}', ['\u{1f1c}', '\0', + '\0']), ('\u{1f15}', ['\u{1f1d}', '\0', '\0']), ('\u{1f20}', ['\u{1f28}', '\0', '\0']), + ('\u{1f21}', ['\u{1f29}', '\0', '\0']), ('\u{1f22}', ['\u{1f2a}', '\0', '\0']), ('\u{1f23}', + ['\u{1f2b}', '\0', '\0']), ('\u{1f24}', ['\u{1f2c}', '\0', '\0']), ('\u{1f25}', ['\u{1f2d}', + '\0', '\0']), ('\u{1f26}', ['\u{1f2e}', '\0', '\0']), ('\u{1f27}', ['\u{1f2f}', '\0', + '\0']), ('\u{1f30}', ['\u{1f38}', '\0', '\0']), ('\u{1f31}', ['\u{1f39}', '\0', '\0']), + ('\u{1f32}', ['\u{1f3a}', '\0', '\0']), ('\u{1f33}', ['\u{1f3b}', '\0', '\0']), ('\u{1f34}', + ['\u{1f3c}', '\0', '\0']), ('\u{1f35}', ['\u{1f3d}', '\0', '\0']), ('\u{1f36}', ['\u{1f3e}', + '\0', '\0']), ('\u{1f37}', ['\u{1f3f}', '\0', '\0']), ('\u{1f40}', ['\u{1f48}', '\0', + '\0']), ('\u{1f41}', ['\u{1f49}', '\0', '\0']), ('\u{1f42}', ['\u{1f4a}', '\0', '\0']), + ('\u{1f43}', ['\u{1f4b}', '\0', '\0']), ('\u{1f44}', ['\u{1f4c}', '\0', '\0']), ('\u{1f45}', + ['\u{1f4d}', '\0', '\0']), ('\u{1f50}', ['\u{3a5}', '\u{313}', '\0']), ('\u{1f51}', + ['\u{1f59}', '\0', '\0']), ('\u{1f52}', ['\u{3a5}', '\u{313}', '\u{300}']), ('\u{1f53}', + ['\u{1f5b}', '\0', '\0']), ('\u{1f54}', ['\u{3a5}', '\u{313}', '\u{301}']), ('\u{1f55}', + ['\u{1f5d}', '\0', '\0']), ('\u{1f56}', ['\u{3a5}', '\u{313}', '\u{342}']), ('\u{1f57}', + ['\u{1f5f}', '\0', '\0']), ('\u{1f60}', ['\u{1f68}', '\0', '\0']), ('\u{1f61}', ['\u{1f69}', + '\0', '\0']), ('\u{1f62}', ['\u{1f6a}', '\0', '\0']), ('\u{1f63}', ['\u{1f6b}', '\0', + '\0']), ('\u{1f64}', ['\u{1f6c}', '\0', '\0']), ('\u{1f65}', ['\u{1f6d}', '\0', '\0']), + ('\u{1f66}', ['\u{1f6e}', '\0', '\0']), ('\u{1f67}', ['\u{1f6f}', '\0', '\0']), ('\u{1f70}', + ['\u{1fba}', '\0', '\0']), ('\u{1f71}', ['\u{1fbb}', '\0', '\0']), ('\u{1f72}', ['\u{1fc8}', + '\0', '\0']), ('\u{1f73}', ['\u{1fc9}', '\0', '\0']), ('\u{1f74}', ['\u{1fca}', '\0', + '\0']), ('\u{1f75}', ['\u{1fcb}', '\0', '\0']), ('\u{1f76}', ['\u{1fda}', '\0', '\0']), + ('\u{1f77}', ['\u{1fdb}', '\0', '\0']), ('\u{1f78}', ['\u{1ff8}', '\0', '\0']), ('\u{1f79}', + ['\u{1ff9}', '\0', '\0']), ('\u{1f7a}', ['\u{1fea}', '\0', '\0']), ('\u{1f7b}', ['\u{1feb}', + '\0', '\0']), ('\u{1f7c}', ['\u{1ffa}', '\0', '\0']), ('\u{1f7d}', ['\u{1ffb}', '\0', + '\0']), ('\u{1f80}', ['\u{1f08}', '\u{399}', '\0']), ('\u{1f81}', ['\u{1f09}', '\u{399}', + '\0']), ('\u{1f82}', ['\u{1f0a}', '\u{399}', '\0']), ('\u{1f83}', ['\u{1f0b}', '\u{399}', + '\0']), ('\u{1f84}', ['\u{1f0c}', '\u{399}', '\0']), ('\u{1f85}', ['\u{1f0d}', '\u{399}', + '\0']), ('\u{1f86}', ['\u{1f0e}', '\u{399}', '\0']), ('\u{1f87}', ['\u{1f0f}', '\u{399}', + '\0']), ('\u{1f88}', ['\u{1f08}', '\u{399}', '\0']), ('\u{1f89}', ['\u{1f09}', '\u{399}', + '\0']), ('\u{1f8a}', ['\u{1f0a}', '\u{399}', '\0']), ('\u{1f8b}', ['\u{1f0b}', '\u{399}', + '\0']), ('\u{1f8c}', ['\u{1f0c}', '\u{399}', '\0']), ('\u{1f8d}', ['\u{1f0d}', '\u{399}', + '\0']), ('\u{1f8e}', ['\u{1f0e}', '\u{399}', '\0']), ('\u{1f8f}', ['\u{1f0f}', '\u{399}', + '\0']), ('\u{1f90}', ['\u{1f28}', '\u{399}', '\0']), ('\u{1f91}', ['\u{1f29}', '\u{399}', + '\0']), ('\u{1f92}', ['\u{1f2a}', '\u{399}', '\0']), ('\u{1f93}', ['\u{1f2b}', '\u{399}', + '\0']), ('\u{1f94}', ['\u{1f2c}', '\u{399}', '\0']), ('\u{1f95}', ['\u{1f2d}', '\u{399}', + '\0']), ('\u{1f96}', ['\u{1f2e}', '\u{399}', '\0']), ('\u{1f97}', ['\u{1f2f}', '\u{399}', + '\0']), ('\u{1f98}', ['\u{1f28}', '\u{399}', '\0']), ('\u{1f99}', ['\u{1f29}', '\u{399}', + '\0']), ('\u{1f9a}', ['\u{1f2a}', '\u{399}', '\0']), ('\u{1f9b}', ['\u{1f2b}', '\u{399}', + '\0']), ('\u{1f9c}', ['\u{1f2c}', '\u{399}', '\0']), ('\u{1f9d}', ['\u{1f2d}', '\u{399}', + '\0']), ('\u{1f9e}', ['\u{1f2e}', '\u{399}', '\0']), ('\u{1f9f}', ['\u{1f2f}', '\u{399}', + '\0']), ('\u{1fa0}', ['\u{1f68}', '\u{399}', '\0']), ('\u{1fa1}', ['\u{1f69}', '\u{399}', + '\0']), ('\u{1fa2}', ['\u{1f6a}', '\u{399}', '\0']), ('\u{1fa3}', ['\u{1f6b}', '\u{399}', + '\0']), ('\u{1fa4}', ['\u{1f6c}', '\u{399}', '\0']), ('\u{1fa5}', ['\u{1f6d}', '\u{399}', + '\0']), ('\u{1fa6}', ['\u{1f6e}', '\u{399}', '\0']), ('\u{1fa7}', ['\u{1f6f}', '\u{399}', + '\0']), ('\u{1fa8}', ['\u{1f68}', '\u{399}', '\0']), ('\u{1fa9}', ['\u{1f69}', '\u{399}', + '\0']), ('\u{1faa}', ['\u{1f6a}', '\u{399}', '\0']), ('\u{1fab}', ['\u{1f6b}', '\u{399}', + '\0']), ('\u{1fac}', ['\u{1f6c}', '\u{399}', '\0']), ('\u{1fad}', ['\u{1f6d}', '\u{399}', + '\0']), ('\u{1fae}', ['\u{1f6e}', '\u{399}', '\0']), ('\u{1faf}', ['\u{1f6f}', '\u{399}', + '\0']), ('\u{1fb0}', ['\u{1fb8}', '\0', '\0']), ('\u{1fb1}', ['\u{1fb9}', '\0', '\0']), + ('\u{1fb2}', ['\u{1fba}', '\u{399}', '\0']), ('\u{1fb3}', ['\u{391}', '\u{399}', '\0']), + ('\u{1fb4}', ['\u{386}', '\u{399}', '\0']), ('\u{1fb6}', ['\u{391}', '\u{342}', '\0']), + ('\u{1fb7}', ['\u{391}', '\u{342}', '\u{399}']), ('\u{1fbc}', ['\u{391}', '\u{399}', '\0']), + ('\u{1fbe}', ['\u{399}', '\0', '\0']), ('\u{1fc2}', ['\u{1fca}', '\u{399}', '\0']), + ('\u{1fc3}', ['\u{397}', '\u{399}', '\0']), ('\u{1fc4}', ['\u{389}', '\u{399}', '\0']), + ('\u{1fc6}', ['\u{397}', '\u{342}', '\0']), ('\u{1fc7}', ['\u{397}', '\u{342}', '\u{399}']), + ('\u{1fcc}', ['\u{397}', '\u{399}', '\0']), ('\u{1fd0}', ['\u{1fd8}', '\0', '\0']), + ('\u{1fd1}', ['\u{1fd9}', '\0', '\0']), ('\u{1fd2}', ['\u{399}', '\u{308}', '\u{300}']), + ('\u{1fd3}', ['\u{399}', '\u{308}', '\u{301}']), ('\u{1fd6}', ['\u{399}', '\u{342}', '\0']), + ('\u{1fd7}', ['\u{399}', '\u{308}', '\u{342}']), ('\u{1fe0}', ['\u{1fe8}', '\0', '\0']), + ('\u{1fe1}', ['\u{1fe9}', '\0', '\0']), ('\u{1fe2}', ['\u{3a5}', '\u{308}', '\u{300}']), + ('\u{1fe3}', ['\u{3a5}', '\u{308}', '\u{301}']), ('\u{1fe4}', ['\u{3a1}', '\u{313}', '\0']), + ('\u{1fe5}', ['\u{1fec}', '\0', '\0']), ('\u{1fe6}', ['\u{3a5}', '\u{342}', '\0']), + ('\u{1fe7}', ['\u{3a5}', '\u{308}', '\u{342}']), ('\u{1ff2}', ['\u{1ffa}', '\u{399}', + '\0']), ('\u{1ff3}', ['\u{3a9}', '\u{399}', '\0']), ('\u{1ff4}', ['\u{38f}', '\u{399}', + '\0']), ('\u{1ff6}', ['\u{3a9}', '\u{342}', '\0']), ('\u{1ff7}', ['\u{3a9}', '\u{342}', + '\u{399}']), ('\u{1ffc}', ['\u{3a9}', '\u{399}', '\0']), ('\u{214e}', ['\u{2132}', '\0', + '\0']), ('\u{2170}', ['\u{2160}', '\0', '\0']), ('\u{2171}', ['\u{2161}', '\0', '\0']), + ('\u{2172}', ['\u{2162}', '\0', '\0']), ('\u{2173}', ['\u{2163}', '\0', '\0']), ('\u{2174}', + ['\u{2164}', '\0', '\0']), ('\u{2175}', ['\u{2165}', '\0', '\0']), ('\u{2176}', ['\u{2166}', + '\0', '\0']), ('\u{2177}', ['\u{2167}', '\0', '\0']), ('\u{2178}', ['\u{2168}', '\0', + '\0']), ('\u{2179}', ['\u{2169}', '\0', '\0']), ('\u{217a}', ['\u{216a}', '\0', '\0']), + ('\u{217b}', ['\u{216b}', '\0', '\0']), ('\u{217c}', ['\u{216c}', '\0', '\0']), ('\u{217d}', + ['\u{216d}', '\0', '\0']), ('\u{217e}', ['\u{216e}', '\0', '\0']), ('\u{217f}', ['\u{216f}', + '\0', '\0']), ('\u{2184}', ['\u{2183}', '\0', '\0']), ('\u{24d0}', ['\u{24b6}', '\0', + '\0']), ('\u{24d1}', ['\u{24b7}', '\0', '\0']), ('\u{24d2}', ['\u{24b8}', '\0', '\0']), + ('\u{24d3}', ['\u{24b9}', '\0', '\0']), ('\u{24d4}', ['\u{24ba}', '\0', '\0']), ('\u{24d5}', + ['\u{24bb}', '\0', '\0']), ('\u{24d6}', ['\u{24bc}', '\0', '\0']), ('\u{24d7}', ['\u{24bd}', + '\0', '\0']), ('\u{24d8}', ['\u{24be}', '\0', '\0']), ('\u{24d9}', ['\u{24bf}', '\0', + '\0']), ('\u{24da}', ['\u{24c0}', '\0', '\0']), ('\u{24db}', ['\u{24c1}', '\0', '\0']), + ('\u{24dc}', ['\u{24c2}', '\0', '\0']), ('\u{24dd}', ['\u{24c3}', '\0', '\0']), ('\u{24de}', + ['\u{24c4}', '\0', '\0']), ('\u{24df}', ['\u{24c5}', '\0', '\0']), ('\u{24e0}', ['\u{24c6}', + '\0', '\0']), ('\u{24e1}', ['\u{24c7}', '\0', '\0']), ('\u{24e2}', ['\u{24c8}', '\0', + '\0']), ('\u{24e3}', ['\u{24c9}', '\0', '\0']), ('\u{24e4}', ['\u{24ca}', '\0', '\0']), + ('\u{24e5}', ['\u{24cb}', '\0', '\0']), ('\u{24e6}', ['\u{24cc}', '\0', '\0']), ('\u{24e7}', + ['\u{24cd}', '\0', '\0']), ('\u{24e8}', ['\u{24ce}', '\0', '\0']), ('\u{24e9}', ['\u{24cf}', + '\0', '\0']), ('\u{2c30}', ['\u{2c00}', '\0', '\0']), ('\u{2c31}', ['\u{2c01}', '\0', + '\0']), ('\u{2c32}', ['\u{2c02}', '\0', '\0']), ('\u{2c33}', ['\u{2c03}', '\0', '\0']), + ('\u{2c34}', ['\u{2c04}', '\0', '\0']), ('\u{2c35}', ['\u{2c05}', '\0', '\0']), ('\u{2c36}', + ['\u{2c06}', '\0', '\0']), ('\u{2c37}', ['\u{2c07}', '\0', '\0']), ('\u{2c38}', ['\u{2c08}', + '\0', '\0']), ('\u{2c39}', ['\u{2c09}', '\0', '\0']), ('\u{2c3a}', ['\u{2c0a}', '\0', + '\0']), ('\u{2c3b}', ['\u{2c0b}', '\0', '\0']), ('\u{2c3c}', ['\u{2c0c}', '\0', '\0']), + ('\u{2c3d}', ['\u{2c0d}', '\0', '\0']), ('\u{2c3e}', ['\u{2c0e}', '\0', '\0']), ('\u{2c3f}', + ['\u{2c0f}', '\0', '\0']), ('\u{2c40}', ['\u{2c10}', '\0', '\0']), ('\u{2c41}', ['\u{2c11}', + '\0', '\0']), ('\u{2c42}', ['\u{2c12}', '\0', '\0']), ('\u{2c43}', ['\u{2c13}', '\0', + '\0']), ('\u{2c44}', ['\u{2c14}', '\0', '\0']), ('\u{2c45}', ['\u{2c15}', '\0', '\0']), + ('\u{2c46}', ['\u{2c16}', '\0', '\0']), ('\u{2c47}', ['\u{2c17}', '\0', '\0']), ('\u{2c48}', + ['\u{2c18}', '\0', '\0']), ('\u{2c49}', ['\u{2c19}', '\0', '\0']), ('\u{2c4a}', ['\u{2c1a}', + '\0', '\0']), ('\u{2c4b}', ['\u{2c1b}', '\0', '\0']), ('\u{2c4c}', ['\u{2c1c}', '\0', + '\0']), ('\u{2c4d}', ['\u{2c1d}', '\0', '\0']), ('\u{2c4e}', ['\u{2c1e}', '\0', '\0']), + ('\u{2c4f}', ['\u{2c1f}', '\0', '\0']), ('\u{2c50}', ['\u{2c20}', '\0', '\0']), ('\u{2c51}', + ['\u{2c21}', '\0', '\0']), ('\u{2c52}', ['\u{2c22}', '\0', '\0']), ('\u{2c53}', ['\u{2c23}', + '\0', '\0']), ('\u{2c54}', ['\u{2c24}', '\0', '\0']), ('\u{2c55}', ['\u{2c25}', '\0', + '\0']), ('\u{2c56}', ['\u{2c26}', '\0', '\0']), ('\u{2c57}', ['\u{2c27}', '\0', '\0']), + ('\u{2c58}', ['\u{2c28}', '\0', '\0']), ('\u{2c59}', ['\u{2c29}', '\0', '\0']), ('\u{2c5a}', + ['\u{2c2a}', '\0', '\0']), ('\u{2c5b}', ['\u{2c2b}', '\0', '\0']), ('\u{2c5c}', ['\u{2c2c}', + '\0', '\0']), ('\u{2c5d}', ['\u{2c2d}', '\0', '\0']), ('\u{2c5e}', ['\u{2c2e}', '\0', + '\0']), ('\u{2c61}', ['\u{2c60}', '\0', '\0']), ('\u{2c65}', ['\u{23a}', '\0', '\0']), + ('\u{2c66}', ['\u{23e}', '\0', '\0']), ('\u{2c68}', ['\u{2c67}', '\0', '\0']), ('\u{2c6a}', + ['\u{2c69}', '\0', '\0']), ('\u{2c6c}', ['\u{2c6b}', '\0', '\0']), ('\u{2c73}', ['\u{2c72}', + '\0', '\0']), ('\u{2c76}', ['\u{2c75}', '\0', '\0']), ('\u{2c81}', ['\u{2c80}', '\0', + '\0']), ('\u{2c83}', ['\u{2c82}', '\0', '\0']), ('\u{2c85}', ['\u{2c84}', '\0', '\0']), + ('\u{2c87}', ['\u{2c86}', '\0', '\0']), ('\u{2c89}', ['\u{2c88}', '\0', '\0']), ('\u{2c8b}', + ['\u{2c8a}', '\0', '\0']), ('\u{2c8d}', ['\u{2c8c}', '\0', '\0']), ('\u{2c8f}', ['\u{2c8e}', + '\0', '\0']), ('\u{2c91}', ['\u{2c90}', '\0', '\0']), ('\u{2c93}', ['\u{2c92}', '\0', + '\0']), ('\u{2c95}', ['\u{2c94}', '\0', '\0']), ('\u{2c97}', ['\u{2c96}', '\0', '\0']), + ('\u{2c99}', ['\u{2c98}', '\0', '\0']), ('\u{2c9b}', ['\u{2c9a}', '\0', '\0']), ('\u{2c9d}', + ['\u{2c9c}', '\0', '\0']), ('\u{2c9f}', ['\u{2c9e}', '\0', '\0']), ('\u{2ca1}', ['\u{2ca0}', + '\0', '\0']), ('\u{2ca3}', ['\u{2ca2}', '\0', '\0']), ('\u{2ca5}', ['\u{2ca4}', '\0', + '\0']), ('\u{2ca7}', ['\u{2ca6}', '\0', '\0']), ('\u{2ca9}', ['\u{2ca8}', '\0', '\0']), + ('\u{2cab}', ['\u{2caa}', '\0', '\0']), ('\u{2cad}', ['\u{2cac}', '\0', '\0']), ('\u{2caf}', + ['\u{2cae}', '\0', '\0']), ('\u{2cb1}', ['\u{2cb0}', '\0', '\0']), ('\u{2cb3}', ['\u{2cb2}', + '\0', '\0']), ('\u{2cb5}', ['\u{2cb4}', '\0', '\0']), ('\u{2cb7}', ['\u{2cb6}', '\0', + '\0']), ('\u{2cb9}', ['\u{2cb8}', '\0', '\0']), ('\u{2cbb}', ['\u{2cba}', '\0', '\0']), + ('\u{2cbd}', ['\u{2cbc}', '\0', '\0']), ('\u{2cbf}', ['\u{2cbe}', '\0', '\0']), ('\u{2cc1}', + ['\u{2cc0}', '\0', '\0']), ('\u{2cc3}', ['\u{2cc2}', '\0', '\0']), ('\u{2cc5}', ['\u{2cc4}', + '\0', '\0']), ('\u{2cc7}', ['\u{2cc6}', '\0', '\0']), ('\u{2cc9}', ['\u{2cc8}', '\0', + '\0']), ('\u{2ccb}', ['\u{2cca}', '\0', '\0']), ('\u{2ccd}', ['\u{2ccc}', '\0', '\0']), + ('\u{2ccf}', ['\u{2cce}', '\0', '\0']), ('\u{2cd1}', ['\u{2cd0}', '\0', '\0']), ('\u{2cd3}', + ['\u{2cd2}', '\0', '\0']), ('\u{2cd5}', ['\u{2cd4}', '\0', '\0']), ('\u{2cd7}', ['\u{2cd6}', + '\0', '\0']), ('\u{2cd9}', ['\u{2cd8}', '\0', '\0']), ('\u{2cdb}', ['\u{2cda}', '\0', + '\0']), ('\u{2cdd}', ['\u{2cdc}', '\0', '\0']), ('\u{2cdf}', ['\u{2cde}', '\0', '\0']), + ('\u{2ce1}', ['\u{2ce0}', '\0', '\0']), ('\u{2ce3}', ['\u{2ce2}', '\0', '\0']), ('\u{2cec}', + ['\u{2ceb}', '\0', '\0']), ('\u{2cee}', ['\u{2ced}', '\0', '\0']), ('\u{2cf3}', ['\u{2cf2}', + '\0', '\0']), ('\u{2d00}', ['\u{10a0}', '\0', '\0']), ('\u{2d01}', ['\u{10a1}', '\0', + '\0']), ('\u{2d02}', ['\u{10a2}', '\0', '\0']), ('\u{2d03}', ['\u{10a3}', '\0', '\0']), + ('\u{2d04}', ['\u{10a4}', '\0', '\0']), ('\u{2d05}', ['\u{10a5}', '\0', '\0']), ('\u{2d06}', + ['\u{10a6}', '\0', '\0']), ('\u{2d07}', ['\u{10a7}', '\0', '\0']), ('\u{2d08}', ['\u{10a8}', + '\0', '\0']), ('\u{2d09}', ['\u{10a9}', '\0', '\0']), ('\u{2d0a}', ['\u{10aa}', '\0', + '\0']), ('\u{2d0b}', ['\u{10ab}', '\0', '\0']), ('\u{2d0c}', ['\u{10ac}', '\0', '\0']), + ('\u{2d0d}', ['\u{10ad}', '\0', '\0']), ('\u{2d0e}', ['\u{10ae}', '\0', '\0']), ('\u{2d0f}', + ['\u{10af}', '\0', '\0']), ('\u{2d10}', ['\u{10b0}', '\0', '\0']), ('\u{2d11}', ['\u{10b1}', + '\0', '\0']), ('\u{2d12}', ['\u{10b2}', '\0', '\0']), ('\u{2d13}', ['\u{10b3}', '\0', + '\0']), ('\u{2d14}', ['\u{10b4}', '\0', '\0']), ('\u{2d15}', ['\u{10b5}', '\0', '\0']), + ('\u{2d16}', ['\u{10b6}', '\0', '\0']), ('\u{2d17}', ['\u{10b7}', '\0', '\0']), ('\u{2d18}', + ['\u{10b8}', '\0', '\0']), ('\u{2d19}', ['\u{10b9}', '\0', '\0']), ('\u{2d1a}', ['\u{10ba}', + '\0', '\0']), ('\u{2d1b}', ['\u{10bb}', '\0', '\0']), ('\u{2d1c}', ['\u{10bc}', '\0', + '\0']), ('\u{2d1d}', ['\u{10bd}', '\0', '\0']), ('\u{2d1e}', ['\u{10be}', '\0', '\0']), + ('\u{2d1f}', ['\u{10bf}', '\0', '\0']), ('\u{2d20}', ['\u{10c0}', '\0', '\0']), ('\u{2d21}', + ['\u{10c1}', '\0', '\0']), ('\u{2d22}', ['\u{10c2}', '\0', '\0']), ('\u{2d23}', ['\u{10c3}', + '\0', '\0']), ('\u{2d24}', ['\u{10c4}', '\0', '\0']), ('\u{2d25}', ['\u{10c5}', '\0', + '\0']), ('\u{2d27}', ['\u{10c7}', '\0', '\0']), ('\u{2d2d}', ['\u{10cd}', '\0', '\0']), + ('\u{a641}', ['\u{a640}', '\0', '\0']), ('\u{a643}', ['\u{a642}', '\0', '\0']), ('\u{a645}', + ['\u{a644}', '\0', '\0']), ('\u{a647}', ['\u{a646}', '\0', '\0']), ('\u{a649}', ['\u{a648}', + '\0', '\0']), ('\u{a64b}', ['\u{a64a}', '\0', '\0']), ('\u{a64d}', ['\u{a64c}', '\0', + '\0']), ('\u{a64f}', ['\u{a64e}', '\0', '\0']), ('\u{a651}', ['\u{a650}', '\0', '\0']), + ('\u{a653}', ['\u{a652}', '\0', '\0']), ('\u{a655}', ['\u{a654}', '\0', '\0']), ('\u{a657}', + ['\u{a656}', '\0', '\0']), ('\u{a659}', ['\u{a658}', '\0', '\0']), ('\u{a65b}', ['\u{a65a}', + '\0', '\0']), ('\u{a65d}', ['\u{a65c}', '\0', '\0']), ('\u{a65f}', ['\u{a65e}', '\0', + '\0']), ('\u{a661}', ['\u{a660}', '\0', '\0']), ('\u{a663}', ['\u{a662}', '\0', '\0']), + ('\u{a665}', ['\u{a664}', '\0', '\0']), ('\u{a667}', ['\u{a666}', '\0', '\0']), ('\u{a669}', + ['\u{a668}', '\0', '\0']), ('\u{a66b}', ['\u{a66a}', '\0', '\0']), ('\u{a66d}', ['\u{a66c}', + '\0', '\0']), ('\u{a681}', ['\u{a680}', '\0', '\0']), ('\u{a683}', ['\u{a682}', '\0', + '\0']), ('\u{a685}', ['\u{a684}', '\0', '\0']), ('\u{a687}', ['\u{a686}', '\0', '\0']), + ('\u{a689}', ['\u{a688}', '\0', '\0']), ('\u{a68b}', ['\u{a68a}', '\0', '\0']), ('\u{a68d}', + ['\u{a68c}', '\0', '\0']), ('\u{a68f}', ['\u{a68e}', '\0', '\0']), ('\u{a691}', ['\u{a690}', + '\0', '\0']), ('\u{a693}', ['\u{a692}', '\0', '\0']), ('\u{a695}', ['\u{a694}', '\0', + '\0']), ('\u{a697}', ['\u{a696}', '\0', '\0']), ('\u{a699}', ['\u{a698}', '\0', '\0']), + ('\u{a69b}', ['\u{a69a}', '\0', '\0']), ('\u{a723}', ['\u{a722}', '\0', '\0']), ('\u{a725}', + ['\u{a724}', '\0', '\0']), ('\u{a727}', ['\u{a726}', '\0', '\0']), ('\u{a729}', ['\u{a728}', + '\0', '\0']), ('\u{a72b}', ['\u{a72a}', '\0', '\0']), ('\u{a72d}', ['\u{a72c}', '\0', + '\0']), ('\u{a72f}', ['\u{a72e}', '\0', '\0']), ('\u{a733}', ['\u{a732}', '\0', '\0']), + ('\u{a735}', ['\u{a734}', '\0', '\0']), ('\u{a737}', ['\u{a736}', '\0', '\0']), ('\u{a739}', + ['\u{a738}', '\0', '\0']), ('\u{a73b}', ['\u{a73a}', '\0', '\0']), ('\u{a73d}', ['\u{a73c}', + '\0', '\0']), ('\u{a73f}', ['\u{a73e}', '\0', '\0']), ('\u{a741}', ['\u{a740}', '\0', + '\0']), ('\u{a743}', ['\u{a742}', '\0', '\0']), ('\u{a745}', ['\u{a744}', '\0', '\0']), + ('\u{a747}', ['\u{a746}', '\0', '\0']), ('\u{a749}', ['\u{a748}', '\0', '\0']), ('\u{a74b}', + ['\u{a74a}', '\0', '\0']), ('\u{a74d}', ['\u{a74c}', '\0', '\0']), ('\u{a74f}', ['\u{a74e}', + '\0', '\0']), ('\u{a751}', ['\u{a750}', '\0', '\0']), ('\u{a753}', ['\u{a752}', '\0', + '\0']), ('\u{a755}', ['\u{a754}', '\0', '\0']), ('\u{a757}', ['\u{a756}', '\0', '\0']), + ('\u{a759}', ['\u{a758}', '\0', '\0']), ('\u{a75b}', ['\u{a75a}', '\0', '\0']), ('\u{a75d}', + ['\u{a75c}', '\0', '\0']), ('\u{a75f}', ['\u{a75e}', '\0', '\0']), ('\u{a761}', ['\u{a760}', + '\0', '\0']), ('\u{a763}', ['\u{a762}', '\0', '\0']), ('\u{a765}', ['\u{a764}', '\0', + '\0']), ('\u{a767}', ['\u{a766}', '\0', '\0']), ('\u{a769}', ['\u{a768}', '\0', '\0']), + ('\u{a76b}', ['\u{a76a}', '\0', '\0']), ('\u{a76d}', ['\u{a76c}', '\0', '\0']), ('\u{a76f}', + ['\u{a76e}', '\0', '\0']), ('\u{a77a}', ['\u{a779}', '\0', '\0']), ('\u{a77c}', ['\u{a77b}', + '\0', '\0']), ('\u{a77f}', ['\u{a77e}', '\0', '\0']), ('\u{a781}', ['\u{a780}', '\0', + '\0']), ('\u{a783}', ['\u{a782}', '\0', '\0']), ('\u{a785}', ['\u{a784}', '\0', '\0']), + ('\u{a787}', ['\u{a786}', '\0', '\0']), ('\u{a78c}', ['\u{a78b}', '\0', '\0']), ('\u{a791}', + ['\u{a790}', '\0', '\0']), ('\u{a793}', ['\u{a792}', '\0', '\0']), ('\u{a797}', ['\u{a796}', + '\0', '\0']), ('\u{a799}', ['\u{a798}', '\0', '\0']), ('\u{a79b}', ['\u{a79a}', '\0', + '\0']), ('\u{a79d}', ['\u{a79c}', '\0', '\0']), ('\u{a79f}', ['\u{a79e}', '\0', '\0']), + ('\u{a7a1}', ['\u{a7a0}', '\0', '\0']), ('\u{a7a3}', ['\u{a7a2}', '\0', '\0']), ('\u{a7a5}', + ['\u{a7a4}', '\0', '\0']), ('\u{a7a7}', ['\u{a7a6}', '\0', '\0']), ('\u{a7a9}', ['\u{a7a8}', + '\0', '\0']), ('\u{a7b5}', ['\u{a7b4}', '\0', '\0']), ('\u{a7b7}', ['\u{a7b6}', '\0', + '\0']), ('\u{ab53}', ['\u{a7b3}', '\0', '\0']), ('\u{ab70}', ['\u{13a0}', '\0', '\0']), + ('\u{ab71}', ['\u{13a1}', '\0', '\0']), ('\u{ab72}', ['\u{13a2}', '\0', '\0']), ('\u{ab73}', + ['\u{13a3}', '\0', '\0']), ('\u{ab74}', ['\u{13a4}', '\0', '\0']), ('\u{ab75}', ['\u{13a5}', + '\0', '\0']), ('\u{ab76}', ['\u{13a6}', '\0', '\0']), ('\u{ab77}', ['\u{13a7}', '\0', + '\0']), ('\u{ab78}', ['\u{13a8}', '\0', '\0']), ('\u{ab79}', ['\u{13a9}', '\0', '\0']), + ('\u{ab7a}', ['\u{13aa}', '\0', '\0']), ('\u{ab7b}', ['\u{13ab}', '\0', '\0']), ('\u{ab7c}', + ['\u{13ac}', '\0', '\0']), ('\u{ab7d}', ['\u{13ad}', '\0', '\0']), ('\u{ab7e}', ['\u{13ae}', + '\0', '\0']), ('\u{ab7f}', ['\u{13af}', '\0', '\0']), ('\u{ab80}', ['\u{13b0}', '\0', + '\0']), ('\u{ab81}', ['\u{13b1}', '\0', '\0']), ('\u{ab82}', ['\u{13b2}', '\0', '\0']), + ('\u{ab83}', ['\u{13b3}', '\0', '\0']), ('\u{ab84}', ['\u{13b4}', '\0', '\0']), ('\u{ab85}', + ['\u{13b5}', '\0', '\0']), ('\u{ab86}', ['\u{13b6}', '\0', '\0']), ('\u{ab87}', ['\u{13b7}', + '\0', '\0']), ('\u{ab88}', ['\u{13b8}', '\0', '\0']), ('\u{ab89}', ['\u{13b9}', '\0', + '\0']), ('\u{ab8a}', ['\u{13ba}', '\0', '\0']), ('\u{ab8b}', ['\u{13bb}', '\0', '\0']), + ('\u{ab8c}', ['\u{13bc}', '\0', '\0']), ('\u{ab8d}', ['\u{13bd}', '\0', '\0']), ('\u{ab8e}', + ['\u{13be}', '\0', '\0']), ('\u{ab8f}', ['\u{13bf}', '\0', '\0']), ('\u{ab90}', ['\u{13c0}', + '\0', '\0']), ('\u{ab91}', ['\u{13c1}', '\0', '\0']), ('\u{ab92}', ['\u{13c2}', '\0', + '\0']), ('\u{ab93}', ['\u{13c3}', '\0', '\0']), ('\u{ab94}', ['\u{13c4}', '\0', '\0']), + ('\u{ab95}', ['\u{13c5}', '\0', '\0']), ('\u{ab96}', ['\u{13c6}', '\0', '\0']), ('\u{ab97}', + ['\u{13c7}', '\0', '\0']), ('\u{ab98}', ['\u{13c8}', '\0', '\0']), ('\u{ab99}', ['\u{13c9}', + '\0', '\0']), ('\u{ab9a}', ['\u{13ca}', '\0', '\0']), ('\u{ab9b}', ['\u{13cb}', '\0', + '\0']), ('\u{ab9c}', ['\u{13cc}', '\0', '\0']), ('\u{ab9d}', ['\u{13cd}', '\0', '\0']), + ('\u{ab9e}', ['\u{13ce}', '\0', '\0']), ('\u{ab9f}', ['\u{13cf}', '\0', '\0']), ('\u{aba0}', + ['\u{13d0}', '\0', '\0']), ('\u{aba1}', ['\u{13d1}', '\0', '\0']), ('\u{aba2}', ['\u{13d2}', + '\0', '\0']), ('\u{aba3}', ['\u{13d3}', '\0', '\0']), ('\u{aba4}', ['\u{13d4}', '\0', + '\0']), ('\u{aba5}', ['\u{13d5}', '\0', '\0']), ('\u{aba6}', ['\u{13d6}', '\0', '\0']), + ('\u{aba7}', ['\u{13d7}', '\0', '\0']), ('\u{aba8}', ['\u{13d8}', '\0', '\0']), ('\u{aba9}', + ['\u{13d9}', '\0', '\0']), ('\u{abaa}', ['\u{13da}', '\0', '\0']), ('\u{abab}', ['\u{13db}', + '\0', '\0']), ('\u{abac}', ['\u{13dc}', '\0', '\0']), ('\u{abad}', ['\u{13dd}', '\0', + '\0']), ('\u{abae}', ['\u{13de}', '\0', '\0']), ('\u{abaf}', ['\u{13df}', '\0', '\0']), + ('\u{abb0}', ['\u{13e0}', '\0', '\0']), ('\u{abb1}', ['\u{13e1}', '\0', '\0']), ('\u{abb2}', + ['\u{13e2}', '\0', '\0']), ('\u{abb3}', ['\u{13e3}', '\0', '\0']), ('\u{abb4}', ['\u{13e4}', + '\0', '\0']), ('\u{abb5}', ['\u{13e5}', '\0', '\0']), ('\u{abb6}', ['\u{13e6}', '\0', + '\0']), ('\u{abb7}', ['\u{13e7}', '\0', '\0']), ('\u{abb8}', ['\u{13e8}', '\0', '\0']), + ('\u{abb9}', ['\u{13e9}', '\0', '\0']), ('\u{abba}', ['\u{13ea}', '\0', '\0']), ('\u{abbb}', + ['\u{13eb}', '\0', '\0']), ('\u{abbc}', ['\u{13ec}', '\0', '\0']), ('\u{abbd}', ['\u{13ed}', + '\0', '\0']), ('\u{abbe}', ['\u{13ee}', '\0', '\0']), ('\u{abbf}', ['\u{13ef}', '\0', + '\0']), ('\u{fb00}', ['\u{46}', '\u{46}', '\0']), ('\u{fb01}', ['\u{46}', '\u{49}', '\0']), + ('\u{fb02}', ['\u{46}', '\u{4c}', '\0']), ('\u{fb03}', ['\u{46}', '\u{46}', '\u{49}']), + ('\u{fb04}', ['\u{46}', '\u{46}', '\u{4c}']), ('\u{fb05}', ['\u{53}', '\u{54}', '\0']), + ('\u{fb06}', ['\u{53}', '\u{54}', '\0']), ('\u{fb13}', ['\u{544}', '\u{546}', '\0']), + ('\u{fb14}', ['\u{544}', '\u{535}', '\0']), ('\u{fb15}', ['\u{544}', '\u{53b}', '\0']), + ('\u{fb16}', ['\u{54e}', '\u{546}', '\0']), ('\u{fb17}', ['\u{544}', '\u{53d}', '\0']), + ('\u{ff41}', ['\u{ff21}', '\0', '\0']), ('\u{ff42}', ['\u{ff22}', '\0', '\0']), ('\u{ff43}', + ['\u{ff23}', '\0', '\0']), ('\u{ff44}', ['\u{ff24}', '\0', '\0']), ('\u{ff45}', ['\u{ff25}', + '\0', '\0']), ('\u{ff46}', ['\u{ff26}', '\0', '\0']), ('\u{ff47}', ['\u{ff27}', '\0', + '\0']), ('\u{ff48}', ['\u{ff28}', '\0', '\0']), ('\u{ff49}', ['\u{ff29}', '\0', '\0']), + ('\u{ff4a}', ['\u{ff2a}', '\0', '\0']), ('\u{ff4b}', ['\u{ff2b}', '\0', '\0']), ('\u{ff4c}', + ['\u{ff2c}', '\0', '\0']), ('\u{ff4d}', ['\u{ff2d}', '\0', '\0']), ('\u{ff4e}', ['\u{ff2e}', + '\0', '\0']), ('\u{ff4f}', ['\u{ff2f}', '\0', '\0']), ('\u{ff50}', ['\u{ff30}', '\0', + '\0']), ('\u{ff51}', ['\u{ff31}', '\0', '\0']), ('\u{ff52}', ['\u{ff32}', '\0', '\0']), + ('\u{ff53}', ['\u{ff33}', '\0', '\0']), ('\u{ff54}', ['\u{ff34}', '\0', '\0']), ('\u{ff55}', + ['\u{ff35}', '\0', '\0']), ('\u{ff56}', ['\u{ff36}', '\0', '\0']), ('\u{ff57}', ['\u{ff37}', + '\0', '\0']), ('\u{ff58}', ['\u{ff38}', '\0', '\0']), ('\u{ff59}', ['\u{ff39}', '\0', + '\0']), ('\u{ff5a}', ['\u{ff3a}', '\0', '\0']), ('\u{10428}', ['\u{10400}', '\0', '\0']), + ('\u{10429}', ['\u{10401}', '\0', '\0']), ('\u{1042a}', ['\u{10402}', '\0', '\0']), + ('\u{1042b}', ['\u{10403}', '\0', '\0']), ('\u{1042c}', ['\u{10404}', '\0', '\0']), + ('\u{1042d}', ['\u{10405}', '\0', '\0']), ('\u{1042e}', ['\u{10406}', '\0', '\0']), + ('\u{1042f}', ['\u{10407}', '\0', '\0']), ('\u{10430}', ['\u{10408}', '\0', '\0']), + ('\u{10431}', ['\u{10409}', '\0', '\0']), ('\u{10432}', ['\u{1040a}', '\0', '\0']), + ('\u{10433}', ['\u{1040b}', '\0', '\0']), ('\u{10434}', ['\u{1040c}', '\0', '\0']), + ('\u{10435}', ['\u{1040d}', '\0', '\0']), ('\u{10436}', ['\u{1040e}', '\0', '\0']), + ('\u{10437}', ['\u{1040f}', '\0', '\0']), ('\u{10438}', ['\u{10410}', '\0', '\0']), + ('\u{10439}', ['\u{10411}', '\0', '\0']), ('\u{1043a}', ['\u{10412}', '\0', '\0']), + ('\u{1043b}', ['\u{10413}', '\0', '\0']), ('\u{1043c}', ['\u{10414}', '\0', '\0']), + ('\u{1043d}', ['\u{10415}', '\0', '\0']), ('\u{1043e}', ['\u{10416}', '\0', '\0']), + ('\u{1043f}', ['\u{10417}', '\0', '\0']), ('\u{10440}', ['\u{10418}', '\0', '\0']), + ('\u{10441}', ['\u{10419}', '\0', '\0']), ('\u{10442}', ['\u{1041a}', '\0', '\0']), + ('\u{10443}', ['\u{1041b}', '\0', '\0']), ('\u{10444}', ['\u{1041c}', '\0', '\0']), + ('\u{10445}', ['\u{1041d}', '\0', '\0']), ('\u{10446}', ['\u{1041e}', '\0', '\0']), + ('\u{10447}', ['\u{1041f}', '\0', '\0']), ('\u{10448}', ['\u{10420}', '\0', '\0']), + ('\u{10449}', ['\u{10421}', '\0', '\0']), ('\u{1044a}', ['\u{10422}', '\0', '\0']), + ('\u{1044b}', ['\u{10423}', '\0', '\0']), ('\u{1044c}', ['\u{10424}', '\0', '\0']), + ('\u{1044d}', ['\u{10425}', '\0', '\0']), ('\u{1044e}', ['\u{10426}', '\0', '\0']), + ('\u{1044f}', ['\u{10427}', '\0', '\0']), ('\u{104d8}', ['\u{104b0}', '\0', '\0']), + ('\u{104d9}', ['\u{104b1}', '\0', '\0']), ('\u{104da}', ['\u{104b2}', '\0', '\0']), + ('\u{104db}', ['\u{104b3}', '\0', '\0']), ('\u{104dc}', ['\u{104b4}', '\0', '\0']), + ('\u{104dd}', ['\u{104b5}', '\0', '\0']), ('\u{104de}', ['\u{104b6}', '\0', '\0']), + ('\u{104df}', ['\u{104b7}', '\0', '\0']), ('\u{104e0}', ['\u{104b8}', '\0', '\0']), + ('\u{104e1}', ['\u{104b9}', '\0', '\0']), ('\u{104e2}', ['\u{104ba}', '\0', '\0']), + ('\u{104e3}', ['\u{104bb}', '\0', '\0']), ('\u{104e4}', ['\u{104bc}', '\0', '\0']), + ('\u{104e5}', ['\u{104bd}', '\0', '\0']), ('\u{104e6}', ['\u{104be}', '\0', '\0']), + ('\u{104e7}', ['\u{104bf}', '\0', '\0']), ('\u{104e8}', ['\u{104c0}', '\0', '\0']), + ('\u{104e9}', ['\u{104c1}', '\0', '\0']), ('\u{104ea}', ['\u{104c2}', '\0', '\0']), + ('\u{104eb}', ['\u{104c3}', '\0', '\0']), ('\u{104ec}', ['\u{104c4}', '\0', '\0']), + ('\u{104ed}', ['\u{104c5}', '\0', '\0']), ('\u{104ee}', ['\u{104c6}', '\0', '\0']), + ('\u{104ef}', ['\u{104c7}', '\0', '\0']), ('\u{104f0}', ['\u{104c8}', '\0', '\0']), + ('\u{104f1}', ['\u{104c9}', '\0', '\0']), ('\u{104f2}', ['\u{104ca}', '\0', '\0']), + ('\u{104f3}', ['\u{104cb}', '\0', '\0']), ('\u{104f4}', ['\u{104cc}', '\0', '\0']), + ('\u{104f5}', ['\u{104cd}', '\0', '\0']), ('\u{104f6}', ['\u{104ce}', '\0', '\0']), + ('\u{104f7}', ['\u{104cf}', '\0', '\0']), ('\u{104f8}', ['\u{104d0}', '\0', '\0']), + ('\u{104f9}', ['\u{104d1}', '\0', '\0']), ('\u{104fa}', ['\u{104d2}', '\0', '\0']), + ('\u{104fb}', ['\u{104d3}', '\0', '\0']), ('\u{10cc0}', ['\u{10c80}', '\0', '\0']), + ('\u{10cc1}', ['\u{10c81}', '\0', '\0']), ('\u{10cc2}', ['\u{10c82}', '\0', '\0']), + ('\u{10cc3}', ['\u{10c83}', '\0', '\0']), ('\u{10cc4}', ['\u{10c84}', '\0', '\0']), + ('\u{10cc5}', ['\u{10c85}', '\0', '\0']), ('\u{10cc6}', ['\u{10c86}', '\0', '\0']), + ('\u{10cc7}', ['\u{10c87}', '\0', '\0']), ('\u{10cc8}', ['\u{10c88}', '\0', '\0']), + ('\u{10cc9}', ['\u{10c89}', '\0', '\0']), ('\u{10cca}', ['\u{10c8a}', '\0', '\0']), + ('\u{10ccb}', ['\u{10c8b}', '\0', '\0']), ('\u{10ccc}', ['\u{10c8c}', '\0', '\0']), + ('\u{10ccd}', ['\u{10c8d}', '\0', '\0']), ('\u{10cce}', ['\u{10c8e}', '\0', '\0']), + ('\u{10ccf}', ['\u{10c8f}', '\0', '\0']), ('\u{10cd0}', ['\u{10c90}', '\0', '\0']), + ('\u{10cd1}', ['\u{10c91}', '\0', '\0']), ('\u{10cd2}', ['\u{10c92}', '\0', '\0']), + ('\u{10cd3}', ['\u{10c93}', '\0', '\0']), ('\u{10cd4}', ['\u{10c94}', '\0', '\0']), + ('\u{10cd5}', ['\u{10c95}', '\0', '\0']), ('\u{10cd6}', ['\u{10c96}', '\0', '\0']), + ('\u{10cd7}', ['\u{10c97}', '\0', '\0']), ('\u{10cd8}', ['\u{10c98}', '\0', '\0']), + ('\u{10cd9}', ['\u{10c99}', '\0', '\0']), ('\u{10cda}', ['\u{10c9a}', '\0', '\0']), + ('\u{10cdb}', ['\u{10c9b}', '\0', '\0']), ('\u{10cdc}', ['\u{10c9c}', '\0', '\0']), + ('\u{10cdd}', ['\u{10c9d}', '\0', '\0']), ('\u{10cde}', ['\u{10c9e}', '\0', '\0']), + ('\u{10cdf}', ['\u{10c9f}', '\0', '\0']), ('\u{10ce0}', ['\u{10ca0}', '\0', '\0']), + ('\u{10ce1}', ['\u{10ca1}', '\0', '\0']), ('\u{10ce2}', ['\u{10ca2}', '\0', '\0']), + ('\u{10ce3}', ['\u{10ca3}', '\0', '\0']), ('\u{10ce4}', ['\u{10ca4}', '\0', '\0']), + ('\u{10ce5}', ['\u{10ca5}', '\0', '\0']), ('\u{10ce6}', ['\u{10ca6}', '\0', '\0']), + ('\u{10ce7}', ['\u{10ca7}', '\0', '\0']), ('\u{10ce8}', ['\u{10ca8}', '\0', '\0']), + ('\u{10ce9}', ['\u{10ca9}', '\0', '\0']), ('\u{10cea}', ['\u{10caa}', '\0', '\0']), + ('\u{10ceb}', ['\u{10cab}', '\0', '\0']), ('\u{10cec}', ['\u{10cac}', '\0', '\0']), + ('\u{10ced}', ['\u{10cad}', '\0', '\0']), ('\u{10cee}', ['\u{10cae}', '\0', '\0']), + ('\u{10cef}', ['\u{10caf}', '\0', '\0']), ('\u{10cf0}', ['\u{10cb0}', '\0', '\0']), + ('\u{10cf1}', ['\u{10cb1}', '\0', '\0']), ('\u{10cf2}', ['\u{10cb2}', '\0', '\0']), + ('\u{118c0}', ['\u{118a0}', '\0', '\0']), ('\u{118c1}', ['\u{118a1}', '\0', '\0']), + ('\u{118c2}', ['\u{118a2}', '\0', '\0']), ('\u{118c3}', ['\u{118a3}', '\0', '\0']), + ('\u{118c4}', ['\u{118a4}', '\0', '\0']), ('\u{118c5}', ['\u{118a5}', '\0', '\0']), + ('\u{118c6}', ['\u{118a6}', '\0', '\0']), ('\u{118c7}', ['\u{118a7}', '\0', '\0']), + ('\u{118c8}', ['\u{118a8}', '\0', '\0']), ('\u{118c9}', ['\u{118a9}', '\0', '\0']), + ('\u{118ca}', ['\u{118aa}', '\0', '\0']), ('\u{118cb}', ['\u{118ab}', '\0', '\0']), + ('\u{118cc}', ['\u{118ac}', '\0', '\0']), ('\u{118cd}', ['\u{118ad}', '\0', '\0']), + ('\u{118ce}', ['\u{118ae}', '\0', '\0']), ('\u{118cf}', ['\u{118af}', '\0', '\0']), + ('\u{118d0}', ['\u{118b0}', '\0', '\0']), ('\u{118d1}', ['\u{118b1}', '\0', '\0']), + ('\u{118d2}', ['\u{118b2}', '\0', '\0']), ('\u{118d3}', ['\u{118b3}', '\0', '\0']), + ('\u{118d4}', ['\u{118b4}', '\0', '\0']), ('\u{118d5}', ['\u{118b5}', '\0', '\0']), + ('\u{118d6}', ['\u{118b6}', '\0', '\0']), ('\u{118d7}', ['\u{118b7}', '\0', '\0']), + ('\u{118d8}', ['\u{118b8}', '\0', '\0']), ('\u{118d9}', ['\u{118b9}', '\0', '\0']), + ('\u{118da}', ['\u{118ba}', '\0', '\0']), ('\u{118db}', ['\u{118bb}', '\0', '\0']), + ('\u{118dc}', ['\u{118bc}', '\0', '\0']), ('\u{118dd}', ['\u{118bd}', '\0', '\0']), + ('\u{118de}', ['\u{118be}', '\0', '\0']), ('\u{118df}', ['\u{118bf}', '\0', '\0']), + ('\u{1e922}', ['\u{1e900}', '\0', '\0']), ('\u{1e923}', ['\u{1e901}', '\0', '\0']), + ('\u{1e924}', ['\u{1e902}', '\0', '\0']), ('\u{1e925}', ['\u{1e903}', '\0', '\0']), + ('\u{1e926}', ['\u{1e904}', '\0', '\0']), ('\u{1e927}', ['\u{1e905}', '\0', '\0']), + ('\u{1e928}', ['\u{1e906}', '\0', '\0']), ('\u{1e929}', ['\u{1e907}', '\0', '\0']), + ('\u{1e92a}', ['\u{1e908}', '\0', '\0']), ('\u{1e92b}', ['\u{1e909}', '\0', '\0']), + ('\u{1e92c}', ['\u{1e90a}', '\0', '\0']), ('\u{1e92d}', ['\u{1e90b}', '\0', '\0']), + ('\u{1e92e}', ['\u{1e90c}', '\0', '\0']), ('\u{1e92f}', ['\u{1e90d}', '\0', '\0']), + ('\u{1e930}', ['\u{1e90e}', '\0', '\0']), ('\u{1e931}', ['\u{1e90f}', '\0', '\0']), + ('\u{1e932}', ['\u{1e910}', '\0', '\0']), ('\u{1e933}', ['\u{1e911}', '\0', '\0']), + ('\u{1e934}', ['\u{1e912}', '\0', '\0']), ('\u{1e935}', ['\u{1e913}', '\0', '\0']), + ('\u{1e936}', ['\u{1e914}', '\0', '\0']), ('\u{1e937}', ['\u{1e915}', '\0', '\0']), + ('\u{1e938}', ['\u{1e916}', '\0', '\0']), ('\u{1e939}', ['\u{1e917}', '\0', '\0']), + ('\u{1e93a}', ['\u{1e918}', '\0', '\0']), ('\u{1e93b}', ['\u{1e919}', '\0', '\0']), + ('\u{1e93c}', ['\u{1e91a}', '\0', '\0']), ('\u{1e93d}', ['\u{1e91b}', '\0', '\0']), + ('\u{1e93e}', ['\u{1e91c}', '\0', '\0']), ('\u{1e93f}', ['\u{1e91d}', '\0', '\0']), + ('\u{1e940}', ['\u{1e91e}', '\0', '\0']), ('\u{1e941}', ['\u{1e91f}', '\0', '\0']), + ('\u{1e942}', ['\u{1e920}', '\0', '\0']), ('\u{1e943}', ['\u{1e921}', '\0', '\0']) + ]; + +} + diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py new file mode 100755 index 00000000000..39b68dc7d9b --- /dev/null +++ b/src/libcore/unicode/unicode.py @@ -0,0 +1,501 @@ +#!/usr/bin/env python +# +# Copyright 2011-2013 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +# This script uses the following Unicode tables: +# - DerivedCoreProperties.txt +# - DerivedNormalizationProps.txt +# - EastAsianWidth.txt +# - auxiliary/GraphemeBreakProperty.txt +# - PropList.txt +# - ReadMe.txt +# - Scripts.txt +# - UnicodeData.txt +# +# Since this should not require frequent updates, we just store this +# out-of-line and check the unicode.rs file into git. + +import fileinput, re, os, sys, operator, math + +preamble = '''// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "./unicode.py", do not edit directly + +#![allow(missing_docs, non_upper_case_globals, non_snake_case)] + +use unicode::version::UnicodeVersion; +use unicode::bool_trie::{BoolTrie, SmallBoolTrie}; +''' + +# Mapping taken from Table 12 from: +# http://www.unicode.org/reports/tr44/#General_Category_Values +expanded_categories = { + 'Lu': ['LC', 'L'], 'Ll': ['LC', 'L'], 'Lt': ['LC', 'L'], + 'Lm': ['L'], 'Lo': ['L'], + 'Mn': ['M'], 'Mc': ['M'], 'Me': ['M'], + 'Nd': ['N'], 'Nl': ['N'], 'No': ['No'], + 'Pc': ['P'], 'Pd': ['P'], 'Ps': ['P'], 'Pe': ['P'], + 'Pi': ['P'], 'Pf': ['P'], 'Po': ['P'], + 'Sm': ['S'], 'Sc': ['S'], 'Sk': ['S'], 'So': ['S'], + 'Zs': ['Z'], 'Zl': ['Z'], 'Zp': ['Z'], + 'Cc': ['C'], 'Cf': ['C'], 'Cs': ['C'], 'Co': ['C'], 'Cn': ['C'], +} + +# these are the surrogate codepoints, which are not valid rust characters +surrogate_codepoints = (0xd800, 0xdfff) + +def fetch(f): + if not os.path.exists(os.path.basename(f)): + os.system("curl -O http://www.unicode.org/Public/UNIDATA/%s" + % f) + + if not os.path.exists(os.path.basename(f)): + sys.stderr.write("cannot load %s" % f) + exit(1) + +def is_surrogate(n): + return surrogate_codepoints[0] <= n <= surrogate_codepoints[1] + +def load_unicode_data(f): + fetch(f) + gencats = {} + to_lower = {} + to_upper = {} + to_title = {} + combines = {} + canon_decomp = {} + compat_decomp = {} + + udict = {} + range_start = -1 + for line in fileinput.input(f): + data = line.split(';') + if len(data) != 15: + continue + cp = int(data[0], 16) + if is_surrogate(cp): + continue + if range_start >= 0: + for i in range(range_start, cp): + udict[i] = data + range_start = -1 + if data[1].endswith(", First>"): + range_start = cp + continue + udict[cp] = data + + for code in udict: + (code_org, name, gencat, combine, bidi, + decomp, deci, digit, num, mirror, + old, iso, upcase, lowcase, titlecase) = udict[code] + + # generate char to char direct common and simple conversions + # uppercase to lowercase + if lowcase != "" and code_org != lowcase: + to_lower[code] = (int(lowcase, 16), 0, 0) + + # lowercase to uppercase + if upcase != "" and code_org != upcase: + to_upper[code] = (int(upcase, 16), 0, 0) + + # title case + if titlecase.strip() != "" and code_org != titlecase: + to_title[code] = (int(titlecase, 16), 0, 0) + + # store decomposition, if given + if decomp != "": + if decomp.startswith('<'): + seq = [] + for i in decomp.split()[1:]: + seq.append(int(i, 16)) + compat_decomp[code] = seq + else: + seq = [] + for i in decomp.split(): + seq.append(int(i, 16)) + canon_decomp[code] = seq + + # place letter in categories as appropriate + for cat in [gencat, "Assigned"] + expanded_categories.get(gencat, []): + if cat not in gencats: + gencats[cat] = [] + gencats[cat].append(code) + + # record combining class, if any + if combine != "0": + if combine not in combines: + combines[combine] = [] + combines[combine].append(code) + + # generate Not_Assigned from Assigned + gencats["Cn"] = gen_unassigned(gencats["Assigned"]) + # Assigned is not a real category + del(gencats["Assigned"]) + # Other contains Not_Assigned + gencats["C"].extend(gencats["Cn"]) + gencats = group_cats(gencats) + combines = to_combines(group_cats(combines)) + + return (canon_decomp, compat_decomp, gencats, combines, to_upper, to_lower, to_title) + +def load_special_casing(f, to_upper, to_lower, to_title): + fetch(f) + for line in fileinput.input(f): + data = line.split('#')[0].split(';') + if len(data) == 5: + code, lower, title, upper, _comment = data + elif len(data) == 6: + code, lower, title, upper, condition, _comment = data + if condition.strip(): # Only keep unconditional mappins + continue + else: + continue + code = code.strip() + lower = lower.strip() + title = title.strip() + upper = upper.strip() + key = int(code, 16) + for (map_, values) in [(to_lower, lower), (to_upper, upper), (to_title, title)]: + if values != code: + values = [int(i, 16) for i in values.split()] + for _ in range(len(values), 3): + values.append(0) + assert len(values) == 3 + map_[key] = values + +def group_cats(cats): + cats_out = {} + for cat in cats: + cats_out[cat] = group_cat(cats[cat]) + return cats_out + +def group_cat(cat): + cat_out = [] + letters = sorted(set(cat)) + cur_start = letters.pop(0) + cur_end = cur_start + for letter in letters: + assert letter > cur_end, \ + "cur_end: %s, letter: %s" % (hex(cur_end), hex(letter)) + if letter == cur_end + 1: + cur_end = letter + else: + cat_out.append((cur_start, cur_end)) + cur_start = cur_end = letter + cat_out.append((cur_start, cur_end)) + return cat_out + +def ungroup_cat(cat): + cat_out = [] + for (lo, hi) in cat: + while lo <= hi: + cat_out.append(lo) + lo += 1 + return cat_out + +def gen_unassigned(assigned): + assigned = set(assigned) + return ([i for i in range(0, 0xd800) if i not in assigned] + + [i for i in range(0xe000, 0x110000) if i not in assigned]) + +def to_combines(combs): + combs_out = [] + for comb in combs: + for (lo, hi) in combs[comb]: + combs_out.append((lo, hi, comb)) + combs_out.sort(key=lambda comb: comb[0]) + return combs_out + +def format_table_content(f, content, indent): + line = " "*indent + first = True + for chunk in content.split(","): + if len(line) + len(chunk) < 98: + if first: + line += chunk + else: + line += ", " + chunk + first = False + else: + f.write(line + ",\n") + line = " "*indent + chunk + f.write(line) + +def load_properties(f, interestingprops): + fetch(f) + props = {} + re1 = re.compile("^ *([0-9A-F]+) *; *(\w+)") + re2 = re.compile("^ *([0-9A-F]+)\.\.([0-9A-F]+) *; *(\w+)") + + for line in fileinput.input(os.path.basename(f)): + prop = None + d_lo = 0 + d_hi = 0 + m = re1.match(line) + if m: + d_lo = m.group(1) + d_hi = m.group(1) + prop = m.group(2) + else: + m = re2.match(line) + if m: + d_lo = m.group(1) + d_hi = m.group(2) + prop = m.group(3) + else: + continue + if interestingprops and prop not in interestingprops: + continue + d_lo = int(d_lo, 16) + d_hi = int(d_hi, 16) + if prop not in props: + props[prop] = [] + props[prop].append((d_lo, d_hi)) + + # optimize if possible + for prop in props: + props[prop] = group_cat(ungroup_cat(props[prop])) + + return props + +def escape_char(c): + return "'\\u{%x}'" % c if c != 0 else "'\\0'" + +def emit_table(f, name, t_data, t_type = "&[(char, char)]", is_pub=True, + pfun=lambda x: "(%s,%s)" % (escape_char(x[0]), escape_char(x[1]))): + pub_string = "" + if is_pub: + pub_string = "pub " + f.write(" %sconst %s: %s = &[\n" % (pub_string, name, t_type)) + data = "" + first = True + for dat in t_data: + if not first: + data += "," + first = False + data += pfun(dat) + format_table_content(f, data, 8) + f.write("\n ];\n\n") + +def compute_trie(rawdata, chunksize): + root = [] + childmap = {} + child_data = [] + for i in range(len(rawdata) // chunksize): + data = rawdata[i * chunksize: (i + 1) * chunksize] + child = '|'.join(map(str, data)) + if child not in childmap: + childmap[child] = len(childmap) + child_data.extend(data) + root.append(childmap[child]) + return (root, child_data) + +def emit_bool_trie(f, name, t_data, is_pub=True): + CHUNK = 64 + rawdata = [False] * 0x110000 + for (lo, hi) in t_data: + for cp in range(lo, hi + 1): + rawdata[cp] = True + + # convert to bitmap chunks of 64 bits each + chunks = [] + for i in range(0x110000 // CHUNK): + chunk = 0 + for j in range(64): + if rawdata[i * 64 + j]: + chunk |= 1 << j + chunks.append(chunk) + + pub_string = "" + if is_pub: + pub_string = "pub " + f.write(" %sconst %s: &super::BoolTrie = &super::BoolTrie {\n" % (pub_string, name)) + f.write(" r1: [\n") + data = ','.join('0x%016x' % chunk for chunk in chunks[0:0x800 // CHUNK]) + format_table_content(f, data, 12) + f.write("\n ],\n") + + # 0x800..0x10000 trie + (r2, r3) = compute_trie(chunks[0x800 // CHUNK : 0x10000 // CHUNK], 64 // CHUNK) + f.write(" r2: [\n") + data = ','.join(str(node) for node in r2) + format_table_content(f, data, 12) + f.write("\n ],\n") + f.write(" r3: &[\n") + data = ','.join('0x%016x' % chunk for chunk in r3) + format_table_content(f, data, 12) + f.write("\n ],\n") + + # 0x10000..0x110000 trie + (mid, r6) = compute_trie(chunks[0x10000 // CHUNK : 0x110000 // CHUNK], 64 // CHUNK) + (r4, r5) = compute_trie(mid, 64) + f.write(" r4: [\n") + data = ','.join(str(node) for node in r4) + format_table_content(f, data, 12) + f.write("\n ],\n") + f.write(" r5: &[\n") + data = ','.join(str(node) for node in r5) + format_table_content(f, data, 12) + f.write("\n ],\n") + f.write(" r6: &[\n") + data = ','.join('0x%016x' % chunk for chunk in r6) + format_table_content(f, data, 12) + f.write("\n ],\n") + + f.write(" };\n\n") + +def emit_small_bool_trie(f, name, t_data, is_pub=True): + last_chunk = max(hi // 64 for (lo, hi) in t_data) + n_chunks = last_chunk + 1 + chunks = [0] * n_chunks + for (lo, hi) in t_data: + for cp in range(lo, hi + 1): + if cp // 64 >= len(chunks): + print(cp, cp // 64, len(chunks), lo, hi) + chunks[cp // 64] |= 1 << (cp & 63) + + pub_string = "" + if is_pub: + pub_string = "pub " + f.write(" %sconst %s: &super::SmallBoolTrie = &super::SmallBoolTrie {\n" + % (pub_string, name)) + + (r1, r2) = compute_trie(chunks, 1) + + f.write(" r1: &[\n") + data = ','.join(str(node) for node in r1) + format_table_content(f, data, 12) + f.write("\n ],\n") + + f.write(" r2: &[\n") + data = ','.join('0x%016x' % node for node in r2) + format_table_content(f, data, 12) + f.write("\n ],\n") + + f.write(" };\n\n") + +def emit_property_module(f, mod, tbl, emit): + f.write("pub mod %s {\n" % mod) + for cat in sorted(emit): + if cat in ["Cc", "White_Space", "Pattern_White_Space"]: + emit_small_bool_trie(f, "%s_table" % cat, tbl[cat]) + f.write(" pub fn %s(c: char) -> bool {\n" % cat) + f.write(" %s_table.lookup(c)\n" % cat) + f.write(" }\n\n") + else: + emit_bool_trie(f, "%s_table" % cat, tbl[cat]) + f.write(" pub fn %s(c: char) -> bool {\n" % cat) + f.write(" %s_table.lookup(c)\n" % cat) + f.write(" }\n\n") + f.write("}\n\n") + +def emit_conversions_module(f, to_upper, to_lower, to_title): + f.write("pub mod conversions {") + f.write(""" + pub fn to_lower(c: char) -> [char; 3] { + match bsearch_case_table(c, to_lowercase_table) { + None => [c, '\\0', '\\0'], + Some(index) => to_lowercase_table[index].1, + } + } + + pub fn to_upper(c: char) -> [char; 3] { + match bsearch_case_table(c, to_uppercase_table) { + None => [c, '\\0', '\\0'], + Some(index) => to_uppercase_table[index].1, + } + } + + fn bsearch_case_table(c: char, table: &[(char, [char; 3])]) -> Option { + table.binary_search_by(|&(key, _)| key.cmp(&c)).ok() + } + +""") + t_type = "&[(char, [char; 3])]" + pfun = lambda x: "(%s,[%s,%s,%s])" % ( + escape_char(x[0]), escape_char(x[1][0]), escape_char(x[1][1]), escape_char(x[1][2])) + emit_table(f, "to_lowercase_table", + sorted(to_lower.items(), key=operator.itemgetter(0)), + is_pub=False, t_type = t_type, pfun=pfun) + emit_table(f, "to_uppercase_table", + sorted(to_upper.items(), key=operator.itemgetter(0)), + is_pub=False, t_type = t_type, pfun=pfun) + f.write("}\n\n") + +def emit_norm_module(f, canon, compat, combine, norm_props): + canon_keys = sorted(canon.keys()) + + compat_keys = sorted(compat.keys()) + + canon_comp = {} + comp_exclusions = norm_props["Full_Composition_Exclusion"] + for char in canon_keys: + if any(lo <= char <= hi for lo, hi in comp_exclusions): + continue + decomp = canon[char] + if len(decomp) == 2: + if decomp[0] not in canon_comp: + canon_comp[decomp[0]] = [] + canon_comp[decomp[0]].append( (decomp[1], char) ) + canon_comp_keys = sorted(canon_comp.keys()) + +if __name__ == "__main__": + r = "tables.rs" + if os.path.exists(r): + os.remove(r) + with open(r, "w") as rf: + # write the file's preamble + rf.write(preamble) + + # download and parse all the data + fetch("ReadMe.txt") + with open("ReadMe.txt") as readme: + pattern = "for Version (\d+)\.(\d+)\.(\d+) of the Unicode" + unicode_version = re.search(pattern, readme.read()).groups() + rf.write(""" +/// The version of [Unicode](http://www.unicode.org/) that the Unicode parts of +/// `CharExt` and `UnicodeStrPrelude` traits are based on. +pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { + major: %s, + minor: %s, + micro: %s, + _priv: (), +}; +""" % unicode_version) + (canon_decomp, compat_decomp, gencats, combines, + to_upper, to_lower, to_title) = load_unicode_data("UnicodeData.txt") + load_special_casing("SpecialCasing.txt", to_upper, to_lower, to_title) + want_derived = ["XID_Start", "XID_Continue", "Alphabetic", "Lowercase", "Uppercase", + "Cased", "Case_Ignorable"] + derived = load_properties("DerivedCoreProperties.txt", want_derived) + scripts = load_properties("Scripts.txt", []) + props = load_properties("PropList.txt", + ["White_Space", "Join_Control", "Noncharacter_Code_Point", "Pattern_White_Space"]) + norm_props = load_properties("DerivedNormalizationProps.txt", + ["Full_Composition_Exclusion"]) + + # category tables + for (name, cat, pfuns) in ("general_category", gencats, ["N", "Cc"]), \ + ("derived_property", derived, want_derived), \ + ("property", props, ["White_Space", "Pattern_White_Space"]): + emit_property_module(rf, name, cat, pfuns) + + # normalizations and conversions module + emit_norm_module(rf, canon_decomp, compat_decomp, combines, norm_props) + emit_conversions_module(rf, to_upper, to_lower, to_title) diff --git a/src/libcore/unicode/version.rs b/src/libcore/unicode/version.rs new file mode 100644 index 00000000000..d82a749d917 --- /dev/null +++ b/src/libcore/unicode/version.rs @@ -0,0 +1,27 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// Represents a Unicode Version. +/// +/// See also: +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct UnicodeVersion { + /// Major version. + pub major: u32, + + /// Minor version. + pub minor: u32, + + /// Micro (or Update) version. + pub micro: u32, + + // Private field to keep struct expandable. + pub(crate) _priv: (), +} diff --git a/src/libstd_unicode/bool_trie.rs b/src/libstd_unicode/bool_trie.rs deleted file mode 100644 index 3e45b08f399..00000000000 --- a/src/libstd_unicode/bool_trie.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// BoolTrie is a trie for representing a set of Unicode codepoints. It is -/// implemented with postfix compression (sharing of identical child nodes), -/// which gives both compact size and fast lookup. -/// -/// The space of Unicode codepoints is divided into 3 subareas, each -/// represented by a trie with different depth. In the first (0..0x800), there -/// is no trie structure at all; each u64 entry corresponds to a bitvector -/// effectively holding 64 bool values. -/// -/// In the second (0x800..0x10000), each child of the root node represents a -/// 64-wide subrange, but instead of storing the full 64-bit value of the leaf, -/// the trie stores an 8-bit index into a shared table of leaf values. This -/// exploits the fact that in reasonable sets, many such leaves can be shared. -/// -/// In the third (0x10000..0x110000), each child of the root node represents a -/// 4096-wide subrange, and the trie stores an 8-bit index into a 64-byte slice -/// of a child tree. Each of these 64 bytes represents an index into the table -/// of shared 64-bit leaf values. This exploits the sparse structure in the -/// non-BMP range of most Unicode sets. -pub struct BoolTrie { - // 0..0x800 (corresponding to 1 and 2 byte utf-8 sequences) - pub r1: [u64; 32], // leaves - - // 0x800..0x10000 (corresponding to 3 byte utf-8 sequences) - pub r2: [u8; 992], // first level - pub r3: &'static [u64], // leaves - - // 0x10000..0x110000 (corresponding to 4 byte utf-8 sequences) - pub r4: [u8; 256], // first level - pub r5: &'static [u8], // second level - pub r6: &'static [u64], // leaves -} -impl BoolTrie { - pub fn lookup(&self, c: char) -> bool { - let c = c as usize; - if c < 0x800 { - trie_range_leaf(c, self.r1[c >> 6]) - } else if c < 0x10000 { - let child = self.r2[(c >> 6) - 0x20]; - trie_range_leaf(c, self.r3[child as usize]) - } else { - let child = self.r4[(c >> 12) - 0x10]; - let leaf = self.r5[((child as usize) << 6) + ((c >> 6) & 0x3f)]; - trie_range_leaf(c, self.r6[leaf as usize]) - } - } -} - -pub struct SmallBoolTrie { - pub(crate) r1: &'static [u8], // first level - pub(crate) r2: &'static [u64], // leaves -} - -impl SmallBoolTrie { - pub fn lookup(&self, c: char) -> bool { - let c = c as usize; - match self.r1.get(c >> 6) { - Some(&child) => trie_range_leaf(c, self.r2[child as usize]), - None => false, - } - } -} - -fn trie_range_leaf(c: usize, bitmap_chunk: u64) -> bool { - ((bitmap_chunk >> (c & 63)) & 1) != 0 -} diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs deleted file mode 100644 index 460f83d875a..00000000000 --- a/src/libstd_unicode/char.rs +++ /dev/null @@ -1,1585 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A character type. -//! -//! The `char` type represents a single character. More specifically, since -//! 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode -//! scalar value]', which is similar to, but not the same as, a '[Unicode code -//! point]'. -//! -//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value -//! [Unicode code point]: http://www.unicode.org/glossary/#code_point -//! -//! This module exists for technical reasons, the primary documentation for -//! `char` is directly on [the `char` primitive type](../../std/primitive.char.html) -//! itself. -//! -//! This module is the home of the iterator implementations for the iterators -//! implemented on `char`, as well as some useful constants and conversion -//! functions that convert various types to `char`. - -#![stable(feature = "rust1", since = "1.0.0")] - -use core::char::CharExt as C; -use core::iter::FusedIterator; -use core::fmt::{self, Write}; -use tables::{conversions, derived_property, general_category, property}; - -// stable re-exports -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::char::{MAX, from_digit, from_u32, from_u32_unchecked}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::char::{EscapeDebug, EscapeDefault, EscapeUnicode}; -#[stable(feature = "decode_utf16", since = "1.9.0")] -pub use core::char::REPLACEMENT_CHARACTER; -#[stable(feature = "char_from_str", since = "1.20.0")] -pub use core::char::ParseCharError; - -// unstable re-exports -#[stable(feature = "try_from", since = "1.26.0")] -pub use core::char::CharTryFromError; -#[unstable(feature = "decode_utf8", issue = "33906")] -pub use core::char::{DecodeUtf8, decode_utf8}; -#[unstable(feature = "unicode", issue = "27783")] -pub use tables::{UNICODE_VERSION}; -#[unstable(feature = "unicode", issue = "27783")] -pub use version::UnicodeVersion; - -/// Returns an iterator that yields the lowercase equivalent of a `char`. -/// -/// This `struct` is created by the [`to_lowercase`] method on [`char`]. See -/// its documentation for more. -/// -/// [`to_lowercase`]: ../../std/primitive.char.html#method.to_lowercase -/// [`char`]: ../../std/primitive.char.html -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug, Clone)] -pub struct ToLowercase(CaseMappingIter); - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for ToLowercase { - type Item = char; - fn next(&mut self) -> Option { - self.0.next() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for ToLowercase {} - -/// Returns an iterator that yields the uppercase equivalent of a `char`. -/// -/// This `struct` is created by the [`to_uppercase`] method on [`char`]. See -/// its documentation for more. -/// -/// [`to_uppercase`]: ../../std/primitive.char.html#method.to_uppercase -/// [`char`]: ../../std/primitive.char.html -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug, Clone)] -pub struct ToUppercase(CaseMappingIter); - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for ToUppercase { - type Item = char; - fn next(&mut self) -> Option { - self.0.next() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for ToUppercase {} - -#[derive(Debug, Clone)] -enum CaseMappingIter { - Three(char, char, char), - Two(char, char), - One(char), - Zero, -} - -impl CaseMappingIter { - fn new(chars: [char; 3]) -> CaseMappingIter { - if chars[2] == '\0' { - if chars[1] == '\0' { - CaseMappingIter::One(chars[0]) // Including if chars[0] == '\0' - } else { - CaseMappingIter::Two(chars[0], chars[1]) - } - } else { - CaseMappingIter::Three(chars[0], chars[1], chars[2]) - } - } -} - -impl Iterator for CaseMappingIter { - type Item = char; - fn next(&mut self) -> Option { - match *self { - CaseMappingIter::Three(a, b, c) => { - *self = CaseMappingIter::Two(b, c); - Some(a) - } - CaseMappingIter::Two(b, c) => { - *self = CaseMappingIter::One(c); - Some(b) - } - CaseMappingIter::One(c) => { - *self = CaseMappingIter::Zero; - Some(c) - } - CaseMappingIter::Zero => None, - } - } -} - -impl fmt::Display for CaseMappingIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - CaseMappingIter::Three(a, b, c) => { - f.write_char(a)?; - f.write_char(b)?; - f.write_char(c) - } - CaseMappingIter::Two(b, c) => { - f.write_char(b)?; - f.write_char(c) - } - CaseMappingIter::One(c) => { - f.write_char(c) - } - CaseMappingIter::Zero => Ok(()), - } - } -} - -#[stable(feature = "char_struct_display", since = "1.16.0")] -impl fmt::Display for ToLowercase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } -} - -#[stable(feature = "char_struct_display", since = "1.16.0")] -impl fmt::Display for ToUppercase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } -} - -#[lang = "char"] -impl char { - /// Checks if a `char` is a digit in the given radix. - /// - /// A 'radix' here is sometimes also called a 'base'. A radix of two - /// indicates a binary number, a radix of ten, decimal, and a radix of - /// sixteen, hexadecimal, to give some common values. Arbitrary - /// radices are supported. - /// - /// Compared to `is_numeric()`, this function only recognizes the characters - /// `0-9`, `a-z` and `A-Z`. - /// - /// 'Digit' is defined to be only the following characters: - /// - /// * `0-9` - /// * `a-z` - /// * `A-Z` - /// - /// For a more comprehensive understanding of 'digit', see [`is_numeric`][is_numeric]. - /// - /// [is_numeric]: #method.is_numeric - /// - /// # Panics - /// - /// Panics if given a radix larger than 36. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!('1'.is_digit(10)); - /// assert!('f'.is_digit(16)); - /// assert!(!'f'.is_digit(10)); - /// ``` - /// - /// Passing a large radix, causing a panic: - /// - /// ``` - /// use std::thread; - /// - /// let result = thread::spawn(|| { - /// // this panics - /// '1'.is_digit(37); - /// }).join(); - /// - /// assert!(result.is_err()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_digit(self, radix: u32) -> bool { - C::is_digit(self, radix) - } - - /// Converts a `char` to a digit in the given radix. - /// - /// A 'radix' here is sometimes also called a 'base'. A radix of two - /// indicates a binary number, a radix of ten, decimal, and a radix of - /// sixteen, hexadecimal, to give some common values. Arbitrary - /// radices are supported. - /// - /// 'Digit' is defined to be only the following characters: - /// - /// * `0-9` - /// * `a-z` - /// * `A-Z` - /// - /// # Errors - /// - /// Returns `None` if the `char` does not refer to a digit in the given radix. - /// - /// # Panics - /// - /// Panics if given a radix larger than 36. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!('1'.to_digit(10), Some(1)); - /// assert_eq!('f'.to_digit(16), Some(15)); - /// ``` - /// - /// Passing a non-digit results in failure: - /// - /// ``` - /// assert_eq!('f'.to_digit(10), None); - /// assert_eq!('z'.to_digit(16), None); - /// ``` - /// - /// Passing a large radix, causing a panic: - /// - /// ``` - /// use std::thread; - /// - /// let result = thread::spawn(|| { - /// '1'.to_digit(37); - /// }).join(); - /// - /// assert!(result.is_err()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_digit(self, radix: u32) -> Option { - C::to_digit(self, radix) - } - - /// Returns an iterator that yields the hexadecimal Unicode escape of a - /// character as `char`s. - /// - /// This will escape characters with the Rust syntax of the form - /// `\u{NNNNNN}` where `NNNNNN` is a hexadecimal representation. - /// - /// # Examples - /// - /// As an iterator: - /// - /// ``` - /// for c in '❤'.escape_unicode() { - /// print!("{}", c); - /// } - /// println!(); - /// ``` - /// - /// Using `println!` directly: - /// - /// ``` - /// println!("{}", '❤'.escape_unicode()); - /// ``` - /// - /// Both are equivalent to: - /// - /// ``` - /// println!("\\u{{2764}}"); - /// ``` - /// - /// Using `to_string`: - /// - /// ``` - /// assert_eq!('❤'.escape_unicode().to_string(), "\\u{2764}"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn escape_unicode(self) -> EscapeUnicode { - C::escape_unicode(self) - } - - /// Returns an iterator that yields the literal escape code of a character - /// as `char`s. - /// - /// This will escape the characters similar to the `Debug` implementations - /// of `str` or `char`. - /// - /// # Examples - /// - /// As an iterator: - /// - /// ``` - /// for c in '\n'.escape_debug() { - /// print!("{}", c); - /// } - /// println!(); - /// ``` - /// - /// Using `println!` directly: - /// - /// ``` - /// println!("{}", '\n'.escape_debug()); - /// ``` - /// - /// Both are equivalent to: - /// - /// ``` - /// println!("\\n"); - /// ``` - /// - /// Using `to_string`: - /// - /// ``` - /// assert_eq!('\n'.escape_debug().to_string(), "\\n"); - /// ``` - #[stable(feature = "char_escape_debug", since = "1.20.0")] - #[inline] - pub fn escape_debug(self) -> EscapeDebug { - C::escape_debug(self) - } - - /// Returns an iterator that yields the literal escape code of a character - /// as `char`s. - /// - /// The default is chosen with a bias toward producing literals that are - /// legal in a variety of languages, including C++11 and similar C-family - /// languages. The exact rules are: - /// - /// * Tab is escaped as `\t`. - /// * Carriage return is escaped as `\r`. - /// * Line feed is escaped as `\n`. - /// * Single quote is escaped as `\'`. - /// * Double quote is escaped as `\"`. - /// * Backslash is escaped as `\\`. - /// * Any character in the 'printable ASCII' range `0x20` .. `0x7e` - /// inclusive is not escaped. - /// * All other characters are given hexadecimal Unicode escapes; see - /// [`escape_unicode`][escape_unicode]. - /// - /// [escape_unicode]: #method.escape_unicode - /// - /// # Examples - /// - /// As an iterator: - /// - /// ``` - /// for c in '"'.escape_default() { - /// print!("{}", c); - /// } - /// println!(); - /// ``` - /// - /// Using `println!` directly: - /// - /// ``` - /// println!("{}", '"'.escape_default()); - /// ``` - /// - /// - /// Both are equivalent to: - /// - /// ``` - /// println!("\\\""); - /// ``` - /// - /// Using `to_string`: - /// - /// ``` - /// assert_eq!('"'.escape_default().to_string(), "\\\""); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn escape_default(self) -> EscapeDefault { - C::escape_default(self) - } - - /// Returns the number of bytes this `char` would need if encoded in UTF-8. - /// - /// That number of bytes is always between 1 and 4, inclusive. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let len = 'A'.len_utf8(); - /// assert_eq!(len, 1); - /// - /// let len = 'ß'.len_utf8(); - /// assert_eq!(len, 2); - /// - /// let len = 'ℝ'.len_utf8(); - /// assert_eq!(len, 3); - /// - /// let len = '💣'.len_utf8(); - /// assert_eq!(len, 4); - /// ``` - /// - /// The `&str` type guarantees that its contents are UTF-8, and so we can compare the length it - /// would take if each code point was represented as a `char` vs in the `&str` itself: - /// - /// ``` - /// // as chars - /// let eastern = '東'; - /// let capitol = '京'; - /// - /// // both can be represented as three bytes - /// assert_eq!(3, eastern.len_utf8()); - /// assert_eq!(3, capitol.len_utf8()); - /// - /// // as a &str, these two are encoded in UTF-8 - /// let tokyo = "東京"; - /// - /// let len = eastern.len_utf8() + capitol.len_utf8(); - /// - /// // we can see that they take six bytes total... - /// assert_eq!(6, tokyo.len()); - /// - /// // ... just like the &str - /// assert_eq!(len, tokyo.len()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn len_utf8(self) -> usize { - C::len_utf8(self) - } - - /// Returns the number of 16-bit code units this `char` would need if - /// encoded in UTF-16. - /// - /// See the documentation for [`len_utf8`] for more explanation of this - /// concept. This function is a mirror, but for UTF-16 instead of UTF-8. - /// - /// [`len_utf8`]: #method.len_utf8 - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 'ß'.len_utf16(); - /// assert_eq!(n, 1); - /// - /// let len = '💣'.len_utf16(); - /// assert_eq!(len, 2); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn len_utf16(self) -> usize { - C::len_utf16(self) - } - - /// Encodes this character as UTF-8 into the provided byte buffer, - /// and then returns the subslice of the buffer that contains the encoded character. - /// - /// # Panics - /// - /// Panics if the buffer is not large enough. - /// A buffer of length four is large enough to encode any `char`. - /// - /// # Examples - /// - /// In both of these examples, 'ß' takes two bytes to encode. - /// - /// ``` - /// let mut b = [0; 2]; - /// - /// let result = 'ß'.encode_utf8(&mut b); - /// - /// assert_eq!(result, "ß"); - /// - /// assert_eq!(result.len(), 2); - /// ``` - /// - /// A buffer that's too small: - /// - /// ``` - /// use std::thread; - /// - /// let result = thread::spawn(|| { - /// let mut b = [0; 1]; - /// - /// // this panics - /// 'ß'.encode_utf8(&mut b); - /// }).join(); - /// - /// assert!(result.is_err()); - /// ``` - #[stable(feature = "unicode_encode_char", since = "1.15.0")] - #[inline] - pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str { - C::encode_utf8(self, dst) - } - - /// Encodes this character as UTF-16 into the provided `u16` buffer, - /// and then returns the subslice of the buffer that contains the encoded character. - /// - /// # Panics - /// - /// Panics if the buffer is not large enough. - /// A buffer of length 2 is large enough to encode any `char`. - /// - /// # Examples - /// - /// In both of these examples, '𝕊' takes two `u16`s to encode. - /// - /// ``` - /// let mut b = [0; 2]; - /// - /// let result = '𝕊'.encode_utf16(&mut b); - /// - /// assert_eq!(result.len(), 2); - /// ``` - /// - /// A buffer that's too small: - /// - /// ``` - /// use std::thread; - /// - /// let result = thread::spawn(|| { - /// let mut b = [0; 1]; - /// - /// // this panics - /// '𝕊'.encode_utf16(&mut b); - /// }).join(); - /// - /// assert!(result.is_err()); - /// ``` - #[stable(feature = "unicode_encode_char", since = "1.15.0")] - #[inline] - pub fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { - C::encode_utf16(self, dst) - } - - /// Returns true if this `char` is an alphabetic code point, and false if not. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!('a'.is_alphabetic()); - /// assert!('京'.is_alphabetic()); - /// - /// let c = '💝'; - /// // love is many things, but it is not alphabetic - /// assert!(!c.is_alphabetic()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_alphabetic(self) -> bool { - match self { - 'a'...'z' | 'A'...'Z' => true, - c if c > '\x7f' => derived_property::Alphabetic(c), - _ => false, - } - } - - /// Returns true if this `char` satisfies the 'XID_Start' Unicode property, and false - /// otherwise. - /// - /// 'XID_Start' is a Unicode Derived Property specified in - /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), - /// mostly similar to `ID_Start` but modified for closure under `NFKx`. - #[unstable(feature = "rustc_private", - reason = "mainly needed for compiler internals", - issue = "27812")] - #[inline] - pub fn is_xid_start(self) -> bool { - derived_property::XID_Start(self) - } - - /// Returns true if this `char` satisfies the 'XID_Continue' Unicode property, and false - /// otherwise. - /// - /// 'XID_Continue' is a Unicode Derived Property specified in - /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), - /// mostly similar to 'ID_Continue' but modified for closure under NFKx. - #[unstable(feature = "rustc_private", - reason = "mainly needed for compiler internals", - issue = "27812")] - #[inline] - pub fn is_xid_continue(self) -> bool { - derived_property::XID_Continue(self) - } - - /// Returns true if this `char` is lowercase, and false otherwise. - /// - /// 'Lowercase' is defined according to the terms of the Unicode Derived Core - /// Property `Lowercase`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!('a'.is_lowercase()); - /// assert!('δ'.is_lowercase()); - /// assert!(!'A'.is_lowercase()); - /// assert!(!'Δ'.is_lowercase()); - /// - /// // The various Chinese scripts do not have case, and so: - /// assert!(!'中'.is_lowercase()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_lowercase(self) -> bool { - match self { - 'a'...'z' => true, - c if c > '\x7f' => derived_property::Lowercase(c), - _ => false, - } - } - - /// Returns true if this `char` is uppercase, and false otherwise. - /// - /// 'Uppercase' is defined according to the terms of the Unicode Derived Core - /// Property `Uppercase`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!(!'a'.is_uppercase()); - /// assert!(!'δ'.is_uppercase()); - /// assert!('A'.is_uppercase()); - /// assert!('Δ'.is_uppercase()); - /// - /// // The various Chinese scripts do not have case, and so: - /// assert!(!'中'.is_uppercase()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_uppercase(self) -> bool { - match self { - 'A'...'Z' => true, - c if c > '\x7f' => derived_property::Uppercase(c), - _ => false, - } - } - - /// Returns true if this `char` is whitespace, and false otherwise. - /// - /// 'Whitespace' is defined according to the terms of the Unicode Derived Core - /// Property `White_Space`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!(' '.is_whitespace()); - /// - /// // a non-breaking space - /// assert!('\u{A0}'.is_whitespace()); - /// - /// assert!(!'越'.is_whitespace()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_whitespace(self) -> bool { - match self { - ' ' | '\x09'...'\x0d' => true, - c if c > '\x7f' => property::White_Space(c), - _ => false, - } - } - - /// Returns true if this `char` is alphanumeric, and false otherwise. - /// - /// 'Alphanumeric'-ness is defined in terms of the Unicode General Categories - /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!('٣'.is_alphanumeric()); - /// assert!('7'.is_alphanumeric()); - /// assert!('৬'.is_alphanumeric()); - /// assert!('K'.is_alphanumeric()); - /// assert!('و'.is_alphanumeric()); - /// assert!('藏'.is_alphanumeric()); - /// assert!(!'¾'.is_alphanumeric()); - /// assert!(!'①'.is_alphanumeric()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_alphanumeric(self) -> bool { - self.is_alphabetic() || self.is_numeric() - } - - /// Returns true if this `char` is a control code point, and false otherwise. - /// - /// 'Control code point' is defined in terms of the Unicode General - /// Category `Cc`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // U+009C, STRING TERMINATOR - /// assert!('œ'.is_control()); - /// assert!(!'q'.is_control()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_control(self) -> bool { - general_category::Cc(self) - } - - /// Returns true if this `char` is numeric, and false otherwise. - /// - /// 'Numeric'-ness is defined in terms of the Unicode General Categories - /// 'Nd', 'Nl', 'No'. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!('٣'.is_numeric()); - /// assert!('7'.is_numeric()); - /// assert!('৬'.is_numeric()); - /// assert!(!'K'.is_numeric()); - /// assert!(!'و'.is_numeric()); - /// assert!(!'藏'.is_numeric()); - /// assert!(!'¾'.is_numeric()); - /// assert!(!'①'.is_numeric()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_numeric(self) -> bool { - match self { - '0'...'9' => true, - c if c > '\x7f' => general_category::N(c), - _ => false, - } - } - - /// Returns an iterator that yields the lowercase equivalent of a `char` - /// as one or more `char`s. - /// - /// If a character does not have a lowercase equivalent, the same character - /// will be returned back by the iterator. - /// - /// This performs complex unconditional mappings with no tailoring: it maps - /// one Unicode character to its lowercase equivalent according to the - /// [Unicode database] and the additional complex mappings - /// [`SpecialCasing.txt`]. Conditional mappings (based on context or - /// language) are not considered here. - /// - /// For a full reference, see [here][reference]. - /// - /// [Unicode database]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt - /// - /// [`SpecialCasing.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt - /// - /// [reference]: http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 - /// - /// # Examples - /// - /// As an iterator: - /// - /// ``` - /// for c in 'İ'.to_lowercase() { - /// print!("{}", c); - /// } - /// println!(); - /// ``` - /// - /// Using `println!` directly: - /// - /// ``` - /// println!("{}", 'İ'.to_lowercase()); - /// ``` - /// - /// Both are equivalent to: - /// - /// ``` - /// println!("i\u{307}"); - /// ``` - /// - /// Using `to_string`: - /// - /// ``` - /// assert_eq!('C'.to_lowercase().to_string(), "c"); - /// - /// // Sometimes the result is more than one character: - /// assert_eq!('İ'.to_lowercase().to_string(), "i\u{307}"); - /// - /// // Characters that do not have both uppercase and lowercase - /// // convert into themselves. - /// assert_eq!('山'.to_lowercase().to_string(), "山"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_lowercase(self) -> ToLowercase { - ToLowercase(CaseMappingIter::new(conversions::to_lower(self))) - } - - /// Returns an iterator that yields the uppercase equivalent of a `char` - /// as one or more `char`s. - /// - /// If a character does not have an uppercase equivalent, the same character - /// will be returned back by the iterator. - /// - /// This performs complex unconditional mappings with no tailoring: it maps - /// one Unicode character to its uppercase equivalent according to the - /// [Unicode database] and the additional complex mappings - /// [`SpecialCasing.txt`]. Conditional mappings (based on context or - /// language) are not considered here. - /// - /// For a full reference, see [here][reference]. - /// - /// [Unicode database]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt - /// - /// [`SpecialCasing.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt - /// - /// [reference]: http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 - /// - /// # Examples - /// - /// As an iterator: - /// - /// ``` - /// for c in 'ß'.to_uppercase() { - /// print!("{}", c); - /// } - /// println!(); - /// ``` - /// - /// Using `println!` directly: - /// - /// ``` - /// println!("{}", 'ß'.to_uppercase()); - /// ``` - /// - /// Both are equivalent to: - /// - /// ``` - /// println!("SS"); - /// ``` - /// - /// Using `to_string`: - /// - /// ``` - /// assert_eq!('c'.to_uppercase().to_string(), "C"); - /// - /// // Sometimes the result is more than one character: - /// assert_eq!('ß'.to_uppercase().to_string(), "SS"); - /// - /// // Characters that do not have both uppercase and lowercase - /// // convert into themselves. - /// assert_eq!('山'.to_uppercase().to_string(), "山"); - /// ``` - /// - /// # Note on locale - /// - /// In Turkish, the equivalent of 'i' in Latin has five forms instead of two: - /// - /// * 'Dotless': I / ı, sometimes written ï - /// * 'Dotted': İ / i - /// - /// Note that the lowercase dotted 'i' is the same as the Latin. Therefore: - /// - /// ``` - /// let upper_i = 'i'.to_uppercase().to_string(); - /// ``` - /// - /// The value of `upper_i` here relies on the language of the text: if we're - /// in `en-US`, it should be `"I"`, but if we're in `tr_TR`, it should - /// be `"İ"`. `to_uppercase()` does not take this into account, and so: - /// - /// ``` - /// let upper_i = 'i'.to_uppercase().to_string(); - /// - /// assert_eq!(upper_i, "I"); - /// ``` - /// - /// holds across languages. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_uppercase(self) -> ToUppercase { - ToUppercase(CaseMappingIter::new(conversions::to_upper(self))) - } - - /// Checks if the value is within the ASCII range. - /// - /// # Examples - /// - /// ``` - /// let ascii = 'a'; - /// let non_ascii = '❤'; - /// - /// assert!(ascii.is_ascii()); - /// assert!(!non_ascii.is_ascii()); - /// ``` - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn is_ascii(&self) -> bool { - *self as u32 <= 0x7F - } - - /// Makes a copy of the value in its ASCII upper case equivalent. - /// - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - /// - /// To uppercase the value in-place, use [`make_ascii_uppercase`]. - /// - /// To uppercase ASCII characters in addition to non-ASCII characters, use - /// [`to_uppercase`]. - /// - /// # Examples - /// - /// ``` - /// let ascii = 'a'; - /// let non_ascii = '❤'; - /// - /// assert_eq!('A', ascii.to_ascii_uppercase()); - /// assert_eq!('❤', non_ascii.to_ascii_uppercase()); - /// ``` - /// - /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase - /// [`to_uppercase`]: #method.to_uppercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn to_ascii_uppercase(&self) -> char { - if self.is_ascii() { - (*self as u8).to_ascii_uppercase() as char - } else { - *self - } - } - - /// Makes a copy of the value in its ASCII lower case equivalent. - /// - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - /// - /// To lowercase the value in-place, use [`make_ascii_lowercase`]. - /// - /// To lowercase ASCII characters in addition to non-ASCII characters, use - /// [`to_lowercase`]. - /// - /// # Examples - /// - /// ``` - /// let ascii = 'A'; - /// let non_ascii = '❤'; - /// - /// assert_eq!('a', ascii.to_ascii_lowercase()); - /// assert_eq!('❤', non_ascii.to_ascii_lowercase()); - /// ``` - /// - /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase - /// [`to_lowercase`]: #method.to_lowercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn to_ascii_lowercase(&self) -> char { - if self.is_ascii() { - (*self as u8).to_ascii_lowercase() as char - } else { - *self - } - } - - /// Checks that two values are an ASCII case-insensitive match. - /// - /// Equivalent to `to_ascii_lowercase(a) == to_ascii_lowercase(b)`. - /// - /// # Examples - /// - /// ``` - /// let upper_a = 'A'; - /// let lower_a = 'a'; - /// let lower_z = 'z'; - /// - /// assert!(upper_a.eq_ignore_ascii_case(&lower_a)); - /// assert!(upper_a.eq_ignore_ascii_case(&upper_a)); - /// assert!(!upper_a.eq_ignore_ascii_case(&lower_z)); - /// ``` - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn eq_ignore_ascii_case(&self, other: &char) -> bool { - self.to_ascii_lowercase() == other.to_ascii_lowercase() - } - - /// Converts this type to its ASCII upper case equivalent in-place. - /// - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new uppercased value without modifying the existing one, use - /// [`to_ascii_uppercase`]. - /// - /// # Examples - /// - /// ``` - /// let mut ascii = 'a'; - /// - /// ascii.make_ascii_uppercase(); - /// - /// assert_eq!('A', ascii); - /// ``` - /// - /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn make_ascii_uppercase(&mut self) { - *self = self.to_ascii_uppercase(); - } - - /// Converts this type to its ASCII lower case equivalent in-place. - /// - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new lowercased value without modifying the existing one, use - /// [`to_ascii_lowercase`]. - /// - /// # Examples - /// - /// ``` - /// let mut ascii = 'A'; - /// - /// ascii.make_ascii_lowercase(); - /// - /// assert_eq!('a', ascii); - /// ``` - /// - /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn make_ascii_lowercase(&mut self) { - *self = self.to_ascii_lowercase(); - } - - /// Checks if the value is an ASCII alphabetic character: - /// - /// - U+0041 'A' ... U+005A 'Z', or - /// - U+0061 'a' ... U+007A 'z'. - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(uppercase_a.is_ascii_alphabetic()); - /// assert!(uppercase_g.is_ascii_alphabetic()); - /// assert!(a.is_ascii_alphabetic()); - /// assert!(g.is_ascii_alphabetic()); - /// assert!(!zero.is_ascii_alphabetic()); - /// assert!(!percent.is_ascii_alphabetic()); - /// assert!(!space.is_ascii_alphabetic()); - /// assert!(!lf.is_ascii_alphabetic()); - /// assert!(!esc.is_ascii_alphabetic()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_alphabetic(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_alphabetic() - } - - /// Checks if the value is an ASCII uppercase character: - /// U+0041 'A' ... U+005A 'Z'. - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(uppercase_a.is_ascii_uppercase()); - /// assert!(uppercase_g.is_ascii_uppercase()); - /// assert!(!a.is_ascii_uppercase()); - /// assert!(!g.is_ascii_uppercase()); - /// assert!(!zero.is_ascii_uppercase()); - /// assert!(!percent.is_ascii_uppercase()); - /// assert!(!space.is_ascii_uppercase()); - /// assert!(!lf.is_ascii_uppercase()); - /// assert!(!esc.is_ascii_uppercase()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_uppercase(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_uppercase() - } - - /// Checks if the value is an ASCII lowercase character: - /// U+0061 'a' ... U+007A 'z'. - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(!uppercase_a.is_ascii_lowercase()); - /// assert!(!uppercase_g.is_ascii_lowercase()); - /// assert!(a.is_ascii_lowercase()); - /// assert!(g.is_ascii_lowercase()); - /// assert!(!zero.is_ascii_lowercase()); - /// assert!(!percent.is_ascii_lowercase()); - /// assert!(!space.is_ascii_lowercase()); - /// assert!(!lf.is_ascii_lowercase()); - /// assert!(!esc.is_ascii_lowercase()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_lowercase(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_lowercase() - } - - /// Checks if the value is an ASCII alphanumeric character: - /// - /// - U+0041 'A' ... U+005A 'Z', or - /// - U+0061 'a' ... U+007A 'z', or - /// - U+0030 '0' ... U+0039 '9'. - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(uppercase_a.is_ascii_alphanumeric()); - /// assert!(uppercase_g.is_ascii_alphanumeric()); - /// assert!(a.is_ascii_alphanumeric()); - /// assert!(g.is_ascii_alphanumeric()); - /// assert!(zero.is_ascii_alphanumeric()); - /// assert!(!percent.is_ascii_alphanumeric()); - /// assert!(!space.is_ascii_alphanumeric()); - /// assert!(!lf.is_ascii_alphanumeric()); - /// assert!(!esc.is_ascii_alphanumeric()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_alphanumeric(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_alphanumeric() - } - - /// Checks if the value is an ASCII decimal digit: - /// U+0030 '0' ... U+0039 '9'. - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(!uppercase_a.is_ascii_digit()); - /// assert!(!uppercase_g.is_ascii_digit()); - /// assert!(!a.is_ascii_digit()); - /// assert!(!g.is_ascii_digit()); - /// assert!(zero.is_ascii_digit()); - /// assert!(!percent.is_ascii_digit()); - /// assert!(!space.is_ascii_digit()); - /// assert!(!lf.is_ascii_digit()); - /// assert!(!esc.is_ascii_digit()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_digit(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_digit() - } - - /// Checks if the value is an ASCII hexadecimal digit: - /// - /// - U+0030 '0' ... U+0039 '9', or - /// - U+0041 'A' ... U+0046 'F', or - /// - U+0061 'a' ... U+0066 'f'. - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(uppercase_a.is_ascii_hexdigit()); - /// assert!(!uppercase_g.is_ascii_hexdigit()); - /// assert!(a.is_ascii_hexdigit()); - /// assert!(!g.is_ascii_hexdigit()); - /// assert!(zero.is_ascii_hexdigit()); - /// assert!(!percent.is_ascii_hexdigit()); - /// assert!(!space.is_ascii_hexdigit()); - /// assert!(!lf.is_ascii_hexdigit()); - /// assert!(!esc.is_ascii_hexdigit()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_hexdigit(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_hexdigit() - } - - /// Checks if the value is an ASCII punctuation character: - /// - /// - U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`, or - /// - U+003A ... U+0040 `: ; < = > ? @`, or - /// - U+005B ... U+0060 ``[ \ ] ^ _ ` ``, or - /// - U+007B ... U+007E `{ | } ~` - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(!uppercase_a.is_ascii_punctuation()); - /// assert!(!uppercase_g.is_ascii_punctuation()); - /// assert!(!a.is_ascii_punctuation()); - /// assert!(!g.is_ascii_punctuation()); - /// assert!(!zero.is_ascii_punctuation()); - /// assert!(percent.is_ascii_punctuation()); - /// assert!(!space.is_ascii_punctuation()); - /// assert!(!lf.is_ascii_punctuation()); - /// assert!(!esc.is_ascii_punctuation()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_punctuation(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_punctuation() - } - - /// Checks if the value is an ASCII graphic character: - /// U+0021 '!' ... U+007E '~'. - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(uppercase_a.is_ascii_graphic()); - /// assert!(uppercase_g.is_ascii_graphic()); - /// assert!(a.is_ascii_graphic()); - /// assert!(g.is_ascii_graphic()); - /// assert!(zero.is_ascii_graphic()); - /// assert!(percent.is_ascii_graphic()); - /// assert!(!space.is_ascii_graphic()); - /// assert!(!lf.is_ascii_graphic()); - /// assert!(!esc.is_ascii_graphic()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_graphic(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_graphic() - } - - /// Checks if the value is an ASCII whitespace character: - /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED, - /// U+000C FORM FEED, or U+000D CARRIAGE RETURN. - /// - /// Rust uses the WhatWG Infra Standard's [definition of ASCII - /// whitespace][infra-aw]. There are several other definitions in - /// wide use. For instance, [the POSIX locale][pct] includes - /// U+000B VERTICAL TAB as well as all the above characters, - /// but—from the very same specification—[the default rule for - /// "field splitting" in the Bourne shell][bfs] considers *only* - /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace. - /// - /// If you are writing a program that will process an existing - /// file format, check what that format's definition of whitespace is - /// before using this function. - /// - /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace - /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 - /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(!uppercase_a.is_ascii_whitespace()); - /// assert!(!uppercase_g.is_ascii_whitespace()); - /// assert!(!a.is_ascii_whitespace()); - /// assert!(!g.is_ascii_whitespace()); - /// assert!(!zero.is_ascii_whitespace()); - /// assert!(!percent.is_ascii_whitespace()); - /// assert!(space.is_ascii_whitespace()); - /// assert!(lf.is_ascii_whitespace()); - /// assert!(!esc.is_ascii_whitespace()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_whitespace(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_whitespace() - } - - /// Checks if the value is an ASCII control character: - /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE. - /// Note that most ASCII whitespace characters are control - /// characters, but SPACE is not. - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(!uppercase_a.is_ascii_control()); - /// assert!(!uppercase_g.is_ascii_control()); - /// assert!(!a.is_ascii_control()); - /// assert!(!g.is_ascii_control()); - /// assert!(!zero.is_ascii_control()); - /// assert!(!percent.is_ascii_control()); - /// assert!(!space.is_ascii_control()); - /// assert!(lf.is_ascii_control()); - /// assert!(esc.is_ascii_control()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_control(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_control() - } -} - -/// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s. -#[stable(feature = "decode_utf16", since = "1.9.0")] -#[derive(Clone, Debug)] -pub struct DecodeUtf16 - where I: Iterator -{ - iter: I, - buf: Option, -} - -/// An error that can be returned when decoding UTF-16 code points. -#[stable(feature = "decode_utf16", since = "1.9.0")] -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct DecodeUtf16Error { - code: u16, -} - -/// Create an iterator over the UTF-16 encoded code points in `iter`, -/// returning unpaired surrogates as `Err`s. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char::decode_utf16; -/// -/// fn main() { -/// // 𝄞music -/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075, -/// 0x0073, 0xDD1E, 0x0069, 0x0063, -/// 0xD834]; -/// -/// assert_eq!(decode_utf16(v.iter().cloned()) -/// .map(|r| r.map_err(|e| e.unpaired_surrogate())) -/// .collect::>(), -/// vec![Ok('𝄞'), -/// Ok('m'), Ok('u'), Ok('s'), -/// Err(0xDD1E), -/// Ok('i'), Ok('c'), -/// Err(0xD834)]); -/// } -/// ``` -/// -/// A lossy decoder can be obtained by replacing `Err` results with the replacement character: -/// -/// ``` -/// use std::char::{decode_utf16, REPLACEMENT_CHARACTER}; -/// -/// fn main() { -/// // 𝄞music -/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075, -/// 0x0073, 0xDD1E, 0x0069, 0x0063, -/// 0xD834]; -/// -/// assert_eq!(decode_utf16(v.iter().cloned()) -/// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) -/// .collect::(), -/// "𝄞mus�ic�"); -/// } -/// ``` -#[stable(feature = "decode_utf16", since = "1.9.0")] -#[inline] -pub fn decode_utf16>(iter: I) -> DecodeUtf16 { - DecodeUtf16 { - iter: iter.into_iter(), - buf: None, - } -} - -#[stable(feature = "decode_utf16", since = "1.9.0")] -impl> Iterator for DecodeUtf16 { - type Item = Result; - - fn next(&mut self) -> Option> { - let u = match self.buf.take() { - Some(buf) => buf, - None => self.iter.next()? - }; - - if u < 0xD800 || 0xDFFF < u { - // not a surrogate - Some(Ok(unsafe { from_u32_unchecked(u as u32) })) - } else if u >= 0xDC00 { - // a trailing surrogate - Some(Err(DecodeUtf16Error { code: u })) - } else { - let u2 = match self.iter.next() { - Some(u2) => u2, - // eof - None => return Some(Err(DecodeUtf16Error { code: u })), - }; - if u2 < 0xDC00 || u2 > 0xDFFF { - // not a trailing surrogate so we're not a valid - // surrogate pair, so rewind to redecode u2 next time. - self.buf = Some(u2); - return Some(Err(DecodeUtf16Error { code: u })); - } - - // all ok, so lets decode it. - let c = (((u - 0xD800) as u32) << 10 | (u2 - 0xDC00) as u32) + 0x1_0000; - Some(Ok(unsafe { from_u32_unchecked(c) })) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (low, high) = self.iter.size_hint(); - // we could be entirely valid surrogates (2 elements per - // char), or entirely non-surrogates (1 element per char) - (low / 2, high) - } -} - -impl DecodeUtf16Error { - /// Returns the unpaired surrogate which caused this error. - #[stable(feature = "decode_utf16", since = "1.9.0")] - pub fn unpaired_surrogate(&self) -> u16 { - self.code - } -} - -#[stable(feature = "decode_utf16", since = "1.9.0")] -impl fmt::Display for DecodeUtf16Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "unpaired surrogate found: {:x}", self.code) - } -} diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index 106a2c0f0c5..8cdeb6c8ad1 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -27,37 +27,9 @@ html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] -#![deny(missing_debug_implementations)] #![no_std] -#![feature(ascii_ctype)] -#![feature(core_char_ext)] -#![feature(str_internals)] -#![feature(decode_utf8)] -#![feature(fn_traits)] -#![feature(lang_items)] -#![feature(non_exhaustive)] +#![feature(unicode)] #![feature(staged_api)] -#![feature(unboxed_closures)] -mod bool_trie; -mod tables; -mod u_str; -mod version; -pub mod char; - -#[allow(deprecated)] -pub mod str { - pub use u_str::{SplitWhitespace, UnicodeStr}; - pub use u_str::Utf16Encoder; -} - -// For use in liballoc, not re-exported in libstd. -pub mod derived_property { - pub use tables::derived_property::{Case_Ignorable, Cased}; -} - -// For use in libsyntax -pub mod property { - pub use tables::property::Pattern_White_Space; -} +pub use core::unicode::*; diff --git a/src/libstd_unicode/tables.rs b/src/libstd_unicode/tables.rs deleted file mode 100644 index b53953b62a7..00000000000 --- a/src/libstd_unicode/tables.rs +++ /dev/null @@ -1,2378 +0,0 @@ -// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// NOTE: The following code was generated by "./unicode.py", do not edit directly - -#![allow(missing_docs, non_upper_case_globals, non_snake_case)] - -use version::UnicodeVersion; -use bool_trie::{BoolTrie, SmallBoolTrie}; - -/// The version of [Unicode](http://www.unicode.org/) that the Unicode parts of -/// `CharExt` and `UnicodeStrPrelude` traits are based on. -pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { - major: 10, - minor: 0, - micro: 0, - _priv: (), -}; -pub mod general_category { - pub const Cc_table: &super::SmallBoolTrie = &super::SmallBoolTrie { - r1: &[ - 0, 1, 0 - ], - r2: &[ - 0x00000000ffffffff, 0x8000000000000000 - ], - }; - - pub fn Cc(c: char) -> bool { - Cc_table.lookup(c) - } - - pub const N_table: &super::BoolTrie = &super::BoolTrie { - r1: [ - 0x03ff000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x000003ff00000000, 0x0000000000000000, 0x03ff000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x00000000000003ff - ], - r2: [ - 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 3, - 0, 0, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 5, 0, 0, 0, 3, 2, 0, 0, 0, 0, 6, 0, 2, 0, 0, 7, 0, 0, 2, 8, 0, 0, 7, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 2, 4, 0, 0, 12, 0, 2, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0 - ], - r3: &[ - 0x0000000000000000, 0x0000ffc000000000, 0x0000000003ff0000, 0x000003ff00000000, - 0x00000000000003ff, 0x0001c00000000000, 0x000000000000ffc0, 0x0000000003ff03ff, - 0x03ff000000000000, 0xffffffff00000000, 0x00000000000001e7, 0x070003fe00000080, - 0x03ff000003ff0000 - ], - r4: [ - 0, 1, 2, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 5, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 - ], - r5: &[ - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 7, 0, 0, 8, 0, 0, 0, 6, 0, 0, 0, 0, 0, 8, 0, 8, 0, 0, 0, - 0, 0, 8, 0, 9, 6, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, - 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, - 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ], - r6: &[ - 0x0000000000000000, 0x001fffffffffffff, 0x0000000000000402, 0x00000000003e0000, - 0x000003ff00000000, 0x0000ffc000000000, 0x03ff000000000000, 0xffc0000000000000, - 0x0000000003ff0000, 0x00000000000003ff, 0xffffffffffffffff, 0x00007fffffffffff, - 0xffffffffffffc000 - ], - }; - - pub fn N(c: char) -> bool { - N_table.lookup(c) - } - -} - -pub mod derived_property { - pub const Alphabetic_table: &super::BoolTrie = &super::BoolTrie { - r1: [ - 0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, - 0x0000000000000000, 0xbcdf000000000020, 0xfffffffbffffd740, 0xffbfffffffffffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, - 0xfffeffffffffffff, 0xfffffffe027fffff, 0xbfff0000000000ff, 0x000707ffffff00b6, - 0xffffffff07ff0000, 0xffffc000feffffff, 0xffffffffffffffff, 0x9c00e1fe1fefffff, - 0xffffffffffff0000, 0xffffffffffffe000, 0x0003ffffffffffff, 0x043007fffffffc00 - ], - r2: [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 36, 36, 36, 36, 36, 36, 36, 36, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 31, 63, 64, 65, 66, 55, 67, 68, 69, 36, 36, 36, 70, 36, 36, - 36, 36, 71, 72, 73, 74, 31, 75, 76, 31, 77, 78, 68, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 79, 80, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 81, 82, 36, 83, 84, 85, 86, 87, 88, 31, 31, 31, - 31, 31, 31, 31, 89, 44, 90, 91, 92, 36, 93, 94, 31, 31, 31, 31, 31, 31, 31, 31, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 55, 31, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 95, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 96, 97, 36, 36, 36, 36, 98, 99, 36, 100, 101, 36, 102, - 103, 104, 105, 36, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 36, 95, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 117, 118, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 36, 36, 36, 36, 36, 119, 36, 120, 121, 122, 123, 124, 36, 36, 36, 36, 125, 126, 127, - 128, 31, 129, 36, 130, 131, 132, 113, 133 - ], - r3: &[ - 0x00001ffffcffffff, 0x000007ff01ffffff, 0x3fdfffff00000000, 0xffff03f8fff00000, - 0xefffffffffffffff, 0xfffe000fffe1dfff, 0xe3c5fdfffff99fef, 0x1003000fb080599f, - 0xc36dfdfffff987ee, 0x003f00005e021987, 0xe3edfdfffffbbfee, 0x1e00000f00011bbf, - 0xe3edfdfffff99fee, 0x0002000fb0c0199f, 0xc3ffc718d63dc7ec, 0x0000000000811dc7, - 0xe3fffdfffffddfef, 0x0000000f07601ddf, 0xe3effdfffffddfef, 0x0006000f40601ddf, - 0xe7fffffffffddfef, 0xfc00000f80f05ddf, 0x2ffbfffffc7fffec, 0x000c0000ff5f807f, - 0x07fffffffffffffe, 0x000000000000207f, 0x3bffecaefef02596, 0x00000000f000205f, - 0x0000000000000001, 0xfffe1ffffffffeff, 0x1ffffffffeffff03, 0x0000000000000000, - 0xf97fffffffffffff, 0xffffc1e7ffff0000, 0xffffffff3000407f, 0xf7ffffffffff20bf, - 0xffffffffffffffff, 0xffffffff3d7f3dff, 0x7f3dffffffff3dff, 0xffffffffff7fff3d, - 0xffffffffff3dffff, 0x0000000087ffffff, 0xffffffff0000ffff, 0x3f3fffffffffffff, - 0xfffffffffffffffe, 0xffff9fffffffffff, 0xffffffff07fffffe, 0x01ffc7ffffffffff, - 0x000fffff000fdfff, 0x000ddfff000fffff, 0xffcfffffffffffff, 0x00000000108001ff, - 0xffffffff00000000, 0x00ffffffffffffff, 0xffff07ffffffffff, 0x003fffffffffffff, - 0x01ff0fff7fffffff, 0x001f3fffffff0000, 0xffff0fffffffffff, 0x00000000000003ff, - 0xffffffff0fffffff, 0x001ffffe7fffffff, 0x0000008000000000, 0xffefffffffffffff, - 0x0000000000000fef, 0xfc00f3ffffffffff, 0x0003ffbfffffffff, 0x3ffffffffc00e000, - 0x00000000000001ff, 0x006fde0000000000, 0x001fff8000000000, 0xffffffff3f3fffff, - 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8002000000000000, - 0x000000001fff0000, 0xf3ffbd503e2ffc84, 0xffffffff000043e0, 0xffc0000000000000, - 0x000003ffffffffff, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, - 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, - 0x0000800000000000, 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, - 0xfffe7fffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, - 0x0000000000001fff, 0x3fffffffffff0000, 0x00000c00ffff1fff, 0x8ff07fffffffffff, - 0x0000ffffffffffff, 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000, - 0x000000fffffff7bb, 0x000fffffffffffff, 0x28fc00000000002f, 0xffff07fffffffc00, - 0x1fffffff0007ffff, 0xfff7ffffffffffff, 0x7c00ffdf00008000, 0x007fffffffffffff, - 0xc47fffff00003fff, 0x7fffffffffffffff, 0x003cffff38000005, 0xffff7f7f007e7e7e, - 0xffff003ff7ffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, 0xffff3fffffffffff, - 0x0000000003ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb, 0x0003ffffffffffff, - 0xfffffffffff80000, 0x3fffffffffffffff, 0xffffffffffff0000, 0xfffffffffffcffff, - 0x0fff0000000000ff, 0xffdf000000000000, 0x1fffffffffffffff, 0x07fffffe00000000, - 0xffffffc007fffffe, 0x000000001cfcfcfc - ], - r4: [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 13, 14, - 15, 7, 16, 17, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - ], - r5: &[ - 0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 13, 14, 15, 4, 4, 2, 2, 2, - 2, 16, 17, 4, 4, 18, 19, 20, 21, 22, 4, 23, 4, 24, 25, 26, 27, 28, 29, 30, 4, 2, 31, 32, - 32, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 33, 34, 35, 32, 36, 2, 37, 38, 4, 39, 40, 41, - 42, 4, 4, 2, 43, 2, 44, 4, 4, 45, 46, 47, 48, 28, 4, 49, 4, 4, 4, 4, 4, 50, 51, 4, 4, 4, - 4, 52, 53, 54, 55, 4, 4, 4, 4, 56, 57, 58, 4, 59, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 61, 4, 2, 62, 2, 2, 2, 63, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 62, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, - 2, 2, 2, 2, 2, 2, 55, 20, 4, 65, 16, 66, 67, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 68, 69, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 71, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 72, 2, 2, 2, 2, 2, 73, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 2, 74, 75, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 76, 77, 78, 79, 80, 2, 2, 2, 2, 81, 82, 83, 84, 85, 86, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 87, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 2, 2, 2, 88, 2, 89, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 90, 91, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 72, 93, 94, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 95, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 96, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 98, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 - ], - r6: &[ - 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, - 0x0000000000000000, 0x001fffffffffffff, 0xffffffff1fffffff, 0x000000000001ffff, - 0xffffe000ffffffff, 0x07ffffffffff07ff, 0xffffffff3fffffff, 0x00000000003eff0f, - 0xffff00003fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, 0x0000000fffffffff, - 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, - 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, 0xc0ffffffffffffff, - 0x000ffffffeeff06f, 0x1fffffff00000000, 0x000000001fffffff, 0x0000001ffffffeff, - 0x003fffffffffffff, 0x0007ffff003fffff, 0x000000000003ffff, 0x00000000000001ff, - 0x0007ffffffffffff, 0x000000000000003f, 0x01fffffffffffffc, 0x000001ffffff0000, - 0x0047ffffffff0000, 0x000000001400001e, 0x409ffffffffbffff, 0xffff01ffbfffbd7f, - 0x000001ffffffffff, 0xe3edfdfffff99fef, 0x0000000fe081199f, 0x00000000000007bb, - 0x00000000000000b3, 0x7f3fffffffffffff, 0x000000003f000000, 0x7fffffffffffffff, - 0x0000000000000011, 0x000007ffe3ffffff, 0xffffffff00000000, 0x80000000ffffffff, - 0x7fe7ffffffffffff, 0xffffffffffff0000, 0x0000000000ffffcf, 0x01ffffffffffffff, - 0x7f7ffffffffffdff, 0xfffc000000000001, 0x007ffefffffcffff, 0xb47ffffffffffb7f, - 0x00000000000000cb, 0x0000000003ffffff, 0x00007fffffffffff, 0x000000000000000f, - 0x000000000000007f, 0x00003fffffff0000, 0xe0fffff80000000f, 0x000000000000ffff, - 0x7fffffffffff001f, 0x00000000fff80000, 0x0000000300000000, 0x00001fffffffffff, - 0xffff000000000000, 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000043ff01ff, - 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, - 0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, - 0xffff7fffffff7fff, 0xfffffdfffffffdff, 0x0000000000000ff7, 0x000007dbf9ffff7f, - 0x000000000000001f, 0x000000000000008f, 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, - 0x0ffffbee0ffffbff, 0xffff03ffffff03ff, 0x00000000000003ff, 0x00000000007fffff, - 0xffff0003ffffffff, 0x00000001ffffffff, 0x000000003fffffff - ], - }; - - pub fn Alphabetic(c: char) -> bool { - Alphabetic_table.lookup(c) - } - - pub const Case_Ignorable_table: &super::BoolTrie = &super::BoolTrie { - r1: [ - 0x0400408000000000, 0x0000000140000000, 0x0190a10000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0xffff000000000000, 0xffffffffffffffff, - 0xffffffffffffffff, 0x0430ffffffffffff, 0x00000000000000b0, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x00000000000003f8, 0x0000000000000000, - 0x0000000000000000, 0x0000000002000000, 0xbffffffffffe0000, 0x00100000000000b6, - 0x0000000017ff003f, 0x00010000fffff801, 0x0000000000000000, 0x00003dffbfc00000, - 0xffff000000028000, 0x00000000000007ff, 0x0001ffc000000000, 0x043ff80000000000 - ], - r2: [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 15, 16, 11, 17, 18, 7, 2, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 34, 35, 36, 37, 38, 39, 2, 40, 2, 2, 2, 41, 42, 43, 2, - 44, 45, 46, 47, 48, 49, 2, 50, 51, 52, 53, 54, 2, 2, 2, 2, 2, 2, 55, 56, 57, 58, 59, 60, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 61, 2, 62, 2, 63, 2, 64, 65, 2, 2, 2, 2, - 2, 2, 2, 66, 2, 67, 68, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 49, 2, 2, 2, 2, 70, 71, 72, 73, 74, 75, 76, 77, 78, 2, 2, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 2, 88, 2, 89, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 90, 2, 91, 92, 2, 2, 2, 2, 2, 2, 2, 2, 93, 94, 2, 95, - 96, 97, 98, 99 - ], - r3: &[ - 0x00003fffffc00000, 0x000000000e000000, 0x0000000000000000, 0xfffffffffff00000, - 0x1400000000000007, 0x0002000c00fe21fe, 0x1000000000000002, 0x0000000c0000201e, - 0x1000000000000006, 0x0023000000023986, 0xfc00000c000021be, 0x9000000000000002, - 0x0000000c0040201e, 0x0000000000000004, 0x0000000000002001, 0xc000000000000001, - 0x0000000c00603dc1, 0x0000000c00003040, 0x1800000000000003, 0x00000000005c0400, - 0x07f2000000000000, 0x0000000000007fc0, 0x1bf2000000000000, 0x0000000000003f40, - 0x02a0000003000000, 0x7ffe000000000000, 0x1ffffffffeffe0df, 0x0000000000000040, - 0x66fde00000000000, 0x001e0001c3000000, 0x0000000020002064, 0x1000000000000000, - 0x00000000e0000000, 0x001c0000001c0000, 0x000c0000000c0000, 0x3fb0000000000000, - 0x00000000208ffe40, 0x0000000000007800, 0x0000000000000008, 0x0000020000000060, - 0x0e04018700000000, 0x0000000009800000, 0x9ff81fe57f400000, 0x7fff008000000000, - 0x17d000000000000f, 0x000ff80000000004, 0x00003b3c00000003, 0x0003a34000000000, - 0x00cff00000000000, 0x3f00000000000000, 0x031021fdfff70000, 0xfffff00000000000, - 0x010007ffffffffff, 0xfffffffff8000000, 0xfbffffffffffffff, 0xa000000000000000, - 0x6000e000e000e003, 0x00007c900300f800, 0x8002ffdf00000000, 0x000000001fff0000, - 0x0001ffffffff0000, 0x3000000000000000, 0x0003800000000000, 0x8000800000000000, - 0xffffffff00000000, 0x0000800000000000, 0x083e3c0000000020, 0x000000007e000000, - 0x7000000000000000, 0x0000000000200000, 0x0000000000001000, 0xbff7800000000000, - 0x00000000f0000000, 0x0003000000000000, 0x00000003ffffffff, 0x0001000000000000, - 0x0000000000000700, 0x0300000000000000, 0x0000006000000844, 0x0003ffff00000030, - 0x00003fc000000000, 0x000000000003ff80, 0x13c8000000000007, 0x0000006000008000, - 0x00667e0000000000, 0x1001000000001008, 0xc19d000000000000, 0x0058300020000002, - 0x00000000f8000000, 0x0000212000000000, 0x0000000040000000, 0xfffc000000000000, - 0x0000000000000003, 0x0000ffff0008ffff, 0x0000000000240000, 0x8000000000000000, - 0x4000000004004080, 0x0001000000000001, 0x00000000c0000000, 0x0e00000800000000 - ], - r4: [ - 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 4, 2, 5, 6, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 - ], - r5: &[ - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 6, 7, 8, 0, 9, 10, 11, 12, 13, 0, 0, 14, 15, 16, 0, 0, 17, 18, 19, 20, - 0, 0, 21, 22, 23, 24, 25, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 0, 0, 0, - 0, 0, 30, 0, 31, 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 48, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 50, 51, 0, 0, 51, 51, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 - ], - r6: &[ - 0x0000000000000000, 0x2000000000000000, 0x0000000100000000, 0x07c0000000000000, - 0x870000000000f06e, 0x0000006000000000, 0xff00000000000002, 0x800000000000007f, - 0x2678000000000003, 0x001fef8000000007, 0x0008000000000000, 0x7fc0000000000003, - 0x0000000000001c00, 0x40d3800000000000, 0x000007f880000000, 0x1000000000000003, - 0x001f1fc000000001, 0xff00000000000000, 0x000000000000005c, 0x85f8000000000000, - 0x000000000000000d, 0xb03c000000000000, 0x0000000030000001, 0xa7f8000000000000, - 0x0000000000000001, 0x00bf280000000000, 0x00000fbce0000000, 0x79f800000000067e, - 0x000000000e7e0080, 0x00000000037ffc00, 0xbf7f000000000000, 0x006dfcfffffc0000, - 0xb47e000000000000, 0x00000000000000bf, 0x001f000000000000, 0x007f000000000000, - 0x000000000000000f, 0x00000000ffff8000, 0x0000000300000000, 0x0000000f60000000, - 0xfff8038000000000, 0x00003c0000000fe7, 0x000000000000001c, 0xf87fffffffffffff, - 0x00201fffffffffff, 0x0000fffef8000010, 0x000007dbf9ffff7f, 0x00000000007f0000, - 0x00000000000007f0, 0xf800000000000000, 0xffffffff00000002, 0xffffffffffffffff, - 0x0000ffffffffffff - ], - }; - - pub fn Case_Ignorable(c: char) -> bool { - Case_Ignorable_table.lookup(c) - } - - pub const Cased_table: &super::BoolTrie = &super::BoolTrie { - r1: [ - 0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xf7ffffffffffffff, 0xfffffffffffffff0, - 0xffffffffffffffff, 0xffffffffffffffff, 0x01ffffffffefffff, 0x0000001f00000003, - 0x0000000000000000, 0xbccf000000000020, 0xfffffffbffffd740, 0xffbfffffffffffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, - 0xfffeffffffffffff, 0xfffffffe007fffff, 0x00000000000000ff, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 - ], - r2: [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 5, 5, 5, - 0, 5, 5, 5, 5, 6, 7, 8, 9, 0, 10, 11, 0, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 15, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 17, 18, 5, 19, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22, - 0, 23, 5, 24, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 27, 5, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 29, 30, 0, 0 - ], - r3: &[ - 0x0000000000000000, 0xffffffff00000000, 0x00000000000020bf, 0x3f3fffffffffffff, - 0x00000000000001ff, 0xffffffffffffffff, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, - 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8002000000000000, 0x000000001fff0000, - 0xf21fbd503e2ffc84, 0xffffffff000043e0, 0x0000000000000018, 0xffc0000000000000, - 0x000003ffffffffff, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, - 0x000020bfffffffff, 0x00003fffffffffff, 0x000000003fffffff, 0xfffffffc00000000, - 0x00ff7fffffff78ff, 0x0700000000000000, 0xffff000000000000, 0xffff003ff7ffffff, - 0x0000000000f8007f, 0x07fffffe00000000, 0x0000000007fffffe - ], - r4: [ - 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 - ], - r5: &[ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 8, 9, 10, 11, 12, 1, 1, 1, 1, 13, 14, 15, 16, 17, 18, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 3, 20, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ], - r6: &[ - 0x0000000000000000, 0xffffffffffffffff, 0x000000000000ffff, 0xffff000000000000, - 0x0fffffffff0fffff, 0x0007ffffffffffff, 0xffffffff00000000, 0x00000000ffffffff, - 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, - 0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, - 0xffff7fffffff7fff, 0xfffffdfffffffdff, 0x0000000000000ff7, 0x000000000000000f, - 0xffff03ffffff03ff, 0x00000000000003ff - ], - }; - - pub fn Cased(c: char) -> bool { - Cased_table.lookup(c) - } - - pub const Lowercase_table: &super::BoolTrie = &super::BoolTrie { - r1: [ - 0x0000000000000000, 0x07fffffe00000000, 0x0420040000000000, 0xff7fffff80000000, - 0x55aaaaaaaaaaaaaa, 0xd4aaaaaaaaaaab55, 0xe6512d2a4e243129, 0xaa29aaaab5555240, - 0x93faaaaaaaaaaaaa, 0xffffffffffffaa85, 0x01ffffffffefffff, 0x0000001f00000003, - 0x0000000000000000, 0x3c8a000000000020, 0xfffff00000010000, 0x192faaaaaae37fff, - 0xffff000000000000, 0xaaaaaaaaffffffff, 0xaaaaaaaaaaaaa802, 0xaaaaaaaaaaaad554, - 0x0000aaaaaaaaaaaa, 0xfffffffe00000000, 0x00000000000000ff, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 - ], - r2: [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 3, 3, - 0, 4, 4, 5, 4, 6, 7, 8, 9, 0, 10, 11, 0, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16, 17, 4, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 0, - 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 26, 3, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 28, 0, 0 - ], - r3: &[ - 0x0000000000000000, 0x3f00000000000000, 0x00000000000001ff, 0xffffffffffffffff, - 0xaaaaaaaaaaaaaaaa, 0xaaaaaaaabfeaaaaa, 0x00ff00ff003f00ff, 0x3fff00ff00ff003f, - 0x40df00ff00ff00ff, 0x00dc00ff00cf00dc, 0x8002000000000000, 0x000000001fff0000, - 0x321080000008c400, 0xffff0000000043c0, 0x0000000000000010, 0x000003ffffff0000, - 0xffff000000000000, 0x3fda15627fffffff, 0x0008501aaaaaaaaa, 0x000020bfffffffff, - 0x00002aaaaaaaaaaa, 0x000000003aaaaaaa, 0xaaabaaa800000000, 0x95ffaaaaaaaaaaaa, - 0x00a002aaaaba50aa, 0x0700000000000000, 0xffff003ff7ffffff, 0x0000000000f8007f, - 0x0000000007fffffe - ], - r4: [ - 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 - ], - r5: &[ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0 - ], - r6: &[ - 0x0000000000000000, 0xffffff0000000000, 0x000000000000ffff, 0x0fffffffff000000, - 0x0007ffffffffffff, 0x00000000ffffffff, 0x000ffffffc000000, 0x000000ffffdfc000, - 0xebc000000ffffffc, 0xfffffc000000ffef, 0x00ffffffc000000f, 0x00000ffffffc0000, - 0xfc000000ffffffc0, 0xffffc000000fffff, 0x0ffffffc000000ff, 0x0000ffffffc00000, - 0x0000003ffffffc00, 0xf0000003f7fffffc, 0xffc000000fdfffff, 0xffff0000003f7fff, - 0xfffffc000000fdff, 0x0000000000000bf7, 0xfffffffc00000000, 0x000000000000000f - ], - }; - - pub fn Lowercase(c: char) -> bool { - Lowercase_table.lookup(c) - } - - pub const Uppercase_table: &super::BoolTrie = &super::BoolTrie { - r1: [ - 0x0000000000000000, 0x0000000007fffffe, 0x0000000000000000, 0x000000007f7fffff, - 0xaa55555555555555, 0x2b555555555554aa, 0x11aed2d5b1dbced6, 0x55d255554aaaa490, - 0x6c05555555555555, 0x000000000000557a, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x8045000000000000, 0x00000ffbfffed740, 0xe6905555551c8000, - 0x0000ffffffffffff, 0x5555555500000000, 0x5555555555555401, 0x5555555555552aab, - 0xfffe555555555555, 0x00000000007fffff, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 - ], - r2: [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 4, 4, 5, 4, 6, 7, 8, 9, 0, 0, 0, 0, 10, 11, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 15, 16, 4, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 19, 0, - 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 23, 0, 0, 0 - ], - r3: &[ - 0x0000000000000000, 0xffffffff00000000, 0x00000000000020bf, 0x003fffffffffffff, - 0x5555555555555555, 0x5555555540155555, 0xff00ff003f00ff00, 0x0000ff00aa003f00, - 0x0f00000000000000, 0x0f001f000f000f00, 0xc00f3d503e273884, 0x0000ffff00000020, - 0x0000000000000008, 0xffc0000000000000, 0x000000000000ffff, 0x00007fffffffffff, - 0xc025ea9d00000000, 0x0004280555555555, 0x0000155555555555, 0x0000000005555555, - 0x5554555400000000, 0x6a00555555555555, 0x005f7d5555452855, 0x07fffffe00000000 - ], - r4: [ - 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 - ], - r5: &[ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ], - r6: &[ - 0x0000000000000000, 0x000000ffffffffff, 0xffff000000000000, 0x00000000000fffff, - 0x0007ffffffffffff, 0xffffffff00000000, 0xfff0000003ffffff, 0xffffff0000003fff, - 0x003fde64d0000003, 0x000003ffffff0000, 0x7b0000001fdfe7b0, 0xfffff0000001fc5f, - 0x03ffffff0000003f, 0x00003ffffff00000, 0xf0000003ffffff00, 0xffff0000003fffff, - 0xffffff00000003ff, 0x07fffffc00000001, 0x001ffffff0000000, 0x00007fffffc00000, - 0x000001ffffff0000, 0x0000000000000400, 0x00000003ffffffff, 0xffff03ffffff03ff, - 0x00000000000003ff - ], - }; - - pub fn Uppercase(c: char) -> bool { - Uppercase_table.lookup(c) - } - - pub const XID_Continue_table: &super::BoolTrie = &super::BoolTrie { - r1: [ - 0x03ff000000000000, 0x07fffffe87fffffe, 0x04a0040000000000, 0xff7fffffff7fffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, - 0xffffffffffffffff, 0xb8dfffffffffffff, 0xfffffffbffffd7c0, 0xffbfffffffffffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffcfb, 0xffffffffffffffff, - 0xfffeffffffffffff, 0xfffffffe027fffff, 0xbffffffffffe00ff, 0x000707ffffff00b6, - 0xffffffff07ff0000, 0xffffc3ffffffffff, 0xffffffffffffffff, 0x9ffffdff9fefffff, - 0xffffffffffff0000, 0xffffffffffffe7ff, 0x0003ffffffffffff, 0x043fffffffffffff - ], - r2: [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 4, 32, 33, 34, 4, 4, 4, 4, 4, 35, 36, 37, 38, 39, 40, - 41, 42, 4, 4, 4, 4, 4, 4, 4, 4, 43, 44, 45, 46, 47, 4, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 4, 61, 4, 62, 50, 63, 64, 65, 4, 4, 4, 66, 4, 4, 4, 4, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 64, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 77, 78, 4, 79, 80, 81, 82, 83, 60, 60, 60, 60, 60, 60, 60, 60, 84, - 42, 85, 86, 87, 4, 88, 89, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 52, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 90, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 91, 92, 4, 4, 4, 4, 93, 94, 4, 95, 96, 4, 97, 98, 99, 62, 4, 100, 101, - 102, 4, 103, 104, 105, 4, 106, 107, 108, 4, 109, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 110, 111, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 101, 4, 112, - 113, 114, 95, 115, 4, 116, 4, 4, 117, 118, 119, 120, 121, 122, 4, 123, 124, 125, 126, - 127 - ], - r3: &[ - 0x00003fffffffffff, 0x000007ff0fffffff, 0x3fdfffff00000000, 0xfffffffbfff00000, - 0xffffffffffffffff, 0xfffeffcfffffffff, 0xf3c5fdfffff99fef, 0x1003ffcfb080799f, - 0xd36dfdfffff987ee, 0x003fffc05e023987, 0xf3edfdfffffbbfee, 0xfe00ffcf00013bbf, - 0xf3edfdfffff99fee, 0x0002ffcfb0c0399f, 0xc3ffc718d63dc7ec, 0x0000ffc000813dc7, - 0xe3fffdfffffddfef, 0x0000ffcf07603ddf, 0xf3effdfffffddfef, 0x0006ffcf40603ddf, - 0xfffffffffffddfef, 0xfc00ffcf80f07ddf, 0x2ffbfffffc7fffec, 0x000cffc0ff5f847f, - 0x07fffffffffffffe, 0x0000000003ff7fff, 0x3bffecaefef02596, 0x00000000f3ff3f5f, - 0xc2a003ff03000001, 0xfffe1ffffffffeff, 0x1ffffffffeffffdf, 0x0000000000000040, - 0xffffffffffff03ff, 0xffffffff3fffffff, 0xf7ffffffffff20bf, 0xffffffff3d7f3dff, - 0x7f3dffffffff3dff, 0xffffffffff7fff3d, 0xffffffffff3dffff, 0x0003fe00e7ffffff, - 0xffffffff0000ffff, 0x3f3fffffffffffff, 0xfffffffffffffffe, 0xffff9fffffffffff, - 0xffffffff07fffffe, 0x01ffc7ffffffffff, 0x001fffff001fdfff, 0x000ddfff000fffff, - 0x000003ff308fffff, 0xffffffff03ff3800, 0x00ffffffffffffff, 0xffff07ffffffffff, - 0x003fffffffffffff, 0x0fff0fff7fffffff, 0x001f3fffffffffc0, 0xffff0fffffffffff, - 0x0000000007ff03ff, 0xffffffff0fffffff, 0x9fffffff7fffffff, 0x3fff008003ff03ff, - 0x0000000000000000, 0x000ff80003ff0fff, 0x000fffffffffffff, 0x3fffffffffffe3ff, - 0x00000000000001ff, 0x03fffffffff70000, 0xfbffffffffffffff, 0xffffffff3f3fffff, - 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8000000000000000, - 0x8002000000100001, 0x000000001fff0000, 0x0001ffe21fff0000, 0xf3fffd503f2ffc84, - 0xffffffff000043e0, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000ff81fffffffff, - 0xffff20bfffffffff, 0x800080ffffffffff, 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, - 0x1f3efffe000000e0, 0xfffffffee67fffff, 0xf7ffffffffffffff, 0xfffe7fffffffffe0, - 0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, 0x0000000000001fff, - 0x3fffffffffff0000, 0x00000fffffff1fff, 0xbff0ffffffffffff, 0x0003ffffffffffff, - 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000, 0x000000ffffffffff, - 0x28ffffff03ff003f, 0xffff3fffffffffff, 0x1fffffff000fffff, 0x7fffffff03ff8001, - 0x007fffffffffffff, 0xfc7fffff03ff3fff, 0x007cffff38000007, 0xffff7f7f007e7e7e, - 0xffff003ff7ffffff, 0x03ff37ffffffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, - 0x0000000003ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb, 0xfffffffffff80000, - 0xfffffff03fffffff, 0x3fffffffffffffff, 0xffffffffffff0000, 0xfffffffffffcffff, - 0x03ff0000000000ff, 0x0018ffff0000ffff, 0xaa8a00000000e000, 0x1fffffffffffffff, - 0x87fffffe03ff0000, 0xffffffc007fffffe, 0x7fffffffffffffff, 0x000000001cfcfcfc - ], - r4: [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 13, - 14, 7, 15, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 17, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - ], - r5: &[ - 0, 1, 2, 3, 4, 5, 4, 6, 4, 4, 7, 8, 9, 10, 11, 12, 2, 2, 13, 14, 15, 16, 4, 4, 2, 2, 2, - 2, 17, 18, 4, 4, 19, 20, 21, 22, 23, 4, 24, 4, 25, 26, 27, 28, 29, 30, 31, 4, 2, 32, 33, - 33, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 34, 3, 35, 36, 37, 2, 38, 39, 4, 40, 41, 42, - 43, 4, 4, 2, 44, 2, 45, 4, 4, 46, 47, 2, 48, 49, 50, 51, 4, 4, 4, 4, 4, 52, 53, 4, 4, 4, - 4, 54, 55, 56, 57, 4, 4, 4, 4, 58, 59, 60, 4, 61, 62, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 63, 4, 2, 64, 2, 2, 2, 65, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 66, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, - 2, 2, 2, 2, 2, 2, 57, 67, 4, 68, 17, 69, 70, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 71, 72, 73, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 21, 75, 2, 2, 2, 2, 2, 76, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 2, 77, 78, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 79, 80, 4, 4, 81, 4, 4, 4, 4, 4, 4, 2, 82, 83, 84, 85, 86, 2, 2, 2, 2, 87, 88, 89, 90, - 91, 92, 4, 4, 4, 4, 4, 4, 4, 4, 93, 94, 95, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 96, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 97, 2, 44, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 98, 99, 100, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 101, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 102, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 103, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 104, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 105, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 - ], - r6: &[ - 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, - 0x0000000000000000, 0x001fffffffffffff, 0x2000000000000000, 0xffffffff1fffffff, - 0x000000010001ffff, 0xffffe000ffffffff, 0x07ffffffffff07ff, 0xffffffff3fffffff, - 0x00000000003eff0f, 0xffff03ff3fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, - 0x0000000fffffffff, 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, - 0x007fffff003fffff, 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, - 0xc0ffffffffffffff, 0x870ffffffeeff06f, 0x1fffffff00000000, 0x000000001fffffff, - 0x0000007ffffffeff, 0x003fffffffffffff, 0x0007ffff003fffff, 0x000000000003ffff, - 0x00000000000001ff, 0x0007ffffffffffff, 0x8000ffc00000007f, 0x03ff01ffffff0000, - 0xffdfffffffffffff, 0x004fffffffff0000, 0x0000000017ff1c1f, 0x40fffffffffbffff, - 0xffff01ffbfffbd7f, 0x03ff07ffffffffff, 0xf3edfdfffff99fef, 0x001f1fcfe081399f, - 0x0000000003ff07ff, 0x0000000003ff00bf, 0xff3fffffffffffff, 0x000000003f000001, - 0x0000000003ff0011, 0x00ffffffffffffff, 0x00000000000003ff, 0x03ff0fffe3ffffff, - 0xffffffff00000000, 0x800003ffffffffff, 0x7fffffffffffffff, 0xffffffffffff0080, - 0x0000000003ffffcf, 0x01ffffffffffffff, 0xff7ffffffffffdff, 0xfffc000003ff0001, - 0x007ffefffffcffff, 0xb47ffffffffffb7f, 0x0000000003ff00ff, 0x0000000003ffffff, - 0x00007fffffffffff, 0x000000000000000f, 0x000000000000007f, 0x000003ff7fffffff, - 0x001f3fffffff0000, 0xe0fffff803ff000f, 0x000000000000ffff, 0x7fffffffffff001f, - 0x00000000ffff8000, 0x0000000300000000, 0x00001fffffffffff, 0xffff000000000000, - 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000063ff01ff, 0xf807e3e000000000, - 0x00003c0000000fe7, 0x000000000000001c, 0xffffffffffdfffff, 0xebffde64dfffffff, - 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffff3fffffffff, - 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, 0xfffffdfffffffdff, - 0xffffffffffffcff7, 0xf87fffffffffffff, 0x00201fffffffffff, 0x0000fffef8000010, - 0x000007dbf9ffff7f, 0x00000000007f001f, 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, - 0x0ffffbee0ffffbff, 0x00000000007fffff, 0xffff0003ffffffff, 0x00000001ffffffff, - 0x000000003fffffff, 0x0000ffffffffffff - ], - }; - - pub fn XID_Continue(c: char) -> bool { - XID_Continue_table.lookup(c) - } - - pub const XID_Start_table: &super::BoolTrie = &super::BoolTrie { - r1: [ - 0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, - 0x0000000000000000, 0xb8df000000000000, 0xfffffffbffffd740, 0xffbfffffffffffff, - 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, - 0xfffeffffffffffff, 0xfffffffe027fffff, 0x00000000000000ff, 0x000707ffffff0000, - 0xffffffff00000000, 0xfffec000000007ff, 0xffffffffffffffff, 0x9c00c060002fffff, - 0x0000fffffffd0000, 0xffffffffffffe000, 0x0002003fffffffff, 0x043007fffffffc00 - ], - r2: [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 23, 25, 26, 27, 28, 29, 3, 30, 31, 32, 33, 34, 34, 34, 34, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 34, 34, 34, 34, 34, 34, 34, 34, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 3, 61, 62, 63, 64, 65, 66, 67, 68, 34, 34, 34, 3, 34, 34, - 34, 34, 69, 70, 71, 72, 3, 73, 74, 3, 75, 76, 67, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 77, - 78, 34, 79, 80, 81, 82, 83, 3, 3, 3, 3, 3, 3, 3, 3, 84, 42, 85, 86, 87, 34, 88, 89, 3, - 3, 3, 3, 3, 3, 3, 3, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 53, 3, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 90, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 91, 92, 34, 34, 34, 34, 93, - 94, 95, 96, 97, 34, 98, 99, 100, 48, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 34, 113, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 114, 115, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 34, 34, 34, 34, 34, - 116, 34, 117, 118, 119, 120, 121, 34, 122, 34, 34, 123, 124, 125, 126, 3, 127, 34, 128, - 129, 130, 131, 132 - ], - r3: &[ - 0x00000110043fffff, 0x000007ff01ffffff, 0x3fdfffff00000000, 0x0000000000000000, - 0x23fffffffffffff0, 0xfffe0003ff010000, 0x23c5fdfffff99fe1, 0x10030003b0004000, - 0x036dfdfffff987e0, 0x001c00005e000000, 0x23edfdfffffbbfe0, 0x0200000300010000, - 0x23edfdfffff99fe0, 0x00020003b0000000, 0x03ffc718d63dc7e8, 0x0000000000010000, - 0x23fffdfffffddfe0, 0x0000000307000000, 0x23effdfffffddfe1, 0x0006000340000000, - 0x27fffffffffddfe0, 0xfc00000380704000, 0x2ffbfffffc7fffe0, 0x000000000000007f, - 0x0005fffffffffffe, 0x2005ecaefef02596, 0x00000000f000005f, 0x0000000000000001, - 0x00001ffffffffeff, 0x0000000000001f00, 0x800007ffffffffff, 0xffe1c0623c3f0000, - 0xffffffff00004003, 0xf7ffffffffff20bf, 0xffffffffffffffff, 0xffffffff3d7f3dff, - 0x7f3dffffffff3dff, 0xffffffffff7fff3d, 0xffffffffff3dffff, 0x0000000007ffffff, - 0xffffffff0000ffff, 0x3f3fffffffffffff, 0xfffffffffffffffe, 0xffff9fffffffffff, - 0xffffffff07fffffe, 0x01ffc7ffffffffff, 0x0003ffff0003dfff, 0x0001dfff0003ffff, - 0x000fffffffffffff, 0x0000000010800000, 0xffffffff00000000, 0x00ffffffffffffff, - 0xffff05ffffffffff, 0x003fffffffffffff, 0x000000007fffffff, 0x001f3fffffff0000, - 0xffff0fffffffffff, 0x00000000000003ff, 0xffffffff007fffff, 0x00000000001fffff, - 0x0000008000000000, 0x000fffffffffffe0, 0x0000000000000fe0, 0xfc00c001fffffff8, - 0x0000003fffffffff, 0x0000000fffffffff, 0x3ffffffffc00e000, 0x00000000000001ff, - 0x0063de0000000000, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, - 0x1fdc1fff0fcf1fdc, 0x8002000000000000, 0x000000001fff0000, 0xf3fffd503f2ffc84, - 0xffffffff000043e0, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, - 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, 0x000000007f7f7f7f, - 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, 0xfffe7fffffffffe0, - 0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, 0x0000000000001fff, - 0x3fffffffffff0000, 0x00000c00ffff1fff, 0x80007fffffffffff, 0xffffffff3fffffff, - 0x0000ffffffffffff, 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000, - 0x00000007fffff7bb, 0x000ffffffffffffc, 0x28fc000000000000, 0xffff003ffffffc00, - 0x1fffffff0000007f, 0x0007fffffffffff0, 0x7c00ffdf00008000, 0x000001ffffffffff, - 0xc47fffff00000ff7, 0x3e62ffffffffffff, 0x001c07ff38000005, 0xffff7f7f007e7e7e, - 0xffff003ff7ffffff, 0x00000007ffffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, - 0xffff3fffffffffff, 0x0000000003ffffff, 0x5f7ffdffa0f8007f, 0xffffffffffffffdb, - 0x0003ffffffffffff, 0xfffffffffff80000, 0xfffffff03fffffff, 0x3fffffffffffffff, - 0xffffffffffff0000, 0xfffffffffffcffff, 0x03ff0000000000ff, 0xaa8a000000000000, - 0x1fffffffffffffff, 0x07fffffe00000000, 0xffffffc007fffffe, 0x7fffffff3fffffff, - 0x000000001cfcfcfc - ], - r4: [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 13, - 14, 7, 15, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - ], - r5: &[ - 0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 13, 14, 15, 4, 4, 2, 2, 2, - 2, 16, 17, 4, 4, 18, 19, 20, 21, 22, 4, 23, 4, 24, 25, 26, 27, 28, 29, 30, 4, 2, 31, 32, - 32, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 33, 4, 34, 35, 36, 37, 38, 39, 40, 4, 41, 20, - 42, 43, 4, 4, 5, 44, 45, 46, 4, 4, 47, 48, 45, 49, 50, 4, 51, 4, 4, 4, 4, 4, 52, 53, 4, - 4, 4, 4, 54, 55, 56, 57, 4, 4, 4, 4, 58, 59, 60, 4, 61, 62, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 51, 4, 2, 47, 2, 2, 2, 63, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 47, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 2, 2, 2, 2, 2, 2, 2, 2, 57, 20, 4, 65, 45, 66, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 2, 67, 68, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 71, 2, 2, 2, 2, 2, - 72, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 2, 73, 74, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 75, 76, 77, 78, 79, 2, 2, 2, 2, 80, 81, 82, 83, 84, - 85, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 86, 2, 63, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 87, 88, 89, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 91, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 93, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 - ], - r6: &[ - 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, - 0x0000000000000000, 0x001fffffffffffff, 0xffffffff1fffffff, 0x000000000001ffff, - 0xffffe000ffffffff, 0x003fffffffff07ff, 0xffffffff3fffffff, 0x00000000003eff0f, - 0xffff00003fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, 0x0000000fffffffff, - 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, - 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, 0xc0ffffffffffffff, - 0x000ffffffeef0001, 0x1fffffff00000000, 0x000000001fffffff, 0x0000001ffffffeff, - 0x003fffffffffffff, 0x0007ffff003fffff, 0x000000000003ffff, 0x00000000000001ff, - 0x0007ffffffffffff, 0x00fffffffffffff8, 0x0000fffffffffff8, 0x000001ffffff0000, - 0x0000007ffffffff8, 0x0047ffffffff0000, 0x0007fffffffffff8, 0x000000001400001e, - 0x00000ffffffbffff, 0xffff01ffbfffbd7f, 0x23edfdfffff99fe0, 0x00000003e0010000, - 0x0000000000000780, 0x0000ffffffffffff, 0x00000000000000b0, 0x00007fffffffffff, - 0x000000000f000000, 0x0000000000000010, 0x000007ffffffffff, 0x0000000003ffffff, - 0xffffffff00000000, 0x80000000ffffffff, 0x0407fffffffff801, 0xfffffffff0010000, - 0x00000000000003cf, 0x01ffffffffffffff, 0x00007ffffffffdff, 0xfffc000000000001, - 0x000000000000ffff, 0x0001fffffffffb7f, 0x0000000000000040, 0x000000000000000f, - 0x000000000000007f, 0x00003fffffff0000, 0xe0fffff80000000f, 0x000000000001001f, - 0x00000000fff80000, 0x0000000300000000, 0x00001fffffffffff, 0xffff000000000000, - 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000003ff01ff, 0xffffffffffdfffff, - 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, - 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, - 0xfffffdfffffffdff, 0x0000000000000ff7, 0x000000000000001f, 0x0af7fe96ffffffef, - 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0x00000000007fffff, 0xffff0003ffffffff, - 0x00000001ffffffff, 0x000000003fffffff - ], - }; - - pub fn XID_Start(c: char) -> bool { - XID_Start_table.lookup(c) - } - -} - -pub mod property { - pub const Pattern_White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie { - r1: &[ - 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 - ], - r2: &[ - 0x0000000100003e00, 0x0000000000000000, 0x0000000000000020, 0x000003000000c000 - ], - }; - - pub fn Pattern_White_Space(c: char) -> bool { - Pattern_White_Space_table.lookup(c) - } - - pub const White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie { - r1: &[ - 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 - ], - r2: &[ - 0x0000000100003e00, 0x0000000000000000, 0x0000000100000020, 0x0000000000000001, - 0x00008300000007ff, 0x0000000080000000 - ], - }; - - pub fn White_Space(c: char) -> bool { - White_Space_table.lookup(c) - } - -} - -pub mod conversions { - use core::option::Option; - use core::option::Option::{Some, None}; - - pub fn to_lower(c: char) -> [char; 3] { - match bsearch_case_table(c, to_lowercase_table) { - None => [c, '\0', '\0'], - Some(index) => to_lowercase_table[index].1, - } - } - - pub fn to_upper(c: char) -> [char; 3] { - match bsearch_case_table(c, to_uppercase_table) { - None => [c, '\0', '\0'], - Some(index) => to_uppercase_table[index].1, - } - } - - fn bsearch_case_table(c: char, table: &[(char, [char; 3])]) -> Option { - table.binary_search_by(|&(key, _)| key.cmp(&c)).ok() - } - - const to_lowercase_table: &[(char, [char; 3])] = &[ - ('\u{41}', ['\u{61}', '\0', '\0']), ('\u{42}', ['\u{62}', '\0', '\0']), ('\u{43}', - ['\u{63}', '\0', '\0']), ('\u{44}', ['\u{64}', '\0', '\0']), ('\u{45}', ['\u{65}', '\0', - '\0']), ('\u{46}', ['\u{66}', '\0', '\0']), ('\u{47}', ['\u{67}', '\0', '\0']), ('\u{48}', - ['\u{68}', '\0', '\0']), ('\u{49}', ['\u{69}', '\0', '\0']), ('\u{4a}', ['\u{6a}', '\0', - '\0']), ('\u{4b}', ['\u{6b}', '\0', '\0']), ('\u{4c}', ['\u{6c}', '\0', '\0']), ('\u{4d}', - ['\u{6d}', '\0', '\0']), ('\u{4e}', ['\u{6e}', '\0', '\0']), ('\u{4f}', ['\u{6f}', '\0', - '\0']), ('\u{50}', ['\u{70}', '\0', '\0']), ('\u{51}', ['\u{71}', '\0', '\0']), ('\u{52}', - ['\u{72}', '\0', '\0']), ('\u{53}', ['\u{73}', '\0', '\0']), ('\u{54}', ['\u{74}', '\0', - '\0']), ('\u{55}', ['\u{75}', '\0', '\0']), ('\u{56}', ['\u{76}', '\0', '\0']), ('\u{57}', - ['\u{77}', '\0', '\0']), ('\u{58}', ['\u{78}', '\0', '\0']), ('\u{59}', ['\u{79}', '\0', - '\0']), ('\u{5a}', ['\u{7a}', '\0', '\0']), ('\u{c0}', ['\u{e0}', '\0', '\0']), ('\u{c1}', - ['\u{e1}', '\0', '\0']), ('\u{c2}', ['\u{e2}', '\0', '\0']), ('\u{c3}', ['\u{e3}', '\0', - '\0']), ('\u{c4}', ['\u{e4}', '\0', '\0']), ('\u{c5}', ['\u{e5}', '\0', '\0']), ('\u{c6}', - ['\u{e6}', '\0', '\0']), ('\u{c7}', ['\u{e7}', '\0', '\0']), ('\u{c8}', ['\u{e8}', '\0', - '\0']), ('\u{c9}', ['\u{e9}', '\0', '\0']), ('\u{ca}', ['\u{ea}', '\0', '\0']), ('\u{cb}', - ['\u{eb}', '\0', '\0']), ('\u{cc}', ['\u{ec}', '\0', '\0']), ('\u{cd}', ['\u{ed}', '\0', - '\0']), ('\u{ce}', ['\u{ee}', '\0', '\0']), ('\u{cf}', ['\u{ef}', '\0', '\0']), ('\u{d0}', - ['\u{f0}', '\0', '\0']), ('\u{d1}', ['\u{f1}', '\0', '\0']), ('\u{d2}', ['\u{f2}', '\0', - '\0']), ('\u{d3}', ['\u{f3}', '\0', '\0']), ('\u{d4}', ['\u{f4}', '\0', '\0']), ('\u{d5}', - ['\u{f5}', '\0', '\0']), ('\u{d6}', ['\u{f6}', '\0', '\0']), ('\u{d8}', ['\u{f8}', '\0', - '\0']), ('\u{d9}', ['\u{f9}', '\0', '\0']), ('\u{da}', ['\u{fa}', '\0', '\0']), ('\u{db}', - ['\u{fb}', '\0', '\0']), ('\u{dc}', ['\u{fc}', '\0', '\0']), ('\u{dd}', ['\u{fd}', '\0', - '\0']), ('\u{de}', ['\u{fe}', '\0', '\0']), ('\u{100}', ['\u{101}', '\0', '\0']), - ('\u{102}', ['\u{103}', '\0', '\0']), ('\u{104}', ['\u{105}', '\0', '\0']), ('\u{106}', - ['\u{107}', '\0', '\0']), ('\u{108}', ['\u{109}', '\0', '\0']), ('\u{10a}', ['\u{10b}', - '\0', '\0']), ('\u{10c}', ['\u{10d}', '\0', '\0']), ('\u{10e}', ['\u{10f}', '\0', '\0']), - ('\u{110}', ['\u{111}', '\0', '\0']), ('\u{112}', ['\u{113}', '\0', '\0']), ('\u{114}', - ['\u{115}', '\0', '\0']), ('\u{116}', ['\u{117}', '\0', '\0']), ('\u{118}', ['\u{119}', - '\0', '\0']), ('\u{11a}', ['\u{11b}', '\0', '\0']), ('\u{11c}', ['\u{11d}', '\0', '\0']), - ('\u{11e}', ['\u{11f}', '\0', '\0']), ('\u{120}', ['\u{121}', '\0', '\0']), ('\u{122}', - ['\u{123}', '\0', '\0']), ('\u{124}', ['\u{125}', '\0', '\0']), ('\u{126}', ['\u{127}', - '\0', '\0']), ('\u{128}', ['\u{129}', '\0', '\0']), ('\u{12a}', ['\u{12b}', '\0', '\0']), - ('\u{12c}', ['\u{12d}', '\0', '\0']), ('\u{12e}', ['\u{12f}', '\0', '\0']), ('\u{130}', - ['\u{69}', '\u{307}', '\0']), ('\u{132}', ['\u{133}', '\0', '\0']), ('\u{134}', ['\u{135}', - '\0', '\0']), ('\u{136}', ['\u{137}', '\0', '\0']), ('\u{139}', ['\u{13a}', '\0', '\0']), - ('\u{13b}', ['\u{13c}', '\0', '\0']), ('\u{13d}', ['\u{13e}', '\0', '\0']), ('\u{13f}', - ['\u{140}', '\0', '\0']), ('\u{141}', ['\u{142}', '\0', '\0']), ('\u{143}', ['\u{144}', - '\0', '\0']), ('\u{145}', ['\u{146}', '\0', '\0']), ('\u{147}', ['\u{148}', '\0', '\0']), - ('\u{14a}', ['\u{14b}', '\0', '\0']), ('\u{14c}', ['\u{14d}', '\0', '\0']), ('\u{14e}', - ['\u{14f}', '\0', '\0']), ('\u{150}', ['\u{151}', '\0', '\0']), ('\u{152}', ['\u{153}', - '\0', '\0']), ('\u{154}', ['\u{155}', '\0', '\0']), ('\u{156}', ['\u{157}', '\0', '\0']), - ('\u{158}', ['\u{159}', '\0', '\0']), ('\u{15a}', ['\u{15b}', '\0', '\0']), ('\u{15c}', - ['\u{15d}', '\0', '\0']), ('\u{15e}', ['\u{15f}', '\0', '\0']), ('\u{160}', ['\u{161}', - '\0', '\0']), ('\u{162}', ['\u{163}', '\0', '\0']), ('\u{164}', ['\u{165}', '\0', '\0']), - ('\u{166}', ['\u{167}', '\0', '\0']), ('\u{168}', ['\u{169}', '\0', '\0']), ('\u{16a}', - ['\u{16b}', '\0', '\0']), ('\u{16c}', ['\u{16d}', '\0', '\0']), ('\u{16e}', ['\u{16f}', - '\0', '\0']), ('\u{170}', ['\u{171}', '\0', '\0']), ('\u{172}', ['\u{173}', '\0', '\0']), - ('\u{174}', ['\u{175}', '\0', '\0']), ('\u{176}', ['\u{177}', '\0', '\0']), ('\u{178}', - ['\u{ff}', '\0', '\0']), ('\u{179}', ['\u{17a}', '\0', '\0']), ('\u{17b}', ['\u{17c}', '\0', - '\0']), ('\u{17d}', ['\u{17e}', '\0', '\0']), ('\u{181}', ['\u{253}', '\0', '\0']), - ('\u{182}', ['\u{183}', '\0', '\0']), ('\u{184}', ['\u{185}', '\0', '\0']), ('\u{186}', - ['\u{254}', '\0', '\0']), ('\u{187}', ['\u{188}', '\0', '\0']), ('\u{189}', ['\u{256}', - '\0', '\0']), ('\u{18a}', ['\u{257}', '\0', '\0']), ('\u{18b}', ['\u{18c}', '\0', '\0']), - ('\u{18e}', ['\u{1dd}', '\0', '\0']), ('\u{18f}', ['\u{259}', '\0', '\0']), ('\u{190}', - ['\u{25b}', '\0', '\0']), ('\u{191}', ['\u{192}', '\0', '\0']), ('\u{193}', ['\u{260}', - '\0', '\0']), ('\u{194}', ['\u{263}', '\0', '\0']), ('\u{196}', ['\u{269}', '\0', '\0']), - ('\u{197}', ['\u{268}', '\0', '\0']), ('\u{198}', ['\u{199}', '\0', '\0']), ('\u{19c}', - ['\u{26f}', '\0', '\0']), ('\u{19d}', ['\u{272}', '\0', '\0']), ('\u{19f}', ['\u{275}', - '\0', '\0']), ('\u{1a0}', ['\u{1a1}', '\0', '\0']), ('\u{1a2}', ['\u{1a3}', '\0', '\0']), - ('\u{1a4}', ['\u{1a5}', '\0', '\0']), ('\u{1a6}', ['\u{280}', '\0', '\0']), ('\u{1a7}', - ['\u{1a8}', '\0', '\0']), ('\u{1a9}', ['\u{283}', '\0', '\0']), ('\u{1ac}', ['\u{1ad}', - '\0', '\0']), ('\u{1ae}', ['\u{288}', '\0', '\0']), ('\u{1af}', ['\u{1b0}', '\0', '\0']), - ('\u{1b1}', ['\u{28a}', '\0', '\0']), ('\u{1b2}', ['\u{28b}', '\0', '\0']), ('\u{1b3}', - ['\u{1b4}', '\0', '\0']), ('\u{1b5}', ['\u{1b6}', '\0', '\0']), ('\u{1b7}', ['\u{292}', - '\0', '\0']), ('\u{1b8}', ['\u{1b9}', '\0', '\0']), ('\u{1bc}', ['\u{1bd}', '\0', '\0']), - ('\u{1c4}', ['\u{1c6}', '\0', '\0']), ('\u{1c5}', ['\u{1c6}', '\0', '\0']), ('\u{1c7}', - ['\u{1c9}', '\0', '\0']), ('\u{1c8}', ['\u{1c9}', '\0', '\0']), ('\u{1ca}', ['\u{1cc}', - '\0', '\0']), ('\u{1cb}', ['\u{1cc}', '\0', '\0']), ('\u{1cd}', ['\u{1ce}', '\0', '\0']), - ('\u{1cf}', ['\u{1d0}', '\0', '\0']), ('\u{1d1}', ['\u{1d2}', '\0', '\0']), ('\u{1d3}', - ['\u{1d4}', '\0', '\0']), ('\u{1d5}', ['\u{1d6}', '\0', '\0']), ('\u{1d7}', ['\u{1d8}', - '\0', '\0']), ('\u{1d9}', ['\u{1da}', '\0', '\0']), ('\u{1db}', ['\u{1dc}', '\0', '\0']), - ('\u{1de}', ['\u{1df}', '\0', '\0']), ('\u{1e0}', ['\u{1e1}', '\0', '\0']), ('\u{1e2}', - ['\u{1e3}', '\0', '\0']), ('\u{1e4}', ['\u{1e5}', '\0', '\0']), ('\u{1e6}', ['\u{1e7}', - '\0', '\0']), ('\u{1e8}', ['\u{1e9}', '\0', '\0']), ('\u{1ea}', ['\u{1eb}', '\0', '\0']), - ('\u{1ec}', ['\u{1ed}', '\0', '\0']), ('\u{1ee}', ['\u{1ef}', '\0', '\0']), ('\u{1f1}', - ['\u{1f3}', '\0', '\0']), ('\u{1f2}', ['\u{1f3}', '\0', '\0']), ('\u{1f4}', ['\u{1f5}', - '\0', '\0']), ('\u{1f6}', ['\u{195}', '\0', '\0']), ('\u{1f7}', ['\u{1bf}', '\0', '\0']), - ('\u{1f8}', ['\u{1f9}', '\0', '\0']), ('\u{1fa}', ['\u{1fb}', '\0', '\0']), ('\u{1fc}', - ['\u{1fd}', '\0', '\0']), ('\u{1fe}', ['\u{1ff}', '\0', '\0']), ('\u{200}', ['\u{201}', - '\0', '\0']), ('\u{202}', ['\u{203}', '\0', '\0']), ('\u{204}', ['\u{205}', '\0', '\0']), - ('\u{206}', ['\u{207}', '\0', '\0']), ('\u{208}', ['\u{209}', '\0', '\0']), ('\u{20a}', - ['\u{20b}', '\0', '\0']), ('\u{20c}', ['\u{20d}', '\0', '\0']), ('\u{20e}', ['\u{20f}', - '\0', '\0']), ('\u{210}', ['\u{211}', '\0', '\0']), ('\u{212}', ['\u{213}', '\0', '\0']), - ('\u{214}', ['\u{215}', '\0', '\0']), ('\u{216}', ['\u{217}', '\0', '\0']), ('\u{218}', - ['\u{219}', '\0', '\0']), ('\u{21a}', ['\u{21b}', '\0', '\0']), ('\u{21c}', ['\u{21d}', - '\0', '\0']), ('\u{21e}', ['\u{21f}', '\0', '\0']), ('\u{220}', ['\u{19e}', '\0', '\0']), - ('\u{222}', ['\u{223}', '\0', '\0']), ('\u{224}', ['\u{225}', '\0', '\0']), ('\u{226}', - ['\u{227}', '\0', '\0']), ('\u{228}', ['\u{229}', '\0', '\0']), ('\u{22a}', ['\u{22b}', - '\0', '\0']), ('\u{22c}', ['\u{22d}', '\0', '\0']), ('\u{22e}', ['\u{22f}', '\0', '\0']), - ('\u{230}', ['\u{231}', '\0', '\0']), ('\u{232}', ['\u{233}', '\0', '\0']), ('\u{23a}', - ['\u{2c65}', '\0', '\0']), ('\u{23b}', ['\u{23c}', '\0', '\0']), ('\u{23d}', ['\u{19a}', - '\0', '\0']), ('\u{23e}', ['\u{2c66}', '\0', '\0']), ('\u{241}', ['\u{242}', '\0', '\0']), - ('\u{243}', ['\u{180}', '\0', '\0']), ('\u{244}', ['\u{289}', '\0', '\0']), ('\u{245}', - ['\u{28c}', '\0', '\0']), ('\u{246}', ['\u{247}', '\0', '\0']), ('\u{248}', ['\u{249}', - '\0', '\0']), ('\u{24a}', ['\u{24b}', '\0', '\0']), ('\u{24c}', ['\u{24d}', '\0', '\0']), - ('\u{24e}', ['\u{24f}', '\0', '\0']), ('\u{370}', ['\u{371}', '\0', '\0']), ('\u{372}', - ['\u{373}', '\0', '\0']), ('\u{376}', ['\u{377}', '\0', '\0']), ('\u{37f}', ['\u{3f3}', - '\0', '\0']), ('\u{386}', ['\u{3ac}', '\0', '\0']), ('\u{388}', ['\u{3ad}', '\0', '\0']), - ('\u{389}', ['\u{3ae}', '\0', '\0']), ('\u{38a}', ['\u{3af}', '\0', '\0']), ('\u{38c}', - ['\u{3cc}', '\0', '\0']), ('\u{38e}', ['\u{3cd}', '\0', '\0']), ('\u{38f}', ['\u{3ce}', - '\0', '\0']), ('\u{391}', ['\u{3b1}', '\0', '\0']), ('\u{392}', ['\u{3b2}', '\0', '\0']), - ('\u{393}', ['\u{3b3}', '\0', '\0']), ('\u{394}', ['\u{3b4}', '\0', '\0']), ('\u{395}', - ['\u{3b5}', '\0', '\0']), ('\u{396}', ['\u{3b6}', '\0', '\0']), ('\u{397}', ['\u{3b7}', - '\0', '\0']), ('\u{398}', ['\u{3b8}', '\0', '\0']), ('\u{399}', ['\u{3b9}', '\0', '\0']), - ('\u{39a}', ['\u{3ba}', '\0', '\0']), ('\u{39b}', ['\u{3bb}', '\0', '\0']), ('\u{39c}', - ['\u{3bc}', '\0', '\0']), ('\u{39d}', ['\u{3bd}', '\0', '\0']), ('\u{39e}', ['\u{3be}', - '\0', '\0']), ('\u{39f}', ['\u{3bf}', '\0', '\0']), ('\u{3a0}', ['\u{3c0}', '\0', '\0']), - ('\u{3a1}', ['\u{3c1}', '\0', '\0']), ('\u{3a3}', ['\u{3c3}', '\0', '\0']), ('\u{3a4}', - ['\u{3c4}', '\0', '\0']), ('\u{3a5}', ['\u{3c5}', '\0', '\0']), ('\u{3a6}', ['\u{3c6}', - '\0', '\0']), ('\u{3a7}', ['\u{3c7}', '\0', '\0']), ('\u{3a8}', ['\u{3c8}', '\0', '\0']), - ('\u{3a9}', ['\u{3c9}', '\0', '\0']), ('\u{3aa}', ['\u{3ca}', '\0', '\0']), ('\u{3ab}', - ['\u{3cb}', '\0', '\0']), ('\u{3cf}', ['\u{3d7}', '\0', '\0']), ('\u{3d8}', ['\u{3d9}', - '\0', '\0']), ('\u{3da}', ['\u{3db}', '\0', '\0']), ('\u{3dc}', ['\u{3dd}', '\0', '\0']), - ('\u{3de}', ['\u{3df}', '\0', '\0']), ('\u{3e0}', ['\u{3e1}', '\0', '\0']), ('\u{3e2}', - ['\u{3e3}', '\0', '\0']), ('\u{3e4}', ['\u{3e5}', '\0', '\0']), ('\u{3e6}', ['\u{3e7}', - '\0', '\0']), ('\u{3e8}', ['\u{3e9}', '\0', '\0']), ('\u{3ea}', ['\u{3eb}', '\0', '\0']), - ('\u{3ec}', ['\u{3ed}', '\0', '\0']), ('\u{3ee}', ['\u{3ef}', '\0', '\0']), ('\u{3f4}', - ['\u{3b8}', '\0', '\0']), ('\u{3f7}', ['\u{3f8}', '\0', '\0']), ('\u{3f9}', ['\u{3f2}', - '\0', '\0']), ('\u{3fa}', ['\u{3fb}', '\0', '\0']), ('\u{3fd}', ['\u{37b}', '\0', '\0']), - ('\u{3fe}', ['\u{37c}', '\0', '\0']), ('\u{3ff}', ['\u{37d}', '\0', '\0']), ('\u{400}', - ['\u{450}', '\0', '\0']), ('\u{401}', ['\u{451}', '\0', '\0']), ('\u{402}', ['\u{452}', - '\0', '\0']), ('\u{403}', ['\u{453}', '\0', '\0']), ('\u{404}', ['\u{454}', '\0', '\0']), - ('\u{405}', ['\u{455}', '\0', '\0']), ('\u{406}', ['\u{456}', '\0', '\0']), ('\u{407}', - ['\u{457}', '\0', '\0']), ('\u{408}', ['\u{458}', '\0', '\0']), ('\u{409}', ['\u{459}', - '\0', '\0']), ('\u{40a}', ['\u{45a}', '\0', '\0']), ('\u{40b}', ['\u{45b}', '\0', '\0']), - ('\u{40c}', ['\u{45c}', '\0', '\0']), ('\u{40d}', ['\u{45d}', '\0', '\0']), ('\u{40e}', - ['\u{45e}', '\0', '\0']), ('\u{40f}', ['\u{45f}', '\0', '\0']), ('\u{410}', ['\u{430}', - '\0', '\0']), ('\u{411}', ['\u{431}', '\0', '\0']), ('\u{412}', ['\u{432}', '\0', '\0']), - ('\u{413}', ['\u{433}', '\0', '\0']), ('\u{414}', ['\u{434}', '\0', '\0']), ('\u{415}', - ['\u{435}', '\0', '\0']), ('\u{416}', ['\u{436}', '\0', '\0']), ('\u{417}', ['\u{437}', - '\0', '\0']), ('\u{418}', ['\u{438}', '\0', '\0']), ('\u{419}', ['\u{439}', '\0', '\0']), - ('\u{41a}', ['\u{43a}', '\0', '\0']), ('\u{41b}', ['\u{43b}', '\0', '\0']), ('\u{41c}', - ['\u{43c}', '\0', '\0']), ('\u{41d}', ['\u{43d}', '\0', '\0']), ('\u{41e}', ['\u{43e}', - '\0', '\0']), ('\u{41f}', ['\u{43f}', '\0', '\0']), ('\u{420}', ['\u{440}', '\0', '\0']), - ('\u{421}', ['\u{441}', '\0', '\0']), ('\u{422}', ['\u{442}', '\0', '\0']), ('\u{423}', - ['\u{443}', '\0', '\0']), ('\u{424}', ['\u{444}', '\0', '\0']), ('\u{425}', ['\u{445}', - '\0', '\0']), ('\u{426}', ['\u{446}', '\0', '\0']), ('\u{427}', ['\u{447}', '\0', '\0']), - ('\u{428}', ['\u{448}', '\0', '\0']), ('\u{429}', ['\u{449}', '\0', '\0']), ('\u{42a}', - ['\u{44a}', '\0', '\0']), ('\u{42b}', ['\u{44b}', '\0', '\0']), ('\u{42c}', ['\u{44c}', - '\0', '\0']), ('\u{42d}', ['\u{44d}', '\0', '\0']), ('\u{42e}', ['\u{44e}', '\0', '\0']), - ('\u{42f}', ['\u{44f}', '\0', '\0']), ('\u{460}', ['\u{461}', '\0', '\0']), ('\u{462}', - ['\u{463}', '\0', '\0']), ('\u{464}', ['\u{465}', '\0', '\0']), ('\u{466}', ['\u{467}', - '\0', '\0']), ('\u{468}', ['\u{469}', '\0', '\0']), ('\u{46a}', ['\u{46b}', '\0', '\0']), - ('\u{46c}', ['\u{46d}', '\0', '\0']), ('\u{46e}', ['\u{46f}', '\0', '\0']), ('\u{470}', - ['\u{471}', '\0', '\0']), ('\u{472}', ['\u{473}', '\0', '\0']), ('\u{474}', ['\u{475}', - '\0', '\0']), ('\u{476}', ['\u{477}', '\0', '\0']), ('\u{478}', ['\u{479}', '\0', '\0']), - ('\u{47a}', ['\u{47b}', '\0', '\0']), ('\u{47c}', ['\u{47d}', '\0', '\0']), ('\u{47e}', - ['\u{47f}', '\0', '\0']), ('\u{480}', ['\u{481}', '\0', '\0']), ('\u{48a}', ['\u{48b}', - '\0', '\0']), ('\u{48c}', ['\u{48d}', '\0', '\0']), ('\u{48e}', ['\u{48f}', '\0', '\0']), - ('\u{490}', ['\u{491}', '\0', '\0']), ('\u{492}', ['\u{493}', '\0', '\0']), ('\u{494}', - ['\u{495}', '\0', '\0']), ('\u{496}', ['\u{497}', '\0', '\0']), ('\u{498}', ['\u{499}', - '\0', '\0']), ('\u{49a}', ['\u{49b}', '\0', '\0']), ('\u{49c}', ['\u{49d}', '\0', '\0']), - ('\u{49e}', ['\u{49f}', '\0', '\0']), ('\u{4a0}', ['\u{4a1}', '\0', '\0']), ('\u{4a2}', - ['\u{4a3}', '\0', '\0']), ('\u{4a4}', ['\u{4a5}', '\0', '\0']), ('\u{4a6}', ['\u{4a7}', - '\0', '\0']), ('\u{4a8}', ['\u{4a9}', '\0', '\0']), ('\u{4aa}', ['\u{4ab}', '\0', '\0']), - ('\u{4ac}', ['\u{4ad}', '\0', '\0']), ('\u{4ae}', ['\u{4af}', '\0', '\0']), ('\u{4b0}', - ['\u{4b1}', '\0', '\0']), ('\u{4b2}', ['\u{4b3}', '\0', '\0']), ('\u{4b4}', ['\u{4b5}', - '\0', '\0']), ('\u{4b6}', ['\u{4b7}', '\0', '\0']), ('\u{4b8}', ['\u{4b9}', '\0', '\0']), - ('\u{4ba}', ['\u{4bb}', '\0', '\0']), ('\u{4bc}', ['\u{4bd}', '\0', '\0']), ('\u{4be}', - ['\u{4bf}', '\0', '\0']), ('\u{4c0}', ['\u{4cf}', '\0', '\0']), ('\u{4c1}', ['\u{4c2}', - '\0', '\0']), ('\u{4c3}', ['\u{4c4}', '\0', '\0']), ('\u{4c5}', ['\u{4c6}', '\0', '\0']), - ('\u{4c7}', ['\u{4c8}', '\0', '\0']), ('\u{4c9}', ['\u{4ca}', '\0', '\0']), ('\u{4cb}', - ['\u{4cc}', '\0', '\0']), ('\u{4cd}', ['\u{4ce}', '\0', '\0']), ('\u{4d0}', ['\u{4d1}', - '\0', '\0']), ('\u{4d2}', ['\u{4d3}', '\0', '\0']), ('\u{4d4}', ['\u{4d5}', '\0', '\0']), - ('\u{4d6}', ['\u{4d7}', '\0', '\0']), ('\u{4d8}', ['\u{4d9}', '\0', '\0']), ('\u{4da}', - ['\u{4db}', '\0', '\0']), ('\u{4dc}', ['\u{4dd}', '\0', '\0']), ('\u{4de}', ['\u{4df}', - '\0', '\0']), ('\u{4e0}', ['\u{4e1}', '\0', '\0']), ('\u{4e2}', ['\u{4e3}', '\0', '\0']), - ('\u{4e4}', ['\u{4e5}', '\0', '\0']), ('\u{4e6}', ['\u{4e7}', '\0', '\0']), ('\u{4e8}', - ['\u{4e9}', '\0', '\0']), ('\u{4ea}', ['\u{4eb}', '\0', '\0']), ('\u{4ec}', ['\u{4ed}', - '\0', '\0']), ('\u{4ee}', ['\u{4ef}', '\0', '\0']), ('\u{4f0}', ['\u{4f1}', '\0', '\0']), - ('\u{4f2}', ['\u{4f3}', '\0', '\0']), ('\u{4f4}', ['\u{4f5}', '\0', '\0']), ('\u{4f6}', - ['\u{4f7}', '\0', '\0']), ('\u{4f8}', ['\u{4f9}', '\0', '\0']), ('\u{4fa}', ['\u{4fb}', - '\0', '\0']), ('\u{4fc}', ['\u{4fd}', '\0', '\0']), ('\u{4fe}', ['\u{4ff}', '\0', '\0']), - ('\u{500}', ['\u{501}', '\0', '\0']), ('\u{502}', ['\u{503}', '\0', '\0']), ('\u{504}', - ['\u{505}', '\0', '\0']), ('\u{506}', ['\u{507}', '\0', '\0']), ('\u{508}', ['\u{509}', - '\0', '\0']), ('\u{50a}', ['\u{50b}', '\0', '\0']), ('\u{50c}', ['\u{50d}', '\0', '\0']), - ('\u{50e}', ['\u{50f}', '\0', '\0']), ('\u{510}', ['\u{511}', '\0', '\0']), ('\u{512}', - ['\u{513}', '\0', '\0']), ('\u{514}', ['\u{515}', '\0', '\0']), ('\u{516}', ['\u{517}', - '\0', '\0']), ('\u{518}', ['\u{519}', '\0', '\0']), ('\u{51a}', ['\u{51b}', '\0', '\0']), - ('\u{51c}', ['\u{51d}', '\0', '\0']), ('\u{51e}', ['\u{51f}', '\0', '\0']), ('\u{520}', - ['\u{521}', '\0', '\0']), ('\u{522}', ['\u{523}', '\0', '\0']), ('\u{524}', ['\u{525}', - '\0', '\0']), ('\u{526}', ['\u{527}', '\0', '\0']), ('\u{528}', ['\u{529}', '\0', '\0']), - ('\u{52a}', ['\u{52b}', '\0', '\0']), ('\u{52c}', ['\u{52d}', '\0', '\0']), ('\u{52e}', - ['\u{52f}', '\0', '\0']), ('\u{531}', ['\u{561}', '\0', '\0']), ('\u{532}', ['\u{562}', - '\0', '\0']), ('\u{533}', ['\u{563}', '\0', '\0']), ('\u{534}', ['\u{564}', '\0', '\0']), - ('\u{535}', ['\u{565}', '\0', '\0']), ('\u{536}', ['\u{566}', '\0', '\0']), ('\u{537}', - ['\u{567}', '\0', '\0']), ('\u{538}', ['\u{568}', '\0', '\0']), ('\u{539}', ['\u{569}', - '\0', '\0']), ('\u{53a}', ['\u{56a}', '\0', '\0']), ('\u{53b}', ['\u{56b}', '\0', '\0']), - ('\u{53c}', ['\u{56c}', '\0', '\0']), ('\u{53d}', ['\u{56d}', '\0', '\0']), ('\u{53e}', - ['\u{56e}', '\0', '\0']), ('\u{53f}', ['\u{56f}', '\0', '\0']), ('\u{540}', ['\u{570}', - '\0', '\0']), ('\u{541}', ['\u{571}', '\0', '\0']), ('\u{542}', ['\u{572}', '\0', '\0']), - ('\u{543}', ['\u{573}', '\0', '\0']), ('\u{544}', ['\u{574}', '\0', '\0']), ('\u{545}', - ['\u{575}', '\0', '\0']), ('\u{546}', ['\u{576}', '\0', '\0']), ('\u{547}', ['\u{577}', - '\0', '\0']), ('\u{548}', ['\u{578}', '\0', '\0']), ('\u{549}', ['\u{579}', '\0', '\0']), - ('\u{54a}', ['\u{57a}', '\0', '\0']), ('\u{54b}', ['\u{57b}', '\0', '\0']), ('\u{54c}', - ['\u{57c}', '\0', '\0']), ('\u{54d}', ['\u{57d}', '\0', '\0']), ('\u{54e}', ['\u{57e}', - '\0', '\0']), ('\u{54f}', ['\u{57f}', '\0', '\0']), ('\u{550}', ['\u{580}', '\0', '\0']), - ('\u{551}', ['\u{581}', '\0', '\0']), ('\u{552}', ['\u{582}', '\0', '\0']), ('\u{553}', - ['\u{583}', '\0', '\0']), ('\u{554}', ['\u{584}', '\0', '\0']), ('\u{555}', ['\u{585}', - '\0', '\0']), ('\u{556}', ['\u{586}', '\0', '\0']), ('\u{10a0}', ['\u{2d00}', '\0', '\0']), - ('\u{10a1}', ['\u{2d01}', '\0', '\0']), ('\u{10a2}', ['\u{2d02}', '\0', '\0']), ('\u{10a3}', - ['\u{2d03}', '\0', '\0']), ('\u{10a4}', ['\u{2d04}', '\0', '\0']), ('\u{10a5}', ['\u{2d05}', - '\0', '\0']), ('\u{10a6}', ['\u{2d06}', '\0', '\0']), ('\u{10a7}', ['\u{2d07}', '\0', - '\0']), ('\u{10a8}', ['\u{2d08}', '\0', '\0']), ('\u{10a9}', ['\u{2d09}', '\0', '\0']), - ('\u{10aa}', ['\u{2d0a}', '\0', '\0']), ('\u{10ab}', ['\u{2d0b}', '\0', '\0']), ('\u{10ac}', - ['\u{2d0c}', '\0', '\0']), ('\u{10ad}', ['\u{2d0d}', '\0', '\0']), ('\u{10ae}', ['\u{2d0e}', - '\0', '\0']), ('\u{10af}', ['\u{2d0f}', '\0', '\0']), ('\u{10b0}', ['\u{2d10}', '\0', - '\0']), ('\u{10b1}', ['\u{2d11}', '\0', '\0']), ('\u{10b2}', ['\u{2d12}', '\0', '\0']), - ('\u{10b3}', ['\u{2d13}', '\0', '\0']), ('\u{10b4}', ['\u{2d14}', '\0', '\0']), ('\u{10b5}', - ['\u{2d15}', '\0', '\0']), ('\u{10b6}', ['\u{2d16}', '\0', '\0']), ('\u{10b7}', ['\u{2d17}', - '\0', '\0']), ('\u{10b8}', ['\u{2d18}', '\0', '\0']), ('\u{10b9}', ['\u{2d19}', '\0', - '\0']), ('\u{10ba}', ['\u{2d1a}', '\0', '\0']), ('\u{10bb}', ['\u{2d1b}', '\0', '\0']), - ('\u{10bc}', ['\u{2d1c}', '\0', '\0']), ('\u{10bd}', ['\u{2d1d}', '\0', '\0']), ('\u{10be}', - ['\u{2d1e}', '\0', '\0']), ('\u{10bf}', ['\u{2d1f}', '\0', '\0']), ('\u{10c0}', ['\u{2d20}', - '\0', '\0']), ('\u{10c1}', ['\u{2d21}', '\0', '\0']), ('\u{10c2}', ['\u{2d22}', '\0', - '\0']), ('\u{10c3}', ['\u{2d23}', '\0', '\0']), ('\u{10c4}', ['\u{2d24}', '\0', '\0']), - ('\u{10c5}', ['\u{2d25}', '\0', '\0']), ('\u{10c7}', ['\u{2d27}', '\0', '\0']), ('\u{10cd}', - ['\u{2d2d}', '\0', '\0']), ('\u{13a0}', ['\u{ab70}', '\0', '\0']), ('\u{13a1}', ['\u{ab71}', - '\0', '\0']), ('\u{13a2}', ['\u{ab72}', '\0', '\0']), ('\u{13a3}', ['\u{ab73}', '\0', - '\0']), ('\u{13a4}', ['\u{ab74}', '\0', '\0']), ('\u{13a5}', ['\u{ab75}', '\0', '\0']), - ('\u{13a6}', ['\u{ab76}', '\0', '\0']), ('\u{13a7}', ['\u{ab77}', '\0', '\0']), ('\u{13a8}', - ['\u{ab78}', '\0', '\0']), ('\u{13a9}', ['\u{ab79}', '\0', '\0']), ('\u{13aa}', ['\u{ab7a}', - '\0', '\0']), ('\u{13ab}', ['\u{ab7b}', '\0', '\0']), ('\u{13ac}', ['\u{ab7c}', '\0', - '\0']), ('\u{13ad}', ['\u{ab7d}', '\0', '\0']), ('\u{13ae}', ['\u{ab7e}', '\0', '\0']), - ('\u{13af}', ['\u{ab7f}', '\0', '\0']), ('\u{13b0}', ['\u{ab80}', '\0', '\0']), ('\u{13b1}', - ['\u{ab81}', '\0', '\0']), ('\u{13b2}', ['\u{ab82}', '\0', '\0']), ('\u{13b3}', ['\u{ab83}', - '\0', '\0']), ('\u{13b4}', ['\u{ab84}', '\0', '\0']), ('\u{13b5}', ['\u{ab85}', '\0', - '\0']), ('\u{13b6}', ['\u{ab86}', '\0', '\0']), ('\u{13b7}', ['\u{ab87}', '\0', '\0']), - ('\u{13b8}', ['\u{ab88}', '\0', '\0']), ('\u{13b9}', ['\u{ab89}', '\0', '\0']), ('\u{13ba}', - ['\u{ab8a}', '\0', '\0']), ('\u{13bb}', ['\u{ab8b}', '\0', '\0']), ('\u{13bc}', ['\u{ab8c}', - '\0', '\0']), ('\u{13bd}', ['\u{ab8d}', '\0', '\0']), ('\u{13be}', ['\u{ab8e}', '\0', - '\0']), ('\u{13bf}', ['\u{ab8f}', '\0', '\0']), ('\u{13c0}', ['\u{ab90}', '\0', '\0']), - ('\u{13c1}', ['\u{ab91}', '\0', '\0']), ('\u{13c2}', ['\u{ab92}', '\0', '\0']), ('\u{13c3}', - ['\u{ab93}', '\0', '\0']), ('\u{13c4}', ['\u{ab94}', '\0', '\0']), ('\u{13c5}', ['\u{ab95}', - '\0', '\0']), ('\u{13c6}', ['\u{ab96}', '\0', '\0']), ('\u{13c7}', ['\u{ab97}', '\0', - '\0']), ('\u{13c8}', ['\u{ab98}', '\0', '\0']), ('\u{13c9}', ['\u{ab99}', '\0', '\0']), - ('\u{13ca}', ['\u{ab9a}', '\0', '\0']), ('\u{13cb}', ['\u{ab9b}', '\0', '\0']), ('\u{13cc}', - ['\u{ab9c}', '\0', '\0']), ('\u{13cd}', ['\u{ab9d}', '\0', '\0']), ('\u{13ce}', ['\u{ab9e}', - '\0', '\0']), ('\u{13cf}', ['\u{ab9f}', '\0', '\0']), ('\u{13d0}', ['\u{aba0}', '\0', - '\0']), ('\u{13d1}', ['\u{aba1}', '\0', '\0']), ('\u{13d2}', ['\u{aba2}', '\0', '\0']), - ('\u{13d3}', ['\u{aba3}', '\0', '\0']), ('\u{13d4}', ['\u{aba4}', '\0', '\0']), ('\u{13d5}', - ['\u{aba5}', '\0', '\0']), ('\u{13d6}', ['\u{aba6}', '\0', '\0']), ('\u{13d7}', ['\u{aba7}', - '\0', '\0']), ('\u{13d8}', ['\u{aba8}', '\0', '\0']), ('\u{13d9}', ['\u{aba9}', '\0', - '\0']), ('\u{13da}', ['\u{abaa}', '\0', '\0']), ('\u{13db}', ['\u{abab}', '\0', '\0']), - ('\u{13dc}', ['\u{abac}', '\0', '\0']), ('\u{13dd}', ['\u{abad}', '\0', '\0']), ('\u{13de}', - ['\u{abae}', '\0', '\0']), ('\u{13df}', ['\u{abaf}', '\0', '\0']), ('\u{13e0}', ['\u{abb0}', - '\0', '\0']), ('\u{13e1}', ['\u{abb1}', '\0', '\0']), ('\u{13e2}', ['\u{abb2}', '\0', - '\0']), ('\u{13e3}', ['\u{abb3}', '\0', '\0']), ('\u{13e4}', ['\u{abb4}', '\0', '\0']), - ('\u{13e5}', ['\u{abb5}', '\0', '\0']), ('\u{13e6}', ['\u{abb6}', '\0', '\0']), ('\u{13e7}', - ['\u{abb7}', '\0', '\0']), ('\u{13e8}', ['\u{abb8}', '\0', '\0']), ('\u{13e9}', ['\u{abb9}', - '\0', '\0']), ('\u{13ea}', ['\u{abba}', '\0', '\0']), ('\u{13eb}', ['\u{abbb}', '\0', - '\0']), ('\u{13ec}', ['\u{abbc}', '\0', '\0']), ('\u{13ed}', ['\u{abbd}', '\0', '\0']), - ('\u{13ee}', ['\u{abbe}', '\0', '\0']), ('\u{13ef}', ['\u{abbf}', '\0', '\0']), ('\u{13f0}', - ['\u{13f8}', '\0', '\0']), ('\u{13f1}', ['\u{13f9}', '\0', '\0']), ('\u{13f2}', ['\u{13fa}', - '\0', '\0']), ('\u{13f3}', ['\u{13fb}', '\0', '\0']), ('\u{13f4}', ['\u{13fc}', '\0', - '\0']), ('\u{13f5}', ['\u{13fd}', '\0', '\0']), ('\u{1e00}', ['\u{1e01}', '\0', '\0']), - ('\u{1e02}', ['\u{1e03}', '\0', '\0']), ('\u{1e04}', ['\u{1e05}', '\0', '\0']), ('\u{1e06}', - ['\u{1e07}', '\0', '\0']), ('\u{1e08}', ['\u{1e09}', '\0', '\0']), ('\u{1e0a}', ['\u{1e0b}', - '\0', '\0']), ('\u{1e0c}', ['\u{1e0d}', '\0', '\0']), ('\u{1e0e}', ['\u{1e0f}', '\0', - '\0']), ('\u{1e10}', ['\u{1e11}', '\0', '\0']), ('\u{1e12}', ['\u{1e13}', '\0', '\0']), - ('\u{1e14}', ['\u{1e15}', '\0', '\0']), ('\u{1e16}', ['\u{1e17}', '\0', '\0']), ('\u{1e18}', - ['\u{1e19}', '\0', '\0']), ('\u{1e1a}', ['\u{1e1b}', '\0', '\0']), ('\u{1e1c}', ['\u{1e1d}', - '\0', '\0']), ('\u{1e1e}', ['\u{1e1f}', '\0', '\0']), ('\u{1e20}', ['\u{1e21}', '\0', - '\0']), ('\u{1e22}', ['\u{1e23}', '\0', '\0']), ('\u{1e24}', ['\u{1e25}', '\0', '\0']), - ('\u{1e26}', ['\u{1e27}', '\0', '\0']), ('\u{1e28}', ['\u{1e29}', '\0', '\0']), ('\u{1e2a}', - ['\u{1e2b}', '\0', '\0']), ('\u{1e2c}', ['\u{1e2d}', '\0', '\0']), ('\u{1e2e}', ['\u{1e2f}', - '\0', '\0']), ('\u{1e30}', ['\u{1e31}', '\0', '\0']), ('\u{1e32}', ['\u{1e33}', '\0', - '\0']), ('\u{1e34}', ['\u{1e35}', '\0', '\0']), ('\u{1e36}', ['\u{1e37}', '\0', '\0']), - ('\u{1e38}', ['\u{1e39}', '\0', '\0']), ('\u{1e3a}', ['\u{1e3b}', '\0', '\0']), ('\u{1e3c}', - ['\u{1e3d}', '\0', '\0']), ('\u{1e3e}', ['\u{1e3f}', '\0', '\0']), ('\u{1e40}', ['\u{1e41}', - '\0', '\0']), ('\u{1e42}', ['\u{1e43}', '\0', '\0']), ('\u{1e44}', ['\u{1e45}', '\0', - '\0']), ('\u{1e46}', ['\u{1e47}', '\0', '\0']), ('\u{1e48}', ['\u{1e49}', '\0', '\0']), - ('\u{1e4a}', ['\u{1e4b}', '\0', '\0']), ('\u{1e4c}', ['\u{1e4d}', '\0', '\0']), ('\u{1e4e}', - ['\u{1e4f}', '\0', '\0']), ('\u{1e50}', ['\u{1e51}', '\0', '\0']), ('\u{1e52}', ['\u{1e53}', - '\0', '\0']), ('\u{1e54}', ['\u{1e55}', '\0', '\0']), ('\u{1e56}', ['\u{1e57}', '\0', - '\0']), ('\u{1e58}', ['\u{1e59}', '\0', '\0']), ('\u{1e5a}', ['\u{1e5b}', '\0', '\0']), - ('\u{1e5c}', ['\u{1e5d}', '\0', '\0']), ('\u{1e5e}', ['\u{1e5f}', '\0', '\0']), ('\u{1e60}', - ['\u{1e61}', '\0', '\0']), ('\u{1e62}', ['\u{1e63}', '\0', '\0']), ('\u{1e64}', ['\u{1e65}', - '\0', '\0']), ('\u{1e66}', ['\u{1e67}', '\0', '\0']), ('\u{1e68}', ['\u{1e69}', '\0', - '\0']), ('\u{1e6a}', ['\u{1e6b}', '\0', '\0']), ('\u{1e6c}', ['\u{1e6d}', '\0', '\0']), - ('\u{1e6e}', ['\u{1e6f}', '\0', '\0']), ('\u{1e70}', ['\u{1e71}', '\0', '\0']), ('\u{1e72}', - ['\u{1e73}', '\0', '\0']), ('\u{1e74}', ['\u{1e75}', '\0', '\0']), ('\u{1e76}', ['\u{1e77}', - '\0', '\0']), ('\u{1e78}', ['\u{1e79}', '\0', '\0']), ('\u{1e7a}', ['\u{1e7b}', '\0', - '\0']), ('\u{1e7c}', ['\u{1e7d}', '\0', '\0']), ('\u{1e7e}', ['\u{1e7f}', '\0', '\0']), - ('\u{1e80}', ['\u{1e81}', '\0', '\0']), ('\u{1e82}', ['\u{1e83}', '\0', '\0']), ('\u{1e84}', - ['\u{1e85}', '\0', '\0']), ('\u{1e86}', ['\u{1e87}', '\0', '\0']), ('\u{1e88}', ['\u{1e89}', - '\0', '\0']), ('\u{1e8a}', ['\u{1e8b}', '\0', '\0']), ('\u{1e8c}', ['\u{1e8d}', '\0', - '\0']), ('\u{1e8e}', ['\u{1e8f}', '\0', '\0']), ('\u{1e90}', ['\u{1e91}', '\0', '\0']), - ('\u{1e92}', ['\u{1e93}', '\0', '\0']), ('\u{1e94}', ['\u{1e95}', '\0', '\0']), ('\u{1e9e}', - ['\u{df}', '\0', '\0']), ('\u{1ea0}', ['\u{1ea1}', '\0', '\0']), ('\u{1ea2}', ['\u{1ea3}', - '\0', '\0']), ('\u{1ea4}', ['\u{1ea5}', '\0', '\0']), ('\u{1ea6}', ['\u{1ea7}', '\0', - '\0']), ('\u{1ea8}', ['\u{1ea9}', '\0', '\0']), ('\u{1eaa}', ['\u{1eab}', '\0', '\0']), - ('\u{1eac}', ['\u{1ead}', '\0', '\0']), ('\u{1eae}', ['\u{1eaf}', '\0', '\0']), ('\u{1eb0}', - ['\u{1eb1}', '\0', '\0']), ('\u{1eb2}', ['\u{1eb3}', '\0', '\0']), ('\u{1eb4}', ['\u{1eb5}', - '\0', '\0']), ('\u{1eb6}', ['\u{1eb7}', '\0', '\0']), ('\u{1eb8}', ['\u{1eb9}', '\0', - '\0']), ('\u{1eba}', ['\u{1ebb}', '\0', '\0']), ('\u{1ebc}', ['\u{1ebd}', '\0', '\0']), - ('\u{1ebe}', ['\u{1ebf}', '\0', '\0']), ('\u{1ec0}', ['\u{1ec1}', '\0', '\0']), ('\u{1ec2}', - ['\u{1ec3}', '\0', '\0']), ('\u{1ec4}', ['\u{1ec5}', '\0', '\0']), ('\u{1ec6}', ['\u{1ec7}', - '\0', '\0']), ('\u{1ec8}', ['\u{1ec9}', '\0', '\0']), ('\u{1eca}', ['\u{1ecb}', '\0', - '\0']), ('\u{1ecc}', ['\u{1ecd}', '\0', '\0']), ('\u{1ece}', ['\u{1ecf}', '\0', '\0']), - ('\u{1ed0}', ['\u{1ed1}', '\0', '\0']), ('\u{1ed2}', ['\u{1ed3}', '\0', '\0']), ('\u{1ed4}', - ['\u{1ed5}', '\0', '\0']), ('\u{1ed6}', ['\u{1ed7}', '\0', '\0']), ('\u{1ed8}', ['\u{1ed9}', - '\0', '\0']), ('\u{1eda}', ['\u{1edb}', '\0', '\0']), ('\u{1edc}', ['\u{1edd}', '\0', - '\0']), ('\u{1ede}', ['\u{1edf}', '\0', '\0']), ('\u{1ee0}', ['\u{1ee1}', '\0', '\0']), - ('\u{1ee2}', ['\u{1ee3}', '\0', '\0']), ('\u{1ee4}', ['\u{1ee5}', '\0', '\0']), ('\u{1ee6}', - ['\u{1ee7}', '\0', '\0']), ('\u{1ee8}', ['\u{1ee9}', '\0', '\0']), ('\u{1eea}', ['\u{1eeb}', - '\0', '\0']), ('\u{1eec}', ['\u{1eed}', '\0', '\0']), ('\u{1eee}', ['\u{1eef}', '\0', - '\0']), ('\u{1ef0}', ['\u{1ef1}', '\0', '\0']), ('\u{1ef2}', ['\u{1ef3}', '\0', '\0']), - ('\u{1ef4}', ['\u{1ef5}', '\0', '\0']), ('\u{1ef6}', ['\u{1ef7}', '\0', '\0']), ('\u{1ef8}', - ['\u{1ef9}', '\0', '\0']), ('\u{1efa}', ['\u{1efb}', '\0', '\0']), ('\u{1efc}', ['\u{1efd}', - '\0', '\0']), ('\u{1efe}', ['\u{1eff}', '\0', '\0']), ('\u{1f08}', ['\u{1f00}', '\0', - '\0']), ('\u{1f09}', ['\u{1f01}', '\0', '\0']), ('\u{1f0a}', ['\u{1f02}', '\0', '\0']), - ('\u{1f0b}', ['\u{1f03}', '\0', '\0']), ('\u{1f0c}', ['\u{1f04}', '\0', '\0']), ('\u{1f0d}', - ['\u{1f05}', '\0', '\0']), ('\u{1f0e}', ['\u{1f06}', '\0', '\0']), ('\u{1f0f}', ['\u{1f07}', - '\0', '\0']), ('\u{1f18}', ['\u{1f10}', '\0', '\0']), ('\u{1f19}', ['\u{1f11}', '\0', - '\0']), ('\u{1f1a}', ['\u{1f12}', '\0', '\0']), ('\u{1f1b}', ['\u{1f13}', '\0', '\0']), - ('\u{1f1c}', ['\u{1f14}', '\0', '\0']), ('\u{1f1d}', ['\u{1f15}', '\0', '\0']), ('\u{1f28}', - ['\u{1f20}', '\0', '\0']), ('\u{1f29}', ['\u{1f21}', '\0', '\0']), ('\u{1f2a}', ['\u{1f22}', - '\0', '\0']), ('\u{1f2b}', ['\u{1f23}', '\0', '\0']), ('\u{1f2c}', ['\u{1f24}', '\0', - '\0']), ('\u{1f2d}', ['\u{1f25}', '\0', '\0']), ('\u{1f2e}', ['\u{1f26}', '\0', '\0']), - ('\u{1f2f}', ['\u{1f27}', '\0', '\0']), ('\u{1f38}', ['\u{1f30}', '\0', '\0']), ('\u{1f39}', - ['\u{1f31}', '\0', '\0']), ('\u{1f3a}', ['\u{1f32}', '\0', '\0']), ('\u{1f3b}', ['\u{1f33}', - '\0', '\0']), ('\u{1f3c}', ['\u{1f34}', '\0', '\0']), ('\u{1f3d}', ['\u{1f35}', '\0', - '\0']), ('\u{1f3e}', ['\u{1f36}', '\0', '\0']), ('\u{1f3f}', ['\u{1f37}', '\0', '\0']), - ('\u{1f48}', ['\u{1f40}', '\0', '\0']), ('\u{1f49}', ['\u{1f41}', '\0', '\0']), ('\u{1f4a}', - ['\u{1f42}', '\0', '\0']), ('\u{1f4b}', ['\u{1f43}', '\0', '\0']), ('\u{1f4c}', ['\u{1f44}', - '\0', '\0']), ('\u{1f4d}', ['\u{1f45}', '\0', '\0']), ('\u{1f59}', ['\u{1f51}', '\0', - '\0']), ('\u{1f5b}', ['\u{1f53}', '\0', '\0']), ('\u{1f5d}', ['\u{1f55}', '\0', '\0']), - ('\u{1f5f}', ['\u{1f57}', '\0', '\0']), ('\u{1f68}', ['\u{1f60}', '\0', '\0']), ('\u{1f69}', - ['\u{1f61}', '\0', '\0']), ('\u{1f6a}', ['\u{1f62}', '\0', '\0']), ('\u{1f6b}', ['\u{1f63}', - '\0', '\0']), ('\u{1f6c}', ['\u{1f64}', '\0', '\0']), ('\u{1f6d}', ['\u{1f65}', '\0', - '\0']), ('\u{1f6e}', ['\u{1f66}', '\0', '\0']), ('\u{1f6f}', ['\u{1f67}', '\0', '\0']), - ('\u{1f88}', ['\u{1f80}', '\0', '\0']), ('\u{1f89}', ['\u{1f81}', '\0', '\0']), ('\u{1f8a}', - ['\u{1f82}', '\0', '\0']), ('\u{1f8b}', ['\u{1f83}', '\0', '\0']), ('\u{1f8c}', ['\u{1f84}', - '\0', '\0']), ('\u{1f8d}', ['\u{1f85}', '\0', '\0']), ('\u{1f8e}', ['\u{1f86}', '\0', - '\0']), ('\u{1f8f}', ['\u{1f87}', '\0', '\0']), ('\u{1f98}', ['\u{1f90}', '\0', '\0']), - ('\u{1f99}', ['\u{1f91}', '\0', '\0']), ('\u{1f9a}', ['\u{1f92}', '\0', '\0']), ('\u{1f9b}', - ['\u{1f93}', '\0', '\0']), ('\u{1f9c}', ['\u{1f94}', '\0', '\0']), ('\u{1f9d}', ['\u{1f95}', - '\0', '\0']), ('\u{1f9e}', ['\u{1f96}', '\0', '\0']), ('\u{1f9f}', ['\u{1f97}', '\0', - '\0']), ('\u{1fa8}', ['\u{1fa0}', '\0', '\0']), ('\u{1fa9}', ['\u{1fa1}', '\0', '\0']), - ('\u{1faa}', ['\u{1fa2}', '\0', '\0']), ('\u{1fab}', ['\u{1fa3}', '\0', '\0']), ('\u{1fac}', - ['\u{1fa4}', '\0', '\0']), ('\u{1fad}', ['\u{1fa5}', '\0', '\0']), ('\u{1fae}', ['\u{1fa6}', - '\0', '\0']), ('\u{1faf}', ['\u{1fa7}', '\0', '\0']), ('\u{1fb8}', ['\u{1fb0}', '\0', - '\0']), ('\u{1fb9}', ['\u{1fb1}', '\0', '\0']), ('\u{1fba}', ['\u{1f70}', '\0', '\0']), - ('\u{1fbb}', ['\u{1f71}', '\0', '\0']), ('\u{1fbc}', ['\u{1fb3}', '\0', '\0']), ('\u{1fc8}', - ['\u{1f72}', '\0', '\0']), ('\u{1fc9}', ['\u{1f73}', '\0', '\0']), ('\u{1fca}', ['\u{1f74}', - '\0', '\0']), ('\u{1fcb}', ['\u{1f75}', '\0', '\0']), ('\u{1fcc}', ['\u{1fc3}', '\0', - '\0']), ('\u{1fd8}', ['\u{1fd0}', '\0', '\0']), ('\u{1fd9}', ['\u{1fd1}', '\0', '\0']), - ('\u{1fda}', ['\u{1f76}', '\0', '\0']), ('\u{1fdb}', ['\u{1f77}', '\0', '\0']), ('\u{1fe8}', - ['\u{1fe0}', '\0', '\0']), ('\u{1fe9}', ['\u{1fe1}', '\0', '\0']), ('\u{1fea}', ['\u{1f7a}', - '\0', '\0']), ('\u{1feb}', ['\u{1f7b}', '\0', '\0']), ('\u{1fec}', ['\u{1fe5}', '\0', - '\0']), ('\u{1ff8}', ['\u{1f78}', '\0', '\0']), ('\u{1ff9}', ['\u{1f79}', '\0', '\0']), - ('\u{1ffa}', ['\u{1f7c}', '\0', '\0']), ('\u{1ffb}', ['\u{1f7d}', '\0', '\0']), ('\u{1ffc}', - ['\u{1ff3}', '\0', '\0']), ('\u{2126}', ['\u{3c9}', '\0', '\0']), ('\u{212a}', ['\u{6b}', - '\0', '\0']), ('\u{212b}', ['\u{e5}', '\0', '\0']), ('\u{2132}', ['\u{214e}', '\0', '\0']), - ('\u{2160}', ['\u{2170}', '\0', '\0']), ('\u{2161}', ['\u{2171}', '\0', '\0']), ('\u{2162}', - ['\u{2172}', '\0', '\0']), ('\u{2163}', ['\u{2173}', '\0', '\0']), ('\u{2164}', ['\u{2174}', - '\0', '\0']), ('\u{2165}', ['\u{2175}', '\0', '\0']), ('\u{2166}', ['\u{2176}', '\0', - '\0']), ('\u{2167}', ['\u{2177}', '\0', '\0']), ('\u{2168}', ['\u{2178}', '\0', '\0']), - ('\u{2169}', ['\u{2179}', '\0', '\0']), ('\u{216a}', ['\u{217a}', '\0', '\0']), ('\u{216b}', - ['\u{217b}', '\0', '\0']), ('\u{216c}', ['\u{217c}', '\0', '\0']), ('\u{216d}', ['\u{217d}', - '\0', '\0']), ('\u{216e}', ['\u{217e}', '\0', '\0']), ('\u{216f}', ['\u{217f}', '\0', - '\0']), ('\u{2183}', ['\u{2184}', '\0', '\0']), ('\u{24b6}', ['\u{24d0}', '\0', '\0']), - ('\u{24b7}', ['\u{24d1}', '\0', '\0']), ('\u{24b8}', ['\u{24d2}', '\0', '\0']), ('\u{24b9}', - ['\u{24d3}', '\0', '\0']), ('\u{24ba}', ['\u{24d4}', '\0', '\0']), ('\u{24bb}', ['\u{24d5}', - '\0', '\0']), ('\u{24bc}', ['\u{24d6}', '\0', '\0']), ('\u{24bd}', ['\u{24d7}', '\0', - '\0']), ('\u{24be}', ['\u{24d8}', '\0', '\0']), ('\u{24bf}', ['\u{24d9}', '\0', '\0']), - ('\u{24c0}', ['\u{24da}', '\0', '\0']), ('\u{24c1}', ['\u{24db}', '\0', '\0']), ('\u{24c2}', - ['\u{24dc}', '\0', '\0']), ('\u{24c3}', ['\u{24dd}', '\0', '\0']), ('\u{24c4}', ['\u{24de}', - '\0', '\0']), ('\u{24c5}', ['\u{24df}', '\0', '\0']), ('\u{24c6}', ['\u{24e0}', '\0', - '\0']), ('\u{24c7}', ['\u{24e1}', '\0', '\0']), ('\u{24c8}', ['\u{24e2}', '\0', '\0']), - ('\u{24c9}', ['\u{24e3}', '\0', '\0']), ('\u{24ca}', ['\u{24e4}', '\0', '\0']), ('\u{24cb}', - ['\u{24e5}', '\0', '\0']), ('\u{24cc}', ['\u{24e6}', '\0', '\0']), ('\u{24cd}', ['\u{24e7}', - '\0', '\0']), ('\u{24ce}', ['\u{24e8}', '\0', '\0']), ('\u{24cf}', ['\u{24e9}', '\0', - '\0']), ('\u{2c00}', ['\u{2c30}', '\0', '\0']), ('\u{2c01}', ['\u{2c31}', '\0', '\0']), - ('\u{2c02}', ['\u{2c32}', '\0', '\0']), ('\u{2c03}', ['\u{2c33}', '\0', '\0']), ('\u{2c04}', - ['\u{2c34}', '\0', '\0']), ('\u{2c05}', ['\u{2c35}', '\0', '\0']), ('\u{2c06}', ['\u{2c36}', - '\0', '\0']), ('\u{2c07}', ['\u{2c37}', '\0', '\0']), ('\u{2c08}', ['\u{2c38}', '\0', - '\0']), ('\u{2c09}', ['\u{2c39}', '\0', '\0']), ('\u{2c0a}', ['\u{2c3a}', '\0', '\0']), - ('\u{2c0b}', ['\u{2c3b}', '\0', '\0']), ('\u{2c0c}', ['\u{2c3c}', '\0', '\0']), ('\u{2c0d}', - ['\u{2c3d}', '\0', '\0']), ('\u{2c0e}', ['\u{2c3e}', '\0', '\0']), ('\u{2c0f}', ['\u{2c3f}', - '\0', '\0']), ('\u{2c10}', ['\u{2c40}', '\0', '\0']), ('\u{2c11}', ['\u{2c41}', '\0', - '\0']), ('\u{2c12}', ['\u{2c42}', '\0', '\0']), ('\u{2c13}', ['\u{2c43}', '\0', '\0']), - ('\u{2c14}', ['\u{2c44}', '\0', '\0']), ('\u{2c15}', ['\u{2c45}', '\0', '\0']), ('\u{2c16}', - ['\u{2c46}', '\0', '\0']), ('\u{2c17}', ['\u{2c47}', '\0', '\0']), ('\u{2c18}', ['\u{2c48}', - '\0', '\0']), ('\u{2c19}', ['\u{2c49}', '\0', '\0']), ('\u{2c1a}', ['\u{2c4a}', '\0', - '\0']), ('\u{2c1b}', ['\u{2c4b}', '\0', '\0']), ('\u{2c1c}', ['\u{2c4c}', '\0', '\0']), - ('\u{2c1d}', ['\u{2c4d}', '\0', '\0']), ('\u{2c1e}', ['\u{2c4e}', '\0', '\0']), ('\u{2c1f}', - ['\u{2c4f}', '\0', '\0']), ('\u{2c20}', ['\u{2c50}', '\0', '\0']), ('\u{2c21}', ['\u{2c51}', - '\0', '\0']), ('\u{2c22}', ['\u{2c52}', '\0', '\0']), ('\u{2c23}', ['\u{2c53}', '\0', - '\0']), ('\u{2c24}', ['\u{2c54}', '\0', '\0']), ('\u{2c25}', ['\u{2c55}', '\0', '\0']), - ('\u{2c26}', ['\u{2c56}', '\0', '\0']), ('\u{2c27}', ['\u{2c57}', '\0', '\0']), ('\u{2c28}', - ['\u{2c58}', '\0', '\0']), ('\u{2c29}', ['\u{2c59}', '\0', '\0']), ('\u{2c2a}', ['\u{2c5a}', - '\0', '\0']), ('\u{2c2b}', ['\u{2c5b}', '\0', '\0']), ('\u{2c2c}', ['\u{2c5c}', '\0', - '\0']), ('\u{2c2d}', ['\u{2c5d}', '\0', '\0']), ('\u{2c2e}', ['\u{2c5e}', '\0', '\0']), - ('\u{2c60}', ['\u{2c61}', '\0', '\0']), ('\u{2c62}', ['\u{26b}', '\0', '\0']), ('\u{2c63}', - ['\u{1d7d}', '\0', '\0']), ('\u{2c64}', ['\u{27d}', '\0', '\0']), ('\u{2c67}', ['\u{2c68}', - '\0', '\0']), ('\u{2c69}', ['\u{2c6a}', '\0', '\0']), ('\u{2c6b}', ['\u{2c6c}', '\0', - '\0']), ('\u{2c6d}', ['\u{251}', '\0', '\0']), ('\u{2c6e}', ['\u{271}', '\0', '\0']), - ('\u{2c6f}', ['\u{250}', '\0', '\0']), ('\u{2c70}', ['\u{252}', '\0', '\0']), ('\u{2c72}', - ['\u{2c73}', '\0', '\0']), ('\u{2c75}', ['\u{2c76}', '\0', '\0']), ('\u{2c7e}', ['\u{23f}', - '\0', '\0']), ('\u{2c7f}', ['\u{240}', '\0', '\0']), ('\u{2c80}', ['\u{2c81}', '\0', '\0']), - ('\u{2c82}', ['\u{2c83}', '\0', '\0']), ('\u{2c84}', ['\u{2c85}', '\0', '\0']), ('\u{2c86}', - ['\u{2c87}', '\0', '\0']), ('\u{2c88}', ['\u{2c89}', '\0', '\0']), ('\u{2c8a}', ['\u{2c8b}', - '\0', '\0']), ('\u{2c8c}', ['\u{2c8d}', '\0', '\0']), ('\u{2c8e}', ['\u{2c8f}', '\0', - '\0']), ('\u{2c90}', ['\u{2c91}', '\0', '\0']), ('\u{2c92}', ['\u{2c93}', '\0', '\0']), - ('\u{2c94}', ['\u{2c95}', '\0', '\0']), ('\u{2c96}', ['\u{2c97}', '\0', '\0']), ('\u{2c98}', - ['\u{2c99}', '\0', '\0']), ('\u{2c9a}', ['\u{2c9b}', '\0', '\0']), ('\u{2c9c}', ['\u{2c9d}', - '\0', '\0']), ('\u{2c9e}', ['\u{2c9f}', '\0', '\0']), ('\u{2ca0}', ['\u{2ca1}', '\0', - '\0']), ('\u{2ca2}', ['\u{2ca3}', '\0', '\0']), ('\u{2ca4}', ['\u{2ca5}', '\0', '\0']), - ('\u{2ca6}', ['\u{2ca7}', '\0', '\0']), ('\u{2ca8}', ['\u{2ca9}', '\0', '\0']), ('\u{2caa}', - ['\u{2cab}', '\0', '\0']), ('\u{2cac}', ['\u{2cad}', '\0', '\0']), ('\u{2cae}', ['\u{2caf}', - '\0', '\0']), ('\u{2cb0}', ['\u{2cb1}', '\0', '\0']), ('\u{2cb2}', ['\u{2cb3}', '\0', - '\0']), ('\u{2cb4}', ['\u{2cb5}', '\0', '\0']), ('\u{2cb6}', ['\u{2cb7}', '\0', '\0']), - ('\u{2cb8}', ['\u{2cb9}', '\0', '\0']), ('\u{2cba}', ['\u{2cbb}', '\0', '\0']), ('\u{2cbc}', - ['\u{2cbd}', '\0', '\0']), ('\u{2cbe}', ['\u{2cbf}', '\0', '\0']), ('\u{2cc0}', ['\u{2cc1}', - '\0', '\0']), ('\u{2cc2}', ['\u{2cc3}', '\0', '\0']), ('\u{2cc4}', ['\u{2cc5}', '\0', - '\0']), ('\u{2cc6}', ['\u{2cc7}', '\0', '\0']), ('\u{2cc8}', ['\u{2cc9}', '\0', '\0']), - ('\u{2cca}', ['\u{2ccb}', '\0', '\0']), ('\u{2ccc}', ['\u{2ccd}', '\0', '\0']), ('\u{2cce}', - ['\u{2ccf}', '\0', '\0']), ('\u{2cd0}', ['\u{2cd1}', '\0', '\0']), ('\u{2cd2}', ['\u{2cd3}', - '\0', '\0']), ('\u{2cd4}', ['\u{2cd5}', '\0', '\0']), ('\u{2cd6}', ['\u{2cd7}', '\0', - '\0']), ('\u{2cd8}', ['\u{2cd9}', '\0', '\0']), ('\u{2cda}', ['\u{2cdb}', '\0', '\0']), - ('\u{2cdc}', ['\u{2cdd}', '\0', '\0']), ('\u{2cde}', ['\u{2cdf}', '\0', '\0']), ('\u{2ce0}', - ['\u{2ce1}', '\0', '\0']), ('\u{2ce2}', ['\u{2ce3}', '\0', '\0']), ('\u{2ceb}', ['\u{2cec}', - '\0', '\0']), ('\u{2ced}', ['\u{2cee}', '\0', '\0']), ('\u{2cf2}', ['\u{2cf3}', '\0', - '\0']), ('\u{a640}', ['\u{a641}', '\0', '\0']), ('\u{a642}', ['\u{a643}', '\0', '\0']), - ('\u{a644}', ['\u{a645}', '\0', '\0']), ('\u{a646}', ['\u{a647}', '\0', '\0']), ('\u{a648}', - ['\u{a649}', '\0', '\0']), ('\u{a64a}', ['\u{a64b}', '\0', '\0']), ('\u{a64c}', ['\u{a64d}', - '\0', '\0']), ('\u{a64e}', ['\u{a64f}', '\0', '\0']), ('\u{a650}', ['\u{a651}', '\0', - '\0']), ('\u{a652}', ['\u{a653}', '\0', '\0']), ('\u{a654}', ['\u{a655}', '\0', '\0']), - ('\u{a656}', ['\u{a657}', '\0', '\0']), ('\u{a658}', ['\u{a659}', '\0', '\0']), ('\u{a65a}', - ['\u{a65b}', '\0', '\0']), ('\u{a65c}', ['\u{a65d}', '\0', '\0']), ('\u{a65e}', ['\u{a65f}', - '\0', '\0']), ('\u{a660}', ['\u{a661}', '\0', '\0']), ('\u{a662}', ['\u{a663}', '\0', - '\0']), ('\u{a664}', ['\u{a665}', '\0', '\0']), ('\u{a666}', ['\u{a667}', '\0', '\0']), - ('\u{a668}', ['\u{a669}', '\0', '\0']), ('\u{a66a}', ['\u{a66b}', '\0', '\0']), ('\u{a66c}', - ['\u{a66d}', '\0', '\0']), ('\u{a680}', ['\u{a681}', '\0', '\0']), ('\u{a682}', ['\u{a683}', - '\0', '\0']), ('\u{a684}', ['\u{a685}', '\0', '\0']), ('\u{a686}', ['\u{a687}', '\0', - '\0']), ('\u{a688}', ['\u{a689}', '\0', '\0']), ('\u{a68a}', ['\u{a68b}', '\0', '\0']), - ('\u{a68c}', ['\u{a68d}', '\0', '\0']), ('\u{a68e}', ['\u{a68f}', '\0', '\0']), ('\u{a690}', - ['\u{a691}', '\0', '\0']), ('\u{a692}', ['\u{a693}', '\0', '\0']), ('\u{a694}', ['\u{a695}', - '\0', '\0']), ('\u{a696}', ['\u{a697}', '\0', '\0']), ('\u{a698}', ['\u{a699}', '\0', - '\0']), ('\u{a69a}', ['\u{a69b}', '\0', '\0']), ('\u{a722}', ['\u{a723}', '\0', '\0']), - ('\u{a724}', ['\u{a725}', '\0', '\0']), ('\u{a726}', ['\u{a727}', '\0', '\0']), ('\u{a728}', - ['\u{a729}', '\0', '\0']), ('\u{a72a}', ['\u{a72b}', '\0', '\0']), ('\u{a72c}', ['\u{a72d}', - '\0', '\0']), ('\u{a72e}', ['\u{a72f}', '\0', '\0']), ('\u{a732}', ['\u{a733}', '\0', - '\0']), ('\u{a734}', ['\u{a735}', '\0', '\0']), ('\u{a736}', ['\u{a737}', '\0', '\0']), - ('\u{a738}', ['\u{a739}', '\0', '\0']), ('\u{a73a}', ['\u{a73b}', '\0', '\0']), ('\u{a73c}', - ['\u{a73d}', '\0', '\0']), ('\u{a73e}', ['\u{a73f}', '\0', '\0']), ('\u{a740}', ['\u{a741}', - '\0', '\0']), ('\u{a742}', ['\u{a743}', '\0', '\0']), ('\u{a744}', ['\u{a745}', '\0', - '\0']), ('\u{a746}', ['\u{a747}', '\0', '\0']), ('\u{a748}', ['\u{a749}', '\0', '\0']), - ('\u{a74a}', ['\u{a74b}', '\0', '\0']), ('\u{a74c}', ['\u{a74d}', '\0', '\0']), ('\u{a74e}', - ['\u{a74f}', '\0', '\0']), ('\u{a750}', ['\u{a751}', '\0', '\0']), ('\u{a752}', ['\u{a753}', - '\0', '\0']), ('\u{a754}', ['\u{a755}', '\0', '\0']), ('\u{a756}', ['\u{a757}', '\0', - '\0']), ('\u{a758}', ['\u{a759}', '\0', '\0']), ('\u{a75a}', ['\u{a75b}', '\0', '\0']), - ('\u{a75c}', ['\u{a75d}', '\0', '\0']), ('\u{a75e}', ['\u{a75f}', '\0', '\0']), ('\u{a760}', - ['\u{a761}', '\0', '\0']), ('\u{a762}', ['\u{a763}', '\0', '\0']), ('\u{a764}', ['\u{a765}', - '\0', '\0']), ('\u{a766}', ['\u{a767}', '\0', '\0']), ('\u{a768}', ['\u{a769}', '\0', - '\0']), ('\u{a76a}', ['\u{a76b}', '\0', '\0']), ('\u{a76c}', ['\u{a76d}', '\0', '\0']), - ('\u{a76e}', ['\u{a76f}', '\0', '\0']), ('\u{a779}', ['\u{a77a}', '\0', '\0']), ('\u{a77b}', - ['\u{a77c}', '\0', '\0']), ('\u{a77d}', ['\u{1d79}', '\0', '\0']), ('\u{a77e}', ['\u{a77f}', - '\0', '\0']), ('\u{a780}', ['\u{a781}', '\0', '\0']), ('\u{a782}', ['\u{a783}', '\0', - '\0']), ('\u{a784}', ['\u{a785}', '\0', '\0']), ('\u{a786}', ['\u{a787}', '\0', '\0']), - ('\u{a78b}', ['\u{a78c}', '\0', '\0']), ('\u{a78d}', ['\u{265}', '\0', '\0']), ('\u{a790}', - ['\u{a791}', '\0', '\0']), ('\u{a792}', ['\u{a793}', '\0', '\0']), ('\u{a796}', ['\u{a797}', - '\0', '\0']), ('\u{a798}', ['\u{a799}', '\0', '\0']), ('\u{a79a}', ['\u{a79b}', '\0', - '\0']), ('\u{a79c}', ['\u{a79d}', '\0', '\0']), ('\u{a79e}', ['\u{a79f}', '\0', '\0']), - ('\u{a7a0}', ['\u{a7a1}', '\0', '\0']), ('\u{a7a2}', ['\u{a7a3}', '\0', '\0']), ('\u{a7a4}', - ['\u{a7a5}', '\0', '\0']), ('\u{a7a6}', ['\u{a7a7}', '\0', '\0']), ('\u{a7a8}', ['\u{a7a9}', - '\0', '\0']), ('\u{a7aa}', ['\u{266}', '\0', '\0']), ('\u{a7ab}', ['\u{25c}', '\0', '\0']), - ('\u{a7ac}', ['\u{261}', '\0', '\0']), ('\u{a7ad}', ['\u{26c}', '\0', '\0']), ('\u{a7ae}', - ['\u{26a}', '\0', '\0']), ('\u{a7b0}', ['\u{29e}', '\0', '\0']), ('\u{a7b1}', ['\u{287}', - '\0', '\0']), ('\u{a7b2}', ['\u{29d}', '\0', '\0']), ('\u{a7b3}', ['\u{ab53}', '\0', '\0']), - ('\u{a7b4}', ['\u{a7b5}', '\0', '\0']), ('\u{a7b6}', ['\u{a7b7}', '\0', '\0']), ('\u{ff21}', - ['\u{ff41}', '\0', '\0']), ('\u{ff22}', ['\u{ff42}', '\0', '\0']), ('\u{ff23}', ['\u{ff43}', - '\0', '\0']), ('\u{ff24}', ['\u{ff44}', '\0', '\0']), ('\u{ff25}', ['\u{ff45}', '\0', - '\0']), ('\u{ff26}', ['\u{ff46}', '\0', '\0']), ('\u{ff27}', ['\u{ff47}', '\0', '\0']), - ('\u{ff28}', ['\u{ff48}', '\0', '\0']), ('\u{ff29}', ['\u{ff49}', '\0', '\0']), ('\u{ff2a}', - ['\u{ff4a}', '\0', '\0']), ('\u{ff2b}', ['\u{ff4b}', '\0', '\0']), ('\u{ff2c}', ['\u{ff4c}', - '\0', '\0']), ('\u{ff2d}', ['\u{ff4d}', '\0', '\0']), ('\u{ff2e}', ['\u{ff4e}', '\0', - '\0']), ('\u{ff2f}', ['\u{ff4f}', '\0', '\0']), ('\u{ff30}', ['\u{ff50}', '\0', '\0']), - ('\u{ff31}', ['\u{ff51}', '\0', '\0']), ('\u{ff32}', ['\u{ff52}', '\0', '\0']), ('\u{ff33}', - ['\u{ff53}', '\0', '\0']), ('\u{ff34}', ['\u{ff54}', '\0', '\0']), ('\u{ff35}', ['\u{ff55}', - '\0', '\0']), ('\u{ff36}', ['\u{ff56}', '\0', '\0']), ('\u{ff37}', ['\u{ff57}', '\0', - '\0']), ('\u{ff38}', ['\u{ff58}', '\0', '\0']), ('\u{ff39}', ['\u{ff59}', '\0', '\0']), - ('\u{ff3a}', ['\u{ff5a}', '\0', '\0']), ('\u{10400}', ['\u{10428}', '\0', '\0']), - ('\u{10401}', ['\u{10429}', '\0', '\0']), ('\u{10402}', ['\u{1042a}', '\0', '\0']), - ('\u{10403}', ['\u{1042b}', '\0', '\0']), ('\u{10404}', ['\u{1042c}', '\0', '\0']), - ('\u{10405}', ['\u{1042d}', '\0', '\0']), ('\u{10406}', ['\u{1042e}', '\0', '\0']), - ('\u{10407}', ['\u{1042f}', '\0', '\0']), ('\u{10408}', ['\u{10430}', '\0', '\0']), - ('\u{10409}', ['\u{10431}', '\0', '\0']), ('\u{1040a}', ['\u{10432}', '\0', '\0']), - ('\u{1040b}', ['\u{10433}', '\0', '\0']), ('\u{1040c}', ['\u{10434}', '\0', '\0']), - ('\u{1040d}', ['\u{10435}', '\0', '\0']), ('\u{1040e}', ['\u{10436}', '\0', '\0']), - ('\u{1040f}', ['\u{10437}', '\0', '\0']), ('\u{10410}', ['\u{10438}', '\0', '\0']), - ('\u{10411}', ['\u{10439}', '\0', '\0']), ('\u{10412}', ['\u{1043a}', '\0', '\0']), - ('\u{10413}', ['\u{1043b}', '\0', '\0']), ('\u{10414}', ['\u{1043c}', '\0', '\0']), - ('\u{10415}', ['\u{1043d}', '\0', '\0']), ('\u{10416}', ['\u{1043e}', '\0', '\0']), - ('\u{10417}', ['\u{1043f}', '\0', '\0']), ('\u{10418}', ['\u{10440}', '\0', '\0']), - ('\u{10419}', ['\u{10441}', '\0', '\0']), ('\u{1041a}', ['\u{10442}', '\0', '\0']), - ('\u{1041b}', ['\u{10443}', '\0', '\0']), ('\u{1041c}', ['\u{10444}', '\0', '\0']), - ('\u{1041d}', ['\u{10445}', '\0', '\0']), ('\u{1041e}', ['\u{10446}', '\0', '\0']), - ('\u{1041f}', ['\u{10447}', '\0', '\0']), ('\u{10420}', ['\u{10448}', '\0', '\0']), - ('\u{10421}', ['\u{10449}', '\0', '\0']), ('\u{10422}', ['\u{1044a}', '\0', '\0']), - ('\u{10423}', ['\u{1044b}', '\0', '\0']), ('\u{10424}', ['\u{1044c}', '\0', '\0']), - ('\u{10425}', ['\u{1044d}', '\0', '\0']), ('\u{10426}', ['\u{1044e}', '\0', '\0']), - ('\u{10427}', ['\u{1044f}', '\0', '\0']), ('\u{104b0}', ['\u{104d8}', '\0', '\0']), - ('\u{104b1}', ['\u{104d9}', '\0', '\0']), ('\u{104b2}', ['\u{104da}', '\0', '\0']), - ('\u{104b3}', ['\u{104db}', '\0', '\0']), ('\u{104b4}', ['\u{104dc}', '\0', '\0']), - ('\u{104b5}', ['\u{104dd}', '\0', '\0']), ('\u{104b6}', ['\u{104de}', '\0', '\0']), - ('\u{104b7}', ['\u{104df}', '\0', '\0']), ('\u{104b8}', ['\u{104e0}', '\0', '\0']), - ('\u{104b9}', ['\u{104e1}', '\0', '\0']), ('\u{104ba}', ['\u{104e2}', '\0', '\0']), - ('\u{104bb}', ['\u{104e3}', '\0', '\0']), ('\u{104bc}', ['\u{104e4}', '\0', '\0']), - ('\u{104bd}', ['\u{104e5}', '\0', '\0']), ('\u{104be}', ['\u{104e6}', '\0', '\0']), - ('\u{104bf}', ['\u{104e7}', '\0', '\0']), ('\u{104c0}', ['\u{104e8}', '\0', '\0']), - ('\u{104c1}', ['\u{104e9}', '\0', '\0']), ('\u{104c2}', ['\u{104ea}', '\0', '\0']), - ('\u{104c3}', ['\u{104eb}', '\0', '\0']), ('\u{104c4}', ['\u{104ec}', '\0', '\0']), - ('\u{104c5}', ['\u{104ed}', '\0', '\0']), ('\u{104c6}', ['\u{104ee}', '\0', '\0']), - ('\u{104c7}', ['\u{104ef}', '\0', '\0']), ('\u{104c8}', ['\u{104f0}', '\0', '\0']), - ('\u{104c9}', ['\u{104f1}', '\0', '\0']), ('\u{104ca}', ['\u{104f2}', '\0', '\0']), - ('\u{104cb}', ['\u{104f3}', '\0', '\0']), ('\u{104cc}', ['\u{104f4}', '\0', '\0']), - ('\u{104cd}', ['\u{104f5}', '\0', '\0']), ('\u{104ce}', ['\u{104f6}', '\0', '\0']), - ('\u{104cf}', ['\u{104f7}', '\0', '\0']), ('\u{104d0}', ['\u{104f8}', '\0', '\0']), - ('\u{104d1}', ['\u{104f9}', '\0', '\0']), ('\u{104d2}', ['\u{104fa}', '\0', '\0']), - ('\u{104d3}', ['\u{104fb}', '\0', '\0']), ('\u{10c80}', ['\u{10cc0}', '\0', '\0']), - ('\u{10c81}', ['\u{10cc1}', '\0', '\0']), ('\u{10c82}', ['\u{10cc2}', '\0', '\0']), - ('\u{10c83}', ['\u{10cc3}', '\0', '\0']), ('\u{10c84}', ['\u{10cc4}', '\0', '\0']), - ('\u{10c85}', ['\u{10cc5}', '\0', '\0']), ('\u{10c86}', ['\u{10cc6}', '\0', '\0']), - ('\u{10c87}', ['\u{10cc7}', '\0', '\0']), ('\u{10c88}', ['\u{10cc8}', '\0', '\0']), - ('\u{10c89}', ['\u{10cc9}', '\0', '\0']), ('\u{10c8a}', ['\u{10cca}', '\0', '\0']), - ('\u{10c8b}', ['\u{10ccb}', '\0', '\0']), ('\u{10c8c}', ['\u{10ccc}', '\0', '\0']), - ('\u{10c8d}', ['\u{10ccd}', '\0', '\0']), ('\u{10c8e}', ['\u{10cce}', '\0', '\0']), - ('\u{10c8f}', ['\u{10ccf}', '\0', '\0']), ('\u{10c90}', ['\u{10cd0}', '\0', '\0']), - ('\u{10c91}', ['\u{10cd1}', '\0', '\0']), ('\u{10c92}', ['\u{10cd2}', '\0', '\0']), - ('\u{10c93}', ['\u{10cd3}', '\0', '\0']), ('\u{10c94}', ['\u{10cd4}', '\0', '\0']), - ('\u{10c95}', ['\u{10cd5}', '\0', '\0']), ('\u{10c96}', ['\u{10cd6}', '\0', '\0']), - ('\u{10c97}', ['\u{10cd7}', '\0', '\0']), ('\u{10c98}', ['\u{10cd8}', '\0', '\0']), - ('\u{10c99}', ['\u{10cd9}', '\0', '\0']), ('\u{10c9a}', ['\u{10cda}', '\0', '\0']), - ('\u{10c9b}', ['\u{10cdb}', '\0', '\0']), ('\u{10c9c}', ['\u{10cdc}', '\0', '\0']), - ('\u{10c9d}', ['\u{10cdd}', '\0', '\0']), ('\u{10c9e}', ['\u{10cde}', '\0', '\0']), - ('\u{10c9f}', ['\u{10cdf}', '\0', '\0']), ('\u{10ca0}', ['\u{10ce0}', '\0', '\0']), - ('\u{10ca1}', ['\u{10ce1}', '\0', '\0']), ('\u{10ca2}', ['\u{10ce2}', '\0', '\0']), - ('\u{10ca3}', ['\u{10ce3}', '\0', '\0']), ('\u{10ca4}', ['\u{10ce4}', '\0', '\0']), - ('\u{10ca5}', ['\u{10ce5}', '\0', '\0']), ('\u{10ca6}', ['\u{10ce6}', '\0', '\0']), - ('\u{10ca7}', ['\u{10ce7}', '\0', '\0']), ('\u{10ca8}', ['\u{10ce8}', '\0', '\0']), - ('\u{10ca9}', ['\u{10ce9}', '\0', '\0']), ('\u{10caa}', ['\u{10cea}', '\0', '\0']), - ('\u{10cab}', ['\u{10ceb}', '\0', '\0']), ('\u{10cac}', ['\u{10cec}', '\0', '\0']), - ('\u{10cad}', ['\u{10ced}', '\0', '\0']), ('\u{10cae}', ['\u{10cee}', '\0', '\0']), - ('\u{10caf}', ['\u{10cef}', '\0', '\0']), ('\u{10cb0}', ['\u{10cf0}', '\0', '\0']), - ('\u{10cb1}', ['\u{10cf1}', '\0', '\0']), ('\u{10cb2}', ['\u{10cf2}', '\0', '\0']), - ('\u{118a0}', ['\u{118c0}', '\0', '\0']), ('\u{118a1}', ['\u{118c1}', '\0', '\0']), - ('\u{118a2}', ['\u{118c2}', '\0', '\0']), ('\u{118a3}', ['\u{118c3}', '\0', '\0']), - ('\u{118a4}', ['\u{118c4}', '\0', '\0']), ('\u{118a5}', ['\u{118c5}', '\0', '\0']), - ('\u{118a6}', ['\u{118c6}', '\0', '\0']), ('\u{118a7}', ['\u{118c7}', '\0', '\0']), - ('\u{118a8}', ['\u{118c8}', '\0', '\0']), ('\u{118a9}', ['\u{118c9}', '\0', '\0']), - ('\u{118aa}', ['\u{118ca}', '\0', '\0']), ('\u{118ab}', ['\u{118cb}', '\0', '\0']), - ('\u{118ac}', ['\u{118cc}', '\0', '\0']), ('\u{118ad}', ['\u{118cd}', '\0', '\0']), - ('\u{118ae}', ['\u{118ce}', '\0', '\0']), ('\u{118af}', ['\u{118cf}', '\0', '\0']), - ('\u{118b0}', ['\u{118d0}', '\0', '\0']), ('\u{118b1}', ['\u{118d1}', '\0', '\0']), - ('\u{118b2}', ['\u{118d2}', '\0', '\0']), ('\u{118b3}', ['\u{118d3}', '\0', '\0']), - ('\u{118b4}', ['\u{118d4}', '\0', '\0']), ('\u{118b5}', ['\u{118d5}', '\0', '\0']), - ('\u{118b6}', ['\u{118d6}', '\0', '\0']), ('\u{118b7}', ['\u{118d7}', '\0', '\0']), - ('\u{118b8}', ['\u{118d8}', '\0', '\0']), ('\u{118b9}', ['\u{118d9}', '\0', '\0']), - ('\u{118ba}', ['\u{118da}', '\0', '\0']), ('\u{118bb}', ['\u{118db}', '\0', '\0']), - ('\u{118bc}', ['\u{118dc}', '\0', '\0']), ('\u{118bd}', ['\u{118dd}', '\0', '\0']), - ('\u{118be}', ['\u{118de}', '\0', '\0']), ('\u{118bf}', ['\u{118df}', '\0', '\0']), - ('\u{1e900}', ['\u{1e922}', '\0', '\0']), ('\u{1e901}', ['\u{1e923}', '\0', '\0']), - ('\u{1e902}', ['\u{1e924}', '\0', '\0']), ('\u{1e903}', ['\u{1e925}', '\0', '\0']), - ('\u{1e904}', ['\u{1e926}', '\0', '\0']), ('\u{1e905}', ['\u{1e927}', '\0', '\0']), - ('\u{1e906}', ['\u{1e928}', '\0', '\0']), ('\u{1e907}', ['\u{1e929}', '\0', '\0']), - ('\u{1e908}', ['\u{1e92a}', '\0', '\0']), ('\u{1e909}', ['\u{1e92b}', '\0', '\0']), - ('\u{1e90a}', ['\u{1e92c}', '\0', '\0']), ('\u{1e90b}', ['\u{1e92d}', '\0', '\0']), - ('\u{1e90c}', ['\u{1e92e}', '\0', '\0']), ('\u{1e90d}', ['\u{1e92f}', '\0', '\0']), - ('\u{1e90e}', ['\u{1e930}', '\0', '\0']), ('\u{1e90f}', ['\u{1e931}', '\0', '\0']), - ('\u{1e910}', ['\u{1e932}', '\0', '\0']), ('\u{1e911}', ['\u{1e933}', '\0', '\0']), - ('\u{1e912}', ['\u{1e934}', '\0', '\0']), ('\u{1e913}', ['\u{1e935}', '\0', '\0']), - ('\u{1e914}', ['\u{1e936}', '\0', '\0']), ('\u{1e915}', ['\u{1e937}', '\0', '\0']), - ('\u{1e916}', ['\u{1e938}', '\0', '\0']), ('\u{1e917}', ['\u{1e939}', '\0', '\0']), - ('\u{1e918}', ['\u{1e93a}', '\0', '\0']), ('\u{1e919}', ['\u{1e93b}', '\0', '\0']), - ('\u{1e91a}', ['\u{1e93c}', '\0', '\0']), ('\u{1e91b}', ['\u{1e93d}', '\0', '\0']), - ('\u{1e91c}', ['\u{1e93e}', '\0', '\0']), ('\u{1e91d}', ['\u{1e93f}', '\0', '\0']), - ('\u{1e91e}', ['\u{1e940}', '\0', '\0']), ('\u{1e91f}', ['\u{1e941}', '\0', '\0']), - ('\u{1e920}', ['\u{1e942}', '\0', '\0']), ('\u{1e921}', ['\u{1e943}', '\0', '\0']) - ]; - - const to_uppercase_table: &[(char, [char; 3])] = &[ - ('\u{61}', ['\u{41}', '\0', '\0']), ('\u{62}', ['\u{42}', '\0', '\0']), ('\u{63}', - ['\u{43}', '\0', '\0']), ('\u{64}', ['\u{44}', '\0', '\0']), ('\u{65}', ['\u{45}', '\0', - '\0']), ('\u{66}', ['\u{46}', '\0', '\0']), ('\u{67}', ['\u{47}', '\0', '\0']), ('\u{68}', - ['\u{48}', '\0', '\0']), ('\u{69}', ['\u{49}', '\0', '\0']), ('\u{6a}', ['\u{4a}', '\0', - '\0']), ('\u{6b}', ['\u{4b}', '\0', '\0']), ('\u{6c}', ['\u{4c}', '\0', '\0']), ('\u{6d}', - ['\u{4d}', '\0', '\0']), ('\u{6e}', ['\u{4e}', '\0', '\0']), ('\u{6f}', ['\u{4f}', '\0', - '\0']), ('\u{70}', ['\u{50}', '\0', '\0']), ('\u{71}', ['\u{51}', '\0', '\0']), ('\u{72}', - ['\u{52}', '\0', '\0']), ('\u{73}', ['\u{53}', '\0', '\0']), ('\u{74}', ['\u{54}', '\0', - '\0']), ('\u{75}', ['\u{55}', '\0', '\0']), ('\u{76}', ['\u{56}', '\0', '\0']), ('\u{77}', - ['\u{57}', '\0', '\0']), ('\u{78}', ['\u{58}', '\0', '\0']), ('\u{79}', ['\u{59}', '\0', - '\0']), ('\u{7a}', ['\u{5a}', '\0', '\0']), ('\u{b5}', ['\u{39c}', '\0', '\0']), ('\u{df}', - ['\u{53}', '\u{53}', '\0']), ('\u{e0}', ['\u{c0}', '\0', '\0']), ('\u{e1}', ['\u{c1}', '\0', - '\0']), ('\u{e2}', ['\u{c2}', '\0', '\0']), ('\u{e3}', ['\u{c3}', '\0', '\0']), ('\u{e4}', - ['\u{c4}', '\0', '\0']), ('\u{e5}', ['\u{c5}', '\0', '\0']), ('\u{e6}', ['\u{c6}', '\0', - '\0']), ('\u{e7}', ['\u{c7}', '\0', '\0']), ('\u{e8}', ['\u{c8}', '\0', '\0']), ('\u{e9}', - ['\u{c9}', '\0', '\0']), ('\u{ea}', ['\u{ca}', '\0', '\0']), ('\u{eb}', ['\u{cb}', '\0', - '\0']), ('\u{ec}', ['\u{cc}', '\0', '\0']), ('\u{ed}', ['\u{cd}', '\0', '\0']), ('\u{ee}', - ['\u{ce}', '\0', '\0']), ('\u{ef}', ['\u{cf}', '\0', '\0']), ('\u{f0}', ['\u{d0}', '\0', - '\0']), ('\u{f1}', ['\u{d1}', '\0', '\0']), ('\u{f2}', ['\u{d2}', '\0', '\0']), ('\u{f3}', - ['\u{d3}', '\0', '\0']), ('\u{f4}', ['\u{d4}', '\0', '\0']), ('\u{f5}', ['\u{d5}', '\0', - '\0']), ('\u{f6}', ['\u{d6}', '\0', '\0']), ('\u{f8}', ['\u{d8}', '\0', '\0']), ('\u{f9}', - ['\u{d9}', '\0', '\0']), ('\u{fa}', ['\u{da}', '\0', '\0']), ('\u{fb}', ['\u{db}', '\0', - '\0']), ('\u{fc}', ['\u{dc}', '\0', '\0']), ('\u{fd}', ['\u{dd}', '\0', '\0']), ('\u{fe}', - ['\u{de}', '\0', '\0']), ('\u{ff}', ['\u{178}', '\0', '\0']), ('\u{101}', ['\u{100}', '\0', - '\0']), ('\u{103}', ['\u{102}', '\0', '\0']), ('\u{105}', ['\u{104}', '\0', '\0']), - ('\u{107}', ['\u{106}', '\0', '\0']), ('\u{109}', ['\u{108}', '\0', '\0']), ('\u{10b}', - ['\u{10a}', '\0', '\0']), ('\u{10d}', ['\u{10c}', '\0', '\0']), ('\u{10f}', ['\u{10e}', - '\0', '\0']), ('\u{111}', ['\u{110}', '\0', '\0']), ('\u{113}', ['\u{112}', '\0', '\0']), - ('\u{115}', ['\u{114}', '\0', '\0']), ('\u{117}', ['\u{116}', '\0', '\0']), ('\u{119}', - ['\u{118}', '\0', '\0']), ('\u{11b}', ['\u{11a}', '\0', '\0']), ('\u{11d}', ['\u{11c}', - '\0', '\0']), ('\u{11f}', ['\u{11e}', '\0', '\0']), ('\u{121}', ['\u{120}', '\0', '\0']), - ('\u{123}', ['\u{122}', '\0', '\0']), ('\u{125}', ['\u{124}', '\0', '\0']), ('\u{127}', - ['\u{126}', '\0', '\0']), ('\u{129}', ['\u{128}', '\0', '\0']), ('\u{12b}', ['\u{12a}', - '\0', '\0']), ('\u{12d}', ['\u{12c}', '\0', '\0']), ('\u{12f}', ['\u{12e}', '\0', '\0']), - ('\u{131}', ['\u{49}', '\0', '\0']), ('\u{133}', ['\u{132}', '\0', '\0']), ('\u{135}', - ['\u{134}', '\0', '\0']), ('\u{137}', ['\u{136}', '\0', '\0']), ('\u{13a}', ['\u{139}', - '\0', '\0']), ('\u{13c}', ['\u{13b}', '\0', '\0']), ('\u{13e}', ['\u{13d}', '\0', '\0']), - ('\u{140}', ['\u{13f}', '\0', '\0']), ('\u{142}', ['\u{141}', '\0', '\0']), ('\u{144}', - ['\u{143}', '\0', '\0']), ('\u{146}', ['\u{145}', '\0', '\0']), ('\u{148}', ['\u{147}', - '\0', '\0']), ('\u{149}', ['\u{2bc}', '\u{4e}', '\0']), ('\u{14b}', ['\u{14a}', '\0', - '\0']), ('\u{14d}', ['\u{14c}', '\0', '\0']), ('\u{14f}', ['\u{14e}', '\0', '\0']), - ('\u{151}', ['\u{150}', '\0', '\0']), ('\u{153}', ['\u{152}', '\0', '\0']), ('\u{155}', - ['\u{154}', '\0', '\0']), ('\u{157}', ['\u{156}', '\0', '\0']), ('\u{159}', ['\u{158}', - '\0', '\0']), ('\u{15b}', ['\u{15a}', '\0', '\0']), ('\u{15d}', ['\u{15c}', '\0', '\0']), - ('\u{15f}', ['\u{15e}', '\0', '\0']), ('\u{161}', ['\u{160}', '\0', '\0']), ('\u{163}', - ['\u{162}', '\0', '\0']), ('\u{165}', ['\u{164}', '\0', '\0']), ('\u{167}', ['\u{166}', - '\0', '\0']), ('\u{169}', ['\u{168}', '\0', '\0']), ('\u{16b}', ['\u{16a}', '\0', '\0']), - ('\u{16d}', ['\u{16c}', '\0', '\0']), ('\u{16f}', ['\u{16e}', '\0', '\0']), ('\u{171}', - ['\u{170}', '\0', '\0']), ('\u{173}', ['\u{172}', '\0', '\0']), ('\u{175}', ['\u{174}', - '\0', '\0']), ('\u{177}', ['\u{176}', '\0', '\0']), ('\u{17a}', ['\u{179}', '\0', '\0']), - ('\u{17c}', ['\u{17b}', '\0', '\0']), ('\u{17e}', ['\u{17d}', '\0', '\0']), ('\u{17f}', - ['\u{53}', '\0', '\0']), ('\u{180}', ['\u{243}', '\0', '\0']), ('\u{183}', ['\u{182}', '\0', - '\0']), ('\u{185}', ['\u{184}', '\0', '\0']), ('\u{188}', ['\u{187}', '\0', '\0']), - ('\u{18c}', ['\u{18b}', '\0', '\0']), ('\u{192}', ['\u{191}', '\0', '\0']), ('\u{195}', - ['\u{1f6}', '\0', '\0']), ('\u{199}', ['\u{198}', '\0', '\0']), ('\u{19a}', ['\u{23d}', - '\0', '\0']), ('\u{19e}', ['\u{220}', '\0', '\0']), ('\u{1a1}', ['\u{1a0}', '\0', '\0']), - ('\u{1a3}', ['\u{1a2}', '\0', '\0']), ('\u{1a5}', ['\u{1a4}', '\0', '\0']), ('\u{1a8}', - ['\u{1a7}', '\0', '\0']), ('\u{1ad}', ['\u{1ac}', '\0', '\0']), ('\u{1b0}', ['\u{1af}', - '\0', '\0']), ('\u{1b4}', ['\u{1b3}', '\0', '\0']), ('\u{1b6}', ['\u{1b5}', '\0', '\0']), - ('\u{1b9}', ['\u{1b8}', '\0', '\0']), ('\u{1bd}', ['\u{1bc}', '\0', '\0']), ('\u{1bf}', - ['\u{1f7}', '\0', '\0']), ('\u{1c5}', ['\u{1c4}', '\0', '\0']), ('\u{1c6}', ['\u{1c4}', - '\0', '\0']), ('\u{1c8}', ['\u{1c7}', '\0', '\0']), ('\u{1c9}', ['\u{1c7}', '\0', '\0']), - ('\u{1cb}', ['\u{1ca}', '\0', '\0']), ('\u{1cc}', ['\u{1ca}', '\0', '\0']), ('\u{1ce}', - ['\u{1cd}', '\0', '\0']), ('\u{1d0}', ['\u{1cf}', '\0', '\0']), ('\u{1d2}', ['\u{1d1}', - '\0', '\0']), ('\u{1d4}', ['\u{1d3}', '\0', '\0']), ('\u{1d6}', ['\u{1d5}', '\0', '\0']), - ('\u{1d8}', ['\u{1d7}', '\0', '\0']), ('\u{1da}', ['\u{1d9}', '\0', '\0']), ('\u{1dc}', - ['\u{1db}', '\0', '\0']), ('\u{1dd}', ['\u{18e}', '\0', '\0']), ('\u{1df}', ['\u{1de}', - '\0', '\0']), ('\u{1e1}', ['\u{1e0}', '\0', '\0']), ('\u{1e3}', ['\u{1e2}', '\0', '\0']), - ('\u{1e5}', ['\u{1e4}', '\0', '\0']), ('\u{1e7}', ['\u{1e6}', '\0', '\0']), ('\u{1e9}', - ['\u{1e8}', '\0', '\0']), ('\u{1eb}', ['\u{1ea}', '\0', '\0']), ('\u{1ed}', ['\u{1ec}', - '\0', '\0']), ('\u{1ef}', ['\u{1ee}', '\0', '\0']), ('\u{1f0}', ['\u{4a}', '\u{30c}', - '\0']), ('\u{1f2}', ['\u{1f1}', '\0', '\0']), ('\u{1f3}', ['\u{1f1}', '\0', '\0']), - ('\u{1f5}', ['\u{1f4}', '\0', '\0']), ('\u{1f9}', ['\u{1f8}', '\0', '\0']), ('\u{1fb}', - ['\u{1fa}', '\0', '\0']), ('\u{1fd}', ['\u{1fc}', '\0', '\0']), ('\u{1ff}', ['\u{1fe}', - '\0', '\0']), ('\u{201}', ['\u{200}', '\0', '\0']), ('\u{203}', ['\u{202}', '\0', '\0']), - ('\u{205}', ['\u{204}', '\0', '\0']), ('\u{207}', ['\u{206}', '\0', '\0']), ('\u{209}', - ['\u{208}', '\0', '\0']), ('\u{20b}', ['\u{20a}', '\0', '\0']), ('\u{20d}', ['\u{20c}', - '\0', '\0']), ('\u{20f}', ['\u{20e}', '\0', '\0']), ('\u{211}', ['\u{210}', '\0', '\0']), - ('\u{213}', ['\u{212}', '\0', '\0']), ('\u{215}', ['\u{214}', '\0', '\0']), ('\u{217}', - ['\u{216}', '\0', '\0']), ('\u{219}', ['\u{218}', '\0', '\0']), ('\u{21b}', ['\u{21a}', - '\0', '\0']), ('\u{21d}', ['\u{21c}', '\0', '\0']), ('\u{21f}', ['\u{21e}', '\0', '\0']), - ('\u{223}', ['\u{222}', '\0', '\0']), ('\u{225}', ['\u{224}', '\0', '\0']), ('\u{227}', - ['\u{226}', '\0', '\0']), ('\u{229}', ['\u{228}', '\0', '\0']), ('\u{22b}', ['\u{22a}', - '\0', '\0']), ('\u{22d}', ['\u{22c}', '\0', '\0']), ('\u{22f}', ['\u{22e}', '\0', '\0']), - ('\u{231}', ['\u{230}', '\0', '\0']), ('\u{233}', ['\u{232}', '\0', '\0']), ('\u{23c}', - ['\u{23b}', '\0', '\0']), ('\u{23f}', ['\u{2c7e}', '\0', '\0']), ('\u{240}', ['\u{2c7f}', - '\0', '\0']), ('\u{242}', ['\u{241}', '\0', '\0']), ('\u{247}', ['\u{246}', '\0', '\0']), - ('\u{249}', ['\u{248}', '\0', '\0']), ('\u{24b}', ['\u{24a}', '\0', '\0']), ('\u{24d}', - ['\u{24c}', '\0', '\0']), ('\u{24f}', ['\u{24e}', '\0', '\0']), ('\u{250}', ['\u{2c6f}', - '\0', '\0']), ('\u{251}', ['\u{2c6d}', '\0', '\0']), ('\u{252}', ['\u{2c70}', '\0', '\0']), - ('\u{253}', ['\u{181}', '\0', '\0']), ('\u{254}', ['\u{186}', '\0', '\0']), ('\u{256}', - ['\u{189}', '\0', '\0']), ('\u{257}', ['\u{18a}', '\0', '\0']), ('\u{259}', ['\u{18f}', - '\0', '\0']), ('\u{25b}', ['\u{190}', '\0', '\0']), ('\u{25c}', ['\u{a7ab}', '\0', '\0']), - ('\u{260}', ['\u{193}', '\0', '\0']), ('\u{261}', ['\u{a7ac}', '\0', '\0']), ('\u{263}', - ['\u{194}', '\0', '\0']), ('\u{265}', ['\u{a78d}', '\0', '\0']), ('\u{266}', ['\u{a7aa}', - '\0', '\0']), ('\u{268}', ['\u{197}', '\0', '\0']), ('\u{269}', ['\u{196}', '\0', '\0']), - ('\u{26a}', ['\u{a7ae}', '\0', '\0']), ('\u{26b}', ['\u{2c62}', '\0', '\0']), ('\u{26c}', - ['\u{a7ad}', '\0', '\0']), ('\u{26f}', ['\u{19c}', '\0', '\0']), ('\u{271}', ['\u{2c6e}', - '\0', '\0']), ('\u{272}', ['\u{19d}', '\0', '\0']), ('\u{275}', ['\u{19f}', '\0', '\0']), - ('\u{27d}', ['\u{2c64}', '\0', '\0']), ('\u{280}', ['\u{1a6}', '\0', '\0']), ('\u{283}', - ['\u{1a9}', '\0', '\0']), ('\u{287}', ['\u{a7b1}', '\0', '\0']), ('\u{288}', ['\u{1ae}', - '\0', '\0']), ('\u{289}', ['\u{244}', '\0', '\0']), ('\u{28a}', ['\u{1b1}', '\0', '\0']), - ('\u{28b}', ['\u{1b2}', '\0', '\0']), ('\u{28c}', ['\u{245}', '\0', '\0']), ('\u{292}', - ['\u{1b7}', '\0', '\0']), ('\u{29d}', ['\u{a7b2}', '\0', '\0']), ('\u{29e}', ['\u{a7b0}', - '\0', '\0']), ('\u{345}', ['\u{399}', '\0', '\0']), ('\u{371}', ['\u{370}', '\0', '\0']), - ('\u{373}', ['\u{372}', '\0', '\0']), ('\u{377}', ['\u{376}', '\0', '\0']), ('\u{37b}', - ['\u{3fd}', '\0', '\0']), ('\u{37c}', ['\u{3fe}', '\0', '\0']), ('\u{37d}', ['\u{3ff}', - '\0', '\0']), ('\u{390}', ['\u{399}', '\u{308}', '\u{301}']), ('\u{3ac}', ['\u{386}', '\0', - '\0']), ('\u{3ad}', ['\u{388}', '\0', '\0']), ('\u{3ae}', ['\u{389}', '\0', '\0']), - ('\u{3af}', ['\u{38a}', '\0', '\0']), ('\u{3b0}', ['\u{3a5}', '\u{308}', '\u{301}']), - ('\u{3b1}', ['\u{391}', '\0', '\0']), ('\u{3b2}', ['\u{392}', '\0', '\0']), ('\u{3b3}', - ['\u{393}', '\0', '\0']), ('\u{3b4}', ['\u{394}', '\0', '\0']), ('\u{3b5}', ['\u{395}', - '\0', '\0']), ('\u{3b6}', ['\u{396}', '\0', '\0']), ('\u{3b7}', ['\u{397}', '\0', '\0']), - ('\u{3b8}', ['\u{398}', '\0', '\0']), ('\u{3b9}', ['\u{399}', '\0', '\0']), ('\u{3ba}', - ['\u{39a}', '\0', '\0']), ('\u{3bb}', ['\u{39b}', '\0', '\0']), ('\u{3bc}', ['\u{39c}', - '\0', '\0']), ('\u{3bd}', ['\u{39d}', '\0', '\0']), ('\u{3be}', ['\u{39e}', '\0', '\0']), - ('\u{3bf}', ['\u{39f}', '\0', '\0']), ('\u{3c0}', ['\u{3a0}', '\0', '\0']), ('\u{3c1}', - ['\u{3a1}', '\0', '\0']), ('\u{3c2}', ['\u{3a3}', '\0', '\0']), ('\u{3c3}', ['\u{3a3}', - '\0', '\0']), ('\u{3c4}', ['\u{3a4}', '\0', '\0']), ('\u{3c5}', ['\u{3a5}', '\0', '\0']), - ('\u{3c6}', ['\u{3a6}', '\0', '\0']), ('\u{3c7}', ['\u{3a7}', '\0', '\0']), ('\u{3c8}', - ['\u{3a8}', '\0', '\0']), ('\u{3c9}', ['\u{3a9}', '\0', '\0']), ('\u{3ca}', ['\u{3aa}', - '\0', '\0']), ('\u{3cb}', ['\u{3ab}', '\0', '\0']), ('\u{3cc}', ['\u{38c}', '\0', '\0']), - ('\u{3cd}', ['\u{38e}', '\0', '\0']), ('\u{3ce}', ['\u{38f}', '\0', '\0']), ('\u{3d0}', - ['\u{392}', '\0', '\0']), ('\u{3d1}', ['\u{398}', '\0', '\0']), ('\u{3d5}', ['\u{3a6}', - '\0', '\0']), ('\u{3d6}', ['\u{3a0}', '\0', '\0']), ('\u{3d7}', ['\u{3cf}', '\0', '\0']), - ('\u{3d9}', ['\u{3d8}', '\0', '\0']), ('\u{3db}', ['\u{3da}', '\0', '\0']), ('\u{3dd}', - ['\u{3dc}', '\0', '\0']), ('\u{3df}', ['\u{3de}', '\0', '\0']), ('\u{3e1}', ['\u{3e0}', - '\0', '\0']), ('\u{3e3}', ['\u{3e2}', '\0', '\0']), ('\u{3e5}', ['\u{3e4}', '\0', '\0']), - ('\u{3e7}', ['\u{3e6}', '\0', '\0']), ('\u{3e9}', ['\u{3e8}', '\0', '\0']), ('\u{3eb}', - ['\u{3ea}', '\0', '\0']), ('\u{3ed}', ['\u{3ec}', '\0', '\0']), ('\u{3ef}', ['\u{3ee}', - '\0', '\0']), ('\u{3f0}', ['\u{39a}', '\0', '\0']), ('\u{3f1}', ['\u{3a1}', '\0', '\0']), - ('\u{3f2}', ['\u{3f9}', '\0', '\0']), ('\u{3f3}', ['\u{37f}', '\0', '\0']), ('\u{3f5}', - ['\u{395}', '\0', '\0']), ('\u{3f8}', ['\u{3f7}', '\0', '\0']), ('\u{3fb}', ['\u{3fa}', - '\0', '\0']), ('\u{430}', ['\u{410}', '\0', '\0']), ('\u{431}', ['\u{411}', '\0', '\0']), - ('\u{432}', ['\u{412}', '\0', '\0']), ('\u{433}', ['\u{413}', '\0', '\0']), ('\u{434}', - ['\u{414}', '\0', '\0']), ('\u{435}', ['\u{415}', '\0', '\0']), ('\u{436}', ['\u{416}', - '\0', '\0']), ('\u{437}', ['\u{417}', '\0', '\0']), ('\u{438}', ['\u{418}', '\0', '\0']), - ('\u{439}', ['\u{419}', '\0', '\0']), ('\u{43a}', ['\u{41a}', '\0', '\0']), ('\u{43b}', - ['\u{41b}', '\0', '\0']), ('\u{43c}', ['\u{41c}', '\0', '\0']), ('\u{43d}', ['\u{41d}', - '\0', '\0']), ('\u{43e}', ['\u{41e}', '\0', '\0']), ('\u{43f}', ['\u{41f}', '\0', '\0']), - ('\u{440}', ['\u{420}', '\0', '\0']), ('\u{441}', ['\u{421}', '\0', '\0']), ('\u{442}', - ['\u{422}', '\0', '\0']), ('\u{443}', ['\u{423}', '\0', '\0']), ('\u{444}', ['\u{424}', - '\0', '\0']), ('\u{445}', ['\u{425}', '\0', '\0']), ('\u{446}', ['\u{426}', '\0', '\0']), - ('\u{447}', ['\u{427}', '\0', '\0']), ('\u{448}', ['\u{428}', '\0', '\0']), ('\u{449}', - ['\u{429}', '\0', '\0']), ('\u{44a}', ['\u{42a}', '\0', '\0']), ('\u{44b}', ['\u{42b}', - '\0', '\0']), ('\u{44c}', ['\u{42c}', '\0', '\0']), ('\u{44d}', ['\u{42d}', '\0', '\0']), - ('\u{44e}', ['\u{42e}', '\0', '\0']), ('\u{44f}', ['\u{42f}', '\0', '\0']), ('\u{450}', - ['\u{400}', '\0', '\0']), ('\u{451}', ['\u{401}', '\0', '\0']), ('\u{452}', ['\u{402}', - '\0', '\0']), ('\u{453}', ['\u{403}', '\0', '\0']), ('\u{454}', ['\u{404}', '\0', '\0']), - ('\u{455}', ['\u{405}', '\0', '\0']), ('\u{456}', ['\u{406}', '\0', '\0']), ('\u{457}', - ['\u{407}', '\0', '\0']), ('\u{458}', ['\u{408}', '\0', '\0']), ('\u{459}', ['\u{409}', - '\0', '\0']), ('\u{45a}', ['\u{40a}', '\0', '\0']), ('\u{45b}', ['\u{40b}', '\0', '\0']), - ('\u{45c}', ['\u{40c}', '\0', '\0']), ('\u{45d}', ['\u{40d}', '\0', '\0']), ('\u{45e}', - ['\u{40e}', '\0', '\0']), ('\u{45f}', ['\u{40f}', '\0', '\0']), ('\u{461}', ['\u{460}', - '\0', '\0']), ('\u{463}', ['\u{462}', '\0', '\0']), ('\u{465}', ['\u{464}', '\0', '\0']), - ('\u{467}', ['\u{466}', '\0', '\0']), ('\u{469}', ['\u{468}', '\0', '\0']), ('\u{46b}', - ['\u{46a}', '\0', '\0']), ('\u{46d}', ['\u{46c}', '\0', '\0']), ('\u{46f}', ['\u{46e}', - '\0', '\0']), ('\u{471}', ['\u{470}', '\0', '\0']), ('\u{473}', ['\u{472}', '\0', '\0']), - ('\u{475}', ['\u{474}', '\0', '\0']), ('\u{477}', ['\u{476}', '\0', '\0']), ('\u{479}', - ['\u{478}', '\0', '\0']), ('\u{47b}', ['\u{47a}', '\0', '\0']), ('\u{47d}', ['\u{47c}', - '\0', '\0']), ('\u{47f}', ['\u{47e}', '\0', '\0']), ('\u{481}', ['\u{480}', '\0', '\0']), - ('\u{48b}', ['\u{48a}', '\0', '\0']), ('\u{48d}', ['\u{48c}', '\0', '\0']), ('\u{48f}', - ['\u{48e}', '\0', '\0']), ('\u{491}', ['\u{490}', '\0', '\0']), ('\u{493}', ['\u{492}', - '\0', '\0']), ('\u{495}', ['\u{494}', '\0', '\0']), ('\u{497}', ['\u{496}', '\0', '\0']), - ('\u{499}', ['\u{498}', '\0', '\0']), ('\u{49b}', ['\u{49a}', '\0', '\0']), ('\u{49d}', - ['\u{49c}', '\0', '\0']), ('\u{49f}', ['\u{49e}', '\0', '\0']), ('\u{4a1}', ['\u{4a0}', - '\0', '\0']), ('\u{4a3}', ['\u{4a2}', '\0', '\0']), ('\u{4a5}', ['\u{4a4}', '\0', '\0']), - ('\u{4a7}', ['\u{4a6}', '\0', '\0']), ('\u{4a9}', ['\u{4a8}', '\0', '\0']), ('\u{4ab}', - ['\u{4aa}', '\0', '\0']), ('\u{4ad}', ['\u{4ac}', '\0', '\0']), ('\u{4af}', ['\u{4ae}', - '\0', '\0']), ('\u{4b1}', ['\u{4b0}', '\0', '\0']), ('\u{4b3}', ['\u{4b2}', '\0', '\0']), - ('\u{4b5}', ['\u{4b4}', '\0', '\0']), ('\u{4b7}', ['\u{4b6}', '\0', '\0']), ('\u{4b9}', - ['\u{4b8}', '\0', '\0']), ('\u{4bb}', ['\u{4ba}', '\0', '\0']), ('\u{4bd}', ['\u{4bc}', - '\0', '\0']), ('\u{4bf}', ['\u{4be}', '\0', '\0']), ('\u{4c2}', ['\u{4c1}', '\0', '\0']), - ('\u{4c4}', ['\u{4c3}', '\0', '\0']), ('\u{4c6}', ['\u{4c5}', '\0', '\0']), ('\u{4c8}', - ['\u{4c7}', '\0', '\0']), ('\u{4ca}', ['\u{4c9}', '\0', '\0']), ('\u{4cc}', ['\u{4cb}', - '\0', '\0']), ('\u{4ce}', ['\u{4cd}', '\0', '\0']), ('\u{4cf}', ['\u{4c0}', '\0', '\0']), - ('\u{4d1}', ['\u{4d0}', '\0', '\0']), ('\u{4d3}', ['\u{4d2}', '\0', '\0']), ('\u{4d5}', - ['\u{4d4}', '\0', '\0']), ('\u{4d7}', ['\u{4d6}', '\0', '\0']), ('\u{4d9}', ['\u{4d8}', - '\0', '\0']), ('\u{4db}', ['\u{4da}', '\0', '\0']), ('\u{4dd}', ['\u{4dc}', '\0', '\0']), - ('\u{4df}', ['\u{4de}', '\0', '\0']), ('\u{4e1}', ['\u{4e0}', '\0', '\0']), ('\u{4e3}', - ['\u{4e2}', '\0', '\0']), ('\u{4e5}', ['\u{4e4}', '\0', '\0']), ('\u{4e7}', ['\u{4e6}', - '\0', '\0']), ('\u{4e9}', ['\u{4e8}', '\0', '\0']), ('\u{4eb}', ['\u{4ea}', '\0', '\0']), - ('\u{4ed}', ['\u{4ec}', '\0', '\0']), ('\u{4ef}', ['\u{4ee}', '\0', '\0']), ('\u{4f1}', - ['\u{4f0}', '\0', '\0']), ('\u{4f3}', ['\u{4f2}', '\0', '\0']), ('\u{4f5}', ['\u{4f4}', - '\0', '\0']), ('\u{4f7}', ['\u{4f6}', '\0', '\0']), ('\u{4f9}', ['\u{4f8}', '\0', '\0']), - ('\u{4fb}', ['\u{4fa}', '\0', '\0']), ('\u{4fd}', ['\u{4fc}', '\0', '\0']), ('\u{4ff}', - ['\u{4fe}', '\0', '\0']), ('\u{501}', ['\u{500}', '\0', '\0']), ('\u{503}', ['\u{502}', - '\0', '\0']), ('\u{505}', ['\u{504}', '\0', '\0']), ('\u{507}', ['\u{506}', '\0', '\0']), - ('\u{509}', ['\u{508}', '\0', '\0']), ('\u{50b}', ['\u{50a}', '\0', '\0']), ('\u{50d}', - ['\u{50c}', '\0', '\0']), ('\u{50f}', ['\u{50e}', '\0', '\0']), ('\u{511}', ['\u{510}', - '\0', '\0']), ('\u{513}', ['\u{512}', '\0', '\0']), ('\u{515}', ['\u{514}', '\0', '\0']), - ('\u{517}', ['\u{516}', '\0', '\0']), ('\u{519}', ['\u{518}', '\0', '\0']), ('\u{51b}', - ['\u{51a}', '\0', '\0']), ('\u{51d}', ['\u{51c}', '\0', '\0']), ('\u{51f}', ['\u{51e}', - '\0', '\0']), ('\u{521}', ['\u{520}', '\0', '\0']), ('\u{523}', ['\u{522}', '\0', '\0']), - ('\u{525}', ['\u{524}', '\0', '\0']), ('\u{527}', ['\u{526}', '\0', '\0']), ('\u{529}', - ['\u{528}', '\0', '\0']), ('\u{52b}', ['\u{52a}', '\0', '\0']), ('\u{52d}', ['\u{52c}', - '\0', '\0']), ('\u{52f}', ['\u{52e}', '\0', '\0']), ('\u{561}', ['\u{531}', '\0', '\0']), - ('\u{562}', ['\u{532}', '\0', '\0']), ('\u{563}', ['\u{533}', '\0', '\0']), ('\u{564}', - ['\u{534}', '\0', '\0']), ('\u{565}', ['\u{535}', '\0', '\0']), ('\u{566}', ['\u{536}', - '\0', '\0']), ('\u{567}', ['\u{537}', '\0', '\0']), ('\u{568}', ['\u{538}', '\0', '\0']), - ('\u{569}', ['\u{539}', '\0', '\0']), ('\u{56a}', ['\u{53a}', '\0', '\0']), ('\u{56b}', - ['\u{53b}', '\0', '\0']), ('\u{56c}', ['\u{53c}', '\0', '\0']), ('\u{56d}', ['\u{53d}', - '\0', '\0']), ('\u{56e}', ['\u{53e}', '\0', '\0']), ('\u{56f}', ['\u{53f}', '\0', '\0']), - ('\u{570}', ['\u{540}', '\0', '\0']), ('\u{571}', ['\u{541}', '\0', '\0']), ('\u{572}', - ['\u{542}', '\0', '\0']), ('\u{573}', ['\u{543}', '\0', '\0']), ('\u{574}', ['\u{544}', - '\0', '\0']), ('\u{575}', ['\u{545}', '\0', '\0']), ('\u{576}', ['\u{546}', '\0', '\0']), - ('\u{577}', ['\u{547}', '\0', '\0']), ('\u{578}', ['\u{548}', '\0', '\0']), ('\u{579}', - ['\u{549}', '\0', '\0']), ('\u{57a}', ['\u{54a}', '\0', '\0']), ('\u{57b}', ['\u{54b}', - '\0', '\0']), ('\u{57c}', ['\u{54c}', '\0', '\0']), ('\u{57d}', ['\u{54d}', '\0', '\0']), - ('\u{57e}', ['\u{54e}', '\0', '\0']), ('\u{57f}', ['\u{54f}', '\0', '\0']), ('\u{580}', - ['\u{550}', '\0', '\0']), ('\u{581}', ['\u{551}', '\0', '\0']), ('\u{582}', ['\u{552}', - '\0', '\0']), ('\u{583}', ['\u{553}', '\0', '\0']), ('\u{584}', ['\u{554}', '\0', '\0']), - ('\u{585}', ['\u{555}', '\0', '\0']), ('\u{586}', ['\u{556}', '\0', '\0']), ('\u{587}', - ['\u{535}', '\u{552}', '\0']), ('\u{13f8}', ['\u{13f0}', '\0', '\0']), ('\u{13f9}', - ['\u{13f1}', '\0', '\0']), ('\u{13fa}', ['\u{13f2}', '\0', '\0']), ('\u{13fb}', ['\u{13f3}', - '\0', '\0']), ('\u{13fc}', ['\u{13f4}', '\0', '\0']), ('\u{13fd}', ['\u{13f5}', '\0', - '\0']), ('\u{1c80}', ['\u{412}', '\0', '\0']), ('\u{1c81}', ['\u{414}', '\0', '\0']), - ('\u{1c82}', ['\u{41e}', '\0', '\0']), ('\u{1c83}', ['\u{421}', '\0', '\0']), ('\u{1c84}', - ['\u{422}', '\0', '\0']), ('\u{1c85}', ['\u{422}', '\0', '\0']), ('\u{1c86}', ['\u{42a}', - '\0', '\0']), ('\u{1c87}', ['\u{462}', '\0', '\0']), ('\u{1c88}', ['\u{a64a}', '\0', '\0']), - ('\u{1d79}', ['\u{a77d}', '\0', '\0']), ('\u{1d7d}', ['\u{2c63}', '\0', '\0']), ('\u{1e01}', - ['\u{1e00}', '\0', '\0']), ('\u{1e03}', ['\u{1e02}', '\0', '\0']), ('\u{1e05}', ['\u{1e04}', - '\0', '\0']), ('\u{1e07}', ['\u{1e06}', '\0', '\0']), ('\u{1e09}', ['\u{1e08}', '\0', - '\0']), ('\u{1e0b}', ['\u{1e0a}', '\0', '\0']), ('\u{1e0d}', ['\u{1e0c}', '\0', '\0']), - ('\u{1e0f}', ['\u{1e0e}', '\0', '\0']), ('\u{1e11}', ['\u{1e10}', '\0', '\0']), ('\u{1e13}', - ['\u{1e12}', '\0', '\0']), ('\u{1e15}', ['\u{1e14}', '\0', '\0']), ('\u{1e17}', ['\u{1e16}', - '\0', '\0']), ('\u{1e19}', ['\u{1e18}', '\0', '\0']), ('\u{1e1b}', ['\u{1e1a}', '\0', - '\0']), ('\u{1e1d}', ['\u{1e1c}', '\0', '\0']), ('\u{1e1f}', ['\u{1e1e}', '\0', '\0']), - ('\u{1e21}', ['\u{1e20}', '\0', '\0']), ('\u{1e23}', ['\u{1e22}', '\0', '\0']), ('\u{1e25}', - ['\u{1e24}', '\0', '\0']), ('\u{1e27}', ['\u{1e26}', '\0', '\0']), ('\u{1e29}', ['\u{1e28}', - '\0', '\0']), ('\u{1e2b}', ['\u{1e2a}', '\0', '\0']), ('\u{1e2d}', ['\u{1e2c}', '\0', - '\0']), ('\u{1e2f}', ['\u{1e2e}', '\0', '\0']), ('\u{1e31}', ['\u{1e30}', '\0', '\0']), - ('\u{1e33}', ['\u{1e32}', '\0', '\0']), ('\u{1e35}', ['\u{1e34}', '\0', '\0']), ('\u{1e37}', - ['\u{1e36}', '\0', '\0']), ('\u{1e39}', ['\u{1e38}', '\0', '\0']), ('\u{1e3b}', ['\u{1e3a}', - '\0', '\0']), ('\u{1e3d}', ['\u{1e3c}', '\0', '\0']), ('\u{1e3f}', ['\u{1e3e}', '\0', - '\0']), ('\u{1e41}', ['\u{1e40}', '\0', '\0']), ('\u{1e43}', ['\u{1e42}', '\0', '\0']), - ('\u{1e45}', ['\u{1e44}', '\0', '\0']), ('\u{1e47}', ['\u{1e46}', '\0', '\0']), ('\u{1e49}', - ['\u{1e48}', '\0', '\0']), ('\u{1e4b}', ['\u{1e4a}', '\0', '\0']), ('\u{1e4d}', ['\u{1e4c}', - '\0', '\0']), ('\u{1e4f}', ['\u{1e4e}', '\0', '\0']), ('\u{1e51}', ['\u{1e50}', '\0', - '\0']), ('\u{1e53}', ['\u{1e52}', '\0', '\0']), ('\u{1e55}', ['\u{1e54}', '\0', '\0']), - ('\u{1e57}', ['\u{1e56}', '\0', '\0']), ('\u{1e59}', ['\u{1e58}', '\0', '\0']), ('\u{1e5b}', - ['\u{1e5a}', '\0', '\0']), ('\u{1e5d}', ['\u{1e5c}', '\0', '\0']), ('\u{1e5f}', ['\u{1e5e}', - '\0', '\0']), ('\u{1e61}', ['\u{1e60}', '\0', '\0']), ('\u{1e63}', ['\u{1e62}', '\0', - '\0']), ('\u{1e65}', ['\u{1e64}', '\0', '\0']), ('\u{1e67}', ['\u{1e66}', '\0', '\0']), - ('\u{1e69}', ['\u{1e68}', '\0', '\0']), ('\u{1e6b}', ['\u{1e6a}', '\0', '\0']), ('\u{1e6d}', - ['\u{1e6c}', '\0', '\0']), ('\u{1e6f}', ['\u{1e6e}', '\0', '\0']), ('\u{1e71}', ['\u{1e70}', - '\0', '\0']), ('\u{1e73}', ['\u{1e72}', '\0', '\0']), ('\u{1e75}', ['\u{1e74}', '\0', - '\0']), ('\u{1e77}', ['\u{1e76}', '\0', '\0']), ('\u{1e79}', ['\u{1e78}', '\0', '\0']), - ('\u{1e7b}', ['\u{1e7a}', '\0', '\0']), ('\u{1e7d}', ['\u{1e7c}', '\0', '\0']), ('\u{1e7f}', - ['\u{1e7e}', '\0', '\0']), ('\u{1e81}', ['\u{1e80}', '\0', '\0']), ('\u{1e83}', ['\u{1e82}', - '\0', '\0']), ('\u{1e85}', ['\u{1e84}', '\0', '\0']), ('\u{1e87}', ['\u{1e86}', '\0', - '\0']), ('\u{1e89}', ['\u{1e88}', '\0', '\0']), ('\u{1e8b}', ['\u{1e8a}', '\0', '\0']), - ('\u{1e8d}', ['\u{1e8c}', '\0', '\0']), ('\u{1e8f}', ['\u{1e8e}', '\0', '\0']), ('\u{1e91}', - ['\u{1e90}', '\0', '\0']), ('\u{1e93}', ['\u{1e92}', '\0', '\0']), ('\u{1e95}', ['\u{1e94}', - '\0', '\0']), ('\u{1e96}', ['\u{48}', '\u{331}', '\0']), ('\u{1e97}', ['\u{54}', '\u{308}', - '\0']), ('\u{1e98}', ['\u{57}', '\u{30a}', '\0']), ('\u{1e99}', ['\u{59}', '\u{30a}', - '\0']), ('\u{1e9a}', ['\u{41}', '\u{2be}', '\0']), ('\u{1e9b}', ['\u{1e60}', '\0', '\0']), - ('\u{1ea1}', ['\u{1ea0}', '\0', '\0']), ('\u{1ea3}', ['\u{1ea2}', '\0', '\0']), ('\u{1ea5}', - ['\u{1ea4}', '\0', '\0']), ('\u{1ea7}', ['\u{1ea6}', '\0', '\0']), ('\u{1ea9}', ['\u{1ea8}', - '\0', '\0']), ('\u{1eab}', ['\u{1eaa}', '\0', '\0']), ('\u{1ead}', ['\u{1eac}', '\0', - '\0']), ('\u{1eaf}', ['\u{1eae}', '\0', '\0']), ('\u{1eb1}', ['\u{1eb0}', '\0', '\0']), - ('\u{1eb3}', ['\u{1eb2}', '\0', '\0']), ('\u{1eb5}', ['\u{1eb4}', '\0', '\0']), ('\u{1eb7}', - ['\u{1eb6}', '\0', '\0']), ('\u{1eb9}', ['\u{1eb8}', '\0', '\0']), ('\u{1ebb}', ['\u{1eba}', - '\0', '\0']), ('\u{1ebd}', ['\u{1ebc}', '\0', '\0']), ('\u{1ebf}', ['\u{1ebe}', '\0', - '\0']), ('\u{1ec1}', ['\u{1ec0}', '\0', '\0']), ('\u{1ec3}', ['\u{1ec2}', '\0', '\0']), - ('\u{1ec5}', ['\u{1ec4}', '\0', '\0']), ('\u{1ec7}', ['\u{1ec6}', '\0', '\0']), ('\u{1ec9}', - ['\u{1ec8}', '\0', '\0']), ('\u{1ecb}', ['\u{1eca}', '\0', '\0']), ('\u{1ecd}', ['\u{1ecc}', - '\0', '\0']), ('\u{1ecf}', ['\u{1ece}', '\0', '\0']), ('\u{1ed1}', ['\u{1ed0}', '\0', - '\0']), ('\u{1ed3}', ['\u{1ed2}', '\0', '\0']), ('\u{1ed5}', ['\u{1ed4}', '\0', '\0']), - ('\u{1ed7}', ['\u{1ed6}', '\0', '\0']), ('\u{1ed9}', ['\u{1ed8}', '\0', '\0']), ('\u{1edb}', - ['\u{1eda}', '\0', '\0']), ('\u{1edd}', ['\u{1edc}', '\0', '\0']), ('\u{1edf}', ['\u{1ede}', - '\0', '\0']), ('\u{1ee1}', ['\u{1ee0}', '\0', '\0']), ('\u{1ee3}', ['\u{1ee2}', '\0', - '\0']), ('\u{1ee5}', ['\u{1ee4}', '\0', '\0']), ('\u{1ee7}', ['\u{1ee6}', '\0', '\0']), - ('\u{1ee9}', ['\u{1ee8}', '\0', '\0']), ('\u{1eeb}', ['\u{1eea}', '\0', '\0']), ('\u{1eed}', - ['\u{1eec}', '\0', '\0']), ('\u{1eef}', ['\u{1eee}', '\0', '\0']), ('\u{1ef1}', ['\u{1ef0}', - '\0', '\0']), ('\u{1ef3}', ['\u{1ef2}', '\0', '\0']), ('\u{1ef5}', ['\u{1ef4}', '\0', - '\0']), ('\u{1ef7}', ['\u{1ef6}', '\0', '\0']), ('\u{1ef9}', ['\u{1ef8}', '\0', '\0']), - ('\u{1efb}', ['\u{1efa}', '\0', '\0']), ('\u{1efd}', ['\u{1efc}', '\0', '\0']), ('\u{1eff}', - ['\u{1efe}', '\0', '\0']), ('\u{1f00}', ['\u{1f08}', '\0', '\0']), ('\u{1f01}', ['\u{1f09}', - '\0', '\0']), ('\u{1f02}', ['\u{1f0a}', '\0', '\0']), ('\u{1f03}', ['\u{1f0b}', '\0', - '\0']), ('\u{1f04}', ['\u{1f0c}', '\0', '\0']), ('\u{1f05}', ['\u{1f0d}', '\0', '\0']), - ('\u{1f06}', ['\u{1f0e}', '\0', '\0']), ('\u{1f07}', ['\u{1f0f}', '\0', '\0']), ('\u{1f10}', - ['\u{1f18}', '\0', '\0']), ('\u{1f11}', ['\u{1f19}', '\0', '\0']), ('\u{1f12}', ['\u{1f1a}', - '\0', '\0']), ('\u{1f13}', ['\u{1f1b}', '\0', '\0']), ('\u{1f14}', ['\u{1f1c}', '\0', - '\0']), ('\u{1f15}', ['\u{1f1d}', '\0', '\0']), ('\u{1f20}', ['\u{1f28}', '\0', '\0']), - ('\u{1f21}', ['\u{1f29}', '\0', '\0']), ('\u{1f22}', ['\u{1f2a}', '\0', '\0']), ('\u{1f23}', - ['\u{1f2b}', '\0', '\0']), ('\u{1f24}', ['\u{1f2c}', '\0', '\0']), ('\u{1f25}', ['\u{1f2d}', - '\0', '\0']), ('\u{1f26}', ['\u{1f2e}', '\0', '\0']), ('\u{1f27}', ['\u{1f2f}', '\0', - '\0']), ('\u{1f30}', ['\u{1f38}', '\0', '\0']), ('\u{1f31}', ['\u{1f39}', '\0', '\0']), - ('\u{1f32}', ['\u{1f3a}', '\0', '\0']), ('\u{1f33}', ['\u{1f3b}', '\0', '\0']), ('\u{1f34}', - ['\u{1f3c}', '\0', '\0']), ('\u{1f35}', ['\u{1f3d}', '\0', '\0']), ('\u{1f36}', ['\u{1f3e}', - '\0', '\0']), ('\u{1f37}', ['\u{1f3f}', '\0', '\0']), ('\u{1f40}', ['\u{1f48}', '\0', - '\0']), ('\u{1f41}', ['\u{1f49}', '\0', '\0']), ('\u{1f42}', ['\u{1f4a}', '\0', '\0']), - ('\u{1f43}', ['\u{1f4b}', '\0', '\0']), ('\u{1f44}', ['\u{1f4c}', '\0', '\0']), ('\u{1f45}', - ['\u{1f4d}', '\0', '\0']), ('\u{1f50}', ['\u{3a5}', '\u{313}', '\0']), ('\u{1f51}', - ['\u{1f59}', '\0', '\0']), ('\u{1f52}', ['\u{3a5}', '\u{313}', '\u{300}']), ('\u{1f53}', - ['\u{1f5b}', '\0', '\0']), ('\u{1f54}', ['\u{3a5}', '\u{313}', '\u{301}']), ('\u{1f55}', - ['\u{1f5d}', '\0', '\0']), ('\u{1f56}', ['\u{3a5}', '\u{313}', '\u{342}']), ('\u{1f57}', - ['\u{1f5f}', '\0', '\0']), ('\u{1f60}', ['\u{1f68}', '\0', '\0']), ('\u{1f61}', ['\u{1f69}', - '\0', '\0']), ('\u{1f62}', ['\u{1f6a}', '\0', '\0']), ('\u{1f63}', ['\u{1f6b}', '\0', - '\0']), ('\u{1f64}', ['\u{1f6c}', '\0', '\0']), ('\u{1f65}', ['\u{1f6d}', '\0', '\0']), - ('\u{1f66}', ['\u{1f6e}', '\0', '\0']), ('\u{1f67}', ['\u{1f6f}', '\0', '\0']), ('\u{1f70}', - ['\u{1fba}', '\0', '\0']), ('\u{1f71}', ['\u{1fbb}', '\0', '\0']), ('\u{1f72}', ['\u{1fc8}', - '\0', '\0']), ('\u{1f73}', ['\u{1fc9}', '\0', '\0']), ('\u{1f74}', ['\u{1fca}', '\0', - '\0']), ('\u{1f75}', ['\u{1fcb}', '\0', '\0']), ('\u{1f76}', ['\u{1fda}', '\0', '\0']), - ('\u{1f77}', ['\u{1fdb}', '\0', '\0']), ('\u{1f78}', ['\u{1ff8}', '\0', '\0']), ('\u{1f79}', - ['\u{1ff9}', '\0', '\0']), ('\u{1f7a}', ['\u{1fea}', '\0', '\0']), ('\u{1f7b}', ['\u{1feb}', - '\0', '\0']), ('\u{1f7c}', ['\u{1ffa}', '\0', '\0']), ('\u{1f7d}', ['\u{1ffb}', '\0', - '\0']), ('\u{1f80}', ['\u{1f08}', '\u{399}', '\0']), ('\u{1f81}', ['\u{1f09}', '\u{399}', - '\0']), ('\u{1f82}', ['\u{1f0a}', '\u{399}', '\0']), ('\u{1f83}', ['\u{1f0b}', '\u{399}', - '\0']), ('\u{1f84}', ['\u{1f0c}', '\u{399}', '\0']), ('\u{1f85}', ['\u{1f0d}', '\u{399}', - '\0']), ('\u{1f86}', ['\u{1f0e}', '\u{399}', '\0']), ('\u{1f87}', ['\u{1f0f}', '\u{399}', - '\0']), ('\u{1f88}', ['\u{1f08}', '\u{399}', '\0']), ('\u{1f89}', ['\u{1f09}', '\u{399}', - '\0']), ('\u{1f8a}', ['\u{1f0a}', '\u{399}', '\0']), ('\u{1f8b}', ['\u{1f0b}', '\u{399}', - '\0']), ('\u{1f8c}', ['\u{1f0c}', '\u{399}', '\0']), ('\u{1f8d}', ['\u{1f0d}', '\u{399}', - '\0']), ('\u{1f8e}', ['\u{1f0e}', '\u{399}', '\0']), ('\u{1f8f}', ['\u{1f0f}', '\u{399}', - '\0']), ('\u{1f90}', ['\u{1f28}', '\u{399}', '\0']), ('\u{1f91}', ['\u{1f29}', '\u{399}', - '\0']), ('\u{1f92}', ['\u{1f2a}', '\u{399}', '\0']), ('\u{1f93}', ['\u{1f2b}', '\u{399}', - '\0']), ('\u{1f94}', ['\u{1f2c}', '\u{399}', '\0']), ('\u{1f95}', ['\u{1f2d}', '\u{399}', - '\0']), ('\u{1f96}', ['\u{1f2e}', '\u{399}', '\0']), ('\u{1f97}', ['\u{1f2f}', '\u{399}', - '\0']), ('\u{1f98}', ['\u{1f28}', '\u{399}', '\0']), ('\u{1f99}', ['\u{1f29}', '\u{399}', - '\0']), ('\u{1f9a}', ['\u{1f2a}', '\u{399}', '\0']), ('\u{1f9b}', ['\u{1f2b}', '\u{399}', - '\0']), ('\u{1f9c}', ['\u{1f2c}', '\u{399}', '\0']), ('\u{1f9d}', ['\u{1f2d}', '\u{399}', - '\0']), ('\u{1f9e}', ['\u{1f2e}', '\u{399}', '\0']), ('\u{1f9f}', ['\u{1f2f}', '\u{399}', - '\0']), ('\u{1fa0}', ['\u{1f68}', '\u{399}', '\0']), ('\u{1fa1}', ['\u{1f69}', '\u{399}', - '\0']), ('\u{1fa2}', ['\u{1f6a}', '\u{399}', '\0']), ('\u{1fa3}', ['\u{1f6b}', '\u{399}', - '\0']), ('\u{1fa4}', ['\u{1f6c}', '\u{399}', '\0']), ('\u{1fa5}', ['\u{1f6d}', '\u{399}', - '\0']), ('\u{1fa6}', ['\u{1f6e}', '\u{399}', '\0']), ('\u{1fa7}', ['\u{1f6f}', '\u{399}', - '\0']), ('\u{1fa8}', ['\u{1f68}', '\u{399}', '\0']), ('\u{1fa9}', ['\u{1f69}', '\u{399}', - '\0']), ('\u{1faa}', ['\u{1f6a}', '\u{399}', '\0']), ('\u{1fab}', ['\u{1f6b}', '\u{399}', - '\0']), ('\u{1fac}', ['\u{1f6c}', '\u{399}', '\0']), ('\u{1fad}', ['\u{1f6d}', '\u{399}', - '\0']), ('\u{1fae}', ['\u{1f6e}', '\u{399}', '\0']), ('\u{1faf}', ['\u{1f6f}', '\u{399}', - '\0']), ('\u{1fb0}', ['\u{1fb8}', '\0', '\0']), ('\u{1fb1}', ['\u{1fb9}', '\0', '\0']), - ('\u{1fb2}', ['\u{1fba}', '\u{399}', '\0']), ('\u{1fb3}', ['\u{391}', '\u{399}', '\0']), - ('\u{1fb4}', ['\u{386}', '\u{399}', '\0']), ('\u{1fb6}', ['\u{391}', '\u{342}', '\0']), - ('\u{1fb7}', ['\u{391}', '\u{342}', '\u{399}']), ('\u{1fbc}', ['\u{391}', '\u{399}', '\0']), - ('\u{1fbe}', ['\u{399}', '\0', '\0']), ('\u{1fc2}', ['\u{1fca}', '\u{399}', '\0']), - ('\u{1fc3}', ['\u{397}', '\u{399}', '\0']), ('\u{1fc4}', ['\u{389}', '\u{399}', '\0']), - ('\u{1fc6}', ['\u{397}', '\u{342}', '\0']), ('\u{1fc7}', ['\u{397}', '\u{342}', '\u{399}']), - ('\u{1fcc}', ['\u{397}', '\u{399}', '\0']), ('\u{1fd0}', ['\u{1fd8}', '\0', '\0']), - ('\u{1fd1}', ['\u{1fd9}', '\0', '\0']), ('\u{1fd2}', ['\u{399}', '\u{308}', '\u{300}']), - ('\u{1fd3}', ['\u{399}', '\u{308}', '\u{301}']), ('\u{1fd6}', ['\u{399}', '\u{342}', '\0']), - ('\u{1fd7}', ['\u{399}', '\u{308}', '\u{342}']), ('\u{1fe0}', ['\u{1fe8}', '\0', '\0']), - ('\u{1fe1}', ['\u{1fe9}', '\0', '\0']), ('\u{1fe2}', ['\u{3a5}', '\u{308}', '\u{300}']), - ('\u{1fe3}', ['\u{3a5}', '\u{308}', '\u{301}']), ('\u{1fe4}', ['\u{3a1}', '\u{313}', '\0']), - ('\u{1fe5}', ['\u{1fec}', '\0', '\0']), ('\u{1fe6}', ['\u{3a5}', '\u{342}', '\0']), - ('\u{1fe7}', ['\u{3a5}', '\u{308}', '\u{342}']), ('\u{1ff2}', ['\u{1ffa}', '\u{399}', - '\0']), ('\u{1ff3}', ['\u{3a9}', '\u{399}', '\0']), ('\u{1ff4}', ['\u{38f}', '\u{399}', - '\0']), ('\u{1ff6}', ['\u{3a9}', '\u{342}', '\0']), ('\u{1ff7}', ['\u{3a9}', '\u{342}', - '\u{399}']), ('\u{1ffc}', ['\u{3a9}', '\u{399}', '\0']), ('\u{214e}', ['\u{2132}', '\0', - '\0']), ('\u{2170}', ['\u{2160}', '\0', '\0']), ('\u{2171}', ['\u{2161}', '\0', '\0']), - ('\u{2172}', ['\u{2162}', '\0', '\0']), ('\u{2173}', ['\u{2163}', '\0', '\0']), ('\u{2174}', - ['\u{2164}', '\0', '\0']), ('\u{2175}', ['\u{2165}', '\0', '\0']), ('\u{2176}', ['\u{2166}', - '\0', '\0']), ('\u{2177}', ['\u{2167}', '\0', '\0']), ('\u{2178}', ['\u{2168}', '\0', - '\0']), ('\u{2179}', ['\u{2169}', '\0', '\0']), ('\u{217a}', ['\u{216a}', '\0', '\0']), - ('\u{217b}', ['\u{216b}', '\0', '\0']), ('\u{217c}', ['\u{216c}', '\0', '\0']), ('\u{217d}', - ['\u{216d}', '\0', '\0']), ('\u{217e}', ['\u{216e}', '\0', '\0']), ('\u{217f}', ['\u{216f}', - '\0', '\0']), ('\u{2184}', ['\u{2183}', '\0', '\0']), ('\u{24d0}', ['\u{24b6}', '\0', - '\0']), ('\u{24d1}', ['\u{24b7}', '\0', '\0']), ('\u{24d2}', ['\u{24b8}', '\0', '\0']), - ('\u{24d3}', ['\u{24b9}', '\0', '\0']), ('\u{24d4}', ['\u{24ba}', '\0', '\0']), ('\u{24d5}', - ['\u{24bb}', '\0', '\0']), ('\u{24d6}', ['\u{24bc}', '\0', '\0']), ('\u{24d7}', ['\u{24bd}', - '\0', '\0']), ('\u{24d8}', ['\u{24be}', '\0', '\0']), ('\u{24d9}', ['\u{24bf}', '\0', - '\0']), ('\u{24da}', ['\u{24c0}', '\0', '\0']), ('\u{24db}', ['\u{24c1}', '\0', '\0']), - ('\u{24dc}', ['\u{24c2}', '\0', '\0']), ('\u{24dd}', ['\u{24c3}', '\0', '\0']), ('\u{24de}', - ['\u{24c4}', '\0', '\0']), ('\u{24df}', ['\u{24c5}', '\0', '\0']), ('\u{24e0}', ['\u{24c6}', - '\0', '\0']), ('\u{24e1}', ['\u{24c7}', '\0', '\0']), ('\u{24e2}', ['\u{24c8}', '\0', - '\0']), ('\u{24e3}', ['\u{24c9}', '\0', '\0']), ('\u{24e4}', ['\u{24ca}', '\0', '\0']), - ('\u{24e5}', ['\u{24cb}', '\0', '\0']), ('\u{24e6}', ['\u{24cc}', '\0', '\0']), ('\u{24e7}', - ['\u{24cd}', '\0', '\0']), ('\u{24e8}', ['\u{24ce}', '\0', '\0']), ('\u{24e9}', ['\u{24cf}', - '\0', '\0']), ('\u{2c30}', ['\u{2c00}', '\0', '\0']), ('\u{2c31}', ['\u{2c01}', '\0', - '\0']), ('\u{2c32}', ['\u{2c02}', '\0', '\0']), ('\u{2c33}', ['\u{2c03}', '\0', '\0']), - ('\u{2c34}', ['\u{2c04}', '\0', '\0']), ('\u{2c35}', ['\u{2c05}', '\0', '\0']), ('\u{2c36}', - ['\u{2c06}', '\0', '\0']), ('\u{2c37}', ['\u{2c07}', '\0', '\0']), ('\u{2c38}', ['\u{2c08}', - '\0', '\0']), ('\u{2c39}', ['\u{2c09}', '\0', '\0']), ('\u{2c3a}', ['\u{2c0a}', '\0', - '\0']), ('\u{2c3b}', ['\u{2c0b}', '\0', '\0']), ('\u{2c3c}', ['\u{2c0c}', '\0', '\0']), - ('\u{2c3d}', ['\u{2c0d}', '\0', '\0']), ('\u{2c3e}', ['\u{2c0e}', '\0', '\0']), ('\u{2c3f}', - ['\u{2c0f}', '\0', '\0']), ('\u{2c40}', ['\u{2c10}', '\0', '\0']), ('\u{2c41}', ['\u{2c11}', - '\0', '\0']), ('\u{2c42}', ['\u{2c12}', '\0', '\0']), ('\u{2c43}', ['\u{2c13}', '\0', - '\0']), ('\u{2c44}', ['\u{2c14}', '\0', '\0']), ('\u{2c45}', ['\u{2c15}', '\0', '\0']), - ('\u{2c46}', ['\u{2c16}', '\0', '\0']), ('\u{2c47}', ['\u{2c17}', '\0', '\0']), ('\u{2c48}', - ['\u{2c18}', '\0', '\0']), ('\u{2c49}', ['\u{2c19}', '\0', '\0']), ('\u{2c4a}', ['\u{2c1a}', - '\0', '\0']), ('\u{2c4b}', ['\u{2c1b}', '\0', '\0']), ('\u{2c4c}', ['\u{2c1c}', '\0', - '\0']), ('\u{2c4d}', ['\u{2c1d}', '\0', '\0']), ('\u{2c4e}', ['\u{2c1e}', '\0', '\0']), - ('\u{2c4f}', ['\u{2c1f}', '\0', '\0']), ('\u{2c50}', ['\u{2c20}', '\0', '\0']), ('\u{2c51}', - ['\u{2c21}', '\0', '\0']), ('\u{2c52}', ['\u{2c22}', '\0', '\0']), ('\u{2c53}', ['\u{2c23}', - '\0', '\0']), ('\u{2c54}', ['\u{2c24}', '\0', '\0']), ('\u{2c55}', ['\u{2c25}', '\0', - '\0']), ('\u{2c56}', ['\u{2c26}', '\0', '\0']), ('\u{2c57}', ['\u{2c27}', '\0', '\0']), - ('\u{2c58}', ['\u{2c28}', '\0', '\0']), ('\u{2c59}', ['\u{2c29}', '\0', '\0']), ('\u{2c5a}', - ['\u{2c2a}', '\0', '\0']), ('\u{2c5b}', ['\u{2c2b}', '\0', '\0']), ('\u{2c5c}', ['\u{2c2c}', - '\0', '\0']), ('\u{2c5d}', ['\u{2c2d}', '\0', '\0']), ('\u{2c5e}', ['\u{2c2e}', '\0', - '\0']), ('\u{2c61}', ['\u{2c60}', '\0', '\0']), ('\u{2c65}', ['\u{23a}', '\0', '\0']), - ('\u{2c66}', ['\u{23e}', '\0', '\0']), ('\u{2c68}', ['\u{2c67}', '\0', '\0']), ('\u{2c6a}', - ['\u{2c69}', '\0', '\0']), ('\u{2c6c}', ['\u{2c6b}', '\0', '\0']), ('\u{2c73}', ['\u{2c72}', - '\0', '\0']), ('\u{2c76}', ['\u{2c75}', '\0', '\0']), ('\u{2c81}', ['\u{2c80}', '\0', - '\0']), ('\u{2c83}', ['\u{2c82}', '\0', '\0']), ('\u{2c85}', ['\u{2c84}', '\0', '\0']), - ('\u{2c87}', ['\u{2c86}', '\0', '\0']), ('\u{2c89}', ['\u{2c88}', '\0', '\0']), ('\u{2c8b}', - ['\u{2c8a}', '\0', '\0']), ('\u{2c8d}', ['\u{2c8c}', '\0', '\0']), ('\u{2c8f}', ['\u{2c8e}', - '\0', '\0']), ('\u{2c91}', ['\u{2c90}', '\0', '\0']), ('\u{2c93}', ['\u{2c92}', '\0', - '\0']), ('\u{2c95}', ['\u{2c94}', '\0', '\0']), ('\u{2c97}', ['\u{2c96}', '\0', '\0']), - ('\u{2c99}', ['\u{2c98}', '\0', '\0']), ('\u{2c9b}', ['\u{2c9a}', '\0', '\0']), ('\u{2c9d}', - ['\u{2c9c}', '\0', '\0']), ('\u{2c9f}', ['\u{2c9e}', '\0', '\0']), ('\u{2ca1}', ['\u{2ca0}', - '\0', '\0']), ('\u{2ca3}', ['\u{2ca2}', '\0', '\0']), ('\u{2ca5}', ['\u{2ca4}', '\0', - '\0']), ('\u{2ca7}', ['\u{2ca6}', '\0', '\0']), ('\u{2ca9}', ['\u{2ca8}', '\0', '\0']), - ('\u{2cab}', ['\u{2caa}', '\0', '\0']), ('\u{2cad}', ['\u{2cac}', '\0', '\0']), ('\u{2caf}', - ['\u{2cae}', '\0', '\0']), ('\u{2cb1}', ['\u{2cb0}', '\0', '\0']), ('\u{2cb3}', ['\u{2cb2}', - '\0', '\0']), ('\u{2cb5}', ['\u{2cb4}', '\0', '\0']), ('\u{2cb7}', ['\u{2cb6}', '\0', - '\0']), ('\u{2cb9}', ['\u{2cb8}', '\0', '\0']), ('\u{2cbb}', ['\u{2cba}', '\0', '\0']), - ('\u{2cbd}', ['\u{2cbc}', '\0', '\0']), ('\u{2cbf}', ['\u{2cbe}', '\0', '\0']), ('\u{2cc1}', - ['\u{2cc0}', '\0', '\0']), ('\u{2cc3}', ['\u{2cc2}', '\0', '\0']), ('\u{2cc5}', ['\u{2cc4}', - '\0', '\0']), ('\u{2cc7}', ['\u{2cc6}', '\0', '\0']), ('\u{2cc9}', ['\u{2cc8}', '\0', - '\0']), ('\u{2ccb}', ['\u{2cca}', '\0', '\0']), ('\u{2ccd}', ['\u{2ccc}', '\0', '\0']), - ('\u{2ccf}', ['\u{2cce}', '\0', '\0']), ('\u{2cd1}', ['\u{2cd0}', '\0', '\0']), ('\u{2cd3}', - ['\u{2cd2}', '\0', '\0']), ('\u{2cd5}', ['\u{2cd4}', '\0', '\0']), ('\u{2cd7}', ['\u{2cd6}', - '\0', '\0']), ('\u{2cd9}', ['\u{2cd8}', '\0', '\0']), ('\u{2cdb}', ['\u{2cda}', '\0', - '\0']), ('\u{2cdd}', ['\u{2cdc}', '\0', '\0']), ('\u{2cdf}', ['\u{2cde}', '\0', '\0']), - ('\u{2ce1}', ['\u{2ce0}', '\0', '\0']), ('\u{2ce3}', ['\u{2ce2}', '\0', '\0']), ('\u{2cec}', - ['\u{2ceb}', '\0', '\0']), ('\u{2cee}', ['\u{2ced}', '\0', '\0']), ('\u{2cf3}', ['\u{2cf2}', - '\0', '\0']), ('\u{2d00}', ['\u{10a0}', '\0', '\0']), ('\u{2d01}', ['\u{10a1}', '\0', - '\0']), ('\u{2d02}', ['\u{10a2}', '\0', '\0']), ('\u{2d03}', ['\u{10a3}', '\0', '\0']), - ('\u{2d04}', ['\u{10a4}', '\0', '\0']), ('\u{2d05}', ['\u{10a5}', '\0', '\0']), ('\u{2d06}', - ['\u{10a6}', '\0', '\0']), ('\u{2d07}', ['\u{10a7}', '\0', '\0']), ('\u{2d08}', ['\u{10a8}', - '\0', '\0']), ('\u{2d09}', ['\u{10a9}', '\0', '\0']), ('\u{2d0a}', ['\u{10aa}', '\0', - '\0']), ('\u{2d0b}', ['\u{10ab}', '\0', '\0']), ('\u{2d0c}', ['\u{10ac}', '\0', '\0']), - ('\u{2d0d}', ['\u{10ad}', '\0', '\0']), ('\u{2d0e}', ['\u{10ae}', '\0', '\0']), ('\u{2d0f}', - ['\u{10af}', '\0', '\0']), ('\u{2d10}', ['\u{10b0}', '\0', '\0']), ('\u{2d11}', ['\u{10b1}', - '\0', '\0']), ('\u{2d12}', ['\u{10b2}', '\0', '\0']), ('\u{2d13}', ['\u{10b3}', '\0', - '\0']), ('\u{2d14}', ['\u{10b4}', '\0', '\0']), ('\u{2d15}', ['\u{10b5}', '\0', '\0']), - ('\u{2d16}', ['\u{10b6}', '\0', '\0']), ('\u{2d17}', ['\u{10b7}', '\0', '\0']), ('\u{2d18}', - ['\u{10b8}', '\0', '\0']), ('\u{2d19}', ['\u{10b9}', '\0', '\0']), ('\u{2d1a}', ['\u{10ba}', - '\0', '\0']), ('\u{2d1b}', ['\u{10bb}', '\0', '\0']), ('\u{2d1c}', ['\u{10bc}', '\0', - '\0']), ('\u{2d1d}', ['\u{10bd}', '\0', '\0']), ('\u{2d1e}', ['\u{10be}', '\0', '\0']), - ('\u{2d1f}', ['\u{10bf}', '\0', '\0']), ('\u{2d20}', ['\u{10c0}', '\0', '\0']), ('\u{2d21}', - ['\u{10c1}', '\0', '\0']), ('\u{2d22}', ['\u{10c2}', '\0', '\0']), ('\u{2d23}', ['\u{10c3}', - '\0', '\0']), ('\u{2d24}', ['\u{10c4}', '\0', '\0']), ('\u{2d25}', ['\u{10c5}', '\0', - '\0']), ('\u{2d27}', ['\u{10c7}', '\0', '\0']), ('\u{2d2d}', ['\u{10cd}', '\0', '\0']), - ('\u{a641}', ['\u{a640}', '\0', '\0']), ('\u{a643}', ['\u{a642}', '\0', '\0']), ('\u{a645}', - ['\u{a644}', '\0', '\0']), ('\u{a647}', ['\u{a646}', '\0', '\0']), ('\u{a649}', ['\u{a648}', - '\0', '\0']), ('\u{a64b}', ['\u{a64a}', '\0', '\0']), ('\u{a64d}', ['\u{a64c}', '\0', - '\0']), ('\u{a64f}', ['\u{a64e}', '\0', '\0']), ('\u{a651}', ['\u{a650}', '\0', '\0']), - ('\u{a653}', ['\u{a652}', '\0', '\0']), ('\u{a655}', ['\u{a654}', '\0', '\0']), ('\u{a657}', - ['\u{a656}', '\0', '\0']), ('\u{a659}', ['\u{a658}', '\0', '\0']), ('\u{a65b}', ['\u{a65a}', - '\0', '\0']), ('\u{a65d}', ['\u{a65c}', '\0', '\0']), ('\u{a65f}', ['\u{a65e}', '\0', - '\0']), ('\u{a661}', ['\u{a660}', '\0', '\0']), ('\u{a663}', ['\u{a662}', '\0', '\0']), - ('\u{a665}', ['\u{a664}', '\0', '\0']), ('\u{a667}', ['\u{a666}', '\0', '\0']), ('\u{a669}', - ['\u{a668}', '\0', '\0']), ('\u{a66b}', ['\u{a66a}', '\0', '\0']), ('\u{a66d}', ['\u{a66c}', - '\0', '\0']), ('\u{a681}', ['\u{a680}', '\0', '\0']), ('\u{a683}', ['\u{a682}', '\0', - '\0']), ('\u{a685}', ['\u{a684}', '\0', '\0']), ('\u{a687}', ['\u{a686}', '\0', '\0']), - ('\u{a689}', ['\u{a688}', '\0', '\0']), ('\u{a68b}', ['\u{a68a}', '\0', '\0']), ('\u{a68d}', - ['\u{a68c}', '\0', '\0']), ('\u{a68f}', ['\u{a68e}', '\0', '\0']), ('\u{a691}', ['\u{a690}', - '\0', '\0']), ('\u{a693}', ['\u{a692}', '\0', '\0']), ('\u{a695}', ['\u{a694}', '\0', - '\0']), ('\u{a697}', ['\u{a696}', '\0', '\0']), ('\u{a699}', ['\u{a698}', '\0', '\0']), - ('\u{a69b}', ['\u{a69a}', '\0', '\0']), ('\u{a723}', ['\u{a722}', '\0', '\0']), ('\u{a725}', - ['\u{a724}', '\0', '\0']), ('\u{a727}', ['\u{a726}', '\0', '\0']), ('\u{a729}', ['\u{a728}', - '\0', '\0']), ('\u{a72b}', ['\u{a72a}', '\0', '\0']), ('\u{a72d}', ['\u{a72c}', '\0', - '\0']), ('\u{a72f}', ['\u{a72e}', '\0', '\0']), ('\u{a733}', ['\u{a732}', '\0', '\0']), - ('\u{a735}', ['\u{a734}', '\0', '\0']), ('\u{a737}', ['\u{a736}', '\0', '\0']), ('\u{a739}', - ['\u{a738}', '\0', '\0']), ('\u{a73b}', ['\u{a73a}', '\0', '\0']), ('\u{a73d}', ['\u{a73c}', - '\0', '\0']), ('\u{a73f}', ['\u{a73e}', '\0', '\0']), ('\u{a741}', ['\u{a740}', '\0', - '\0']), ('\u{a743}', ['\u{a742}', '\0', '\0']), ('\u{a745}', ['\u{a744}', '\0', '\0']), - ('\u{a747}', ['\u{a746}', '\0', '\0']), ('\u{a749}', ['\u{a748}', '\0', '\0']), ('\u{a74b}', - ['\u{a74a}', '\0', '\0']), ('\u{a74d}', ['\u{a74c}', '\0', '\0']), ('\u{a74f}', ['\u{a74e}', - '\0', '\0']), ('\u{a751}', ['\u{a750}', '\0', '\0']), ('\u{a753}', ['\u{a752}', '\0', - '\0']), ('\u{a755}', ['\u{a754}', '\0', '\0']), ('\u{a757}', ['\u{a756}', '\0', '\0']), - ('\u{a759}', ['\u{a758}', '\0', '\0']), ('\u{a75b}', ['\u{a75a}', '\0', '\0']), ('\u{a75d}', - ['\u{a75c}', '\0', '\0']), ('\u{a75f}', ['\u{a75e}', '\0', '\0']), ('\u{a761}', ['\u{a760}', - '\0', '\0']), ('\u{a763}', ['\u{a762}', '\0', '\0']), ('\u{a765}', ['\u{a764}', '\0', - '\0']), ('\u{a767}', ['\u{a766}', '\0', '\0']), ('\u{a769}', ['\u{a768}', '\0', '\0']), - ('\u{a76b}', ['\u{a76a}', '\0', '\0']), ('\u{a76d}', ['\u{a76c}', '\0', '\0']), ('\u{a76f}', - ['\u{a76e}', '\0', '\0']), ('\u{a77a}', ['\u{a779}', '\0', '\0']), ('\u{a77c}', ['\u{a77b}', - '\0', '\0']), ('\u{a77f}', ['\u{a77e}', '\0', '\0']), ('\u{a781}', ['\u{a780}', '\0', - '\0']), ('\u{a783}', ['\u{a782}', '\0', '\0']), ('\u{a785}', ['\u{a784}', '\0', '\0']), - ('\u{a787}', ['\u{a786}', '\0', '\0']), ('\u{a78c}', ['\u{a78b}', '\0', '\0']), ('\u{a791}', - ['\u{a790}', '\0', '\0']), ('\u{a793}', ['\u{a792}', '\0', '\0']), ('\u{a797}', ['\u{a796}', - '\0', '\0']), ('\u{a799}', ['\u{a798}', '\0', '\0']), ('\u{a79b}', ['\u{a79a}', '\0', - '\0']), ('\u{a79d}', ['\u{a79c}', '\0', '\0']), ('\u{a79f}', ['\u{a79e}', '\0', '\0']), - ('\u{a7a1}', ['\u{a7a0}', '\0', '\0']), ('\u{a7a3}', ['\u{a7a2}', '\0', '\0']), ('\u{a7a5}', - ['\u{a7a4}', '\0', '\0']), ('\u{a7a7}', ['\u{a7a6}', '\0', '\0']), ('\u{a7a9}', ['\u{a7a8}', - '\0', '\0']), ('\u{a7b5}', ['\u{a7b4}', '\0', '\0']), ('\u{a7b7}', ['\u{a7b6}', '\0', - '\0']), ('\u{ab53}', ['\u{a7b3}', '\0', '\0']), ('\u{ab70}', ['\u{13a0}', '\0', '\0']), - ('\u{ab71}', ['\u{13a1}', '\0', '\0']), ('\u{ab72}', ['\u{13a2}', '\0', '\0']), ('\u{ab73}', - ['\u{13a3}', '\0', '\0']), ('\u{ab74}', ['\u{13a4}', '\0', '\0']), ('\u{ab75}', ['\u{13a5}', - '\0', '\0']), ('\u{ab76}', ['\u{13a6}', '\0', '\0']), ('\u{ab77}', ['\u{13a7}', '\0', - '\0']), ('\u{ab78}', ['\u{13a8}', '\0', '\0']), ('\u{ab79}', ['\u{13a9}', '\0', '\0']), - ('\u{ab7a}', ['\u{13aa}', '\0', '\0']), ('\u{ab7b}', ['\u{13ab}', '\0', '\0']), ('\u{ab7c}', - ['\u{13ac}', '\0', '\0']), ('\u{ab7d}', ['\u{13ad}', '\0', '\0']), ('\u{ab7e}', ['\u{13ae}', - '\0', '\0']), ('\u{ab7f}', ['\u{13af}', '\0', '\0']), ('\u{ab80}', ['\u{13b0}', '\0', - '\0']), ('\u{ab81}', ['\u{13b1}', '\0', '\0']), ('\u{ab82}', ['\u{13b2}', '\0', '\0']), - ('\u{ab83}', ['\u{13b3}', '\0', '\0']), ('\u{ab84}', ['\u{13b4}', '\0', '\0']), ('\u{ab85}', - ['\u{13b5}', '\0', '\0']), ('\u{ab86}', ['\u{13b6}', '\0', '\0']), ('\u{ab87}', ['\u{13b7}', - '\0', '\0']), ('\u{ab88}', ['\u{13b8}', '\0', '\0']), ('\u{ab89}', ['\u{13b9}', '\0', - '\0']), ('\u{ab8a}', ['\u{13ba}', '\0', '\0']), ('\u{ab8b}', ['\u{13bb}', '\0', '\0']), - ('\u{ab8c}', ['\u{13bc}', '\0', '\0']), ('\u{ab8d}', ['\u{13bd}', '\0', '\0']), ('\u{ab8e}', - ['\u{13be}', '\0', '\0']), ('\u{ab8f}', ['\u{13bf}', '\0', '\0']), ('\u{ab90}', ['\u{13c0}', - '\0', '\0']), ('\u{ab91}', ['\u{13c1}', '\0', '\0']), ('\u{ab92}', ['\u{13c2}', '\0', - '\0']), ('\u{ab93}', ['\u{13c3}', '\0', '\0']), ('\u{ab94}', ['\u{13c4}', '\0', '\0']), - ('\u{ab95}', ['\u{13c5}', '\0', '\0']), ('\u{ab96}', ['\u{13c6}', '\0', '\0']), ('\u{ab97}', - ['\u{13c7}', '\0', '\0']), ('\u{ab98}', ['\u{13c8}', '\0', '\0']), ('\u{ab99}', ['\u{13c9}', - '\0', '\0']), ('\u{ab9a}', ['\u{13ca}', '\0', '\0']), ('\u{ab9b}', ['\u{13cb}', '\0', - '\0']), ('\u{ab9c}', ['\u{13cc}', '\0', '\0']), ('\u{ab9d}', ['\u{13cd}', '\0', '\0']), - ('\u{ab9e}', ['\u{13ce}', '\0', '\0']), ('\u{ab9f}', ['\u{13cf}', '\0', '\0']), ('\u{aba0}', - ['\u{13d0}', '\0', '\0']), ('\u{aba1}', ['\u{13d1}', '\0', '\0']), ('\u{aba2}', ['\u{13d2}', - '\0', '\0']), ('\u{aba3}', ['\u{13d3}', '\0', '\0']), ('\u{aba4}', ['\u{13d4}', '\0', - '\0']), ('\u{aba5}', ['\u{13d5}', '\0', '\0']), ('\u{aba6}', ['\u{13d6}', '\0', '\0']), - ('\u{aba7}', ['\u{13d7}', '\0', '\0']), ('\u{aba8}', ['\u{13d8}', '\0', '\0']), ('\u{aba9}', - ['\u{13d9}', '\0', '\0']), ('\u{abaa}', ['\u{13da}', '\0', '\0']), ('\u{abab}', ['\u{13db}', - '\0', '\0']), ('\u{abac}', ['\u{13dc}', '\0', '\0']), ('\u{abad}', ['\u{13dd}', '\0', - '\0']), ('\u{abae}', ['\u{13de}', '\0', '\0']), ('\u{abaf}', ['\u{13df}', '\0', '\0']), - ('\u{abb0}', ['\u{13e0}', '\0', '\0']), ('\u{abb1}', ['\u{13e1}', '\0', '\0']), ('\u{abb2}', - ['\u{13e2}', '\0', '\0']), ('\u{abb3}', ['\u{13e3}', '\0', '\0']), ('\u{abb4}', ['\u{13e4}', - '\0', '\0']), ('\u{abb5}', ['\u{13e5}', '\0', '\0']), ('\u{abb6}', ['\u{13e6}', '\0', - '\0']), ('\u{abb7}', ['\u{13e7}', '\0', '\0']), ('\u{abb8}', ['\u{13e8}', '\0', '\0']), - ('\u{abb9}', ['\u{13e9}', '\0', '\0']), ('\u{abba}', ['\u{13ea}', '\0', '\0']), ('\u{abbb}', - ['\u{13eb}', '\0', '\0']), ('\u{abbc}', ['\u{13ec}', '\0', '\0']), ('\u{abbd}', ['\u{13ed}', - '\0', '\0']), ('\u{abbe}', ['\u{13ee}', '\0', '\0']), ('\u{abbf}', ['\u{13ef}', '\0', - '\0']), ('\u{fb00}', ['\u{46}', '\u{46}', '\0']), ('\u{fb01}', ['\u{46}', '\u{49}', '\0']), - ('\u{fb02}', ['\u{46}', '\u{4c}', '\0']), ('\u{fb03}', ['\u{46}', '\u{46}', '\u{49}']), - ('\u{fb04}', ['\u{46}', '\u{46}', '\u{4c}']), ('\u{fb05}', ['\u{53}', '\u{54}', '\0']), - ('\u{fb06}', ['\u{53}', '\u{54}', '\0']), ('\u{fb13}', ['\u{544}', '\u{546}', '\0']), - ('\u{fb14}', ['\u{544}', '\u{535}', '\0']), ('\u{fb15}', ['\u{544}', '\u{53b}', '\0']), - ('\u{fb16}', ['\u{54e}', '\u{546}', '\0']), ('\u{fb17}', ['\u{544}', '\u{53d}', '\0']), - ('\u{ff41}', ['\u{ff21}', '\0', '\0']), ('\u{ff42}', ['\u{ff22}', '\0', '\0']), ('\u{ff43}', - ['\u{ff23}', '\0', '\0']), ('\u{ff44}', ['\u{ff24}', '\0', '\0']), ('\u{ff45}', ['\u{ff25}', - '\0', '\0']), ('\u{ff46}', ['\u{ff26}', '\0', '\0']), ('\u{ff47}', ['\u{ff27}', '\0', - '\0']), ('\u{ff48}', ['\u{ff28}', '\0', '\0']), ('\u{ff49}', ['\u{ff29}', '\0', '\0']), - ('\u{ff4a}', ['\u{ff2a}', '\0', '\0']), ('\u{ff4b}', ['\u{ff2b}', '\0', '\0']), ('\u{ff4c}', - ['\u{ff2c}', '\0', '\0']), ('\u{ff4d}', ['\u{ff2d}', '\0', '\0']), ('\u{ff4e}', ['\u{ff2e}', - '\0', '\0']), ('\u{ff4f}', ['\u{ff2f}', '\0', '\0']), ('\u{ff50}', ['\u{ff30}', '\0', - '\0']), ('\u{ff51}', ['\u{ff31}', '\0', '\0']), ('\u{ff52}', ['\u{ff32}', '\0', '\0']), - ('\u{ff53}', ['\u{ff33}', '\0', '\0']), ('\u{ff54}', ['\u{ff34}', '\0', '\0']), ('\u{ff55}', - ['\u{ff35}', '\0', '\0']), ('\u{ff56}', ['\u{ff36}', '\0', '\0']), ('\u{ff57}', ['\u{ff37}', - '\0', '\0']), ('\u{ff58}', ['\u{ff38}', '\0', '\0']), ('\u{ff59}', ['\u{ff39}', '\0', - '\0']), ('\u{ff5a}', ['\u{ff3a}', '\0', '\0']), ('\u{10428}', ['\u{10400}', '\0', '\0']), - ('\u{10429}', ['\u{10401}', '\0', '\0']), ('\u{1042a}', ['\u{10402}', '\0', '\0']), - ('\u{1042b}', ['\u{10403}', '\0', '\0']), ('\u{1042c}', ['\u{10404}', '\0', '\0']), - ('\u{1042d}', ['\u{10405}', '\0', '\0']), ('\u{1042e}', ['\u{10406}', '\0', '\0']), - ('\u{1042f}', ['\u{10407}', '\0', '\0']), ('\u{10430}', ['\u{10408}', '\0', '\0']), - ('\u{10431}', ['\u{10409}', '\0', '\0']), ('\u{10432}', ['\u{1040a}', '\0', '\0']), - ('\u{10433}', ['\u{1040b}', '\0', '\0']), ('\u{10434}', ['\u{1040c}', '\0', '\0']), - ('\u{10435}', ['\u{1040d}', '\0', '\0']), ('\u{10436}', ['\u{1040e}', '\0', '\0']), - ('\u{10437}', ['\u{1040f}', '\0', '\0']), ('\u{10438}', ['\u{10410}', '\0', '\0']), - ('\u{10439}', ['\u{10411}', '\0', '\0']), ('\u{1043a}', ['\u{10412}', '\0', '\0']), - ('\u{1043b}', ['\u{10413}', '\0', '\0']), ('\u{1043c}', ['\u{10414}', '\0', '\0']), - ('\u{1043d}', ['\u{10415}', '\0', '\0']), ('\u{1043e}', ['\u{10416}', '\0', '\0']), - ('\u{1043f}', ['\u{10417}', '\0', '\0']), ('\u{10440}', ['\u{10418}', '\0', '\0']), - ('\u{10441}', ['\u{10419}', '\0', '\0']), ('\u{10442}', ['\u{1041a}', '\0', '\0']), - ('\u{10443}', ['\u{1041b}', '\0', '\0']), ('\u{10444}', ['\u{1041c}', '\0', '\0']), - ('\u{10445}', ['\u{1041d}', '\0', '\0']), ('\u{10446}', ['\u{1041e}', '\0', '\0']), - ('\u{10447}', ['\u{1041f}', '\0', '\0']), ('\u{10448}', ['\u{10420}', '\0', '\0']), - ('\u{10449}', ['\u{10421}', '\0', '\0']), ('\u{1044a}', ['\u{10422}', '\0', '\0']), - ('\u{1044b}', ['\u{10423}', '\0', '\0']), ('\u{1044c}', ['\u{10424}', '\0', '\0']), - ('\u{1044d}', ['\u{10425}', '\0', '\0']), ('\u{1044e}', ['\u{10426}', '\0', '\0']), - ('\u{1044f}', ['\u{10427}', '\0', '\0']), ('\u{104d8}', ['\u{104b0}', '\0', '\0']), - ('\u{104d9}', ['\u{104b1}', '\0', '\0']), ('\u{104da}', ['\u{104b2}', '\0', '\0']), - ('\u{104db}', ['\u{104b3}', '\0', '\0']), ('\u{104dc}', ['\u{104b4}', '\0', '\0']), - ('\u{104dd}', ['\u{104b5}', '\0', '\0']), ('\u{104de}', ['\u{104b6}', '\0', '\0']), - ('\u{104df}', ['\u{104b7}', '\0', '\0']), ('\u{104e0}', ['\u{104b8}', '\0', '\0']), - ('\u{104e1}', ['\u{104b9}', '\0', '\0']), ('\u{104e2}', ['\u{104ba}', '\0', '\0']), - ('\u{104e3}', ['\u{104bb}', '\0', '\0']), ('\u{104e4}', ['\u{104bc}', '\0', '\0']), - ('\u{104e5}', ['\u{104bd}', '\0', '\0']), ('\u{104e6}', ['\u{104be}', '\0', '\0']), - ('\u{104e7}', ['\u{104bf}', '\0', '\0']), ('\u{104e8}', ['\u{104c0}', '\0', '\0']), - ('\u{104e9}', ['\u{104c1}', '\0', '\0']), ('\u{104ea}', ['\u{104c2}', '\0', '\0']), - ('\u{104eb}', ['\u{104c3}', '\0', '\0']), ('\u{104ec}', ['\u{104c4}', '\0', '\0']), - ('\u{104ed}', ['\u{104c5}', '\0', '\0']), ('\u{104ee}', ['\u{104c6}', '\0', '\0']), - ('\u{104ef}', ['\u{104c7}', '\0', '\0']), ('\u{104f0}', ['\u{104c8}', '\0', '\0']), - ('\u{104f1}', ['\u{104c9}', '\0', '\0']), ('\u{104f2}', ['\u{104ca}', '\0', '\0']), - ('\u{104f3}', ['\u{104cb}', '\0', '\0']), ('\u{104f4}', ['\u{104cc}', '\0', '\0']), - ('\u{104f5}', ['\u{104cd}', '\0', '\0']), ('\u{104f6}', ['\u{104ce}', '\0', '\0']), - ('\u{104f7}', ['\u{104cf}', '\0', '\0']), ('\u{104f8}', ['\u{104d0}', '\0', '\0']), - ('\u{104f9}', ['\u{104d1}', '\0', '\0']), ('\u{104fa}', ['\u{104d2}', '\0', '\0']), - ('\u{104fb}', ['\u{104d3}', '\0', '\0']), ('\u{10cc0}', ['\u{10c80}', '\0', '\0']), - ('\u{10cc1}', ['\u{10c81}', '\0', '\0']), ('\u{10cc2}', ['\u{10c82}', '\0', '\0']), - ('\u{10cc3}', ['\u{10c83}', '\0', '\0']), ('\u{10cc4}', ['\u{10c84}', '\0', '\0']), - ('\u{10cc5}', ['\u{10c85}', '\0', '\0']), ('\u{10cc6}', ['\u{10c86}', '\0', '\0']), - ('\u{10cc7}', ['\u{10c87}', '\0', '\0']), ('\u{10cc8}', ['\u{10c88}', '\0', '\0']), - ('\u{10cc9}', ['\u{10c89}', '\0', '\0']), ('\u{10cca}', ['\u{10c8a}', '\0', '\0']), - ('\u{10ccb}', ['\u{10c8b}', '\0', '\0']), ('\u{10ccc}', ['\u{10c8c}', '\0', '\0']), - ('\u{10ccd}', ['\u{10c8d}', '\0', '\0']), ('\u{10cce}', ['\u{10c8e}', '\0', '\0']), - ('\u{10ccf}', ['\u{10c8f}', '\0', '\0']), ('\u{10cd0}', ['\u{10c90}', '\0', '\0']), - ('\u{10cd1}', ['\u{10c91}', '\0', '\0']), ('\u{10cd2}', ['\u{10c92}', '\0', '\0']), - ('\u{10cd3}', ['\u{10c93}', '\0', '\0']), ('\u{10cd4}', ['\u{10c94}', '\0', '\0']), - ('\u{10cd5}', ['\u{10c95}', '\0', '\0']), ('\u{10cd6}', ['\u{10c96}', '\0', '\0']), - ('\u{10cd7}', ['\u{10c97}', '\0', '\0']), ('\u{10cd8}', ['\u{10c98}', '\0', '\0']), - ('\u{10cd9}', ['\u{10c99}', '\0', '\0']), ('\u{10cda}', ['\u{10c9a}', '\0', '\0']), - ('\u{10cdb}', ['\u{10c9b}', '\0', '\0']), ('\u{10cdc}', ['\u{10c9c}', '\0', '\0']), - ('\u{10cdd}', ['\u{10c9d}', '\0', '\0']), ('\u{10cde}', ['\u{10c9e}', '\0', '\0']), - ('\u{10cdf}', ['\u{10c9f}', '\0', '\0']), ('\u{10ce0}', ['\u{10ca0}', '\0', '\0']), - ('\u{10ce1}', ['\u{10ca1}', '\0', '\0']), ('\u{10ce2}', ['\u{10ca2}', '\0', '\0']), - ('\u{10ce3}', ['\u{10ca3}', '\0', '\0']), ('\u{10ce4}', ['\u{10ca4}', '\0', '\0']), - ('\u{10ce5}', ['\u{10ca5}', '\0', '\0']), ('\u{10ce6}', ['\u{10ca6}', '\0', '\0']), - ('\u{10ce7}', ['\u{10ca7}', '\0', '\0']), ('\u{10ce8}', ['\u{10ca8}', '\0', '\0']), - ('\u{10ce9}', ['\u{10ca9}', '\0', '\0']), ('\u{10cea}', ['\u{10caa}', '\0', '\0']), - ('\u{10ceb}', ['\u{10cab}', '\0', '\0']), ('\u{10cec}', ['\u{10cac}', '\0', '\0']), - ('\u{10ced}', ['\u{10cad}', '\0', '\0']), ('\u{10cee}', ['\u{10cae}', '\0', '\0']), - ('\u{10cef}', ['\u{10caf}', '\0', '\0']), ('\u{10cf0}', ['\u{10cb0}', '\0', '\0']), - ('\u{10cf1}', ['\u{10cb1}', '\0', '\0']), ('\u{10cf2}', ['\u{10cb2}', '\0', '\0']), - ('\u{118c0}', ['\u{118a0}', '\0', '\0']), ('\u{118c1}', ['\u{118a1}', '\0', '\0']), - ('\u{118c2}', ['\u{118a2}', '\0', '\0']), ('\u{118c3}', ['\u{118a3}', '\0', '\0']), - ('\u{118c4}', ['\u{118a4}', '\0', '\0']), ('\u{118c5}', ['\u{118a5}', '\0', '\0']), - ('\u{118c6}', ['\u{118a6}', '\0', '\0']), ('\u{118c7}', ['\u{118a7}', '\0', '\0']), - ('\u{118c8}', ['\u{118a8}', '\0', '\0']), ('\u{118c9}', ['\u{118a9}', '\0', '\0']), - ('\u{118ca}', ['\u{118aa}', '\0', '\0']), ('\u{118cb}', ['\u{118ab}', '\0', '\0']), - ('\u{118cc}', ['\u{118ac}', '\0', '\0']), ('\u{118cd}', ['\u{118ad}', '\0', '\0']), - ('\u{118ce}', ['\u{118ae}', '\0', '\0']), ('\u{118cf}', ['\u{118af}', '\0', '\0']), - ('\u{118d0}', ['\u{118b0}', '\0', '\0']), ('\u{118d1}', ['\u{118b1}', '\0', '\0']), - ('\u{118d2}', ['\u{118b2}', '\0', '\0']), ('\u{118d3}', ['\u{118b3}', '\0', '\0']), - ('\u{118d4}', ['\u{118b4}', '\0', '\0']), ('\u{118d5}', ['\u{118b5}', '\0', '\0']), - ('\u{118d6}', ['\u{118b6}', '\0', '\0']), ('\u{118d7}', ['\u{118b7}', '\0', '\0']), - ('\u{118d8}', ['\u{118b8}', '\0', '\0']), ('\u{118d9}', ['\u{118b9}', '\0', '\0']), - ('\u{118da}', ['\u{118ba}', '\0', '\0']), ('\u{118db}', ['\u{118bb}', '\0', '\0']), - ('\u{118dc}', ['\u{118bc}', '\0', '\0']), ('\u{118dd}', ['\u{118bd}', '\0', '\0']), - ('\u{118de}', ['\u{118be}', '\0', '\0']), ('\u{118df}', ['\u{118bf}', '\0', '\0']), - ('\u{1e922}', ['\u{1e900}', '\0', '\0']), ('\u{1e923}', ['\u{1e901}', '\0', '\0']), - ('\u{1e924}', ['\u{1e902}', '\0', '\0']), ('\u{1e925}', ['\u{1e903}', '\0', '\0']), - ('\u{1e926}', ['\u{1e904}', '\0', '\0']), ('\u{1e927}', ['\u{1e905}', '\0', '\0']), - ('\u{1e928}', ['\u{1e906}', '\0', '\0']), ('\u{1e929}', ['\u{1e907}', '\0', '\0']), - ('\u{1e92a}', ['\u{1e908}', '\0', '\0']), ('\u{1e92b}', ['\u{1e909}', '\0', '\0']), - ('\u{1e92c}', ['\u{1e90a}', '\0', '\0']), ('\u{1e92d}', ['\u{1e90b}', '\0', '\0']), - ('\u{1e92e}', ['\u{1e90c}', '\0', '\0']), ('\u{1e92f}', ['\u{1e90d}', '\0', '\0']), - ('\u{1e930}', ['\u{1e90e}', '\0', '\0']), ('\u{1e931}', ['\u{1e90f}', '\0', '\0']), - ('\u{1e932}', ['\u{1e910}', '\0', '\0']), ('\u{1e933}', ['\u{1e911}', '\0', '\0']), - ('\u{1e934}', ['\u{1e912}', '\0', '\0']), ('\u{1e935}', ['\u{1e913}', '\0', '\0']), - ('\u{1e936}', ['\u{1e914}', '\0', '\0']), ('\u{1e937}', ['\u{1e915}', '\0', '\0']), - ('\u{1e938}', ['\u{1e916}', '\0', '\0']), ('\u{1e939}', ['\u{1e917}', '\0', '\0']), - ('\u{1e93a}', ['\u{1e918}', '\0', '\0']), ('\u{1e93b}', ['\u{1e919}', '\0', '\0']), - ('\u{1e93c}', ['\u{1e91a}', '\0', '\0']), ('\u{1e93d}', ['\u{1e91b}', '\0', '\0']), - ('\u{1e93e}', ['\u{1e91c}', '\0', '\0']), ('\u{1e93f}', ['\u{1e91d}', '\0', '\0']), - ('\u{1e940}', ['\u{1e91e}', '\0', '\0']), ('\u{1e941}', ['\u{1e91f}', '\0', '\0']), - ('\u{1e942}', ['\u{1e920}', '\0', '\0']), ('\u{1e943}', ['\u{1e921}', '\0', '\0']) - ]; - -} - diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs deleted file mode 100644 index a72e1210d93..00000000000 --- a/src/libstd_unicode/u_str.rs +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unicode-intensive string manipulations. -//! -//! This module provides functionality to `str` that requires the Unicode -//! methods provided by the unicode parts of the CharExt trait. - -use core::char; -use core::iter::{Filter, FusedIterator}; -use core::str::Split; - -/// An iterator over the non-whitespace substrings of a string, -/// separated by any amount of whitespace. -/// -/// This struct is created by the [`split_whitespace`] method on [`str`]. -/// See its documentation for more. -/// -/// [`split_whitespace`]: ../../std/primitive.str.html#method.split_whitespace -/// [`str`]: ../../std/primitive.str.html -#[stable(feature = "split_whitespace", since = "1.1.0")] -#[derive(Clone, Debug)] -pub struct SplitWhitespace<'a> { - inner: Filter, IsNotEmpty>, -} - -/// Methods for Unicode string slices -#[allow(missing_docs)] // docs in liballoc -pub trait UnicodeStr { - fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>; - fn is_whitespace(&self) -> bool; - fn is_alphanumeric(&self) -> bool; - fn trim(&self) -> &str; - fn trim_left(&self) -> &str; - fn trim_right(&self) -> &str; -} - -impl UnicodeStr for str { - #[inline] - fn split_whitespace(&self) -> SplitWhitespace { - SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } - } - - #[inline] - fn is_whitespace(&self) -> bool { - self.chars().all(|c| c.is_whitespace()) - } - - #[inline] - fn is_alphanumeric(&self) -> bool { - self.chars().all(|c| c.is_alphanumeric()) - } - - #[inline] - fn trim(&self) -> &str { - self.trim_matches(|c: char| c.is_whitespace()) - } - - #[inline] - fn trim_left(&self) -> &str { - self.trim_left_matches(|c: char| c.is_whitespace()) - } - - #[inline] - fn trim_right(&self) -> &str { - self.trim_right_matches(|c: char| c.is_whitespace()) - } -} - -/// Iterator adaptor for encoding `char`s to UTF-16. -#[derive(Clone)] -#[allow(missing_debug_implementations)] -pub struct Utf16Encoder { - chars: I, - extra: u16, -} - -impl Utf16Encoder { - /// Create a UTF-16 encoder from any `char` iterator. - pub fn new(chars: I) -> Utf16Encoder - where I: Iterator - { - Utf16Encoder { - chars, - extra: 0, - } - } -} - -impl Iterator for Utf16Encoder - where I: Iterator -{ - type Item = u16; - - #[inline] - fn next(&mut self) -> Option { - if self.extra != 0 { - let tmp = self.extra; - self.extra = 0; - return Some(tmp); - } - - let mut buf = [0; 2]; - self.chars.next().map(|ch| { - let n = CharExt::encode_utf16(ch, &mut buf).len(); - if n == 2 { - self.extra = buf[1]; - } - buf[0] - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (low, high) = self.chars.size_hint(); - // every char gets either one u16 or two u16, - // so this iterator is between 1 or 2 times as - // long as the underlying iterator. - (low, high.and_then(|n| n.checked_mul(2))) - } -} - -impl FusedIterator for Utf16Encoder - where I: FusedIterator {} - -#[derive(Clone)] -struct IsWhitespace; - -impl FnOnce<(char, )> for IsWhitespace { - type Output = bool; - - #[inline] - extern "rust-call" fn call_once(mut self, arg: (char, )) -> bool { - self.call_mut(arg) - } -} - -impl FnMut<(char, )> for IsWhitespace { - #[inline] - extern "rust-call" fn call_mut(&mut self, arg: (char, )) -> bool { - arg.0.is_whitespace() - } -} - -#[derive(Clone)] -struct IsNotEmpty; - -impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty { - type Output = bool; - - #[inline] - extern "rust-call" fn call_once(mut self, arg: (&&str, )) -> bool { - self.call_mut(arg) - } -} - -impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty { - #[inline] - extern "rust-call" fn call_mut(&mut self, arg: (&&str, )) -> bool { - !arg.0.is_empty() - } -} - - -#[stable(feature = "split_whitespace", since = "1.1.0")] -impl<'a> Iterator for SplitWhitespace<'a> { - type Item = &'a str; - - fn next(&mut self) -> Option<&'a str> { - self.inner.next() - } -} - -#[stable(feature = "split_whitespace", since = "1.1.0")] -impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { - fn next_back(&mut self) -> Option<&'a str> { - self.inner.next_back() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a> FusedIterator for SplitWhitespace<'a> {} diff --git a/src/libstd_unicode/unicode.py b/src/libstd_unicode/unicode.py deleted file mode 100755 index a8629493086..00000000000 --- a/src/libstd_unicode/unicode.py +++ /dev/null @@ -1,504 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2011-2013 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -# This script uses the following Unicode tables: -# - DerivedCoreProperties.txt -# - DerivedNormalizationProps.txt -# - EastAsianWidth.txt -# - auxiliary/GraphemeBreakProperty.txt -# - PropList.txt -# - ReadMe.txt -# - Scripts.txt -# - UnicodeData.txt -# -# Since this should not require frequent updates, we just store this -# out-of-line and check the unicode.rs file into git. - -import fileinput, re, os, sys, operator, math - -preamble = '''// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// NOTE: The following code was generated by "./unicode.py", do not edit directly - -#![allow(missing_docs, non_upper_case_globals, non_snake_case)] - -use version::UnicodeVersion; -use bool_trie::{BoolTrie, SmallBoolTrie}; -''' - -# Mapping taken from Table 12 from: -# http://www.unicode.org/reports/tr44/#General_Category_Values -expanded_categories = { - 'Lu': ['LC', 'L'], 'Ll': ['LC', 'L'], 'Lt': ['LC', 'L'], - 'Lm': ['L'], 'Lo': ['L'], - 'Mn': ['M'], 'Mc': ['M'], 'Me': ['M'], - 'Nd': ['N'], 'Nl': ['N'], 'No': ['No'], - 'Pc': ['P'], 'Pd': ['P'], 'Ps': ['P'], 'Pe': ['P'], - 'Pi': ['P'], 'Pf': ['P'], 'Po': ['P'], - 'Sm': ['S'], 'Sc': ['S'], 'Sk': ['S'], 'So': ['S'], - 'Zs': ['Z'], 'Zl': ['Z'], 'Zp': ['Z'], - 'Cc': ['C'], 'Cf': ['C'], 'Cs': ['C'], 'Co': ['C'], 'Cn': ['C'], -} - -# these are the surrogate codepoints, which are not valid rust characters -surrogate_codepoints = (0xd800, 0xdfff) - -def fetch(f): - if not os.path.exists(os.path.basename(f)): - os.system("curl -O http://www.unicode.org/Public/UNIDATA/%s" - % f) - - if not os.path.exists(os.path.basename(f)): - sys.stderr.write("cannot load %s" % f) - exit(1) - -def is_surrogate(n): - return surrogate_codepoints[0] <= n <= surrogate_codepoints[1] - -def load_unicode_data(f): - fetch(f) - gencats = {} - to_lower = {} - to_upper = {} - to_title = {} - combines = {} - canon_decomp = {} - compat_decomp = {} - - udict = {} - range_start = -1 - for line in fileinput.input(f): - data = line.split(';') - if len(data) != 15: - continue - cp = int(data[0], 16) - if is_surrogate(cp): - continue - if range_start >= 0: - for i in range(range_start, cp): - udict[i] = data - range_start = -1 - if data[1].endswith(", First>"): - range_start = cp - continue - udict[cp] = data - - for code in udict: - (code_org, name, gencat, combine, bidi, - decomp, deci, digit, num, mirror, - old, iso, upcase, lowcase, titlecase) = udict[code] - - # generate char to char direct common and simple conversions - # uppercase to lowercase - if lowcase != "" and code_org != lowcase: - to_lower[code] = (int(lowcase, 16), 0, 0) - - # lowercase to uppercase - if upcase != "" and code_org != upcase: - to_upper[code] = (int(upcase, 16), 0, 0) - - # title case - if titlecase.strip() != "" and code_org != titlecase: - to_title[code] = (int(titlecase, 16), 0, 0) - - # store decomposition, if given - if decomp != "": - if decomp.startswith('<'): - seq = [] - for i in decomp.split()[1:]: - seq.append(int(i, 16)) - compat_decomp[code] = seq - else: - seq = [] - for i in decomp.split(): - seq.append(int(i, 16)) - canon_decomp[code] = seq - - # place letter in categories as appropriate - for cat in [gencat, "Assigned"] + expanded_categories.get(gencat, []): - if cat not in gencats: - gencats[cat] = [] - gencats[cat].append(code) - - # record combining class, if any - if combine != "0": - if combine not in combines: - combines[combine] = [] - combines[combine].append(code) - - # generate Not_Assigned from Assigned - gencats["Cn"] = gen_unassigned(gencats["Assigned"]) - # Assigned is not a real category - del(gencats["Assigned"]) - # Other contains Not_Assigned - gencats["C"].extend(gencats["Cn"]) - gencats = group_cats(gencats) - combines = to_combines(group_cats(combines)) - - return (canon_decomp, compat_decomp, gencats, combines, to_upper, to_lower, to_title) - -def load_special_casing(f, to_upper, to_lower, to_title): - fetch(f) - for line in fileinput.input(f): - data = line.split('#')[0].split(';') - if len(data) == 5: - code, lower, title, upper, _comment = data - elif len(data) == 6: - code, lower, title, upper, condition, _comment = data - if condition.strip(): # Only keep unconditional mappins - continue - else: - continue - code = code.strip() - lower = lower.strip() - title = title.strip() - upper = upper.strip() - key = int(code, 16) - for (map_, values) in [(to_lower, lower), (to_upper, upper), (to_title, title)]: - if values != code: - values = [int(i, 16) for i in values.split()] - for _ in range(len(values), 3): - values.append(0) - assert len(values) == 3 - map_[key] = values - -def group_cats(cats): - cats_out = {} - for cat in cats: - cats_out[cat] = group_cat(cats[cat]) - return cats_out - -def group_cat(cat): - cat_out = [] - letters = sorted(set(cat)) - cur_start = letters.pop(0) - cur_end = cur_start - for letter in letters: - assert letter > cur_end, \ - "cur_end: %s, letter: %s" % (hex(cur_end), hex(letter)) - if letter == cur_end + 1: - cur_end = letter - else: - cat_out.append((cur_start, cur_end)) - cur_start = cur_end = letter - cat_out.append((cur_start, cur_end)) - return cat_out - -def ungroup_cat(cat): - cat_out = [] - for (lo, hi) in cat: - while lo <= hi: - cat_out.append(lo) - lo += 1 - return cat_out - -def gen_unassigned(assigned): - assigned = set(assigned) - return ([i for i in range(0, 0xd800) if i not in assigned] + - [i for i in range(0xe000, 0x110000) if i not in assigned]) - -def to_combines(combs): - combs_out = [] - for comb in combs: - for (lo, hi) in combs[comb]: - combs_out.append((lo, hi, comb)) - combs_out.sort(key=lambda comb: comb[0]) - return combs_out - -def format_table_content(f, content, indent): - line = " "*indent - first = True - for chunk in content.split(","): - if len(line) + len(chunk) < 98: - if first: - line += chunk - else: - line += ", " + chunk - first = False - else: - f.write(line + ",\n") - line = " "*indent + chunk - f.write(line) - -def load_properties(f, interestingprops): - fetch(f) - props = {} - re1 = re.compile("^ *([0-9A-F]+) *; *(\w+)") - re2 = re.compile("^ *([0-9A-F]+)\.\.([0-9A-F]+) *; *(\w+)") - - for line in fileinput.input(os.path.basename(f)): - prop = None - d_lo = 0 - d_hi = 0 - m = re1.match(line) - if m: - d_lo = m.group(1) - d_hi = m.group(1) - prop = m.group(2) - else: - m = re2.match(line) - if m: - d_lo = m.group(1) - d_hi = m.group(2) - prop = m.group(3) - else: - continue - if interestingprops and prop not in interestingprops: - continue - d_lo = int(d_lo, 16) - d_hi = int(d_hi, 16) - if prop not in props: - props[prop] = [] - props[prop].append((d_lo, d_hi)) - - # optimize if possible - for prop in props: - props[prop] = group_cat(ungroup_cat(props[prop])) - - return props - -def escape_char(c): - return "'\\u{%x}'" % c if c != 0 else "'\\0'" - -def emit_table(f, name, t_data, t_type = "&[(char, char)]", is_pub=True, - pfun=lambda x: "(%s,%s)" % (escape_char(x[0]), escape_char(x[1]))): - pub_string = "" - if is_pub: - pub_string = "pub " - f.write(" %sconst %s: %s = &[\n" % (pub_string, name, t_type)) - data = "" - first = True - for dat in t_data: - if not first: - data += "," - first = False - data += pfun(dat) - format_table_content(f, data, 8) - f.write("\n ];\n\n") - -def compute_trie(rawdata, chunksize): - root = [] - childmap = {} - child_data = [] - for i in range(len(rawdata) // chunksize): - data = rawdata[i * chunksize: (i + 1) * chunksize] - child = '|'.join(map(str, data)) - if child not in childmap: - childmap[child] = len(childmap) - child_data.extend(data) - root.append(childmap[child]) - return (root, child_data) - -def emit_bool_trie(f, name, t_data, is_pub=True): - CHUNK = 64 - rawdata = [False] * 0x110000 - for (lo, hi) in t_data: - for cp in range(lo, hi + 1): - rawdata[cp] = True - - # convert to bitmap chunks of 64 bits each - chunks = [] - for i in range(0x110000 // CHUNK): - chunk = 0 - for j in range(64): - if rawdata[i * 64 + j]: - chunk |= 1 << j - chunks.append(chunk) - - pub_string = "" - if is_pub: - pub_string = "pub " - f.write(" %sconst %s: &super::BoolTrie = &super::BoolTrie {\n" % (pub_string, name)) - f.write(" r1: [\n") - data = ','.join('0x%016x' % chunk for chunk in chunks[0:0x800 // CHUNK]) - format_table_content(f, data, 12) - f.write("\n ],\n") - - # 0x800..0x10000 trie - (r2, r3) = compute_trie(chunks[0x800 // CHUNK : 0x10000 // CHUNK], 64 // CHUNK) - f.write(" r2: [\n") - data = ','.join(str(node) for node in r2) - format_table_content(f, data, 12) - f.write("\n ],\n") - f.write(" r3: &[\n") - data = ','.join('0x%016x' % chunk for chunk in r3) - format_table_content(f, data, 12) - f.write("\n ],\n") - - # 0x10000..0x110000 trie - (mid, r6) = compute_trie(chunks[0x10000 // CHUNK : 0x110000 // CHUNK], 64 // CHUNK) - (r4, r5) = compute_trie(mid, 64) - f.write(" r4: [\n") - data = ','.join(str(node) for node in r4) - format_table_content(f, data, 12) - f.write("\n ],\n") - f.write(" r5: &[\n") - data = ','.join(str(node) for node in r5) - format_table_content(f, data, 12) - f.write("\n ],\n") - f.write(" r6: &[\n") - data = ','.join('0x%016x' % chunk for chunk in r6) - format_table_content(f, data, 12) - f.write("\n ],\n") - - f.write(" };\n\n") - -def emit_small_bool_trie(f, name, t_data, is_pub=True): - last_chunk = max(hi // 64 for (lo, hi) in t_data) - n_chunks = last_chunk + 1 - chunks = [0] * n_chunks - for (lo, hi) in t_data: - for cp in range(lo, hi + 1): - if cp // 64 >= len(chunks): - print(cp, cp // 64, len(chunks), lo, hi) - chunks[cp // 64] |= 1 << (cp & 63) - - pub_string = "" - if is_pub: - pub_string = "pub " - f.write(" %sconst %s: &super::SmallBoolTrie = &super::SmallBoolTrie {\n" - % (pub_string, name)) - - (r1, r2) = compute_trie(chunks, 1) - - f.write(" r1: &[\n") - data = ','.join(str(node) for node in r1) - format_table_content(f, data, 12) - f.write("\n ],\n") - - f.write(" r2: &[\n") - data = ','.join('0x%016x' % node for node in r2) - format_table_content(f, data, 12) - f.write("\n ],\n") - - f.write(" };\n\n") - -def emit_property_module(f, mod, tbl, emit): - f.write("pub mod %s {\n" % mod) - for cat in sorted(emit): - if cat in ["Cc", "White_Space", "Pattern_White_Space"]: - emit_small_bool_trie(f, "%s_table" % cat, tbl[cat]) - f.write(" pub fn %s(c: char) -> bool {\n" % cat) - f.write(" %s_table.lookup(c)\n" % cat) - f.write(" }\n\n") - else: - emit_bool_trie(f, "%s_table" % cat, tbl[cat]) - f.write(" pub fn %s(c: char) -> bool {\n" % cat) - f.write(" %s_table.lookup(c)\n" % cat) - f.write(" }\n\n") - f.write("}\n\n") - -def emit_conversions_module(f, to_upper, to_lower, to_title): - f.write("pub mod conversions {") - f.write(""" - use core::option::Option; - use core::option::Option::{Some, None}; - - pub fn to_lower(c: char) -> [char; 3] { - match bsearch_case_table(c, to_lowercase_table) { - None => [c, '\\0', '\\0'], - Some(index) => to_lowercase_table[index].1, - } - } - - pub fn to_upper(c: char) -> [char; 3] { - match bsearch_case_table(c, to_uppercase_table) { - None => [c, '\\0', '\\0'], - Some(index) => to_uppercase_table[index].1, - } - } - - fn bsearch_case_table(c: char, table: &[(char, [char; 3])]) -> Option { - table.binary_search_by(|&(key, _)| key.cmp(&c)).ok() - } - -""") - t_type = "&[(char, [char; 3])]" - pfun = lambda x: "(%s,[%s,%s,%s])" % ( - escape_char(x[0]), escape_char(x[1][0]), escape_char(x[1][1]), escape_char(x[1][2])) - emit_table(f, "to_lowercase_table", - sorted(to_lower.items(), key=operator.itemgetter(0)), - is_pub=False, t_type = t_type, pfun=pfun) - emit_table(f, "to_uppercase_table", - sorted(to_upper.items(), key=operator.itemgetter(0)), - is_pub=False, t_type = t_type, pfun=pfun) - f.write("}\n\n") - -def emit_norm_module(f, canon, compat, combine, norm_props): - canon_keys = sorted(canon.keys()) - - compat_keys = sorted(compat.keys()) - - canon_comp = {} - comp_exclusions = norm_props["Full_Composition_Exclusion"] - for char in canon_keys: - if any(lo <= char <= hi for lo, hi in comp_exclusions): - continue - decomp = canon[char] - if len(decomp) == 2: - if decomp[0] not in canon_comp: - canon_comp[decomp[0]] = [] - canon_comp[decomp[0]].append( (decomp[1], char) ) - canon_comp_keys = sorted(canon_comp.keys()) - -if __name__ == "__main__": - r = "tables.rs" - if os.path.exists(r): - os.remove(r) - with open(r, "w") as rf: - # write the file's preamble - rf.write(preamble) - - # download and parse all the data - fetch("ReadMe.txt") - with open("ReadMe.txt") as readme: - pattern = "for Version (\d+)\.(\d+)\.(\d+) of the Unicode" - unicode_version = re.search(pattern, readme.read()).groups() - rf.write(""" -/// The version of [Unicode](http://www.unicode.org/) that the Unicode parts of -/// `CharExt` and `UnicodeStrPrelude` traits are based on. -pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { - major: %s, - minor: %s, - micro: %s, - _priv: (), -}; -""" % unicode_version) - (canon_decomp, compat_decomp, gencats, combines, - to_upper, to_lower, to_title) = load_unicode_data("UnicodeData.txt") - load_special_casing("SpecialCasing.txt", to_upper, to_lower, to_title) - want_derived = ["XID_Start", "XID_Continue", "Alphabetic", "Lowercase", "Uppercase", - "Cased", "Case_Ignorable"] - derived = load_properties("DerivedCoreProperties.txt", want_derived) - scripts = load_properties("Scripts.txt", []) - props = load_properties("PropList.txt", - ["White_Space", "Join_Control", "Noncharacter_Code_Point", "Pattern_White_Space"]) - norm_props = load_properties("DerivedNormalizationProps.txt", - ["Full_Composition_Exclusion"]) - - # category tables - for (name, cat, pfuns) in ("general_category", gencats, ["N", "Cc"]), \ - ("derived_property", derived, want_derived), \ - ("property", props, ["White_Space", "Pattern_White_Space"]): - emit_property_module(rf, name, cat, pfuns) - - # normalizations and conversions module - emit_norm_module(rf, canon_decomp, compat_decomp, combines, norm_props) - emit_conversions_module(rf, to_upper, to_lower, to_title) diff --git a/src/libstd_unicode/version.rs b/src/libstd_unicode/version.rs deleted file mode 100644 index d82a749d917..00000000000 --- a/src/libstd_unicode/version.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// Represents a Unicode Version. -/// -/// See also: -#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] -pub struct UnicodeVersion { - /// Major version. - pub major: u32, - - /// Minor version. - pub minor: u32, - - /// Micro (or Update) version. - pub micro: u32, - - // Private field to keep struct expandable. - pub(crate) _priv: (), -} diff --git a/src/test/compile-fail/single-primitive-inherent-impl.rs b/src/test/compile-fail/single-primitive-inherent-impl.rs index 5ceb870528a..365387c3e5e 100644 --- a/src/test/compile-fail/single-primitive-inherent-impl.rs +++ b/src/test/compile-fail/single-primitive-inherent-impl.rs @@ -15,9 +15,9 @@ #![no_std] // OK -#[lang = "char"] -impl char {} +#[lang = "str"] +impl str {} -impl char { -//~^ error: only a single inherent implementation marked with `#[lang = "char"]` is allowed for the `char` primitive +impl str { +//~^ error: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive } -- cgit 1.4.1-3-g733a5 From b2027ef17c03e47a4d716d8ea8148ed785934b04 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 5 Apr 2018 17:20:08 +0200 Subject: Deprecate the std_unicode crate --- src/Cargo.lock | 1 - src/ci/docker/wasm32-unknown/Dockerfile | 1 - src/doc/unstable-book/src/language-features/lang-items.md | 2 +- src/liballoc/Cargo.toml | 1 - src/liballoc/lib.rs | 2 -- src/liballoc/str.rs | 7 +++---- src/liballoc/string.rs | 2 +- src/liballoc/tests/lib.rs | 2 +- src/liballoc/tests/str.rs | 2 +- src/liballoc/tests/string.rs | 2 +- src/libcore/char.rs | 2 +- src/librustdoc/lib.rs | 1 - src/libstd/lib.rs | 3 +-- src/libstd_unicode/lib.rs | 1 + src/libsyntax/lib.rs | 2 +- src/libsyntax/parse/lexer/mod.rs | 2 +- 16 files changed, 13 insertions(+), 20 deletions(-) (limited to 'src/libcore') diff --git a/src/Cargo.lock b/src/Cargo.lock index a60679e417a..6e7c4b67acf 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -13,7 +13,6 @@ dependencies = [ "compiler_builtins 0.0.0", "core 0.0.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "std_unicode 0.0.0", ] [[package]] diff --git a/src/ci/docker/wasm32-unknown/Dockerfile b/src/ci/docker/wasm32-unknown/Dockerfile index 6c0ec1ad9d4..853923ad947 100644 --- a/src/ci/docker/wasm32-unknown/Dockerfile +++ b/src/ci/docker/wasm32-unknown/Dockerfile @@ -34,4 +34,3 @@ ENV SCRIPT python2.7 /checkout/x.py test --target $TARGETS \ src/test/mir-opt \ src/test/codegen-units \ src/libcore \ - src/libstd_unicode/ \ diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md index c5167418614..6a7aea7f1c2 100644 --- a/src/doc/unstable-book/src/language-features/lang-items.md +++ b/src/doc/unstable-book/src/language-features/lang-items.md @@ -243,7 +243,7 @@ the source code. - `usize`: `libcore/num/mod.rs` - `f32`: `libstd/f32.rs` - `f64`: `libstd/f64.rs` - - `char`: `libstd_unicode/char.rs` + - `char`: `libcore/char.rs` - `slice`: `liballoc/slice.rs` - `str`: `liballoc/str.rs` - `const_ptr`: `libcore/ptr.rs` diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index 2eb8ea12604..6383bd1e941 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -9,7 +9,6 @@ path = "lib.rs" [dependencies] core = { path = "../libcore" } -std_unicode = { path = "../libstd_unicode" } compiler_builtins = { path = "../rustc/compiler_builtins_shim" } [dev-dependencies] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index b08bd66b47c..d1a91ab4a9c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -135,8 +135,6 @@ extern crate test; #[cfg(test)] extern crate rand; -extern crate std_unicode; - // Module with internal macros used by other modules (needs to be included before other modules). #[macro_use] mod macros; diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index d5ef41df0d8..eaca9eb49f9 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -45,12 +45,11 @@ use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; use core::ptr; use core::iter::FusedIterator; -use std_unicode::str::{UnicodeStr, Utf16Encoder}; +use core::unicode::str::{UnicodeStr, Utf16Encoder}; use vec_deque::VecDeque; use borrow::{Borrow, ToOwned}; use string::String; -use std_unicode; use vec::Vec; use slice::{SliceConcatExt, SliceIndex}; use boxed::Box; @@ -75,7 +74,7 @@ pub use core::str::{from_utf8, from_utf8_mut, Chars, CharIndices, Bytes}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError}; #[stable(feature = "rust1", since = "1.0.0")] -pub use std_unicode::str::SplitWhitespace; +pub use core::unicode::str::SplitWhitespace; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::pattern; @@ -1960,7 +1959,7 @@ impl str { } fn case_ignoreable_then_cased>(iter: I) -> bool { - use std_unicode::derived_property::{Cased, Case_Ignorable}; + use core::unicode::derived_property::{Cased, Case_Ignorable}; match iter.skip_while(|&c| Case_Ignorable(c)).next() { Some(c) => Cased(c), None => false, diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 5f90e28cb3c..a902f0bb06b 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -64,7 +64,7 @@ use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds}; use core::ptr; use core::str::pattern::Pattern; use core::str::lossy; -use std_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; +use core::unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; use borrow::{Cow, ToOwned}; use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 17f1d0464a5..fddf341d0d1 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -29,7 +29,7 @@ #![feature(inclusive_range_fields)] extern crate alloc_system; -extern crate std_unicode; +extern crate core; extern crate rand; use std::hash::{Hash, Hasher}; diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index a14a5d32738..763dbe675b9 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -1204,7 +1204,7 @@ fn test_rev_split_char_iterator_no_trailing() { #[test] fn test_utf16_code_units() { - use std_unicode::str::Utf16Encoder; + use core::unicode::str::Utf16Encoder; assert_eq!(Utf16Encoder::new(vec!['é', '\u{1F4A9}'].into_iter()).collect::>(), [0xE9, 0xD83D, 0xDCA9]) } diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index cb4a17a22d8..33f20be100d 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -132,7 +132,7 @@ fn test_from_utf16() { let s_as_utf16 = s.encode_utf16().collect::>(); let u_as_string = String::from_utf16(&u).unwrap(); - assert!(::std_unicode::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok())); + assert!(::core::unicode::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok())); assert_eq!(s_as_utf16, u); assert_eq!(u_as_string, s); diff --git a/src/libcore/char.rs b/src/libcore/char.rs index b5554a59db5..6e2626cc362 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -10,7 +10,7 @@ //! Character manipulation. //! -//! For more details, see ::std_unicode::char (a.k.a. std::char) +//! For more details, see ::core::unicode::char (a.k.a. std::char) #![allow(non_snake_case)] #![stable(feature = "core_char", since = "1.2.0")] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 730f61e0aa6..9ac034869ac 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -41,7 +41,6 @@ extern crate serialize; #[macro_use] extern crate syntax; extern crate syntax_pos; extern crate test as testing; -extern crate std_unicode; #[macro_use] extern crate log; extern crate rustc_errors as errors; extern crate pulldown_cmark; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 672723341eb..16bca9ddcd3 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -354,7 +354,6 @@ extern crate core as __core; #[macro_reexport(vec, format)] extern crate alloc; extern crate alloc_system; -extern crate std_unicode; #[doc(masked)] extern crate libc; @@ -455,7 +454,7 @@ pub use alloc::string; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc::vec; #[stable(feature = "rust1", since = "1.0.0")] -pub use std_unicode::char; +pub use core::unicode::char; #[stable(feature = "i128", since = "1.26.0")] pub use core::u128; diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index 8cdeb6c8ad1..29de017c64d 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -31,5 +31,6 @@ #![feature(unicode)] #![feature(staged_api)] +#![rustc_deprecated(since = "1.27.0", reason = "moved into libcore")] pub use core::unicode::*; diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index d80430f609b..9de905c01d6 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -32,9 +32,9 @@ extern crate rustc_cratesio_shim; #[macro_use] extern crate bitflags; +extern crate core; extern crate serialize; #[macro_use] extern crate log; -extern crate std_unicode; pub extern crate rustc_errors as errors; extern crate syntax_pos; extern crate rustc_data_structures; diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 39b2f77f230..cb3323c7eca 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -15,7 +15,7 @@ use errors::{FatalError, DiagnosticBuilder}; use parse::{token, ParseSess}; use str::char_at; use symbol::{Symbol, keywords}; -use std_unicode::property::Pattern_White_Space; +use core::unicode::property::Pattern_White_Space; use std::borrow::Cow; use std::char; -- cgit 1.4.1-3-g733a5 From 3613b0b52fec8cb7844149804efa76e6e904896c Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 5 Apr 2018 17:35:13 +0200 Subject: Move the core::char module to its own directory --- src/etc/char_private.py | 254 ------------ src/libcore/char.rs | 926 ----------------------------------------- src/libcore/char/mod.rs | 928 ++++++++++++++++++++++++++++++++++++++++++ src/libcore/char/printable.py | 254 ++++++++++++ src/libcore/char/printable.rs | 531 ++++++++++++++++++++++++ src/libcore/char_private.rs | 531 ------------------------ src/libcore/lib.rs | 1 - 7 files changed, 1713 insertions(+), 1712 deletions(-) delete mode 100644 src/etc/char_private.py delete mode 100644 src/libcore/char.rs create mode 100644 src/libcore/char/mod.rs create mode 100644 src/libcore/char/printable.py create mode 100644 src/libcore/char/printable.rs delete mode 100644 src/libcore/char_private.rs (limited to 'src/libcore') diff --git a/src/etc/char_private.py b/src/etc/char_private.py deleted file mode 100644 index cfe5b01e934..00000000000 --- a/src/etc/char_private.py +++ /dev/null @@ -1,254 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2011-2016 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -# This script uses the following Unicode tables: -# - UnicodeData.txt - - -from collections import namedtuple -import csv -import os -import subprocess - -NUM_CODEPOINTS=0x110000 - -def to_ranges(iter): - current = None - for i in iter: - if current is None or i != current[1] or i in (0x10000, 0x20000): - if current is not None: - yield tuple(current) - current = [i, i + 1] - else: - current[1] += 1 - if current is not None: - yield tuple(current) - -def get_escaped(codepoints): - for c in codepoints: - if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord(' '): - yield c.value - -def get_file(f): - try: - return open(os.path.basename(f)) - except FileNotFoundError: - subprocess.run(["curl", "-O", f], check=True) - return open(os.path.basename(f)) - -Codepoint = namedtuple('Codepoint', 'value class_') - -def get_codepoints(f): - r = csv.reader(f, delimiter=";") - prev_codepoint = 0 - class_first = None - for row in r: - codepoint = int(row[0], 16) - name = row[1] - class_ = row[2] - - if class_first is not None: - if not name.endswith("Last>"): - raise ValueError("Missing Last after First") - - for c in range(prev_codepoint + 1, codepoint): - yield Codepoint(c, class_first) - - class_first = None - if name.endswith("First>"): - class_first = class_ - - yield Codepoint(codepoint, class_) - prev_codepoint = codepoint - - if class_first != None: - raise ValueError("Missing Last after First") - - for c in range(prev_codepoint + 1, NUM_CODEPOINTS): - yield Codepoint(c, None) - -def compress_singletons(singletons): - uppers = [] # (upper, # items in lowers) - lowers = [] - - for i in singletons: - upper = i >> 8 - lower = i & 0xff - if len(uppers) == 0 or uppers[-1][0] != upper: - uppers.append((upper, 1)) - else: - upper, count = uppers[-1] - uppers[-1] = upper, count + 1 - lowers.append(lower) - - return uppers, lowers - -def compress_normal(normal): - # lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f - # lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff - compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)] - - prev_start = 0 - for start, count in normal: - truelen = start - prev_start - falselen = count - prev_start = start + count - - assert truelen < 0x8000 and falselen < 0x8000 - entry = [] - if truelen > 0x7f: - entry.append(0x80 | (truelen >> 8)) - entry.append(truelen & 0xff) - else: - entry.append(truelen & 0x7f) - if falselen > 0x7f: - entry.append(0x80 | (falselen >> 8)) - entry.append(falselen & 0xff) - else: - entry.append(falselen & 0x7f) - - compressed.append(entry) - - return compressed - -def print_singletons(uppers, lowers, uppersname, lowersname): - print("const {}: &'static [(u8, u8)] = &[".format(uppersname)) - for u, c in uppers: - print(" ({:#04x}, {}),".format(u, c)) - print("];") - print("const {}: &'static [u8] = &[".format(lowersname)) - for i in range(0, len(lowers), 8): - print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8]))) - print("];") - -def print_normal(normal, normalname): - print("const {}: &'static [u8] = &[".format(normalname)) - for v in normal: - print(" {}".format(" ".join("{:#04x},".format(i) for i in v))) - print("];") - -def main(): - file = get_file("http://www.unicode.org/Public/UNIDATA/UnicodeData.txt") - - codepoints = get_codepoints(file) - - CUTOFF=0x10000 - singletons0 = [] - singletons1 = [] - normal0 = [] - normal1 = [] - extra = [] - - for a, b in to_ranges(get_escaped(codepoints)): - if a > 2 * CUTOFF: - extra.append((a, b - a)) - elif a == b - 1: - if a & CUTOFF: - singletons1.append(a & ~CUTOFF) - else: - singletons0.append(a) - elif a == b - 2: - if a & CUTOFF: - singletons1.append(a & ~CUTOFF) - singletons1.append((a + 1) & ~CUTOFF) - else: - singletons0.append(a) - singletons0.append(a + 1) - else: - if a >= 2 * CUTOFF: - extra.append((a, b - a)) - elif a & CUTOFF: - normal1.append((a & ~CUTOFF, b - a)) - else: - normal0.append((a, b - a)) - - singletons0u, singletons0l = compress_singletons(singletons0) - singletons1u, singletons1l = compress_singletons(singletons1) - normal0 = compress_normal(normal0) - normal1 = compress_normal(normal1) - - print("""\ -// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// NOTE: The following code was generated by "src/etc/char_private.py", -// do not edit directly! - -fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], - normal: &[u8]) -> bool { - let xupper = (x >> 8) as u8; - let mut lowerstart = 0; - for &(upper, lowercount) in singletonuppers { - let lowerend = lowerstart + lowercount as usize; - if xupper == upper { - for &lower in &singletonlowers[lowerstart..lowerend] { - if lower == x as u8 { - return false; - } - } - } else if xupper < upper { - break; - } - lowerstart = lowerend; - } - - let mut x = x as i32; - let mut normal = normal.iter().cloned(); - let mut current = true; - while let Some(v) = normal.next() { - let len = if v & 0x80 != 0 { - ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32 - } else { - v as i32 - }; - x -= len; - if x < 0 { - break; - } - current = !current; - } - current -} - -pub(crate) fn is_printable(x: char) -> bool { - let x = x as u32; - let lower = x as u16; - if x < 0x10000 { - check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) - } else if x < 0x20000 { - check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) - } else {\ -""") - for a, b in extra: - print(" if 0x{:x} <= x && x < 0x{:x} {{".format(a, a + b)) - print(" return false;") - print(" }") - print("""\ - true - } -}\ -""") - print() - print_singletons(singletons0u, singletons0l, 'SINGLETONS0U', 'SINGLETONS0L') - print_singletons(singletons1u, singletons1l, 'SINGLETONS1U', 'SINGLETONS1L') - print_normal(normal0, 'NORMAL0') - print_normal(normal1, 'NORMAL1') - -if __name__ == '__main__': - main() diff --git a/src/libcore/char.rs b/src/libcore/char.rs deleted file mode 100644 index 6e2626cc362..00000000000 --- a/src/libcore/char.rs +++ /dev/null @@ -1,926 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Character manipulation. -//! -//! For more details, see ::core::unicode::char (a.k.a. std::char) - -#![allow(non_snake_case)] -#![stable(feature = "core_char", since = "1.2.0")] - -use char_private::is_printable; -use convert::TryFrom; -use fmt::{self, Write}; -use slice; -use str::{from_utf8_unchecked_mut, FromStr}; -use iter::FusedIterator; -use mem::transmute; - -// UTF-8 ranges and tags for encoding characters -const TAG_CONT: u8 = 0b1000_0000; -const TAG_TWO_B: u8 = 0b1100_0000; -const TAG_THREE_B: u8 = 0b1110_0000; -const TAG_FOUR_B: u8 = 0b1111_0000; -const MAX_ONE_B: u32 = 0x80; -const MAX_TWO_B: u32 = 0x800; -const MAX_THREE_B: u32 = 0x10000; - -/* - Lu Uppercase_Letter an uppercase letter - Ll Lowercase_Letter a lowercase letter - Lt Titlecase_Letter a digraphic character, with first part uppercase - Lm Modifier_Letter a modifier letter - Lo Other_Letter other letters, including syllables and ideographs - Mn Nonspacing_Mark a nonspacing combining mark (zero advance width) - Mc Spacing_Mark a spacing combining mark (positive advance width) - Me Enclosing_Mark an enclosing combining mark - Nd Decimal_Number a decimal digit - Nl Letter_Number a letterlike numeric character - No Other_Number a numeric character of other type - Pc Connector_Punctuation a connecting punctuation mark, like a tie - Pd Dash_Punctuation a dash or hyphen punctuation mark - Ps Open_Punctuation an opening punctuation mark (of a pair) - Pe Close_Punctuation a closing punctuation mark (of a pair) - Pi Initial_Punctuation an initial quotation mark - Pf Final_Punctuation a final quotation mark - Po Other_Punctuation a punctuation mark of other type - Sm Math_Symbol a symbol of primarily mathematical use - Sc Currency_Symbol a currency sign - Sk Modifier_Symbol a non-letterlike modifier symbol - So Other_Symbol a symbol of other type - Zs Space_Separator a space character (of various non-zero widths) - Zl Line_Separator U+2028 LINE SEPARATOR only - Zp Paragraph_Separator U+2029 PARAGRAPH SEPARATOR only - Cc Control a C0 or C1 control code - Cf Format a format control character - Cs Surrogate a surrogate code point - Co Private_Use a private-use character - Cn Unassigned a reserved unassigned code point or a noncharacter -*/ - -/// The highest valid code point a `char` can have. -/// -/// A [`char`] is a [Unicode Scalar Value], which means that it is a [Code -/// Point], but only ones within a certain range. `MAX` is the highest valid -/// code point that's a valid [Unicode Scalar Value]. -/// -/// [`char`]: ../../std/primitive.char.html -/// [Unicode Scalar Value]: http://www.unicode.org/glossary/#unicode_scalar_value -/// [Code Point]: http://www.unicode.org/glossary/#code_point -#[stable(feature = "rust1", since = "1.0.0")] -pub const MAX: char = '\u{10ffff}'; - -/// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a -/// decoding error. -/// -/// It can occur, for example, when giving ill-formed UTF-8 bytes to -/// [`String::from_utf8_lossy`](../../std/string/struct.String.html#method.from_utf8_lossy). -#[stable(feature = "decode_utf16", since = "1.9.0")] -pub const REPLACEMENT_CHARACTER: char = '\u{FFFD}'; - -/// Converts a `u32` to a `char`. -/// -/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with -/// [`as`]: -/// -/// ``` -/// let c = '💯'; -/// let i = c as u32; -/// -/// assert_eq!(128175, i); -/// ``` -/// -/// However, the reverse is not true: not all valid [`u32`]s are valid -/// [`char`]s. `from_u32()` will return `None` if the input is not a valid value -/// for a [`char`]. -/// -/// [`char`]: ../../std/primitive.char.html -/// [`u32`]: ../../std/primitive.u32.html -/// [`as`]: ../../book/first-edition/casting-between-types.html#as -/// -/// For an unsafe version of this function which ignores these checks, see -/// [`from_u32_unchecked`]. -/// -/// [`from_u32_unchecked`]: fn.from_u32_unchecked.html -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_u32(0x2764); -/// -/// assert_eq!(Some('❤'), c); -/// ``` -/// -/// Returning `None` when the input is not a valid [`char`]: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_u32(0x110000); -/// -/// assert_eq!(None, c); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn from_u32(i: u32) -> Option { - char::try_from(i).ok() -} - -/// Converts a `u32` to a `char`, ignoring validity. -/// -/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with -/// [`as`]: -/// -/// ``` -/// let c = '💯'; -/// let i = c as u32; -/// -/// assert_eq!(128175, i); -/// ``` -/// -/// However, the reverse is not true: not all valid [`u32`]s are valid -/// [`char`]s. `from_u32_unchecked()` will ignore this, and blindly cast to -/// [`char`], possibly creating an invalid one. -/// -/// [`char`]: ../../std/primitive.char.html -/// [`u32`]: ../../std/primitive.u32.html -/// [`as`]: ../../book/first-edition/casting-between-types.html#as -/// -/// # Safety -/// -/// This function is unsafe, as it may construct invalid `char` values. -/// -/// For a safe version of this function, see the [`from_u32`] function. -/// -/// [`from_u32`]: fn.from_u32.html -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char; -/// -/// let c = unsafe { char::from_u32_unchecked(0x2764) }; -/// -/// assert_eq!('❤', c); -/// ``` -#[inline] -#[stable(feature = "char_from_unchecked", since = "1.5.0")] -pub unsafe fn from_u32_unchecked(i: u32) -> char { - transmute(i) -} - -#[stable(feature = "char_convert", since = "1.13.0")] -impl From for u32 { - #[inline] - fn from(c: char) -> Self { - c as u32 - } -} - -/// Maps a byte in 0x00...0xFF to a `char` whose code point has the same value, in U+0000 to U+00FF. -/// -/// Unicode is designed such that this effectively decodes bytes -/// with the character encoding that IANA calls ISO-8859-1. -/// This encoding is compatible with ASCII. -/// -/// Note that this is different from ISO/IEC 8859-1 a.k.a. ISO 8859-1 (with one less hyphen), -/// which leaves some "blanks", byte values that are not assigned to any character. -/// ISO-8859-1 (the IANA one) assigns them to the C0 and C1 control codes. -/// -/// Note that this is *also* different from Windows-1252 a.k.a. code page 1252, -/// which is a superset ISO/IEC 8859-1 that assigns some (not all!) blanks -/// to punctuation and various Latin characters. -/// -/// To confuse things further, [on the Web](https://encoding.spec.whatwg.org/) -/// `ascii`, `iso-8859-1`, and `windows-1252` are all aliases -/// for a superset of Windows-1252 that fills the remaining blanks with corresponding -/// C0 and C1 control codes. -#[stable(feature = "char_convert", since = "1.13.0")] -impl From for char { - #[inline] - fn from(i: u8) -> Self { - i as char - } -} - - -/// An error which can be returned when parsing a char. -#[stable(feature = "char_from_str", since = "1.20.0")] -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ParseCharError { - kind: CharErrorKind, -} - -impl ParseCharError { - #[unstable(feature = "char_error_internals", - reason = "this method should not be available publicly", - issue = "0")] - #[doc(hidden)] - pub fn __description(&self) -> &str { - match self.kind { - CharErrorKind::EmptyString => { - "cannot parse char from empty string" - }, - CharErrorKind::TooManyChars => "too many characters in string" - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -enum CharErrorKind { - EmptyString, - TooManyChars, -} - -#[stable(feature = "char_from_str", since = "1.20.0")] -impl fmt::Display for ParseCharError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.__description().fmt(f) - } -} - - -#[stable(feature = "char_from_str", since = "1.20.0")] -impl FromStr for char { - type Err = ParseCharError; - - #[inline] - fn from_str(s: &str) -> Result { - let mut chars = s.chars(); - match (chars.next(), chars.next()) { - (None, _) => { - Err(ParseCharError { kind: CharErrorKind::EmptyString }) - }, - (Some(c), None) => Ok(c), - _ => { - Err(ParseCharError { kind: CharErrorKind::TooManyChars }) - } - } - } -} - - -#[stable(feature = "try_from", since = "1.26.0")] -impl TryFrom for char { - type Error = CharTryFromError; - - #[inline] - fn try_from(i: u32) -> Result { - if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) { - Err(CharTryFromError(())) - } else { - Ok(unsafe { from_u32_unchecked(i) }) - } - } -} - -/// The error type returned when a conversion from u32 to char fails. -#[stable(feature = "try_from", since = "1.26.0")] -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct CharTryFromError(()); - -#[stable(feature = "try_from", since = "1.26.0")] -impl fmt::Display for CharTryFromError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "converted integer out of range for `char`".fmt(f) - } -} - -/// Converts a digit in the given radix to a `char`. -/// -/// A 'radix' here is sometimes also called a 'base'. A radix of two -/// indicates a binary number, a radix of ten, decimal, and a radix of -/// sixteen, hexadecimal, to give some common values. Arbitrary -/// radices are supported. -/// -/// `from_digit()` will return `None` if the input is not a digit in -/// the given radix. -/// -/// # Panics -/// -/// Panics if given a radix larger than 36. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_digit(4, 10); -/// -/// assert_eq!(Some('4'), c); -/// -/// // Decimal 11 is a single digit in base 16 -/// let c = char::from_digit(11, 16); -/// -/// assert_eq!(Some('b'), c); -/// ``` -/// -/// Returning `None` when the input is not a digit: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_digit(20, 10); -/// -/// assert_eq!(None, c); -/// ``` -/// -/// Passing a large radix, causing a panic: -/// -/// ``` -/// use std::thread; -/// use std::char; -/// -/// let result = thread::spawn(|| { -/// // this panics -/// let c = char::from_digit(1, 37); -/// }).join(); -/// -/// assert!(result.is_err()); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn from_digit(num: u32, radix: u32) -> Option { - if radix > 36 { - panic!("from_digit: radix is too high (maximum 36)"); - } - if num < radix { - let num = num as u8; - if num < 10 { - Some((b'0' + num) as char) - } else { - Some((b'a' + num - 10) as char) - } - } else { - None - } -} - -// NB: the stabilization and documentation for this trait is in -// unicode/char.rs, not here -#[allow(missing_docs)] // docs in libunicode/u_char.rs -#[doc(hidden)] -#[unstable(feature = "core_char_ext", - reason = "the stable interface is `impl char` in later crate", - issue = "32110")] -pub trait CharExt { - #[stable(feature = "core", since = "1.6.0")] - fn is_digit(self, radix: u32) -> bool; - #[stable(feature = "core", since = "1.6.0")] - fn to_digit(self, radix: u32) -> Option; - #[stable(feature = "core", since = "1.6.0")] - fn escape_unicode(self) -> EscapeUnicode; - #[stable(feature = "core", since = "1.6.0")] - fn escape_default(self) -> EscapeDefault; - #[stable(feature = "char_escape_debug", since = "1.20.0")] - fn escape_debug(self) -> EscapeDebug; - #[stable(feature = "core", since = "1.6.0")] - fn len_utf8(self) -> usize; - #[stable(feature = "core", since = "1.6.0")] - fn len_utf16(self) -> usize; - #[stable(feature = "unicode_encode_char", since = "1.15.0")] - fn encode_utf8(self, dst: &mut [u8]) -> &mut str; - #[stable(feature = "unicode_encode_char", since = "1.15.0")] - fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16]; -} - -#[stable(feature = "core", since = "1.6.0")] -impl CharExt for char { - #[inline] - fn is_digit(self, radix: u32) -> bool { - self.to_digit(radix).is_some() - } - - #[inline] - fn to_digit(self, radix: u32) -> Option { - if radix > 36 { - panic!("to_digit: radix is too high (maximum 36)"); - } - let val = match self { - '0' ... '9' => self as u32 - '0' as u32, - 'a' ... 'z' => self as u32 - 'a' as u32 + 10, - 'A' ... 'Z' => self as u32 - 'A' as u32 + 10, - _ => return None, - }; - if val < radix { Some(val) } - else { None } - } - - #[inline] - fn escape_unicode(self) -> EscapeUnicode { - let c = self as u32; - - // or-ing 1 ensures that for c==0 the code computes that one - // digit should be printed and (which is the same) avoids the - // (31 - 32) underflow - let msb = 31 - (c | 1).leading_zeros(); - - // the index of the most significant hex digit - let ms_hex_digit = msb / 4; - EscapeUnicode { - c: self, - state: EscapeUnicodeState::Backslash, - hex_digit_idx: ms_hex_digit as usize, - } - } - - #[inline] - fn escape_default(self) -> EscapeDefault { - let init_state = match self { - '\t' => EscapeDefaultState::Backslash('t'), - '\r' => EscapeDefaultState::Backslash('r'), - '\n' => EscapeDefaultState::Backslash('n'), - '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), - '\x20' ... '\x7e' => EscapeDefaultState::Char(self), - _ => EscapeDefaultState::Unicode(self.escape_unicode()) - }; - EscapeDefault { state: init_state } - } - - #[inline] - fn escape_debug(self) -> EscapeDebug { - let init_state = match self { - '\t' => EscapeDefaultState::Backslash('t'), - '\r' => EscapeDefaultState::Backslash('r'), - '\n' => EscapeDefaultState::Backslash('n'), - '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), - c if is_printable(c) => EscapeDefaultState::Char(c), - c => EscapeDefaultState::Unicode(c.escape_unicode()), - }; - EscapeDebug(EscapeDefault { state: init_state }) - } - - #[inline] - fn len_utf8(self) -> usize { - let code = self as u32; - if code < MAX_ONE_B { - 1 - } else if code < MAX_TWO_B { - 2 - } else if code < MAX_THREE_B { - 3 - } else { - 4 - } - } - - #[inline] - fn len_utf16(self) -> usize { - let ch = self as u32; - if (ch & 0xFFFF) == ch { 1 } else { 2 } - } - - #[inline] - fn encode_utf8(self, dst: &mut [u8]) -> &mut str { - let code = self as u32; - unsafe { - let len = - if code < MAX_ONE_B && !dst.is_empty() { - *dst.get_unchecked_mut(0) = code as u8; - 1 - } else if code < MAX_TWO_B && dst.len() >= 2 { - *dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; - *dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT; - 2 - } else if code < MAX_THREE_B && dst.len() >= 3 { - *dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; - *dst.get_unchecked_mut(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT; - 3 - } else if dst.len() >= 4 { - *dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; - *dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT; - 4 - } else { - panic!("encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", - from_u32_unchecked(code).len_utf8(), - code, - dst.len()) - }; - from_utf8_unchecked_mut(dst.get_unchecked_mut(..len)) - } - } - - #[inline] - fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { - let mut code = self as u32; - unsafe { - if (code & 0xFFFF) == code && !dst.is_empty() { - // The BMP falls through (assuming non-surrogate, as it should) - *dst.get_unchecked_mut(0) = code as u16; - slice::from_raw_parts_mut(dst.as_mut_ptr(), 1) - } else if dst.len() >= 2 { - // Supplementary planes break into surrogates. - code -= 0x1_0000; - *dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16); - *dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF); - slice::from_raw_parts_mut(dst.as_mut_ptr(), 2) - } else { - panic!("encode_utf16: need {} units to encode U+{:X}, but the buffer has {}", - from_u32_unchecked(code).len_utf16(), - code, - dst.len()) - } - } - } -} - -/// Returns an iterator that yields the hexadecimal Unicode escape of a -/// character, as `char`s. -/// -/// This `struct` is created by the [`escape_unicode`] method on [`char`]. See -/// its documentation for more. -/// -/// [`escape_unicode`]: ../../std/primitive.char.html#method.escape_unicode -/// [`char`]: ../../std/primitive.char.html -#[derive(Clone, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct EscapeUnicode { - c: char, - state: EscapeUnicodeState, - - // The index of the next hex digit to be printed (0 if none), - // i.e. the number of remaining hex digits to be printed; - // increasing from the least significant digit: 0x543210 - hex_digit_idx: usize, -} - -// The enum values are ordered so that their representation is the -// same as the remaining length (besides the hexadecimal digits). This -// likely makes `len()` a single load from memory) and inline-worth. -#[derive(Clone, Debug)] -enum EscapeUnicodeState { - Done, - RightBrace, - Value, - LeftBrace, - Type, - Backslash, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for EscapeUnicode { - type Item = char; - - fn next(&mut self) -> Option { - match self.state { - EscapeUnicodeState::Backslash => { - self.state = EscapeUnicodeState::Type; - Some('\\') - } - EscapeUnicodeState::Type => { - self.state = EscapeUnicodeState::LeftBrace; - Some('u') - } - EscapeUnicodeState::LeftBrace => { - self.state = EscapeUnicodeState::Value; - Some('{') - } - EscapeUnicodeState::Value => { - let hex_digit = ((self.c as u32) >> (self.hex_digit_idx * 4)) & 0xf; - let c = from_digit(hex_digit, 16).unwrap(); - if self.hex_digit_idx == 0 { - self.state = EscapeUnicodeState::RightBrace; - } else { - self.hex_digit_idx -= 1; - } - Some(c) - } - EscapeUnicodeState::RightBrace => { - self.state = EscapeUnicodeState::Done; - Some('}') - } - EscapeUnicodeState::Done => None, - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let n = self.len(); - (n, Some(n)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - fn last(self) -> Option { - match self.state { - EscapeUnicodeState::Done => None, - - EscapeUnicodeState::RightBrace | - EscapeUnicodeState::Value | - EscapeUnicodeState::LeftBrace | - EscapeUnicodeState::Type | - EscapeUnicodeState::Backslash => Some('}'), - } - } -} - -#[stable(feature = "exact_size_escape", since = "1.11.0")] -impl ExactSizeIterator for EscapeUnicode { - #[inline] - fn len(&self) -> usize { - // The match is a single memory access with no branching - self.hex_digit_idx + match self.state { - EscapeUnicodeState::Done => 0, - EscapeUnicodeState::RightBrace => 1, - EscapeUnicodeState::Value => 2, - EscapeUnicodeState::LeftBrace => 3, - EscapeUnicodeState::Type => 4, - EscapeUnicodeState::Backslash => 5, - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for EscapeUnicode {} - -#[stable(feature = "char_struct_display", since = "1.16.0")] -impl fmt::Display for EscapeUnicode { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for c in self.clone() { - f.write_char(c)?; - } - Ok(()) - } -} - -/// An iterator that yields the literal escape code of a `char`. -/// -/// This `struct` is created by the [`escape_default`] method on [`char`]. See -/// its documentation for more. -/// -/// [`escape_default`]: ../../std/primitive.char.html#method.escape_default -/// [`char`]: ../../std/primitive.char.html -#[derive(Clone, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct EscapeDefault { - state: EscapeDefaultState -} - -#[derive(Clone, Debug)] -enum EscapeDefaultState { - Done, - Char(char), - Backslash(char), - Unicode(EscapeUnicode), -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for EscapeDefault { - type Item = char; - - fn next(&mut self) -> Option { - match self.state { - EscapeDefaultState::Backslash(c) => { - self.state = EscapeDefaultState::Char(c); - Some('\\') - } - EscapeDefaultState::Char(c) => { - self.state = EscapeDefaultState::Done; - Some(c) - } - EscapeDefaultState::Done => None, - EscapeDefaultState::Unicode(ref mut iter) => iter.next(), - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let n = self.len(); - (n, Some(n)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - fn nth(&mut self, n: usize) -> Option { - match self.state { - EscapeDefaultState::Backslash(c) if n == 0 => { - self.state = EscapeDefaultState::Char(c); - Some('\\') - }, - EscapeDefaultState::Backslash(c) if n == 1 => { - self.state = EscapeDefaultState::Done; - Some(c) - }, - EscapeDefaultState::Backslash(_) => { - self.state = EscapeDefaultState::Done; - None - }, - EscapeDefaultState::Char(c) => { - self.state = EscapeDefaultState::Done; - - if n == 0 { - Some(c) - } else { - None - } - }, - EscapeDefaultState::Done => return None, - EscapeDefaultState::Unicode(ref mut i) => return i.nth(n), - } - } - - fn last(self) -> Option { - match self.state { - EscapeDefaultState::Unicode(iter) => iter.last(), - EscapeDefaultState::Done => None, - EscapeDefaultState::Backslash(c) | EscapeDefaultState::Char(c) => Some(c), - } - } -} - -#[stable(feature = "exact_size_escape", since = "1.11.0")] -impl ExactSizeIterator for EscapeDefault { - fn len(&self) -> usize { - match self.state { - EscapeDefaultState::Done => 0, - EscapeDefaultState::Char(_) => 1, - EscapeDefaultState::Backslash(_) => 2, - EscapeDefaultState::Unicode(ref iter) => iter.len(), - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for EscapeDefault {} - -#[stable(feature = "char_struct_display", since = "1.16.0")] -impl fmt::Display for EscapeDefault { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for c in self.clone() { - f.write_char(c)?; - } - Ok(()) - } -} - -/// An iterator that yields the literal escape code of a `char`. -/// -/// This `struct` is created by the [`escape_debug`] method on [`char`]. See its -/// documentation for more. -/// -/// [`escape_debug`]: ../../std/primitive.char.html#method.escape_debug -/// [`char`]: ../../std/primitive.char.html -#[stable(feature = "char_escape_debug", since = "1.20.0")] -#[derive(Clone, Debug)] -pub struct EscapeDebug(EscapeDefault); - -#[stable(feature = "char_escape_debug", since = "1.20.0")] -impl Iterator for EscapeDebug { - type Item = char; - fn next(&mut self) -> Option { self.0.next() } - fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } -} - -#[stable(feature = "char_escape_debug", since = "1.20.0")] -impl ExactSizeIterator for EscapeDebug { } - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for EscapeDebug {} - -#[stable(feature = "char_escape_debug", since = "1.20.0")] -impl fmt::Display for EscapeDebug { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } -} - - - -/// An iterator over an iterator of bytes of the characters the bytes represent -/// as UTF-8 -#[unstable(feature = "decode_utf8", issue = "33906")] -#[derive(Clone, Debug)] -pub struct DecodeUtf8>(::iter::Peekable); - -/// Decodes an `Iterator` of bytes as UTF-8. -#[unstable(feature = "decode_utf8", issue = "33906")] -#[inline] -pub fn decode_utf8>(i: I) -> DecodeUtf8 { - DecodeUtf8(i.into_iter().peekable()) -} - -/// `::next` returns this for an invalid input sequence. -#[unstable(feature = "decode_utf8", issue = "33906")] -#[derive(PartialEq, Eq, Debug)] -pub struct InvalidSequence(()); - -#[unstable(feature = "decode_utf8", issue = "33906")] -impl> Iterator for DecodeUtf8 { - type Item = Result; - #[inline] - - fn next(&mut self) -> Option> { - self.0.next().map(|first_byte| { - // Emit InvalidSequence according to - // Unicode §5.22 Best Practice for U+FFFD Substitution - // http://www.unicode.org/versions/Unicode9.0.0/ch05.pdf#G40630 - - // Roughly: consume at least one byte, - // then validate one byte at a time and stop before the first unexpected byte - // (which might be the valid start of the next byte sequence). - - let mut code_point; - macro_rules! first_byte { - ($mask: expr) => { - code_point = u32::from(first_byte & $mask) - } - } - macro_rules! continuation_byte { - () => { continuation_byte!(0x80...0xBF) }; - ($range: pat) => { - match self.0.peek() { - Some(&byte @ $range) => { - code_point = (code_point << 6) | u32::from(byte & 0b0011_1111); - self.0.next(); - } - _ => return Err(InvalidSequence(())) - } - } - } - - match first_byte { - 0x00...0x7F => { - first_byte!(0b1111_1111); - } - 0xC2...0xDF => { - first_byte!(0b0001_1111); - continuation_byte!(); - } - 0xE0 => { - first_byte!(0b0000_1111); - continuation_byte!(0xA0...0xBF); // 0x80...0x9F here are overlong - continuation_byte!(); - } - 0xE1...0xEC | 0xEE...0xEF => { - first_byte!(0b0000_1111); - continuation_byte!(); - continuation_byte!(); - } - 0xED => { - first_byte!(0b0000_1111); - continuation_byte!(0x80...0x9F); // 0xA0..0xBF here are surrogates - continuation_byte!(); - } - 0xF0 => { - first_byte!(0b0000_0111); - continuation_byte!(0x90...0xBF); // 0x80..0x8F here are overlong - continuation_byte!(); - continuation_byte!(); - } - 0xF1...0xF3 => { - first_byte!(0b0000_0111); - continuation_byte!(); - continuation_byte!(); - continuation_byte!(); - } - 0xF4 => { - first_byte!(0b0000_0111); - continuation_byte!(0x80...0x8F); // 0x90..0xBF here are beyond char::MAX - continuation_byte!(); - continuation_byte!(); - } - _ => return Err(InvalidSequence(())) // Illegal first byte, overlong, or beyond MAX - } - unsafe { - Ok(from_u32_unchecked(code_point)) - } - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (lower, upper) = self.0.size_hint(); - - // A code point is at most 4 bytes long. - let min_code_points = lower / 4; - - (min_code_points, upper) - } -} - -#[unstable(feature = "decode_utf8", issue = "33906")] -impl> FusedIterator for DecodeUtf8 {} diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs new file mode 100644 index 00000000000..c6b620e5238 --- /dev/null +++ b/src/libcore/char/mod.rs @@ -0,0 +1,928 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Character manipulation. +//! +//! For more details, see ::core::unicode::char (a.k.a. std::char) + +#![allow(non_snake_case)] +#![stable(feature = "core_char", since = "1.2.0")] + +mod printable; + +use self::printable::is_printable; +use convert::TryFrom; +use fmt::{self, Write}; +use slice; +use str::{from_utf8_unchecked_mut, FromStr}; +use iter::FusedIterator; +use mem::transmute; + +// UTF-8 ranges and tags for encoding characters +const TAG_CONT: u8 = 0b1000_0000; +const TAG_TWO_B: u8 = 0b1100_0000; +const TAG_THREE_B: u8 = 0b1110_0000; +const TAG_FOUR_B: u8 = 0b1111_0000; +const MAX_ONE_B: u32 = 0x80; +const MAX_TWO_B: u32 = 0x800; +const MAX_THREE_B: u32 = 0x10000; + +/* + Lu Uppercase_Letter an uppercase letter + Ll Lowercase_Letter a lowercase letter + Lt Titlecase_Letter a digraphic character, with first part uppercase + Lm Modifier_Letter a modifier letter + Lo Other_Letter other letters, including syllables and ideographs + Mn Nonspacing_Mark a nonspacing combining mark (zero advance width) + Mc Spacing_Mark a spacing combining mark (positive advance width) + Me Enclosing_Mark an enclosing combining mark + Nd Decimal_Number a decimal digit + Nl Letter_Number a letterlike numeric character + No Other_Number a numeric character of other type + Pc Connector_Punctuation a connecting punctuation mark, like a tie + Pd Dash_Punctuation a dash or hyphen punctuation mark + Ps Open_Punctuation an opening punctuation mark (of a pair) + Pe Close_Punctuation a closing punctuation mark (of a pair) + Pi Initial_Punctuation an initial quotation mark + Pf Final_Punctuation a final quotation mark + Po Other_Punctuation a punctuation mark of other type + Sm Math_Symbol a symbol of primarily mathematical use + Sc Currency_Symbol a currency sign + Sk Modifier_Symbol a non-letterlike modifier symbol + So Other_Symbol a symbol of other type + Zs Space_Separator a space character (of various non-zero widths) + Zl Line_Separator U+2028 LINE SEPARATOR only + Zp Paragraph_Separator U+2029 PARAGRAPH SEPARATOR only + Cc Control a C0 or C1 control code + Cf Format a format control character + Cs Surrogate a surrogate code point + Co Private_Use a private-use character + Cn Unassigned a reserved unassigned code point or a noncharacter +*/ + +/// The highest valid code point a `char` can have. +/// +/// A [`char`] is a [Unicode Scalar Value], which means that it is a [Code +/// Point], but only ones within a certain range. `MAX` is the highest valid +/// code point that's a valid [Unicode Scalar Value]. +/// +/// [`char`]: ../../std/primitive.char.html +/// [Unicode Scalar Value]: http://www.unicode.org/glossary/#unicode_scalar_value +/// [Code Point]: http://www.unicode.org/glossary/#code_point +#[stable(feature = "rust1", since = "1.0.0")] +pub const MAX: char = '\u{10ffff}'; + +/// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a +/// decoding error. +/// +/// It can occur, for example, when giving ill-formed UTF-8 bytes to +/// [`String::from_utf8_lossy`](../../std/string/struct.String.html#method.from_utf8_lossy). +#[stable(feature = "decode_utf16", since = "1.9.0")] +pub const REPLACEMENT_CHARACTER: char = '\u{FFFD}'; + +/// Converts a `u32` to a `char`. +/// +/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with +/// [`as`]: +/// +/// ``` +/// let c = '💯'; +/// let i = c as u32; +/// +/// assert_eq!(128175, i); +/// ``` +/// +/// However, the reverse is not true: not all valid [`u32`]s are valid +/// [`char`]s. `from_u32()` will return `None` if the input is not a valid value +/// for a [`char`]. +/// +/// [`char`]: ../../std/primitive.char.html +/// [`u32`]: ../../std/primitive.u32.html +/// [`as`]: ../../book/first-edition/casting-between-types.html#as +/// +/// For an unsafe version of this function which ignores these checks, see +/// [`from_u32_unchecked`]. +/// +/// [`from_u32_unchecked`]: fn.from_u32_unchecked.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::char; +/// +/// let c = char::from_u32(0x2764); +/// +/// assert_eq!(Some('❤'), c); +/// ``` +/// +/// Returning `None` when the input is not a valid [`char`]: +/// +/// ``` +/// use std::char; +/// +/// let c = char::from_u32(0x110000); +/// +/// assert_eq!(None, c); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn from_u32(i: u32) -> Option { + char::try_from(i).ok() +} + +/// Converts a `u32` to a `char`, ignoring validity. +/// +/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with +/// [`as`]: +/// +/// ``` +/// let c = '💯'; +/// let i = c as u32; +/// +/// assert_eq!(128175, i); +/// ``` +/// +/// However, the reverse is not true: not all valid [`u32`]s are valid +/// [`char`]s. `from_u32_unchecked()` will ignore this, and blindly cast to +/// [`char`], possibly creating an invalid one. +/// +/// [`char`]: ../../std/primitive.char.html +/// [`u32`]: ../../std/primitive.u32.html +/// [`as`]: ../../book/first-edition/casting-between-types.html#as +/// +/// # Safety +/// +/// This function is unsafe, as it may construct invalid `char` values. +/// +/// For a safe version of this function, see the [`from_u32`] function. +/// +/// [`from_u32`]: fn.from_u32.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::char; +/// +/// let c = unsafe { char::from_u32_unchecked(0x2764) }; +/// +/// assert_eq!('❤', c); +/// ``` +#[inline] +#[stable(feature = "char_from_unchecked", since = "1.5.0")] +pub unsafe fn from_u32_unchecked(i: u32) -> char { + transmute(i) +} + +#[stable(feature = "char_convert", since = "1.13.0")] +impl From for u32 { + #[inline] + fn from(c: char) -> Self { + c as u32 + } +} + +/// Maps a byte in 0x00...0xFF to a `char` whose code point has the same value, in U+0000 to U+00FF. +/// +/// Unicode is designed such that this effectively decodes bytes +/// with the character encoding that IANA calls ISO-8859-1. +/// This encoding is compatible with ASCII. +/// +/// Note that this is different from ISO/IEC 8859-1 a.k.a. ISO 8859-1 (with one less hyphen), +/// which leaves some "blanks", byte values that are not assigned to any character. +/// ISO-8859-1 (the IANA one) assigns them to the C0 and C1 control codes. +/// +/// Note that this is *also* different from Windows-1252 a.k.a. code page 1252, +/// which is a superset ISO/IEC 8859-1 that assigns some (not all!) blanks +/// to punctuation and various Latin characters. +/// +/// To confuse things further, [on the Web](https://encoding.spec.whatwg.org/) +/// `ascii`, `iso-8859-1`, and `windows-1252` are all aliases +/// for a superset of Windows-1252 that fills the remaining blanks with corresponding +/// C0 and C1 control codes. +#[stable(feature = "char_convert", since = "1.13.0")] +impl From for char { + #[inline] + fn from(i: u8) -> Self { + i as char + } +} + + +/// An error which can be returned when parsing a char. +#[stable(feature = "char_from_str", since = "1.20.0")] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ParseCharError { + kind: CharErrorKind, +} + +impl ParseCharError { + #[unstable(feature = "char_error_internals", + reason = "this method should not be available publicly", + issue = "0")] + #[doc(hidden)] + pub fn __description(&self) -> &str { + match self.kind { + CharErrorKind::EmptyString => { + "cannot parse char from empty string" + }, + CharErrorKind::TooManyChars => "too many characters in string" + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum CharErrorKind { + EmptyString, + TooManyChars, +} + +#[stable(feature = "char_from_str", since = "1.20.0")] +impl fmt::Display for ParseCharError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.__description().fmt(f) + } +} + + +#[stable(feature = "char_from_str", since = "1.20.0")] +impl FromStr for char { + type Err = ParseCharError; + + #[inline] + fn from_str(s: &str) -> Result { + let mut chars = s.chars(); + match (chars.next(), chars.next()) { + (None, _) => { + Err(ParseCharError { kind: CharErrorKind::EmptyString }) + }, + (Some(c), None) => Ok(c), + _ => { + Err(ParseCharError { kind: CharErrorKind::TooManyChars }) + } + } + } +} + + +#[stable(feature = "try_from", since = "1.26.0")] +impl TryFrom for char { + type Error = CharTryFromError; + + #[inline] + fn try_from(i: u32) -> Result { + if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) { + Err(CharTryFromError(())) + } else { + Ok(unsafe { from_u32_unchecked(i) }) + } + } +} + +/// The error type returned when a conversion from u32 to char fails. +#[stable(feature = "try_from", since = "1.26.0")] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct CharTryFromError(()); + +#[stable(feature = "try_from", since = "1.26.0")] +impl fmt::Display for CharTryFromError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "converted integer out of range for `char`".fmt(f) + } +} + +/// Converts a digit in the given radix to a `char`. +/// +/// A 'radix' here is sometimes also called a 'base'. A radix of two +/// indicates a binary number, a radix of ten, decimal, and a radix of +/// sixteen, hexadecimal, to give some common values. Arbitrary +/// radices are supported. +/// +/// `from_digit()` will return `None` if the input is not a digit in +/// the given radix. +/// +/// # Panics +/// +/// Panics if given a radix larger than 36. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::char; +/// +/// let c = char::from_digit(4, 10); +/// +/// assert_eq!(Some('4'), c); +/// +/// // Decimal 11 is a single digit in base 16 +/// let c = char::from_digit(11, 16); +/// +/// assert_eq!(Some('b'), c); +/// ``` +/// +/// Returning `None` when the input is not a digit: +/// +/// ``` +/// use std::char; +/// +/// let c = char::from_digit(20, 10); +/// +/// assert_eq!(None, c); +/// ``` +/// +/// Passing a large radix, causing a panic: +/// +/// ``` +/// use std::thread; +/// use std::char; +/// +/// let result = thread::spawn(|| { +/// // this panics +/// let c = char::from_digit(1, 37); +/// }).join(); +/// +/// assert!(result.is_err()); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn from_digit(num: u32, radix: u32) -> Option { + if radix > 36 { + panic!("from_digit: radix is too high (maximum 36)"); + } + if num < radix { + let num = num as u8; + if num < 10 { + Some((b'0' + num) as char) + } else { + Some((b'a' + num - 10) as char) + } + } else { + None + } +} + +// NB: the stabilization and documentation for this trait is in +// unicode/char.rs, not here +#[allow(missing_docs)] // docs in libunicode/u_char.rs +#[doc(hidden)] +#[unstable(feature = "core_char_ext", + reason = "the stable interface is `impl char` in later crate", + issue = "32110")] +pub trait CharExt { + #[stable(feature = "core", since = "1.6.0")] + fn is_digit(self, radix: u32) -> bool; + #[stable(feature = "core", since = "1.6.0")] + fn to_digit(self, radix: u32) -> Option; + #[stable(feature = "core", since = "1.6.0")] + fn escape_unicode(self) -> EscapeUnicode; + #[stable(feature = "core", since = "1.6.0")] + fn escape_default(self) -> EscapeDefault; + #[stable(feature = "char_escape_debug", since = "1.20.0")] + fn escape_debug(self) -> EscapeDebug; + #[stable(feature = "core", since = "1.6.0")] + fn len_utf8(self) -> usize; + #[stable(feature = "core", since = "1.6.0")] + fn len_utf16(self) -> usize; + #[stable(feature = "unicode_encode_char", since = "1.15.0")] + fn encode_utf8(self, dst: &mut [u8]) -> &mut str; + #[stable(feature = "unicode_encode_char", since = "1.15.0")] + fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16]; +} + +#[stable(feature = "core", since = "1.6.0")] +impl CharExt for char { + #[inline] + fn is_digit(self, radix: u32) -> bool { + self.to_digit(radix).is_some() + } + + #[inline] + fn to_digit(self, radix: u32) -> Option { + if radix > 36 { + panic!("to_digit: radix is too high (maximum 36)"); + } + let val = match self { + '0' ... '9' => self as u32 - '0' as u32, + 'a' ... 'z' => self as u32 - 'a' as u32 + 10, + 'A' ... 'Z' => self as u32 - 'A' as u32 + 10, + _ => return None, + }; + if val < radix { Some(val) } + else { None } + } + + #[inline] + fn escape_unicode(self) -> EscapeUnicode { + let c = self as u32; + + // or-ing 1 ensures that for c==0 the code computes that one + // digit should be printed and (which is the same) avoids the + // (31 - 32) underflow + let msb = 31 - (c | 1).leading_zeros(); + + // the index of the most significant hex digit + let ms_hex_digit = msb / 4; + EscapeUnicode { + c: self, + state: EscapeUnicodeState::Backslash, + hex_digit_idx: ms_hex_digit as usize, + } + } + + #[inline] + fn escape_default(self) -> EscapeDefault { + let init_state = match self { + '\t' => EscapeDefaultState::Backslash('t'), + '\r' => EscapeDefaultState::Backslash('r'), + '\n' => EscapeDefaultState::Backslash('n'), + '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), + '\x20' ... '\x7e' => EscapeDefaultState::Char(self), + _ => EscapeDefaultState::Unicode(self.escape_unicode()) + }; + EscapeDefault { state: init_state } + } + + #[inline] + fn escape_debug(self) -> EscapeDebug { + let init_state = match self { + '\t' => EscapeDefaultState::Backslash('t'), + '\r' => EscapeDefaultState::Backslash('r'), + '\n' => EscapeDefaultState::Backslash('n'), + '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), + c if is_printable(c) => EscapeDefaultState::Char(c), + c => EscapeDefaultState::Unicode(c.escape_unicode()), + }; + EscapeDebug(EscapeDefault { state: init_state }) + } + + #[inline] + fn len_utf8(self) -> usize { + let code = self as u32; + if code < MAX_ONE_B { + 1 + } else if code < MAX_TWO_B { + 2 + } else if code < MAX_THREE_B { + 3 + } else { + 4 + } + } + + #[inline] + fn len_utf16(self) -> usize { + let ch = self as u32; + if (ch & 0xFFFF) == ch { 1 } else { 2 } + } + + #[inline] + fn encode_utf8(self, dst: &mut [u8]) -> &mut str { + let code = self as u32; + unsafe { + let len = + if code < MAX_ONE_B && !dst.is_empty() { + *dst.get_unchecked_mut(0) = code as u8; + 1 + } else if code < MAX_TWO_B && dst.len() >= 2 { + *dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; + *dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT; + 2 + } else if code < MAX_THREE_B && dst.len() >= 3 { + *dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; + *dst.get_unchecked_mut(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT; + 3 + } else if dst.len() >= 4 { + *dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; + *dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT; + *dst.get_unchecked_mut(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT; + 4 + } else { + panic!("encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", + from_u32_unchecked(code).len_utf8(), + code, + dst.len()) + }; + from_utf8_unchecked_mut(dst.get_unchecked_mut(..len)) + } + } + + #[inline] + fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { + let mut code = self as u32; + unsafe { + if (code & 0xFFFF) == code && !dst.is_empty() { + // The BMP falls through (assuming non-surrogate, as it should) + *dst.get_unchecked_mut(0) = code as u16; + slice::from_raw_parts_mut(dst.as_mut_ptr(), 1) + } else if dst.len() >= 2 { + // Supplementary planes break into surrogates. + code -= 0x1_0000; + *dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16); + *dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF); + slice::from_raw_parts_mut(dst.as_mut_ptr(), 2) + } else { + panic!("encode_utf16: need {} units to encode U+{:X}, but the buffer has {}", + from_u32_unchecked(code).len_utf16(), + code, + dst.len()) + } + } + } +} + +/// Returns an iterator that yields the hexadecimal Unicode escape of a +/// character, as `char`s. +/// +/// This `struct` is created by the [`escape_unicode`] method on [`char`]. See +/// its documentation for more. +/// +/// [`escape_unicode`]: ../../std/primitive.char.html#method.escape_unicode +/// [`char`]: ../../std/primitive.char.html +#[derive(Clone, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct EscapeUnicode { + c: char, + state: EscapeUnicodeState, + + // The index of the next hex digit to be printed (0 if none), + // i.e. the number of remaining hex digits to be printed; + // increasing from the least significant digit: 0x543210 + hex_digit_idx: usize, +} + +// The enum values are ordered so that their representation is the +// same as the remaining length (besides the hexadecimal digits). This +// likely makes `len()` a single load from memory) and inline-worth. +#[derive(Clone, Debug)] +enum EscapeUnicodeState { + Done, + RightBrace, + Value, + LeftBrace, + Type, + Backslash, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for EscapeUnicode { + type Item = char; + + fn next(&mut self) -> Option { + match self.state { + EscapeUnicodeState::Backslash => { + self.state = EscapeUnicodeState::Type; + Some('\\') + } + EscapeUnicodeState::Type => { + self.state = EscapeUnicodeState::LeftBrace; + Some('u') + } + EscapeUnicodeState::LeftBrace => { + self.state = EscapeUnicodeState::Value; + Some('{') + } + EscapeUnicodeState::Value => { + let hex_digit = ((self.c as u32) >> (self.hex_digit_idx * 4)) & 0xf; + let c = from_digit(hex_digit, 16).unwrap(); + if self.hex_digit_idx == 0 { + self.state = EscapeUnicodeState::RightBrace; + } else { + self.hex_digit_idx -= 1; + } + Some(c) + } + EscapeUnicodeState::RightBrace => { + self.state = EscapeUnicodeState::Done; + Some('}') + } + EscapeUnicodeState::Done => None, + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.len(); + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + fn last(self) -> Option { + match self.state { + EscapeUnicodeState::Done => None, + + EscapeUnicodeState::RightBrace | + EscapeUnicodeState::Value | + EscapeUnicodeState::LeftBrace | + EscapeUnicodeState::Type | + EscapeUnicodeState::Backslash => Some('}'), + } + } +} + +#[stable(feature = "exact_size_escape", since = "1.11.0")] +impl ExactSizeIterator for EscapeUnicode { + #[inline] + fn len(&self) -> usize { + // The match is a single memory access with no branching + self.hex_digit_idx + match self.state { + EscapeUnicodeState::Done => 0, + EscapeUnicodeState::RightBrace => 1, + EscapeUnicodeState::Value => 2, + EscapeUnicodeState::LeftBrace => 3, + EscapeUnicodeState::Type => 4, + EscapeUnicodeState::Backslash => 5, + } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for EscapeUnicode {} + +#[stable(feature = "char_struct_display", since = "1.16.0")] +impl fmt::Display for EscapeUnicode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for c in self.clone() { + f.write_char(c)?; + } + Ok(()) + } +} + +/// An iterator that yields the literal escape code of a `char`. +/// +/// This `struct` is created by the [`escape_default`] method on [`char`]. See +/// its documentation for more. +/// +/// [`escape_default`]: ../../std/primitive.char.html#method.escape_default +/// [`char`]: ../../std/primitive.char.html +#[derive(Clone, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct EscapeDefault { + state: EscapeDefaultState +} + +#[derive(Clone, Debug)] +enum EscapeDefaultState { + Done, + Char(char), + Backslash(char), + Unicode(EscapeUnicode), +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for EscapeDefault { + type Item = char; + + fn next(&mut self) -> Option { + match self.state { + EscapeDefaultState::Backslash(c) => { + self.state = EscapeDefaultState::Char(c); + Some('\\') + } + EscapeDefaultState::Char(c) => { + self.state = EscapeDefaultState::Done; + Some(c) + } + EscapeDefaultState::Done => None, + EscapeDefaultState::Unicode(ref mut iter) => iter.next(), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.len(); + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + fn nth(&mut self, n: usize) -> Option { + match self.state { + EscapeDefaultState::Backslash(c) if n == 0 => { + self.state = EscapeDefaultState::Char(c); + Some('\\') + }, + EscapeDefaultState::Backslash(c) if n == 1 => { + self.state = EscapeDefaultState::Done; + Some(c) + }, + EscapeDefaultState::Backslash(_) => { + self.state = EscapeDefaultState::Done; + None + }, + EscapeDefaultState::Char(c) => { + self.state = EscapeDefaultState::Done; + + if n == 0 { + Some(c) + } else { + None + } + }, + EscapeDefaultState::Done => return None, + EscapeDefaultState::Unicode(ref mut i) => return i.nth(n), + } + } + + fn last(self) -> Option { + match self.state { + EscapeDefaultState::Unicode(iter) => iter.last(), + EscapeDefaultState::Done => None, + EscapeDefaultState::Backslash(c) | EscapeDefaultState::Char(c) => Some(c), + } + } +} + +#[stable(feature = "exact_size_escape", since = "1.11.0")] +impl ExactSizeIterator for EscapeDefault { + fn len(&self) -> usize { + match self.state { + EscapeDefaultState::Done => 0, + EscapeDefaultState::Char(_) => 1, + EscapeDefaultState::Backslash(_) => 2, + EscapeDefaultState::Unicode(ref iter) => iter.len(), + } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for EscapeDefault {} + +#[stable(feature = "char_struct_display", since = "1.16.0")] +impl fmt::Display for EscapeDefault { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for c in self.clone() { + f.write_char(c)?; + } + Ok(()) + } +} + +/// An iterator that yields the literal escape code of a `char`. +/// +/// This `struct` is created by the [`escape_debug`] method on [`char`]. See its +/// documentation for more. +/// +/// [`escape_debug`]: ../../std/primitive.char.html#method.escape_debug +/// [`char`]: ../../std/primitive.char.html +#[stable(feature = "char_escape_debug", since = "1.20.0")] +#[derive(Clone, Debug)] +pub struct EscapeDebug(EscapeDefault); + +#[stable(feature = "char_escape_debug", since = "1.20.0")] +impl Iterator for EscapeDebug { + type Item = char; + fn next(&mut self) -> Option { self.0.next() } + fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } +} + +#[stable(feature = "char_escape_debug", since = "1.20.0")] +impl ExactSizeIterator for EscapeDebug { } + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for EscapeDebug {} + +#[stable(feature = "char_escape_debug", since = "1.20.0")] +impl fmt::Display for EscapeDebug { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + + + +/// An iterator over an iterator of bytes of the characters the bytes represent +/// as UTF-8 +#[unstable(feature = "decode_utf8", issue = "33906")] +#[derive(Clone, Debug)] +pub struct DecodeUtf8>(::iter::Peekable); + +/// Decodes an `Iterator` of bytes as UTF-8. +#[unstable(feature = "decode_utf8", issue = "33906")] +#[inline] +pub fn decode_utf8>(i: I) -> DecodeUtf8 { + DecodeUtf8(i.into_iter().peekable()) +} + +/// `::next` returns this for an invalid input sequence. +#[unstable(feature = "decode_utf8", issue = "33906")] +#[derive(PartialEq, Eq, Debug)] +pub struct InvalidSequence(()); + +#[unstable(feature = "decode_utf8", issue = "33906")] +impl> Iterator for DecodeUtf8 { + type Item = Result; + #[inline] + + fn next(&mut self) -> Option> { + self.0.next().map(|first_byte| { + // Emit InvalidSequence according to + // Unicode §5.22 Best Practice for U+FFFD Substitution + // http://www.unicode.org/versions/Unicode9.0.0/ch05.pdf#G40630 + + // Roughly: consume at least one byte, + // then validate one byte at a time and stop before the first unexpected byte + // (which might be the valid start of the next byte sequence). + + let mut code_point; + macro_rules! first_byte { + ($mask: expr) => { + code_point = u32::from(first_byte & $mask) + } + } + macro_rules! continuation_byte { + () => { continuation_byte!(0x80...0xBF) }; + ($range: pat) => { + match self.0.peek() { + Some(&byte @ $range) => { + code_point = (code_point << 6) | u32::from(byte & 0b0011_1111); + self.0.next(); + } + _ => return Err(InvalidSequence(())) + } + } + } + + match first_byte { + 0x00...0x7F => { + first_byte!(0b1111_1111); + } + 0xC2...0xDF => { + first_byte!(0b0001_1111); + continuation_byte!(); + } + 0xE0 => { + first_byte!(0b0000_1111); + continuation_byte!(0xA0...0xBF); // 0x80...0x9F here are overlong + continuation_byte!(); + } + 0xE1...0xEC | 0xEE...0xEF => { + first_byte!(0b0000_1111); + continuation_byte!(); + continuation_byte!(); + } + 0xED => { + first_byte!(0b0000_1111); + continuation_byte!(0x80...0x9F); // 0xA0..0xBF here are surrogates + continuation_byte!(); + } + 0xF0 => { + first_byte!(0b0000_0111); + continuation_byte!(0x90...0xBF); // 0x80..0x8F here are overlong + continuation_byte!(); + continuation_byte!(); + } + 0xF1...0xF3 => { + first_byte!(0b0000_0111); + continuation_byte!(); + continuation_byte!(); + continuation_byte!(); + } + 0xF4 => { + first_byte!(0b0000_0111); + continuation_byte!(0x80...0x8F); // 0x90..0xBF here are beyond char::MAX + continuation_byte!(); + continuation_byte!(); + } + _ => return Err(InvalidSequence(())) // Illegal first byte, overlong, or beyond MAX + } + unsafe { + Ok(from_u32_unchecked(code_point)) + } + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (lower, upper) = self.0.size_hint(); + + // A code point is at most 4 bytes long. + let min_code_points = lower / 4; + + (min_code_points, upper) + } +} + +#[unstable(feature = "decode_utf8", issue = "33906")] +impl> FusedIterator for DecodeUtf8 {} diff --git a/src/libcore/char/printable.py b/src/libcore/char/printable.py new file mode 100644 index 00000000000..484822e10aa --- /dev/null +++ b/src/libcore/char/printable.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python +# +# Copyright 2011-2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +# This script uses the following Unicode tables: +# - UnicodeData.txt + + +from collections import namedtuple +import csv +import os +import subprocess + +NUM_CODEPOINTS=0x110000 + +def to_ranges(iter): + current = None + for i in iter: + if current is None or i != current[1] or i in (0x10000, 0x20000): + if current is not None: + yield tuple(current) + current = [i, i + 1] + else: + current[1] += 1 + if current is not None: + yield tuple(current) + +def get_escaped(codepoints): + for c in codepoints: + if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord(' '): + yield c.value + +def get_file(f): + try: + return open(os.path.basename(f)) + except FileNotFoundError: + subprocess.run(["curl", "-O", f], check=True) + return open(os.path.basename(f)) + +Codepoint = namedtuple('Codepoint', 'value class_') + +def get_codepoints(f): + r = csv.reader(f, delimiter=";") + prev_codepoint = 0 + class_first = None + for row in r: + codepoint = int(row[0], 16) + name = row[1] + class_ = row[2] + + if class_first is not None: + if not name.endswith("Last>"): + raise ValueError("Missing Last after First") + + for c in range(prev_codepoint + 1, codepoint): + yield Codepoint(c, class_first) + + class_first = None + if name.endswith("First>"): + class_first = class_ + + yield Codepoint(codepoint, class_) + prev_codepoint = codepoint + + if class_first != None: + raise ValueError("Missing Last after First") + + for c in range(prev_codepoint + 1, NUM_CODEPOINTS): + yield Codepoint(c, None) + +def compress_singletons(singletons): + uppers = [] # (upper, # items in lowers) + lowers = [] + + for i in singletons: + upper = i >> 8 + lower = i & 0xff + if len(uppers) == 0 or uppers[-1][0] != upper: + uppers.append((upper, 1)) + else: + upper, count = uppers[-1] + uppers[-1] = upper, count + 1 + lowers.append(lower) + + return uppers, lowers + +def compress_normal(normal): + # lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f + # lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff + compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)] + + prev_start = 0 + for start, count in normal: + truelen = start - prev_start + falselen = count + prev_start = start + count + + assert truelen < 0x8000 and falselen < 0x8000 + entry = [] + if truelen > 0x7f: + entry.append(0x80 | (truelen >> 8)) + entry.append(truelen & 0xff) + else: + entry.append(truelen & 0x7f) + if falselen > 0x7f: + entry.append(0x80 | (falselen >> 8)) + entry.append(falselen & 0xff) + else: + entry.append(falselen & 0x7f) + + compressed.append(entry) + + return compressed + +def print_singletons(uppers, lowers, uppersname, lowersname): + print("const {}: &'static [(u8, u8)] = &[".format(uppersname)) + for u, c in uppers: + print(" ({:#04x}, {}),".format(u, c)) + print("];") + print("const {}: &'static [u8] = &[".format(lowersname)) + for i in range(0, len(lowers), 8): + print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8]))) + print("];") + +def print_normal(normal, normalname): + print("const {}: &'static [u8] = &[".format(normalname)) + for v in normal: + print(" {}".format(" ".join("{:#04x},".format(i) for i in v))) + print("];") + +def main(): + file = get_file("http://www.unicode.org/Public/UNIDATA/UnicodeData.txt") + + codepoints = get_codepoints(file) + + CUTOFF=0x10000 + singletons0 = [] + singletons1 = [] + normal0 = [] + normal1 = [] + extra = [] + + for a, b in to_ranges(get_escaped(codepoints)): + if a > 2 * CUTOFF: + extra.append((a, b - a)) + elif a == b - 1: + if a & CUTOFF: + singletons1.append(a & ~CUTOFF) + else: + singletons0.append(a) + elif a == b - 2: + if a & CUTOFF: + singletons1.append(a & ~CUTOFF) + singletons1.append((a + 1) & ~CUTOFF) + else: + singletons0.append(a) + singletons0.append(a + 1) + else: + if a >= 2 * CUTOFF: + extra.append((a, b - a)) + elif a & CUTOFF: + normal1.append((a & ~CUTOFF, b - a)) + else: + normal0.append((a, b - a)) + + singletons0u, singletons0l = compress_singletons(singletons0) + singletons1u, singletons1l = compress_singletons(singletons1) + normal0 = compress_normal(normal0) + normal1 = compress_normal(normal1) + + print("""\ +// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "src/libcore/char/printable.py", +// do not edit directly! + +fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], + normal: &[u8]) -> bool { + let xupper = (x >> 8) as u8; + let mut lowerstart = 0; + for &(upper, lowercount) in singletonuppers { + let lowerend = lowerstart + lowercount as usize; + if xupper == upper { + for &lower in &singletonlowers[lowerstart..lowerend] { + if lower == x as u8 { + return false; + } + } + } else if xupper < upper { + break; + } + lowerstart = lowerend; + } + + let mut x = x as i32; + let mut normal = normal.iter().cloned(); + let mut current = true; + while let Some(v) = normal.next() { + let len = if v & 0x80 != 0 { + ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32 + } else { + v as i32 + }; + x -= len; + if x < 0 { + break; + } + current = !current; + } + current +} + +pub(crate) fn is_printable(x: char) -> bool { + let x = x as u32; + let lower = x as u16; + if x < 0x10000 { + check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) + } else if x < 0x20000 { + check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) + } else {\ +""") + for a, b in extra: + print(" if 0x{:x} <= x && x < 0x{:x} {{".format(a, a + b)) + print(" return false;") + print(" }") + print("""\ + true + } +}\ +""") + print() + print_singletons(singletons0u, singletons0l, 'SINGLETONS0U', 'SINGLETONS0L') + print_singletons(singletons1u, singletons1l, 'SINGLETONS1U', 'SINGLETONS1L') + print_normal(normal0, 'NORMAL0') + print_normal(normal1, 'NORMAL1') + +if __name__ == '__main__': + main() diff --git a/src/libcore/char/printable.rs b/src/libcore/char/printable.rs new file mode 100644 index 00000000000..ce011fab187 --- /dev/null +++ b/src/libcore/char/printable.rs @@ -0,0 +1,531 @@ +// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "src/libcore/char/printable.py", +// do not edit directly! + +fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], + normal: &[u8]) -> bool { + let xupper = (x >> 8) as u8; + let mut lowerstart = 0; + for &(upper, lowercount) in singletonuppers { + let lowerend = lowerstart + lowercount as usize; + if xupper == upper { + for &lower in &singletonlowers[lowerstart..lowerend] { + if lower == x as u8 { + return false; + } + } + } else if xupper < upper { + break; + } + lowerstart = lowerend; + } + + let mut x = x as i32; + let mut normal = normal.iter().cloned(); + let mut current = true; + while let Some(v) = normal.next() { + let len = if v & 0x80 != 0 { + ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32 + } else { + v as i32 + }; + x -= len; + if x < 0 { + break; + } + current = !current; + } + current +} + +pub(crate) fn is_printable(x: char) -> bool { + let x = x as u32; + let lower = x as u16; + if x < 0x10000 { + check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) + } else if x < 0x20000 { + check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) + } else { + if 0x2a6d7 <= x && x < 0x2a700 { + return false; + } + if 0x2b735 <= x && x < 0x2b740 { + return false; + } + if 0x2b81e <= x && x < 0x2b820 { + return false; + } + if 0x2cea2 <= x && x < 0x2ceb0 { + return false; + } + if 0x2ebe1 <= x && x < 0x2f800 { + return false; + } + if 0x2fa1e <= x && x < 0xe0100 { + return false; + } + if 0xe01f0 <= x && x < 0x110000 { + return false; + } + true + } +} + +const SINGLETONS0U: &'static [(u8, u8)] = &[ + (0x00, 1), + (0x03, 5), + (0x05, 8), + (0x06, 3), + (0x07, 4), + (0x08, 8), + (0x09, 16), + (0x0a, 27), + (0x0b, 25), + (0x0c, 22), + (0x0d, 18), + (0x0e, 22), + (0x0f, 4), + (0x10, 3), + (0x12, 18), + (0x13, 9), + (0x16, 1), + (0x17, 5), + (0x18, 2), + (0x19, 3), + (0x1a, 7), + (0x1d, 1), + (0x1f, 22), + (0x20, 3), + (0x2b, 5), + (0x2c, 2), + (0x2d, 11), + (0x2e, 1), + (0x30, 3), + (0x31, 3), + (0x32, 2), + (0xa7, 1), + (0xa8, 2), + (0xa9, 2), + (0xaa, 4), + (0xab, 8), + (0xfa, 2), + (0xfb, 5), + (0xfd, 4), + (0xfe, 3), + (0xff, 9), +]; +const SINGLETONS0L: &'static [u8] = &[ + 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, + 0x58, 0x60, 0x88, 0x8b, 0x8c, 0x90, 0x1c, 0x1d, + 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0x2e, 0x2f, 0x3f, + 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, + 0x91, 0x92, 0xa9, 0xb1, 0xba, 0xbb, 0xc5, 0xc6, + 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0x04, 0x11, 0x12, + 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, + 0x4a, 0x5d, 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, + 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, 0xe4, 0xe5, + 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, + 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, + 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, 0xc9, 0xce, + 0xcf, 0x04, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, + 0x64, 0x65, 0x84, 0x8d, 0x91, 0xa9, 0xb4, 0xba, + 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x04, + 0x0d, 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x81, + 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, 0xd7, 0xf0, + 0xf1, 0x83, 0x85, 0x86, 0x89, 0x8b, 0x8c, 0x98, + 0xa0, 0xa4, 0xa6, 0xa8, 0xa9, 0xac, 0xba, 0xbe, + 0xbf, 0xc5, 0xc7, 0xce, 0xcf, 0xda, 0xdb, 0x48, + 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, 0x4e, + 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, + 0xb1, 0xb6, 0xb7, 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, + 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe, + 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, + 0x0f, 0x1f, 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, + 0x7e, 0xae, 0xaf, 0xfa, 0x16, 0x17, 0x1e, 0x1f, + 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, + 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, + 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0x74, 0x75, 0x96, + 0x97, 0xc9, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, + 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, + 0x40, 0x97, 0x98, 0x2f, 0x30, 0x8f, 0x1f, 0xff, + 0xaf, 0xfe, 0xff, 0xce, 0xff, 0x4e, 0x4f, 0x5a, + 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, + 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, + 0x90, 0x91, 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, + 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff, +]; +const SINGLETONS1U: &'static [(u8, u8)] = &[ + (0x00, 6), + (0x01, 1), + (0x03, 1), + (0x04, 2), + (0x08, 8), + (0x09, 2), + (0x0a, 3), + (0x0b, 2), + (0x10, 1), + (0x11, 4), + (0x12, 5), + (0x13, 18), + (0x14, 2), + (0x15, 2), + (0x1a, 3), + (0x1c, 5), + (0x1d, 4), + (0x24, 1), + (0x6a, 3), + (0x6b, 2), + (0xbc, 2), + (0xd1, 2), + (0xd4, 12), + (0xd5, 9), + (0xd6, 2), + (0xd7, 2), + (0xda, 1), + (0xe0, 5), + (0xe8, 2), + (0xee, 32), + (0xf0, 4), + (0xf1, 1), + (0xf9, 1), +]; +const SINGLETONS1L: &'static [u8] = &[ + 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, + 0x9e, 0x9f, 0x06, 0x07, 0x09, 0x36, 0x3d, 0x3e, + 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x56, + 0x57, 0xbd, 0x35, 0xce, 0xcf, 0xe0, 0x12, 0x87, + 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, + 0x29, 0x31, 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, + 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5a, 0x5c, 0xb6, + 0xb7, 0x84, 0x85, 0x9d, 0x09, 0x37, 0x90, 0x91, + 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x6f, 0x5f, 0xee, + 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, 0x28, 0x55, + 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, + 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, + 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, 0xcd, + 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0xc5, 0xc6, + 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, + 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53, 0x55, 0x56, + 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, + 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, + 0xaf, 0xb0, 0xc0, 0xd0, 0x2f, 0x3f, +]; +const NORMAL0: &'static [u8] = &[ + 0x00, 0x20, + 0x5f, 0x22, + 0x82, 0xdf, 0x04, + 0x82, 0x44, 0x08, + 0x1b, 0x05, + 0x05, 0x11, + 0x81, 0xac, 0x0e, + 0x3b, 0x05, + 0x6b, 0x35, + 0x1e, 0x16, + 0x80, 0xdf, 0x03, + 0x19, 0x08, + 0x01, 0x04, + 0x22, 0x03, + 0x0a, 0x04, + 0x34, 0x04, + 0x07, 0x03, + 0x01, 0x07, + 0x06, 0x07, + 0x10, 0x0b, + 0x50, 0x0f, + 0x12, 0x07, + 0x55, 0x08, + 0x02, 0x04, + 0x1c, 0x0a, + 0x09, 0x03, + 0x08, 0x03, + 0x07, 0x03, + 0x02, 0x03, + 0x03, 0x03, + 0x0c, 0x04, + 0x05, 0x03, + 0x0b, 0x06, + 0x01, 0x0e, + 0x15, 0x05, + 0x3a, 0x03, + 0x11, 0x07, + 0x06, 0x05, + 0x10, 0x08, + 0x56, 0x07, + 0x02, 0x07, + 0x15, 0x0d, + 0x50, 0x04, + 0x43, 0x03, + 0x2d, 0x03, + 0x01, 0x04, + 0x11, 0x06, + 0x0f, 0x0c, + 0x3a, 0x04, + 0x1d, 0x25, + 0x0d, 0x06, + 0x4c, 0x20, + 0x6d, 0x04, + 0x6a, 0x25, + 0x80, 0xc8, 0x05, + 0x82, 0xb0, 0x03, + 0x1a, 0x06, + 0x82, 0xfd, 0x03, + 0x59, 0x07, + 0x15, 0x0b, + 0x17, 0x09, + 0x14, 0x0c, + 0x14, 0x0c, + 0x6a, 0x06, + 0x0a, 0x06, + 0x1a, 0x06, + 0x58, 0x08, + 0x2b, 0x05, + 0x46, 0x0a, + 0x2c, 0x04, + 0x0c, 0x04, + 0x01, 0x03, + 0x31, 0x0b, + 0x2c, 0x04, + 0x1a, 0x06, + 0x0b, 0x03, + 0x80, 0xac, 0x06, + 0x0a, 0x06, + 0x1f, 0x41, + 0x4c, 0x04, + 0x2d, 0x03, + 0x74, 0x08, + 0x3c, 0x03, + 0x0f, 0x03, + 0x3c, 0x37, + 0x08, 0x08, + 0x2a, 0x06, + 0x82, 0xff, 0x11, + 0x18, 0x08, + 0x2f, 0x11, + 0x2d, 0x03, + 0x20, 0x10, + 0x21, 0x0f, + 0x80, 0x8c, 0x04, + 0x82, 0x97, 0x19, + 0x0b, 0x15, + 0x87, 0x5a, 0x03, + 0x16, 0x19, + 0x04, 0x10, + 0x80, 0xf4, 0x05, + 0x2f, 0x05, + 0x3b, 0x07, + 0x02, 0x0e, + 0x18, 0x09, + 0x80, 0xaa, 0x36, + 0x74, 0x0c, + 0x80, 0xd6, 0x1a, + 0x0c, 0x05, + 0x80, 0xff, 0x05, + 0x80, 0xb6, 0x05, + 0x24, 0x0c, + 0x9b, 0xc6, 0x0a, + 0xd2, 0x2b, 0x15, + 0x84, 0x8d, 0x03, + 0x37, 0x09, + 0x81, 0x5c, 0x14, + 0x80, 0xb8, 0x08, + 0x80, 0xb8, 0x3f, + 0x35, 0x04, + 0x0a, 0x06, + 0x38, 0x08, + 0x46, 0x08, + 0x0c, 0x06, + 0x74, 0x0b, + 0x1e, 0x03, + 0x5a, 0x04, + 0x59, 0x09, + 0x80, 0x83, 0x18, + 0x1c, 0x0a, + 0x16, 0x09, + 0x46, 0x0a, + 0x80, 0x8a, 0x06, + 0xab, 0xa4, 0x0c, + 0x17, 0x04, + 0x31, 0xa1, 0x04, + 0x81, 0xda, 0x26, + 0x07, 0x0c, + 0x05, 0x05, + 0x80, 0xa5, 0x11, + 0x81, 0x6d, 0x10, + 0x78, 0x28, + 0x2a, 0x06, + 0x4c, 0x04, + 0x80, 0x8d, 0x04, + 0x80, 0xbe, 0x03, + 0x1b, 0x03, + 0x0f, 0x0d, +]; +const NORMAL1: &'static [u8] = &[ + 0x5e, 0x22, + 0x7b, 0x05, + 0x03, 0x04, + 0x2d, 0x03, + 0x65, 0x04, + 0x01, 0x2f, + 0x2e, 0x80, 0x82, + 0x1d, 0x03, + 0x31, 0x0f, + 0x1c, 0x04, + 0x24, 0x09, + 0x1e, 0x05, + 0x2b, 0x05, + 0x44, 0x04, + 0x0e, 0x2a, + 0x80, 0xaa, 0x06, + 0x24, 0x04, + 0x24, 0x04, + 0x28, 0x08, + 0x34, 0x0b, + 0x01, 0x80, 0x90, + 0x81, 0x37, 0x09, + 0x16, 0x0a, + 0x08, 0x80, 0x98, + 0x39, 0x03, + 0x63, 0x08, + 0x09, 0x30, + 0x16, 0x05, + 0x21, 0x03, + 0x1b, 0x05, + 0x01, 0x40, + 0x38, 0x04, + 0x4b, 0x05, + 0x28, 0x04, + 0x03, 0x04, + 0x09, 0x08, + 0x09, 0x07, + 0x40, 0x20, + 0x27, 0x04, + 0x0c, 0x09, + 0x36, 0x03, + 0x3a, 0x05, + 0x1a, 0x07, + 0x04, 0x0c, + 0x07, 0x50, + 0x49, 0x37, + 0x33, 0x0d, + 0x33, 0x07, + 0x06, 0x81, 0x60, + 0x1f, 0x81, 0x81, + 0x4e, 0x04, + 0x1e, 0x0f, + 0x43, 0x0e, + 0x19, 0x07, + 0x0a, 0x06, + 0x44, 0x0c, + 0x27, 0x09, + 0x75, 0x0b, + 0x3f, 0x41, + 0x2a, 0x06, + 0x3b, 0x05, + 0x0a, 0x06, + 0x51, 0x06, + 0x01, 0x05, + 0x10, 0x03, + 0x05, 0x80, 0x8b, + 0x5e, 0x22, + 0x48, 0x08, + 0x0a, 0x80, 0xa6, + 0x5e, 0x22, + 0x45, 0x0b, + 0x0a, 0x06, + 0x0d, 0x13, + 0x38, 0x08, + 0x0a, 0x36, + 0x1a, 0x03, + 0x0f, 0x04, + 0x10, 0x81, 0x60, + 0x53, 0x0c, + 0x01, 0x81, 0x00, + 0x48, 0x08, + 0x53, 0x1d, + 0x39, 0x81, 0x07, + 0x46, 0x0a, + 0x1d, 0x03, + 0x47, 0x49, + 0x37, 0x03, + 0x0e, 0x08, + 0x0a, 0x82, 0xa6, + 0x83, 0x9a, 0x66, + 0x75, 0x0b, + 0x80, 0xc4, 0x8a, 0xbc, + 0x84, 0x2f, 0x8f, 0xd1, + 0x82, 0x47, 0xa1, 0xb9, + 0x82, 0x39, 0x07, + 0x2a, 0x04, + 0x02, 0x60, + 0x26, 0x0a, + 0x46, 0x0a, + 0x28, 0x05, + 0x13, 0x83, 0x70, + 0x45, 0x0b, + 0x2f, 0x10, + 0x11, 0x40, + 0x02, 0x1e, + 0x97, 0xed, 0x13, + 0x82, 0xf3, 0xa5, 0x0d, + 0x81, 0x1f, 0x51, + 0x81, 0x8c, 0x89, 0x04, + 0x6b, 0x05, + 0x0d, 0x03, + 0x09, 0x07, + 0x10, 0x93, 0x60, + 0x80, 0xf6, 0x0a, + 0x73, 0x08, + 0x6e, 0x17, + 0x46, 0x80, 0xba, + 0x57, 0x09, + 0x12, 0x80, 0x8e, + 0x81, 0x47, 0x03, + 0x85, 0x42, 0x0f, + 0x15, 0x85, 0x50, + 0x2b, 0x87, 0xd5, + 0x80, 0xd7, 0x29, + 0x4b, 0x05, + 0x0a, 0x04, + 0x02, 0x84, 0xa0, + 0x3c, 0x06, + 0x01, 0x04, + 0x55, 0x05, + 0x1b, 0x34, + 0x02, 0x81, 0x0e, + 0x2c, 0x04, + 0x64, 0x0c, + 0x56, 0x0a, + 0x0d, 0x03, + 0x5c, 0x04, + 0x3d, 0x39, + 0x1d, 0x0d, + 0x2c, 0x04, + 0x09, 0x07, + 0x02, 0x0e, + 0x06, 0x80, 0x9a, + 0x83, 0xd5, 0x0b, + 0x0d, 0x03, + 0x09, 0x07, + 0x74, 0x0c, + 0x55, 0x2b, + 0x0c, 0x04, + 0x38, 0x08, + 0x0a, 0x06, + 0x28, 0x08, + 0x1e, 0x52, + 0x0c, 0x04, + 0x3d, 0x03, + 0x1c, 0x14, + 0x18, 0x28, + 0x01, 0x0f, + 0x17, 0x86, 0x19, +]; diff --git a/src/libcore/char_private.rs b/src/libcore/char_private.rs deleted file mode 100644 index e6803745ab5..00000000000 --- a/src/libcore/char_private.rs +++ /dev/null @@ -1,531 +0,0 @@ -// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// NOTE: The following code was generated by "src/etc/char_private.py", -// do not edit directly! - -fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], - normal: &[u8]) -> bool { - let xupper = (x >> 8) as u8; - let mut lowerstart = 0; - for &(upper, lowercount) in singletonuppers { - let lowerend = lowerstart + lowercount as usize; - if xupper == upper { - for &lower in &singletonlowers[lowerstart..lowerend] { - if lower == x as u8 { - return false; - } - } - } else if xupper < upper { - break; - } - lowerstart = lowerend; - } - - let mut x = x as i32; - let mut normal = normal.iter().cloned(); - let mut current = true; - while let Some(v) = normal.next() { - let len = if v & 0x80 != 0 { - ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32 - } else { - v as i32 - }; - x -= len; - if x < 0 { - break; - } - current = !current; - } - current -} - -pub(crate) fn is_printable(x: char) -> bool { - let x = x as u32; - let lower = x as u16; - if x < 0x10000 { - check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) - } else if x < 0x20000 { - check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) - } else { - if 0x2a6d7 <= x && x < 0x2a700 { - return false; - } - if 0x2b735 <= x && x < 0x2b740 { - return false; - } - if 0x2b81e <= x && x < 0x2b820 { - return false; - } - if 0x2cea2 <= x && x < 0x2ceb0 { - return false; - } - if 0x2ebe1 <= x && x < 0x2f800 { - return false; - } - if 0x2fa1e <= x && x < 0xe0100 { - return false; - } - if 0xe01f0 <= x && x < 0x110000 { - return false; - } - true - } -} - -const SINGLETONS0U: &'static [(u8, u8)] = &[ - (0x00, 1), - (0x03, 5), - (0x05, 8), - (0x06, 3), - (0x07, 4), - (0x08, 8), - (0x09, 16), - (0x0a, 27), - (0x0b, 25), - (0x0c, 22), - (0x0d, 18), - (0x0e, 22), - (0x0f, 4), - (0x10, 3), - (0x12, 18), - (0x13, 9), - (0x16, 1), - (0x17, 5), - (0x18, 2), - (0x19, 3), - (0x1a, 7), - (0x1d, 1), - (0x1f, 22), - (0x20, 3), - (0x2b, 5), - (0x2c, 2), - (0x2d, 11), - (0x2e, 1), - (0x30, 3), - (0x31, 3), - (0x32, 2), - (0xa7, 1), - (0xa8, 2), - (0xa9, 2), - (0xaa, 4), - (0xab, 8), - (0xfa, 2), - (0xfb, 5), - (0xfd, 4), - (0xfe, 3), - (0xff, 9), -]; -const SINGLETONS0L: &'static [u8] = &[ - 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, - 0x58, 0x60, 0x88, 0x8b, 0x8c, 0x90, 0x1c, 0x1d, - 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0x2e, 0x2f, 0x3f, - 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, - 0x91, 0x92, 0xa9, 0xb1, 0xba, 0xbb, 0xc5, 0xc6, - 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0x04, 0x11, 0x12, - 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, - 0x4a, 0x5d, 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, - 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, 0xe4, 0xe5, - 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, - 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, - 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, 0xc9, 0xce, - 0xcf, 0x04, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, - 0x64, 0x65, 0x84, 0x8d, 0x91, 0xa9, 0xb4, 0xba, - 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x04, - 0x0d, 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x81, - 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, 0xd7, 0xf0, - 0xf1, 0x83, 0x85, 0x86, 0x89, 0x8b, 0x8c, 0x98, - 0xa0, 0xa4, 0xa6, 0xa8, 0xa9, 0xac, 0xba, 0xbe, - 0xbf, 0xc5, 0xc7, 0xce, 0xcf, 0xda, 0xdb, 0x48, - 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, 0x4e, - 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, - 0xb1, 0xb6, 0xb7, 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, - 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe, - 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, - 0x0f, 0x1f, 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, - 0x7e, 0xae, 0xaf, 0xfa, 0x16, 0x17, 0x1e, 0x1f, - 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, - 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, - 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0x74, 0x75, 0x96, - 0x97, 0xc9, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, - 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, - 0x40, 0x97, 0x98, 0x2f, 0x30, 0x8f, 0x1f, 0xff, - 0xaf, 0xfe, 0xff, 0xce, 0xff, 0x4e, 0x4f, 0x5a, - 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, - 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, - 0x90, 0x91, 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, - 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff, -]; -const SINGLETONS1U: &'static [(u8, u8)] = &[ - (0x00, 6), - (0x01, 1), - (0x03, 1), - (0x04, 2), - (0x08, 8), - (0x09, 2), - (0x0a, 3), - (0x0b, 2), - (0x10, 1), - (0x11, 4), - (0x12, 5), - (0x13, 18), - (0x14, 2), - (0x15, 2), - (0x1a, 3), - (0x1c, 5), - (0x1d, 4), - (0x24, 1), - (0x6a, 3), - (0x6b, 2), - (0xbc, 2), - (0xd1, 2), - (0xd4, 12), - (0xd5, 9), - (0xd6, 2), - (0xd7, 2), - (0xda, 1), - (0xe0, 5), - (0xe8, 2), - (0xee, 32), - (0xf0, 4), - (0xf1, 1), - (0xf9, 1), -]; -const SINGLETONS1L: &'static [u8] = &[ - 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, - 0x9e, 0x9f, 0x06, 0x07, 0x09, 0x36, 0x3d, 0x3e, - 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x56, - 0x57, 0xbd, 0x35, 0xce, 0xcf, 0xe0, 0x12, 0x87, - 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, - 0x29, 0x31, 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, - 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5a, 0x5c, 0xb6, - 0xb7, 0x84, 0x85, 0x9d, 0x09, 0x37, 0x90, 0x91, - 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x6f, 0x5f, 0xee, - 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, 0x28, 0x55, - 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, - 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, - 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, 0xcd, - 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0xc5, 0xc6, - 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, - 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53, 0x55, 0x56, - 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, - 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, - 0xaf, 0xb0, 0xc0, 0xd0, 0x2f, 0x3f, -]; -const NORMAL0: &'static [u8] = &[ - 0x00, 0x20, - 0x5f, 0x22, - 0x82, 0xdf, 0x04, - 0x82, 0x44, 0x08, - 0x1b, 0x05, - 0x05, 0x11, - 0x81, 0xac, 0x0e, - 0x3b, 0x05, - 0x6b, 0x35, - 0x1e, 0x16, - 0x80, 0xdf, 0x03, - 0x19, 0x08, - 0x01, 0x04, - 0x22, 0x03, - 0x0a, 0x04, - 0x34, 0x04, - 0x07, 0x03, - 0x01, 0x07, - 0x06, 0x07, - 0x10, 0x0b, - 0x50, 0x0f, - 0x12, 0x07, - 0x55, 0x08, - 0x02, 0x04, - 0x1c, 0x0a, - 0x09, 0x03, - 0x08, 0x03, - 0x07, 0x03, - 0x02, 0x03, - 0x03, 0x03, - 0x0c, 0x04, - 0x05, 0x03, - 0x0b, 0x06, - 0x01, 0x0e, - 0x15, 0x05, - 0x3a, 0x03, - 0x11, 0x07, - 0x06, 0x05, - 0x10, 0x08, - 0x56, 0x07, - 0x02, 0x07, - 0x15, 0x0d, - 0x50, 0x04, - 0x43, 0x03, - 0x2d, 0x03, - 0x01, 0x04, - 0x11, 0x06, - 0x0f, 0x0c, - 0x3a, 0x04, - 0x1d, 0x25, - 0x0d, 0x06, - 0x4c, 0x20, - 0x6d, 0x04, - 0x6a, 0x25, - 0x80, 0xc8, 0x05, - 0x82, 0xb0, 0x03, - 0x1a, 0x06, - 0x82, 0xfd, 0x03, - 0x59, 0x07, - 0x15, 0x0b, - 0x17, 0x09, - 0x14, 0x0c, - 0x14, 0x0c, - 0x6a, 0x06, - 0x0a, 0x06, - 0x1a, 0x06, - 0x58, 0x08, - 0x2b, 0x05, - 0x46, 0x0a, - 0x2c, 0x04, - 0x0c, 0x04, - 0x01, 0x03, - 0x31, 0x0b, - 0x2c, 0x04, - 0x1a, 0x06, - 0x0b, 0x03, - 0x80, 0xac, 0x06, - 0x0a, 0x06, - 0x1f, 0x41, - 0x4c, 0x04, - 0x2d, 0x03, - 0x74, 0x08, - 0x3c, 0x03, - 0x0f, 0x03, - 0x3c, 0x37, - 0x08, 0x08, - 0x2a, 0x06, - 0x82, 0xff, 0x11, - 0x18, 0x08, - 0x2f, 0x11, - 0x2d, 0x03, - 0x20, 0x10, - 0x21, 0x0f, - 0x80, 0x8c, 0x04, - 0x82, 0x97, 0x19, - 0x0b, 0x15, - 0x87, 0x5a, 0x03, - 0x16, 0x19, - 0x04, 0x10, - 0x80, 0xf4, 0x05, - 0x2f, 0x05, - 0x3b, 0x07, - 0x02, 0x0e, - 0x18, 0x09, - 0x80, 0xaa, 0x36, - 0x74, 0x0c, - 0x80, 0xd6, 0x1a, - 0x0c, 0x05, - 0x80, 0xff, 0x05, - 0x80, 0xb6, 0x05, - 0x24, 0x0c, - 0x9b, 0xc6, 0x0a, - 0xd2, 0x2b, 0x15, - 0x84, 0x8d, 0x03, - 0x37, 0x09, - 0x81, 0x5c, 0x14, - 0x80, 0xb8, 0x08, - 0x80, 0xb8, 0x3f, - 0x35, 0x04, - 0x0a, 0x06, - 0x38, 0x08, - 0x46, 0x08, - 0x0c, 0x06, - 0x74, 0x0b, - 0x1e, 0x03, - 0x5a, 0x04, - 0x59, 0x09, - 0x80, 0x83, 0x18, - 0x1c, 0x0a, - 0x16, 0x09, - 0x46, 0x0a, - 0x80, 0x8a, 0x06, - 0xab, 0xa4, 0x0c, - 0x17, 0x04, - 0x31, 0xa1, 0x04, - 0x81, 0xda, 0x26, - 0x07, 0x0c, - 0x05, 0x05, - 0x80, 0xa5, 0x11, - 0x81, 0x6d, 0x10, - 0x78, 0x28, - 0x2a, 0x06, - 0x4c, 0x04, - 0x80, 0x8d, 0x04, - 0x80, 0xbe, 0x03, - 0x1b, 0x03, - 0x0f, 0x0d, -]; -const NORMAL1: &'static [u8] = &[ - 0x5e, 0x22, - 0x7b, 0x05, - 0x03, 0x04, - 0x2d, 0x03, - 0x65, 0x04, - 0x01, 0x2f, - 0x2e, 0x80, 0x82, - 0x1d, 0x03, - 0x31, 0x0f, - 0x1c, 0x04, - 0x24, 0x09, - 0x1e, 0x05, - 0x2b, 0x05, - 0x44, 0x04, - 0x0e, 0x2a, - 0x80, 0xaa, 0x06, - 0x24, 0x04, - 0x24, 0x04, - 0x28, 0x08, - 0x34, 0x0b, - 0x01, 0x80, 0x90, - 0x81, 0x37, 0x09, - 0x16, 0x0a, - 0x08, 0x80, 0x98, - 0x39, 0x03, - 0x63, 0x08, - 0x09, 0x30, - 0x16, 0x05, - 0x21, 0x03, - 0x1b, 0x05, - 0x01, 0x40, - 0x38, 0x04, - 0x4b, 0x05, - 0x28, 0x04, - 0x03, 0x04, - 0x09, 0x08, - 0x09, 0x07, - 0x40, 0x20, - 0x27, 0x04, - 0x0c, 0x09, - 0x36, 0x03, - 0x3a, 0x05, - 0x1a, 0x07, - 0x04, 0x0c, - 0x07, 0x50, - 0x49, 0x37, - 0x33, 0x0d, - 0x33, 0x07, - 0x06, 0x81, 0x60, - 0x1f, 0x81, 0x81, - 0x4e, 0x04, - 0x1e, 0x0f, - 0x43, 0x0e, - 0x19, 0x07, - 0x0a, 0x06, - 0x44, 0x0c, - 0x27, 0x09, - 0x75, 0x0b, - 0x3f, 0x41, - 0x2a, 0x06, - 0x3b, 0x05, - 0x0a, 0x06, - 0x51, 0x06, - 0x01, 0x05, - 0x10, 0x03, - 0x05, 0x80, 0x8b, - 0x5e, 0x22, - 0x48, 0x08, - 0x0a, 0x80, 0xa6, - 0x5e, 0x22, - 0x45, 0x0b, - 0x0a, 0x06, - 0x0d, 0x13, - 0x38, 0x08, - 0x0a, 0x36, - 0x1a, 0x03, - 0x0f, 0x04, - 0x10, 0x81, 0x60, - 0x53, 0x0c, - 0x01, 0x81, 0x00, - 0x48, 0x08, - 0x53, 0x1d, - 0x39, 0x81, 0x07, - 0x46, 0x0a, - 0x1d, 0x03, - 0x47, 0x49, - 0x37, 0x03, - 0x0e, 0x08, - 0x0a, 0x82, 0xa6, - 0x83, 0x9a, 0x66, - 0x75, 0x0b, - 0x80, 0xc4, 0x8a, 0xbc, - 0x84, 0x2f, 0x8f, 0xd1, - 0x82, 0x47, 0xa1, 0xb9, - 0x82, 0x39, 0x07, - 0x2a, 0x04, - 0x02, 0x60, - 0x26, 0x0a, - 0x46, 0x0a, - 0x28, 0x05, - 0x13, 0x83, 0x70, - 0x45, 0x0b, - 0x2f, 0x10, - 0x11, 0x40, - 0x02, 0x1e, - 0x97, 0xed, 0x13, - 0x82, 0xf3, 0xa5, 0x0d, - 0x81, 0x1f, 0x51, - 0x81, 0x8c, 0x89, 0x04, - 0x6b, 0x05, - 0x0d, 0x03, - 0x09, 0x07, - 0x10, 0x93, 0x60, - 0x80, 0xf6, 0x0a, - 0x73, 0x08, - 0x6e, 0x17, - 0x46, 0x80, 0xba, - 0x57, 0x09, - 0x12, 0x80, 0x8e, - 0x81, 0x47, 0x03, - 0x85, 0x42, 0x0f, - 0x15, 0x85, 0x50, - 0x2b, 0x87, 0xd5, - 0x80, 0xd7, 0x29, - 0x4b, 0x05, - 0x0a, 0x04, - 0x02, 0x84, 0xa0, - 0x3c, 0x06, - 0x01, 0x04, - 0x55, 0x05, - 0x1b, 0x34, - 0x02, 0x81, 0x0e, - 0x2c, 0x04, - 0x64, 0x0c, - 0x56, 0x0a, - 0x0d, 0x03, - 0x5c, 0x04, - 0x3d, 0x39, - 0x1d, 0x0d, - 0x2c, 0x04, - 0x09, 0x07, - 0x02, 0x0e, - 0x06, 0x80, 0x9a, - 0x83, 0xd5, 0x0b, - 0x0d, 0x03, - 0x09, 0x07, - 0x74, 0x0c, - 0x55, 0x2b, - 0x0c, 0x04, - 0x38, 0x08, - 0x0a, 0x06, - 0x28, 0x08, - 0x1e, 0x52, - 0x0c, 0x04, - 0x3d, 0x03, - 0x1c, 0x14, - 0x18, 0x28, - 0x01, 0x0f, - 0x17, 0x86, 0x19, -]; diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 7cb635a299a..9ff8465bc0f 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -187,7 +187,6 @@ pub mod unicode; pub mod heap; // note: does not need to be public -mod char_private; mod iter_private; mod tuple; mod unit; -- cgit 1.4.1-3-g733a5 From 939692409da499ff3d498eae782620435f16a981 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 5 Apr 2018 17:56:46 +0200 Subject: Reexport from core::unicode::char in core::char rather than vice versa --- src/liballoc/string.rs | 2 +- src/liballoc/tests/string.rs | 2 +- src/libcore/char/mod.rs | 12 ++++++++++++ src/libcore/unicode/char.rs | 21 +-------------------- src/libcore/unicode/mod.rs | 6 +++--- src/libstd/lib.rs | 2 +- 6 files changed, 19 insertions(+), 26 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index a902f0bb06b..29d759b1f00 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -56,6 +56,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use core::char::{decode_utf16, REPLACEMENT_CHARACTER}; use core::fmt; use core::hash; use core::iter::{FromIterator, FusedIterator}; @@ -64,7 +65,6 @@ use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds}; use core::ptr; use core::str::pattern::Pattern; use core::str::lossy; -use core::unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; use borrow::{Cow, ToOwned}; use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index 33f20be100d..17d53e4cf3e 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -132,7 +132,7 @@ fn test_from_utf16() { let s_as_utf16 = s.encode_utf16().collect::>(); let u_as_string = String::from_utf16(&u).unwrap(); - assert!(::core::unicode::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok())); + assert!(::core::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok())); assert_eq!(s_as_utf16, u); assert_eq!(u_as_string, s); diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index c6b620e5238..3efa8396331 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -15,6 +15,18 @@ #![allow(non_snake_case)] #![stable(feature = "core_char", since = "1.2.0")] +// stable re-exports +#[stable(feature = "rust1", since = "1.0.0")] +pub use unicode::char::{ToLowercase, ToUppercase}; +#[stable(feature = "decode_utf16", since = "1.9.0")] +pub use unicode::char::{decode_utf16, DecodeUtf16, DecodeUtf16Error}; + +// unstable re-exports +#[unstable(feature = "unicode", issue = "27783")] +pub use unicode::tables::{UNICODE_VERSION}; +#[unstable(feature = "unicode", issue = "27783")] +pub use unicode::version::UnicodeVersion; + mod printable; use self::printable::is_printable; diff --git a/src/libcore/unicode/char.rs b/src/libcore/unicode/char.rs index 0e8b09f621a..e75338aedf1 100644 --- a/src/libcore/unicode/char.rs +++ b/src/libcore/unicode/char.rs @@ -28,31 +28,12 @@ #![stable(feature = "rust1", since = "1.0.0")] +use char::*; use char::CharExt as C; use iter::FusedIterator; use fmt::{self, Write}; use unicode::tables::{conversions, derived_property, general_category, property}; -// stable re-exports -#[stable(feature = "rust1", since = "1.0.0")] -pub use char::{MAX, from_digit, from_u32, from_u32_unchecked}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use char::{EscapeDebug, EscapeDefault, EscapeUnicode}; -#[stable(feature = "decode_utf16", since = "1.9.0")] -pub use char::REPLACEMENT_CHARACTER; -#[stable(feature = "char_from_str", since = "1.20.0")] -pub use char::ParseCharError; - -// unstable re-exports -#[stable(feature = "try_from", since = "1.26.0")] -pub use char::CharTryFromError; -#[unstable(feature = "decode_utf8", issue = "33906")] -pub use char::{DecodeUtf8, decode_utf8}; -#[unstable(feature = "unicode", issue = "27783")] -pub use unicode::tables::{UNICODE_VERSION}; -#[unstable(feature = "unicode", issue = "27783")] -pub use unicode::version::UnicodeVersion; - /// Returns an iterator that yields the lowercase equivalent of a `char`. /// /// This `struct` is created by the [`to_lowercase`] method on [`char`]. See diff --git a/src/libcore/unicode/mod.rs b/src/libcore/unicode/mod.rs index aaf8081799f..0ea1aa12146 100644 --- a/src/libcore/unicode/mod.rs +++ b/src/libcore/unicode/mod.rs @@ -12,11 +12,11 @@ #![allow(missing_docs)] mod bool_trie; -mod tables; -mod version; +pub(crate) mod tables; +pub(crate) mod version; pub mod str; -pub mod char; +pub(crate) mod char; // For use in liballoc, not re-exported in libstd. pub mod derived_property { diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 16bca9ddcd3..94e48732c26 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -454,7 +454,7 @@ pub use alloc::string; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc::vec; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::unicode::char; +pub use core::char; #[stable(feature = "i128", since = "1.26.0")] pub use core::u128; -- cgit 1.4.1-3-g733a5 From 955450212aac9c2babd6cb511974092224fcf93d Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 5 Apr 2018 18:02:52 +0200 Subject: Move char decoding iterators into a separate private module. --- src/libcore/char/decode.rs | 259 ++++++++++++++++++++++++++++++++++++++++++++ src/libcore/char/mod.rs | 126 +-------------------- src/libcore/unicode/char.rs | 129 ---------------------- 3 files changed, 265 insertions(+), 249 deletions(-) create mode 100644 src/libcore/char/decode.rs (limited to 'src/libcore') diff --git a/src/libcore/char/decode.rs b/src/libcore/char/decode.rs new file mode 100644 index 00000000000..48b531104f8 --- /dev/null +++ b/src/libcore/char/decode.rs @@ -0,0 +1,259 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! UTF-8 and UTF-16 decoding iterators + +use fmt; +use iter::FusedIterator; +use super::from_u32_unchecked; + +/// An iterator over an iterator of bytes of the characters the bytes represent +/// as UTF-8 +#[unstable(feature = "decode_utf8", issue = "33906")] +#[derive(Clone, Debug)] +pub struct DecodeUtf8>(::iter::Peekable); + +/// Decodes an `Iterator` of bytes as UTF-8. +#[unstable(feature = "decode_utf8", issue = "33906")] +#[inline] +pub fn decode_utf8>(i: I) -> DecodeUtf8 { + DecodeUtf8(i.into_iter().peekable()) +} + +/// `::next` returns this for an invalid input sequence. +#[unstable(feature = "decode_utf8", issue = "33906")] +#[derive(PartialEq, Eq, Debug)] +pub struct InvalidSequence(()); + +#[unstable(feature = "decode_utf8", issue = "33906")] +impl> Iterator for DecodeUtf8 { + type Item = Result; + #[inline] + + fn next(&mut self) -> Option> { + self.0.next().map(|first_byte| { + // Emit InvalidSequence according to + // Unicode §5.22 Best Practice for U+FFFD Substitution + // http://www.unicode.org/versions/Unicode9.0.0/ch05.pdf#G40630 + + // Roughly: consume at least one byte, + // then validate one byte at a time and stop before the first unexpected byte + // (which might be the valid start of the next byte sequence). + + let mut code_point; + macro_rules! first_byte { + ($mask: expr) => { + code_point = u32::from(first_byte & $mask) + } + } + macro_rules! continuation_byte { + () => { continuation_byte!(0x80...0xBF) }; + ($range: pat) => { + match self.0.peek() { + Some(&byte @ $range) => { + code_point = (code_point << 6) | u32::from(byte & 0b0011_1111); + self.0.next(); + } + _ => return Err(InvalidSequence(())) + } + } + } + + match first_byte { + 0x00...0x7F => { + first_byte!(0b1111_1111); + } + 0xC2...0xDF => { + first_byte!(0b0001_1111); + continuation_byte!(); + } + 0xE0 => { + first_byte!(0b0000_1111); + continuation_byte!(0xA0...0xBF); // 0x80...0x9F here are overlong + continuation_byte!(); + } + 0xE1...0xEC | 0xEE...0xEF => { + first_byte!(0b0000_1111); + continuation_byte!(); + continuation_byte!(); + } + 0xED => { + first_byte!(0b0000_1111); + continuation_byte!(0x80...0x9F); // 0xA0..0xBF here are surrogates + continuation_byte!(); + } + 0xF0 => { + first_byte!(0b0000_0111); + continuation_byte!(0x90...0xBF); // 0x80..0x8F here are overlong + continuation_byte!(); + continuation_byte!(); + } + 0xF1...0xF3 => { + first_byte!(0b0000_0111); + continuation_byte!(); + continuation_byte!(); + continuation_byte!(); + } + 0xF4 => { + first_byte!(0b0000_0111); + continuation_byte!(0x80...0x8F); // 0x90..0xBF here are beyond char::MAX + continuation_byte!(); + continuation_byte!(); + } + _ => return Err(InvalidSequence(())) // Illegal first byte, overlong, or beyond MAX + } + unsafe { + Ok(from_u32_unchecked(code_point)) + } + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (lower, upper) = self.0.size_hint(); + + // A code point is at most 4 bytes long. + let min_code_points = lower / 4; + + (min_code_points, upper) + } +} + +#[unstable(feature = "decode_utf8", issue = "33906")] +impl> FusedIterator for DecodeUtf8 {} + +/// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s. +#[stable(feature = "decode_utf16", since = "1.9.0")] +#[derive(Clone, Debug)] +pub struct DecodeUtf16 + where I: Iterator +{ + iter: I, + buf: Option, +} + +/// An error that can be returned when decoding UTF-16 code points. +#[stable(feature = "decode_utf16", since = "1.9.0")] +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct DecodeUtf16Error { + code: u16, +} + +/// Create an iterator over the UTF-16 encoded code points in `iter`, +/// returning unpaired surrogates as `Err`s. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::char::decode_utf16; +/// +/// fn main() { +/// // 𝄞music +/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075, +/// 0x0073, 0xDD1E, 0x0069, 0x0063, +/// 0xD834]; +/// +/// assert_eq!(decode_utf16(v.iter().cloned()) +/// .map(|r| r.map_err(|e| e.unpaired_surrogate())) +/// .collect::>(), +/// vec![Ok('𝄞'), +/// Ok('m'), Ok('u'), Ok('s'), +/// Err(0xDD1E), +/// Ok('i'), Ok('c'), +/// Err(0xD834)]); +/// } +/// ``` +/// +/// A lossy decoder can be obtained by replacing `Err` results with the replacement character: +/// +/// ``` +/// use std::char::{decode_utf16, REPLACEMENT_CHARACTER}; +/// +/// fn main() { +/// // 𝄞music +/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075, +/// 0x0073, 0xDD1E, 0x0069, 0x0063, +/// 0xD834]; +/// +/// assert_eq!(decode_utf16(v.iter().cloned()) +/// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) +/// .collect::(), +/// "𝄞mus�ic�"); +/// } +/// ``` +#[stable(feature = "decode_utf16", since = "1.9.0")] +#[inline] +pub fn decode_utf16>(iter: I) -> DecodeUtf16 { + DecodeUtf16 { + iter: iter.into_iter(), + buf: None, + } +} + +#[stable(feature = "decode_utf16", since = "1.9.0")] +impl> Iterator for DecodeUtf16 { + type Item = Result; + + fn next(&mut self) -> Option> { + let u = match self.buf.take() { + Some(buf) => buf, + None => self.iter.next()? + }; + + if u < 0xD800 || 0xDFFF < u { + // not a surrogate + Some(Ok(unsafe { from_u32_unchecked(u as u32) })) + } else if u >= 0xDC00 { + // a trailing surrogate + Some(Err(DecodeUtf16Error { code: u })) + } else { + let u2 = match self.iter.next() { + Some(u2) => u2, + // eof + None => return Some(Err(DecodeUtf16Error { code: u })), + }; + if u2 < 0xDC00 || u2 > 0xDFFF { + // not a trailing surrogate so we're not a valid + // surrogate pair, so rewind to redecode u2 next time. + self.buf = Some(u2); + return Some(Err(DecodeUtf16Error { code: u })); + } + + // all ok, so lets decode it. + let c = (((u - 0xD800) as u32) << 10 | (u2 - 0xDC00) as u32) + 0x1_0000; + Some(Ok(unsafe { from_u32_unchecked(c) })) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (low, high) = self.iter.size_hint(); + // we could be entirely valid surrogates (2 elements per + // char), or entirely non-surrogates (1 element per char) + (low / 2, high) + } +} + +impl DecodeUtf16Error { + /// Returns the unpaired surrogate which caused this error. + #[stable(feature = "decode_utf16", since = "1.9.0")] + pub fn unpaired_surrogate(&self) -> u16 { + self.code + } +} + +#[stable(feature = "decode_utf16", since = "1.9.0")] +impl fmt::Display for DecodeUtf16Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "unpaired surrogate found: {:x}", self.code) + } +} diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index 3efa8396331..388bc47750d 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -15,19 +15,22 @@ #![allow(non_snake_case)] #![stable(feature = "core_char", since = "1.2.0")] +mod printable; +mod decode; + // stable re-exports #[stable(feature = "rust1", since = "1.0.0")] pub use unicode::char::{ToLowercase, ToUppercase}; #[stable(feature = "decode_utf16", since = "1.9.0")] -pub use unicode::char::{decode_utf16, DecodeUtf16, DecodeUtf16Error}; +pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error}; // unstable re-exports #[unstable(feature = "unicode", issue = "27783")] pub use unicode::tables::{UNICODE_VERSION}; #[unstable(feature = "unicode", issue = "27783")] pub use unicode::version::UnicodeVersion; - -mod printable; +#[unstable(feature = "decode_utf8", issue = "33906")] +pub use self::decode::{decode_utf8, DecodeUtf8, InvalidSequence}; use self::printable::is_printable; use convert::TryFrom; @@ -821,120 +824,3 @@ impl fmt::Display for EscapeDebug { fmt::Display::fmt(&self.0, f) } } - - - -/// An iterator over an iterator of bytes of the characters the bytes represent -/// as UTF-8 -#[unstable(feature = "decode_utf8", issue = "33906")] -#[derive(Clone, Debug)] -pub struct DecodeUtf8>(::iter::Peekable); - -/// Decodes an `Iterator` of bytes as UTF-8. -#[unstable(feature = "decode_utf8", issue = "33906")] -#[inline] -pub fn decode_utf8>(i: I) -> DecodeUtf8 { - DecodeUtf8(i.into_iter().peekable()) -} - -/// `::next` returns this for an invalid input sequence. -#[unstable(feature = "decode_utf8", issue = "33906")] -#[derive(PartialEq, Eq, Debug)] -pub struct InvalidSequence(()); - -#[unstable(feature = "decode_utf8", issue = "33906")] -impl> Iterator for DecodeUtf8 { - type Item = Result; - #[inline] - - fn next(&mut self) -> Option> { - self.0.next().map(|first_byte| { - // Emit InvalidSequence according to - // Unicode §5.22 Best Practice for U+FFFD Substitution - // http://www.unicode.org/versions/Unicode9.0.0/ch05.pdf#G40630 - - // Roughly: consume at least one byte, - // then validate one byte at a time and stop before the first unexpected byte - // (which might be the valid start of the next byte sequence). - - let mut code_point; - macro_rules! first_byte { - ($mask: expr) => { - code_point = u32::from(first_byte & $mask) - } - } - macro_rules! continuation_byte { - () => { continuation_byte!(0x80...0xBF) }; - ($range: pat) => { - match self.0.peek() { - Some(&byte @ $range) => { - code_point = (code_point << 6) | u32::from(byte & 0b0011_1111); - self.0.next(); - } - _ => return Err(InvalidSequence(())) - } - } - } - - match first_byte { - 0x00...0x7F => { - first_byte!(0b1111_1111); - } - 0xC2...0xDF => { - first_byte!(0b0001_1111); - continuation_byte!(); - } - 0xE0 => { - first_byte!(0b0000_1111); - continuation_byte!(0xA0...0xBF); // 0x80...0x9F here are overlong - continuation_byte!(); - } - 0xE1...0xEC | 0xEE...0xEF => { - first_byte!(0b0000_1111); - continuation_byte!(); - continuation_byte!(); - } - 0xED => { - first_byte!(0b0000_1111); - continuation_byte!(0x80...0x9F); // 0xA0..0xBF here are surrogates - continuation_byte!(); - } - 0xF0 => { - first_byte!(0b0000_0111); - continuation_byte!(0x90...0xBF); // 0x80..0x8F here are overlong - continuation_byte!(); - continuation_byte!(); - } - 0xF1...0xF3 => { - first_byte!(0b0000_0111); - continuation_byte!(); - continuation_byte!(); - continuation_byte!(); - } - 0xF4 => { - first_byte!(0b0000_0111); - continuation_byte!(0x80...0x8F); // 0x90..0xBF here are beyond char::MAX - continuation_byte!(); - continuation_byte!(); - } - _ => return Err(InvalidSequence(())) // Illegal first byte, overlong, or beyond MAX - } - unsafe { - Ok(from_u32_unchecked(code_point)) - } - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (lower, upper) = self.0.size_hint(); - - // A code point is at most 4 bytes long. - let min_code_points = lower / 4; - - (min_code_points, upper) - } -} - -#[unstable(feature = "decode_utf8", issue = "33906")] -impl> FusedIterator for DecodeUtf8 {} diff --git a/src/libcore/unicode/char.rs b/src/libcore/unicode/char.rs index e75338aedf1..fda1914a50f 100644 --- a/src/libcore/unicode/char.rs +++ b/src/libcore/unicode/char.rs @@ -1435,132 +1435,3 @@ impl char { self.is_ascii() && (*self as u8).is_ascii_control() } } - -/// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s. -#[stable(feature = "decode_utf16", since = "1.9.0")] -#[derive(Clone, Debug)] -pub struct DecodeUtf16 - where I: Iterator -{ - iter: I, - buf: Option, -} - -/// An error that can be returned when decoding UTF-16 code points. -#[stable(feature = "decode_utf16", since = "1.9.0")] -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct DecodeUtf16Error { - code: u16, -} - -/// Create an iterator over the UTF-16 encoded code points in `iter`, -/// returning unpaired surrogates as `Err`s. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char::decode_utf16; -/// -/// fn main() { -/// // 𝄞music -/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075, -/// 0x0073, 0xDD1E, 0x0069, 0x0063, -/// 0xD834]; -/// -/// assert_eq!(decode_utf16(v.iter().cloned()) -/// .map(|r| r.map_err(|e| e.unpaired_surrogate())) -/// .collect::>(), -/// vec![Ok('𝄞'), -/// Ok('m'), Ok('u'), Ok('s'), -/// Err(0xDD1E), -/// Ok('i'), Ok('c'), -/// Err(0xD834)]); -/// } -/// ``` -/// -/// A lossy decoder can be obtained by replacing `Err` results with the replacement character: -/// -/// ``` -/// use std::char::{decode_utf16, REPLACEMENT_CHARACTER}; -/// -/// fn main() { -/// // 𝄞music -/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075, -/// 0x0073, 0xDD1E, 0x0069, 0x0063, -/// 0xD834]; -/// -/// assert_eq!(decode_utf16(v.iter().cloned()) -/// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) -/// .collect::(), -/// "𝄞mus�ic�"); -/// } -/// ``` -#[stable(feature = "decode_utf16", since = "1.9.0")] -#[inline] -pub fn decode_utf16>(iter: I) -> DecodeUtf16 { - DecodeUtf16 { - iter: iter.into_iter(), - buf: None, - } -} - -#[stable(feature = "decode_utf16", since = "1.9.0")] -impl> Iterator for DecodeUtf16 { - type Item = Result; - - fn next(&mut self) -> Option> { - let u = match self.buf.take() { - Some(buf) => buf, - None => self.iter.next()? - }; - - if u < 0xD800 || 0xDFFF < u { - // not a surrogate - Some(Ok(unsafe { from_u32_unchecked(u as u32) })) - } else if u >= 0xDC00 { - // a trailing surrogate - Some(Err(DecodeUtf16Error { code: u })) - } else { - let u2 = match self.iter.next() { - Some(u2) => u2, - // eof - None => return Some(Err(DecodeUtf16Error { code: u })), - }; - if u2 < 0xDC00 || u2 > 0xDFFF { - // not a trailing surrogate so we're not a valid - // surrogate pair, so rewind to redecode u2 next time. - self.buf = Some(u2); - return Some(Err(DecodeUtf16Error { code: u })); - } - - // all ok, so lets decode it. - let c = (((u - 0xD800) as u32) << 10 | (u2 - 0xDC00) as u32) + 0x1_0000; - Some(Ok(unsafe { from_u32_unchecked(c) })) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (low, high) = self.iter.size_hint(); - // we could be entirely valid surrogates (2 elements per - // char), or entirely non-surrogates (1 element per char) - (low / 2, high) - } -} - -impl DecodeUtf16Error { - /// Returns the unpaired surrogate which caused this error. - #[stable(feature = "decode_utf16", since = "1.9.0")] - pub fn unpaired_surrogate(&self) -> u16 { - self.code - } -} - -#[stable(feature = "decode_utf16", since = "1.9.0")] -impl fmt::Display for DecodeUtf16Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "unpaired surrogate found: {:x}", self.code) - } -} -- cgit 1.4.1-3-g733a5 From 1800d695b9bd2c256f2d081da07a94e7a6cba832 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 5 Apr 2018 18:26:58 +0200 Subject: Move char conversions into a separate private module. --- src/libcore/char/convert.rs | 304 ++++++++++++++++++++++++++++++++++++++++++++ src/libcore/char/mod.rs | 301 ++----------------------------------------- 2 files changed, 315 insertions(+), 290 deletions(-) create mode 100644 src/libcore/char/convert.rs (limited to 'src/libcore') diff --git a/src/libcore/char/convert.rs b/src/libcore/char/convert.rs new file mode 100644 index 00000000000..150562a4a9b --- /dev/null +++ b/src/libcore/char/convert.rs @@ -0,0 +1,304 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Character conversions. + +use convert::TryFrom; +use fmt; +use mem::transmute; +use str::FromStr; +use super::MAX; + +/// Converts a `u32` to a `char`. +/// +/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with +/// [`as`]: +/// +/// ``` +/// let c = '💯'; +/// let i = c as u32; +/// +/// assert_eq!(128175, i); +/// ``` +/// +/// However, the reverse is not true: not all valid [`u32`]s are valid +/// [`char`]s. `from_u32()` will return `None` if the input is not a valid value +/// for a [`char`]. +/// +/// [`char`]: ../../std/primitive.char.html +/// [`u32`]: ../../std/primitive.u32.html +/// [`as`]: ../../book/first-edition/casting-between-types.html#as +/// +/// For an unsafe version of this function which ignores these checks, see +/// [`from_u32_unchecked`]. +/// +/// [`from_u32_unchecked`]: fn.from_u32_unchecked.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::char; +/// +/// let c = char::from_u32(0x2764); +/// +/// assert_eq!(Some('❤'), c); +/// ``` +/// +/// Returning `None` when the input is not a valid [`char`]: +/// +/// ``` +/// use std::char; +/// +/// let c = char::from_u32(0x110000); +/// +/// assert_eq!(None, c); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn from_u32(i: u32) -> Option { + char::try_from(i).ok() +} + +/// Converts a `u32` to a `char`, ignoring validity. +/// +/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with +/// [`as`]: +/// +/// ``` +/// let c = '💯'; +/// let i = c as u32; +/// +/// assert_eq!(128175, i); +/// ``` +/// +/// However, the reverse is not true: not all valid [`u32`]s are valid +/// [`char`]s. `from_u32_unchecked()` will ignore this, and blindly cast to +/// [`char`], possibly creating an invalid one. +/// +/// [`char`]: ../../std/primitive.char.html +/// [`u32`]: ../../std/primitive.u32.html +/// [`as`]: ../../book/first-edition/casting-between-types.html#as +/// +/// # Safety +/// +/// This function is unsafe, as it may construct invalid `char` values. +/// +/// For a safe version of this function, see the [`from_u32`] function. +/// +/// [`from_u32`]: fn.from_u32.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::char; +/// +/// let c = unsafe { char::from_u32_unchecked(0x2764) }; +/// +/// assert_eq!('❤', c); +/// ``` +#[inline] +#[stable(feature = "char_from_unchecked", since = "1.5.0")] +pub unsafe fn from_u32_unchecked(i: u32) -> char { + transmute(i) +} + +#[stable(feature = "char_convert", since = "1.13.0")] +impl From for u32 { + #[inline] + fn from(c: char) -> Self { + c as u32 + } +} + +/// Maps a byte in 0x00...0xFF to a `char` whose code point has the same value, in U+0000 to U+00FF. +/// +/// Unicode is designed such that this effectively decodes bytes +/// with the character encoding that IANA calls ISO-8859-1. +/// This encoding is compatible with ASCII. +/// +/// Note that this is different from ISO/IEC 8859-1 a.k.a. ISO 8859-1 (with one less hyphen), +/// which leaves some "blanks", byte values that are not assigned to any character. +/// ISO-8859-1 (the IANA one) assigns them to the C0 and C1 control codes. +/// +/// Note that this is *also* different from Windows-1252 a.k.a. code page 1252, +/// which is a superset ISO/IEC 8859-1 that assigns some (not all!) blanks +/// to punctuation and various Latin characters. +/// +/// To confuse things further, [on the Web](https://encoding.spec.whatwg.org/) +/// `ascii`, `iso-8859-1`, and `windows-1252` are all aliases +/// for a superset of Windows-1252 that fills the remaining blanks with corresponding +/// C0 and C1 control codes. +#[stable(feature = "char_convert", since = "1.13.0")] +impl From for char { + #[inline] + fn from(i: u8) -> Self { + i as char + } +} + + +/// An error which can be returned when parsing a char. +#[stable(feature = "char_from_str", since = "1.20.0")] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ParseCharError { + kind: CharErrorKind, +} + +impl ParseCharError { + #[unstable(feature = "char_error_internals", + reason = "this method should not be available publicly", + issue = "0")] + #[doc(hidden)] + pub fn __description(&self) -> &str { + match self.kind { + CharErrorKind::EmptyString => { + "cannot parse char from empty string" + }, + CharErrorKind::TooManyChars => "too many characters in string" + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum CharErrorKind { + EmptyString, + TooManyChars, +} + +#[stable(feature = "char_from_str", since = "1.20.0")] +impl fmt::Display for ParseCharError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.__description().fmt(f) + } +} + + +#[stable(feature = "char_from_str", since = "1.20.0")] +impl FromStr for char { + type Err = ParseCharError; + + #[inline] + fn from_str(s: &str) -> Result { + let mut chars = s.chars(); + match (chars.next(), chars.next()) { + (None, _) => { + Err(ParseCharError { kind: CharErrorKind::EmptyString }) + }, + (Some(c), None) => Ok(c), + _ => { + Err(ParseCharError { kind: CharErrorKind::TooManyChars }) + } + } + } +} + + +#[stable(feature = "try_from", since = "1.26.0")] +impl TryFrom for char { + type Error = CharTryFromError; + + #[inline] + fn try_from(i: u32) -> Result { + if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) { + Err(CharTryFromError(())) + } else { + Ok(unsafe { from_u32_unchecked(i) }) + } + } +} + +/// The error type returned when a conversion from u32 to char fails. +#[stable(feature = "try_from", since = "1.26.0")] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct CharTryFromError(()); + +#[stable(feature = "try_from", since = "1.26.0")] +impl fmt::Display for CharTryFromError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "converted integer out of range for `char`".fmt(f) + } +} + +/// Converts a digit in the given radix to a `char`. +/// +/// A 'radix' here is sometimes also called a 'base'. A radix of two +/// indicates a binary number, a radix of ten, decimal, and a radix of +/// sixteen, hexadecimal, to give some common values. Arbitrary +/// radices are supported. +/// +/// `from_digit()` will return `None` if the input is not a digit in +/// the given radix. +/// +/// # Panics +/// +/// Panics if given a radix larger than 36. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::char; +/// +/// let c = char::from_digit(4, 10); +/// +/// assert_eq!(Some('4'), c); +/// +/// // Decimal 11 is a single digit in base 16 +/// let c = char::from_digit(11, 16); +/// +/// assert_eq!(Some('b'), c); +/// ``` +/// +/// Returning `None` when the input is not a digit: +/// +/// ``` +/// use std::char; +/// +/// let c = char::from_digit(20, 10); +/// +/// assert_eq!(None, c); +/// ``` +/// +/// Passing a large radix, causing a panic: +/// +/// ``` +/// use std::thread; +/// use std::char; +/// +/// let result = thread::spawn(|| { +/// // this panics +/// let c = char::from_digit(1, 37); +/// }).join(); +/// +/// assert!(result.is_err()); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn from_digit(num: u32, radix: u32) -> Option { + if radix > 36 { + panic!("from_digit: radix is too high (maximum 36)"); + } + if num < radix { + let num = num as u8; + if num < 10 { + Some((b'0' + num) as char) + } else { + Some((b'a' + num - 10) as char) + } + } else { + None + } +} + diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index 388bc47750d..01a7b49ac74 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -15,11 +15,20 @@ #![allow(non_snake_case)] #![stable(feature = "core_char", since = "1.2.0")] -mod printable; +mod convert; mod decode; +mod printable; // stable re-exports #[stable(feature = "rust1", since = "1.0.0")] +pub use self::convert::{from_u32, from_digit}; +#[stable(feature = "char_from_unchecked", since = "1.5.0")] +pub use self::convert::from_u32_unchecked; +#[stable(feature = "char_from_str", since = "1.20.0")] +pub use self::convert::ParseCharError; +#[stable(feature = "try_from", since = "1.26.0")] +pub use self::convert::CharTryFromError; +#[stable(feature = "rust1", since = "1.0.0")] pub use unicode::char::{ToLowercase, ToUppercase}; #[stable(feature = "decode_utf16", since = "1.9.0")] pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error}; @@ -33,12 +42,10 @@ pub use unicode::version::UnicodeVersion; pub use self::decode::{decode_utf8, DecodeUtf8, InvalidSequence}; use self::printable::is_printable; -use convert::TryFrom; use fmt::{self, Write}; use slice; -use str::{from_utf8_unchecked_mut, FromStr}; +use str::from_utf8_unchecked_mut; use iter::FusedIterator; -use mem::transmute; // UTF-8 ranges and tags for encoding characters const TAG_CONT: u8 = 0b1000_0000; @@ -102,292 +109,6 @@ pub const MAX: char = '\u{10ffff}'; #[stable(feature = "decode_utf16", since = "1.9.0")] pub const REPLACEMENT_CHARACTER: char = '\u{FFFD}'; -/// Converts a `u32` to a `char`. -/// -/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with -/// [`as`]: -/// -/// ``` -/// let c = '💯'; -/// let i = c as u32; -/// -/// assert_eq!(128175, i); -/// ``` -/// -/// However, the reverse is not true: not all valid [`u32`]s are valid -/// [`char`]s. `from_u32()` will return `None` if the input is not a valid value -/// for a [`char`]. -/// -/// [`char`]: ../../std/primitive.char.html -/// [`u32`]: ../../std/primitive.u32.html -/// [`as`]: ../../book/first-edition/casting-between-types.html#as -/// -/// For an unsafe version of this function which ignores these checks, see -/// [`from_u32_unchecked`]. -/// -/// [`from_u32_unchecked`]: fn.from_u32_unchecked.html -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_u32(0x2764); -/// -/// assert_eq!(Some('❤'), c); -/// ``` -/// -/// Returning `None` when the input is not a valid [`char`]: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_u32(0x110000); -/// -/// assert_eq!(None, c); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn from_u32(i: u32) -> Option { - char::try_from(i).ok() -} - -/// Converts a `u32` to a `char`, ignoring validity. -/// -/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with -/// [`as`]: -/// -/// ``` -/// let c = '💯'; -/// let i = c as u32; -/// -/// assert_eq!(128175, i); -/// ``` -/// -/// However, the reverse is not true: not all valid [`u32`]s are valid -/// [`char`]s. `from_u32_unchecked()` will ignore this, and blindly cast to -/// [`char`], possibly creating an invalid one. -/// -/// [`char`]: ../../std/primitive.char.html -/// [`u32`]: ../../std/primitive.u32.html -/// [`as`]: ../../book/first-edition/casting-between-types.html#as -/// -/// # Safety -/// -/// This function is unsafe, as it may construct invalid `char` values. -/// -/// For a safe version of this function, see the [`from_u32`] function. -/// -/// [`from_u32`]: fn.from_u32.html -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char; -/// -/// let c = unsafe { char::from_u32_unchecked(0x2764) }; -/// -/// assert_eq!('❤', c); -/// ``` -#[inline] -#[stable(feature = "char_from_unchecked", since = "1.5.0")] -pub unsafe fn from_u32_unchecked(i: u32) -> char { - transmute(i) -} - -#[stable(feature = "char_convert", since = "1.13.0")] -impl From for u32 { - #[inline] - fn from(c: char) -> Self { - c as u32 - } -} - -/// Maps a byte in 0x00...0xFF to a `char` whose code point has the same value, in U+0000 to U+00FF. -/// -/// Unicode is designed such that this effectively decodes bytes -/// with the character encoding that IANA calls ISO-8859-1. -/// This encoding is compatible with ASCII. -/// -/// Note that this is different from ISO/IEC 8859-1 a.k.a. ISO 8859-1 (with one less hyphen), -/// which leaves some "blanks", byte values that are not assigned to any character. -/// ISO-8859-1 (the IANA one) assigns them to the C0 and C1 control codes. -/// -/// Note that this is *also* different from Windows-1252 a.k.a. code page 1252, -/// which is a superset ISO/IEC 8859-1 that assigns some (not all!) blanks -/// to punctuation and various Latin characters. -/// -/// To confuse things further, [on the Web](https://encoding.spec.whatwg.org/) -/// `ascii`, `iso-8859-1`, and `windows-1252` are all aliases -/// for a superset of Windows-1252 that fills the remaining blanks with corresponding -/// C0 and C1 control codes. -#[stable(feature = "char_convert", since = "1.13.0")] -impl From for char { - #[inline] - fn from(i: u8) -> Self { - i as char - } -} - - -/// An error which can be returned when parsing a char. -#[stable(feature = "char_from_str", since = "1.20.0")] -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ParseCharError { - kind: CharErrorKind, -} - -impl ParseCharError { - #[unstable(feature = "char_error_internals", - reason = "this method should not be available publicly", - issue = "0")] - #[doc(hidden)] - pub fn __description(&self) -> &str { - match self.kind { - CharErrorKind::EmptyString => { - "cannot parse char from empty string" - }, - CharErrorKind::TooManyChars => "too many characters in string" - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -enum CharErrorKind { - EmptyString, - TooManyChars, -} - -#[stable(feature = "char_from_str", since = "1.20.0")] -impl fmt::Display for ParseCharError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.__description().fmt(f) - } -} - - -#[stable(feature = "char_from_str", since = "1.20.0")] -impl FromStr for char { - type Err = ParseCharError; - - #[inline] - fn from_str(s: &str) -> Result { - let mut chars = s.chars(); - match (chars.next(), chars.next()) { - (None, _) => { - Err(ParseCharError { kind: CharErrorKind::EmptyString }) - }, - (Some(c), None) => Ok(c), - _ => { - Err(ParseCharError { kind: CharErrorKind::TooManyChars }) - } - } - } -} - - -#[stable(feature = "try_from", since = "1.26.0")] -impl TryFrom for char { - type Error = CharTryFromError; - - #[inline] - fn try_from(i: u32) -> Result { - if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) { - Err(CharTryFromError(())) - } else { - Ok(unsafe { from_u32_unchecked(i) }) - } - } -} - -/// The error type returned when a conversion from u32 to char fails. -#[stable(feature = "try_from", since = "1.26.0")] -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct CharTryFromError(()); - -#[stable(feature = "try_from", since = "1.26.0")] -impl fmt::Display for CharTryFromError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "converted integer out of range for `char`".fmt(f) - } -} - -/// Converts a digit in the given radix to a `char`. -/// -/// A 'radix' here is sometimes also called a 'base'. A radix of two -/// indicates a binary number, a radix of ten, decimal, and a radix of -/// sixteen, hexadecimal, to give some common values. Arbitrary -/// radices are supported. -/// -/// `from_digit()` will return `None` if the input is not a digit in -/// the given radix. -/// -/// # Panics -/// -/// Panics if given a radix larger than 36. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_digit(4, 10); -/// -/// assert_eq!(Some('4'), c); -/// -/// // Decimal 11 is a single digit in base 16 -/// let c = char::from_digit(11, 16); -/// -/// assert_eq!(Some('b'), c); -/// ``` -/// -/// Returning `None` when the input is not a digit: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_digit(20, 10); -/// -/// assert_eq!(None, c); -/// ``` -/// -/// Passing a large radix, causing a panic: -/// -/// ``` -/// use std::thread; -/// use std::char; -/// -/// let result = thread::spawn(|| { -/// // this panics -/// let c = char::from_digit(1, 37); -/// }).join(); -/// -/// assert!(result.is_err()); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn from_digit(num: u32, radix: u32) -> Option { - if radix > 36 { - panic!("from_digit: radix is too high (maximum 36)"); - } - if num < radix { - let num = num as u8; - if num < 10 { - Some((b'0' + num) as char) - } else { - Some((b'a' + num - 10) as char) - } - } else { - None - } -} - // NB: the stabilization and documentation for this trait is in // unicode/char.rs, not here #[allow(missing_docs)] // docs in libunicode/u_char.rs -- cgit 1.4.1-3-g733a5 From 34c52534f72f035b898efe3b86028741576f1499 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 5 Apr 2018 18:36:02 +0200 Subject: Move the rest of core::unicode::char to core::unicode --- src/libcore/char/methods.rs | 1442 +++++++++++++++++++++++++++++++++++++++++++ src/libcore/char/mod.rs | 288 +++++---- src/libcore/unicode/char.rs | 1437 ------------------------------------------ src/libcore/unicode/mod.rs | 1 - 4 files changed, 1580 insertions(+), 1588 deletions(-) create mode 100644 src/libcore/char/methods.rs delete mode 100644 src/libcore/unicode/char.rs (limited to 'src/libcore') diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs new file mode 100644 index 00000000000..0958c67ea05 --- /dev/null +++ b/src/libcore/char/methods.rs @@ -0,0 +1,1442 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! impl char {} + +use slice; +use str::from_utf8_unchecked_mut; +use super::*; +use super::CharExt as C; +use super::printable::is_printable; +use unicode::tables::{conversions, derived_property, general_category, property}; + +#[stable(feature = "core", since = "1.6.0")] +impl CharExt for char { + #[inline] + fn is_digit(self, radix: u32) -> bool { + self.to_digit(radix).is_some() + } + + #[inline] + fn to_digit(self, radix: u32) -> Option { + if radix > 36 { + panic!("to_digit: radix is too high (maximum 36)"); + } + let val = match self { + '0' ... '9' => self as u32 - '0' as u32, + 'a' ... 'z' => self as u32 - 'a' as u32 + 10, + 'A' ... 'Z' => self as u32 - 'A' as u32 + 10, + _ => return None, + }; + if val < radix { Some(val) } + else { None } + } + + #[inline] + fn escape_unicode(self) -> EscapeUnicode { + let c = self as u32; + + // or-ing 1 ensures that for c==0 the code computes that one + // digit should be printed and (which is the same) avoids the + // (31 - 32) underflow + let msb = 31 - (c | 1).leading_zeros(); + + // the index of the most significant hex digit + let ms_hex_digit = msb / 4; + EscapeUnicode { + c: self, + state: EscapeUnicodeState::Backslash, + hex_digit_idx: ms_hex_digit as usize, + } + } + + #[inline] + fn escape_default(self) -> EscapeDefault { + let init_state = match self { + '\t' => EscapeDefaultState::Backslash('t'), + '\r' => EscapeDefaultState::Backslash('r'), + '\n' => EscapeDefaultState::Backslash('n'), + '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), + '\x20' ... '\x7e' => EscapeDefaultState::Char(self), + _ => EscapeDefaultState::Unicode(self.escape_unicode()) + }; + EscapeDefault { state: init_state } + } + + #[inline] + fn escape_debug(self) -> EscapeDebug { + let init_state = match self { + '\t' => EscapeDefaultState::Backslash('t'), + '\r' => EscapeDefaultState::Backslash('r'), + '\n' => EscapeDefaultState::Backslash('n'), + '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), + c if is_printable(c) => EscapeDefaultState::Char(c), + c => EscapeDefaultState::Unicode(c.escape_unicode()), + }; + EscapeDebug(EscapeDefault { state: init_state }) + } + + #[inline] + fn len_utf8(self) -> usize { + let code = self as u32; + if code < MAX_ONE_B { + 1 + } else if code < MAX_TWO_B { + 2 + } else if code < MAX_THREE_B { + 3 + } else { + 4 + } + } + + #[inline] + fn len_utf16(self) -> usize { + let ch = self as u32; + if (ch & 0xFFFF) == ch { 1 } else { 2 } + } + + #[inline] + fn encode_utf8(self, dst: &mut [u8]) -> &mut str { + let code = self as u32; + unsafe { + let len = + if code < MAX_ONE_B && !dst.is_empty() { + *dst.get_unchecked_mut(0) = code as u8; + 1 + } else if code < MAX_TWO_B && dst.len() >= 2 { + *dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; + *dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT; + 2 + } else if code < MAX_THREE_B && dst.len() >= 3 { + *dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; + *dst.get_unchecked_mut(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT; + 3 + } else if dst.len() >= 4 { + *dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; + *dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT; + *dst.get_unchecked_mut(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT; + 4 + } else { + panic!("encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", + from_u32_unchecked(code).len_utf8(), + code, + dst.len()) + }; + from_utf8_unchecked_mut(dst.get_unchecked_mut(..len)) + } + } + + #[inline] + fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { + let mut code = self as u32; + unsafe { + if (code & 0xFFFF) == code && !dst.is_empty() { + // The BMP falls through (assuming non-surrogate, as it should) + *dst.get_unchecked_mut(0) = code as u16; + slice::from_raw_parts_mut(dst.as_mut_ptr(), 1) + } else if dst.len() >= 2 { + // Supplementary planes break into surrogates. + code -= 0x1_0000; + *dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16); + *dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF); + slice::from_raw_parts_mut(dst.as_mut_ptr(), 2) + } else { + panic!("encode_utf16: need {} units to encode U+{:X}, but the buffer has {}", + from_u32_unchecked(code).len_utf16(), + code, + dst.len()) + } + } + } +} + +#[lang = "char"] +impl char { + /// Checks if a `char` is a digit in the given radix. + /// + /// A 'radix' here is sometimes also called a 'base'. A radix of two + /// indicates a binary number, a radix of ten, decimal, and a radix of + /// sixteen, hexadecimal, to give some common values. Arbitrary + /// radices are supported. + /// + /// Compared to `is_numeric()`, this function only recognizes the characters + /// `0-9`, `a-z` and `A-Z`. + /// + /// 'Digit' is defined to be only the following characters: + /// + /// * `0-9` + /// * `a-z` + /// * `A-Z` + /// + /// For a more comprehensive understanding of 'digit', see [`is_numeric`][is_numeric]. + /// + /// [is_numeric]: #method.is_numeric + /// + /// # Panics + /// + /// Panics if given a radix larger than 36. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert!('1'.is_digit(10)); + /// assert!('f'.is_digit(16)); + /// assert!(!'f'.is_digit(10)); + /// ``` + /// + /// Passing a large radix, causing a panic: + /// + /// ``` + /// use std::thread; + /// + /// let result = thread::spawn(|| { + /// // this panics + /// '1'.is_digit(37); + /// }).join(); + /// + /// assert!(result.is_err()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_digit(self, radix: u32) -> bool { + C::is_digit(self, radix) + } + + /// Converts a `char` to a digit in the given radix. + /// + /// A 'radix' here is sometimes also called a 'base'. A radix of two + /// indicates a binary number, a radix of ten, decimal, and a radix of + /// sixteen, hexadecimal, to give some common values. Arbitrary + /// radices are supported. + /// + /// 'Digit' is defined to be only the following characters: + /// + /// * `0-9` + /// * `a-z` + /// * `A-Z` + /// + /// # Errors + /// + /// Returns `None` if the `char` does not refer to a digit in the given radix. + /// + /// # Panics + /// + /// Panics if given a radix larger than 36. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert_eq!('1'.to_digit(10), Some(1)); + /// assert_eq!('f'.to_digit(16), Some(15)); + /// ``` + /// + /// Passing a non-digit results in failure: + /// + /// ``` + /// assert_eq!('f'.to_digit(10), None); + /// assert_eq!('z'.to_digit(16), None); + /// ``` + /// + /// Passing a large radix, causing a panic: + /// + /// ``` + /// use std::thread; + /// + /// let result = thread::spawn(|| { + /// '1'.to_digit(37); + /// }).join(); + /// + /// assert!(result.is_err()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_digit(self, radix: u32) -> Option { + C::to_digit(self, radix) + } + + /// Returns an iterator that yields the hexadecimal Unicode escape of a + /// character as `char`s. + /// + /// This will escape characters with the Rust syntax of the form + /// `\u{NNNNNN}` where `NNNNNN` is a hexadecimal representation. + /// + /// # Examples + /// + /// As an iterator: + /// + /// ``` + /// for c in '❤'.escape_unicode() { + /// print!("{}", c); + /// } + /// println!(); + /// ``` + /// + /// Using `println!` directly: + /// + /// ``` + /// println!("{}", '❤'.escape_unicode()); + /// ``` + /// + /// Both are equivalent to: + /// + /// ``` + /// println!("\\u{{2764}}"); + /// ``` + /// + /// Using `to_string`: + /// + /// ``` + /// assert_eq!('❤'.escape_unicode().to_string(), "\\u{2764}"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn escape_unicode(self) -> EscapeUnicode { + C::escape_unicode(self) + } + + /// Returns an iterator that yields the literal escape code of a character + /// as `char`s. + /// + /// This will escape the characters similar to the `Debug` implementations + /// of `str` or `char`. + /// + /// # Examples + /// + /// As an iterator: + /// + /// ``` + /// for c in '\n'.escape_debug() { + /// print!("{}", c); + /// } + /// println!(); + /// ``` + /// + /// Using `println!` directly: + /// + /// ``` + /// println!("{}", '\n'.escape_debug()); + /// ``` + /// + /// Both are equivalent to: + /// + /// ``` + /// println!("\\n"); + /// ``` + /// + /// Using `to_string`: + /// + /// ``` + /// assert_eq!('\n'.escape_debug().to_string(), "\\n"); + /// ``` + #[stable(feature = "char_escape_debug", since = "1.20.0")] + #[inline] + pub fn escape_debug(self) -> EscapeDebug { + C::escape_debug(self) + } + + /// Returns an iterator that yields the literal escape code of a character + /// as `char`s. + /// + /// The default is chosen with a bias toward producing literals that are + /// legal in a variety of languages, including C++11 and similar C-family + /// languages. The exact rules are: + /// + /// * Tab is escaped as `\t`. + /// * Carriage return is escaped as `\r`. + /// * Line feed is escaped as `\n`. + /// * Single quote is escaped as `\'`. + /// * Double quote is escaped as `\"`. + /// * Backslash is escaped as `\\`. + /// * Any character in the 'printable ASCII' range `0x20` .. `0x7e` + /// inclusive is not escaped. + /// * All other characters are given hexadecimal Unicode escapes; see + /// [`escape_unicode`][escape_unicode]. + /// + /// [escape_unicode]: #method.escape_unicode + /// + /// # Examples + /// + /// As an iterator: + /// + /// ``` + /// for c in '"'.escape_default() { + /// print!("{}", c); + /// } + /// println!(); + /// ``` + /// + /// Using `println!` directly: + /// + /// ``` + /// println!("{}", '"'.escape_default()); + /// ``` + /// + /// + /// Both are equivalent to: + /// + /// ``` + /// println!("\\\""); + /// ``` + /// + /// Using `to_string`: + /// + /// ``` + /// assert_eq!('"'.escape_default().to_string(), "\\\""); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn escape_default(self) -> EscapeDefault { + C::escape_default(self) + } + + /// Returns the number of bytes this `char` would need if encoded in UTF-8. + /// + /// That number of bytes is always between 1 and 4, inclusive. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let len = 'A'.len_utf8(); + /// assert_eq!(len, 1); + /// + /// let len = 'ß'.len_utf8(); + /// assert_eq!(len, 2); + /// + /// let len = 'ℝ'.len_utf8(); + /// assert_eq!(len, 3); + /// + /// let len = '💣'.len_utf8(); + /// assert_eq!(len, 4); + /// ``` + /// + /// The `&str` type guarantees that its contents are UTF-8, and so we can compare the length it + /// would take if each code point was represented as a `char` vs in the `&str` itself: + /// + /// ``` + /// // as chars + /// let eastern = '東'; + /// let capitol = '京'; + /// + /// // both can be represented as three bytes + /// assert_eq!(3, eastern.len_utf8()); + /// assert_eq!(3, capitol.len_utf8()); + /// + /// // as a &str, these two are encoded in UTF-8 + /// let tokyo = "東京"; + /// + /// let len = eastern.len_utf8() + capitol.len_utf8(); + /// + /// // we can see that they take six bytes total... + /// assert_eq!(6, tokyo.len()); + /// + /// // ... just like the &str + /// assert_eq!(len, tokyo.len()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn len_utf8(self) -> usize { + C::len_utf8(self) + } + + /// Returns the number of 16-bit code units this `char` would need if + /// encoded in UTF-16. + /// + /// See the documentation for [`len_utf8`] for more explanation of this + /// concept. This function is a mirror, but for UTF-16 instead of UTF-8. + /// + /// [`len_utf8`]: #method.len_utf8 + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let n = 'ß'.len_utf16(); + /// assert_eq!(n, 1); + /// + /// let len = '💣'.len_utf16(); + /// assert_eq!(len, 2); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn len_utf16(self) -> usize { + C::len_utf16(self) + } + + /// Encodes this character as UTF-8 into the provided byte buffer, + /// and then returns the subslice of the buffer that contains the encoded character. + /// + /// # Panics + /// + /// Panics if the buffer is not large enough. + /// A buffer of length four is large enough to encode any `char`. + /// + /// # Examples + /// + /// In both of these examples, 'ß' takes two bytes to encode. + /// + /// ``` + /// let mut b = [0; 2]; + /// + /// let result = 'ß'.encode_utf8(&mut b); + /// + /// assert_eq!(result, "ß"); + /// + /// assert_eq!(result.len(), 2); + /// ``` + /// + /// A buffer that's too small: + /// + /// ``` + /// use std::thread; + /// + /// let result = thread::spawn(|| { + /// let mut b = [0; 1]; + /// + /// // this panics + /// 'ß'.encode_utf8(&mut b); + /// }).join(); + /// + /// assert!(result.is_err()); + /// ``` + #[stable(feature = "unicode_encode_char", since = "1.15.0")] + #[inline] + pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str { + C::encode_utf8(self, dst) + } + + /// Encodes this character as UTF-16 into the provided `u16` buffer, + /// and then returns the subslice of the buffer that contains the encoded character. + /// + /// # Panics + /// + /// Panics if the buffer is not large enough. + /// A buffer of length 2 is large enough to encode any `char`. + /// + /// # Examples + /// + /// In both of these examples, '𝕊' takes two `u16`s to encode. + /// + /// ``` + /// let mut b = [0; 2]; + /// + /// let result = '𝕊'.encode_utf16(&mut b); + /// + /// assert_eq!(result.len(), 2); + /// ``` + /// + /// A buffer that's too small: + /// + /// ``` + /// use std::thread; + /// + /// let result = thread::spawn(|| { + /// let mut b = [0; 1]; + /// + /// // this panics + /// '𝕊'.encode_utf16(&mut b); + /// }).join(); + /// + /// assert!(result.is_err()); + /// ``` + #[stable(feature = "unicode_encode_char", since = "1.15.0")] + #[inline] + pub fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { + C::encode_utf16(self, dst) + } + + /// Returns true if this `char` is an alphabetic code point, and false if not. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert!('a'.is_alphabetic()); + /// assert!('京'.is_alphabetic()); + /// + /// let c = '💝'; + /// // love is many things, but it is not alphabetic + /// assert!(!c.is_alphabetic()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_alphabetic(self) -> bool { + match self { + 'a'...'z' | 'A'...'Z' => true, + c if c > '\x7f' => derived_property::Alphabetic(c), + _ => false, + } + } + + /// Returns true if this `char` satisfies the 'XID_Start' Unicode property, and false + /// otherwise. + /// + /// 'XID_Start' is a Unicode Derived Property specified in + /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), + /// mostly similar to `ID_Start` but modified for closure under `NFKx`. + #[unstable(feature = "rustc_private", + reason = "mainly needed for compiler internals", + issue = "27812")] + #[inline] + pub fn is_xid_start(self) -> bool { + derived_property::XID_Start(self) + } + + /// Returns true if this `char` satisfies the 'XID_Continue' Unicode property, and false + /// otherwise. + /// + /// 'XID_Continue' is a Unicode Derived Property specified in + /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), + /// mostly similar to 'ID_Continue' but modified for closure under NFKx. + #[unstable(feature = "rustc_private", + reason = "mainly needed for compiler internals", + issue = "27812")] + #[inline] + pub fn is_xid_continue(self) -> bool { + derived_property::XID_Continue(self) + } + + /// Returns true if this `char` is lowercase, and false otherwise. + /// + /// 'Lowercase' is defined according to the terms of the Unicode Derived Core + /// Property `Lowercase`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert!('a'.is_lowercase()); + /// assert!('δ'.is_lowercase()); + /// assert!(!'A'.is_lowercase()); + /// assert!(!'Δ'.is_lowercase()); + /// + /// // The various Chinese scripts do not have case, and so: + /// assert!(!'中'.is_lowercase()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_lowercase(self) -> bool { + match self { + 'a'...'z' => true, + c if c > '\x7f' => derived_property::Lowercase(c), + _ => false, + } + } + + /// Returns true if this `char` is uppercase, and false otherwise. + /// + /// 'Uppercase' is defined according to the terms of the Unicode Derived Core + /// Property `Uppercase`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert!(!'a'.is_uppercase()); + /// assert!(!'δ'.is_uppercase()); + /// assert!('A'.is_uppercase()); + /// assert!('Δ'.is_uppercase()); + /// + /// // The various Chinese scripts do not have case, and so: + /// assert!(!'中'.is_uppercase()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_uppercase(self) -> bool { + match self { + 'A'...'Z' => true, + c if c > '\x7f' => derived_property::Uppercase(c), + _ => false, + } + } + + /// Returns true if this `char` is whitespace, and false otherwise. + /// + /// 'Whitespace' is defined according to the terms of the Unicode Derived Core + /// Property `White_Space`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert!(' '.is_whitespace()); + /// + /// // a non-breaking space + /// assert!('\u{A0}'.is_whitespace()); + /// + /// assert!(!'越'.is_whitespace()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_whitespace(self) -> bool { + match self { + ' ' | '\x09'...'\x0d' => true, + c if c > '\x7f' => property::White_Space(c), + _ => false, + } + } + + /// Returns true if this `char` is alphanumeric, and false otherwise. + /// + /// 'Alphanumeric'-ness is defined in terms of the Unicode General Categories + /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert!('٣'.is_alphanumeric()); + /// assert!('7'.is_alphanumeric()); + /// assert!('৬'.is_alphanumeric()); + /// assert!('K'.is_alphanumeric()); + /// assert!('و'.is_alphanumeric()); + /// assert!('藏'.is_alphanumeric()); + /// assert!(!'¾'.is_alphanumeric()); + /// assert!(!'①'.is_alphanumeric()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_alphanumeric(self) -> bool { + self.is_alphabetic() || self.is_numeric() + } + + /// Returns true if this `char` is a control code point, and false otherwise. + /// + /// 'Control code point' is defined in terms of the Unicode General + /// Category `Cc`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // U+009C, STRING TERMINATOR + /// assert!('œ'.is_control()); + /// assert!(!'q'.is_control()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_control(self) -> bool { + general_category::Cc(self) + } + + /// Returns true if this `char` is numeric, and false otherwise. + /// + /// 'Numeric'-ness is defined in terms of the Unicode General Categories + /// 'Nd', 'Nl', 'No'. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert!('٣'.is_numeric()); + /// assert!('7'.is_numeric()); + /// assert!('৬'.is_numeric()); + /// assert!(!'K'.is_numeric()); + /// assert!(!'و'.is_numeric()); + /// assert!(!'藏'.is_numeric()); + /// assert!(!'¾'.is_numeric()); + /// assert!(!'①'.is_numeric()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_numeric(self) -> bool { + match self { + '0'...'9' => true, + c if c > '\x7f' => general_category::N(c), + _ => false, + } + } + + /// Returns an iterator that yields the lowercase equivalent of a `char` + /// as one or more `char`s. + /// + /// If a character does not have a lowercase equivalent, the same character + /// will be returned back by the iterator. + /// + /// This performs complex unconditional mappings with no tailoring: it maps + /// one Unicode character to its lowercase equivalent according to the + /// [Unicode database] and the additional complex mappings + /// [`SpecialCasing.txt`]. Conditional mappings (based on context or + /// language) are not considered here. + /// + /// For a full reference, see [here][reference]. + /// + /// [Unicode database]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt + /// + /// [`SpecialCasing.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt + /// + /// [reference]: http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 + /// + /// # Examples + /// + /// As an iterator: + /// + /// ``` + /// for c in 'İ'.to_lowercase() { + /// print!("{}", c); + /// } + /// println!(); + /// ``` + /// + /// Using `println!` directly: + /// + /// ``` + /// println!("{}", 'İ'.to_lowercase()); + /// ``` + /// + /// Both are equivalent to: + /// + /// ``` + /// println!("i\u{307}"); + /// ``` + /// + /// Using `to_string`: + /// + /// ``` + /// assert_eq!('C'.to_lowercase().to_string(), "c"); + /// + /// // Sometimes the result is more than one character: + /// assert_eq!('İ'.to_lowercase().to_string(), "i\u{307}"); + /// + /// // Characters that do not have both uppercase and lowercase + /// // convert into themselves. + /// assert_eq!('山'.to_lowercase().to_string(), "山"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_lowercase(self) -> ToLowercase { + ToLowercase(CaseMappingIter::new(conversions::to_lower(self))) + } + + /// Returns an iterator that yields the uppercase equivalent of a `char` + /// as one or more `char`s. + /// + /// If a character does not have an uppercase equivalent, the same character + /// will be returned back by the iterator. + /// + /// This performs complex unconditional mappings with no tailoring: it maps + /// one Unicode character to its uppercase equivalent according to the + /// [Unicode database] and the additional complex mappings + /// [`SpecialCasing.txt`]. Conditional mappings (based on context or + /// language) are not considered here. + /// + /// For a full reference, see [here][reference]. + /// + /// [Unicode database]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt + /// + /// [`SpecialCasing.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt + /// + /// [reference]: http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 + /// + /// # Examples + /// + /// As an iterator: + /// + /// ``` + /// for c in 'ß'.to_uppercase() { + /// print!("{}", c); + /// } + /// println!(); + /// ``` + /// + /// Using `println!` directly: + /// + /// ``` + /// println!("{}", 'ß'.to_uppercase()); + /// ``` + /// + /// Both are equivalent to: + /// + /// ``` + /// println!("SS"); + /// ``` + /// + /// Using `to_string`: + /// + /// ``` + /// assert_eq!('c'.to_uppercase().to_string(), "C"); + /// + /// // Sometimes the result is more than one character: + /// assert_eq!('ß'.to_uppercase().to_string(), "SS"); + /// + /// // Characters that do not have both uppercase and lowercase + /// // convert into themselves. + /// assert_eq!('山'.to_uppercase().to_string(), "山"); + /// ``` + /// + /// # Note on locale + /// + /// In Turkish, the equivalent of 'i' in Latin has five forms instead of two: + /// + /// * 'Dotless': I / ı, sometimes written ï + /// * 'Dotted': İ / i + /// + /// Note that the lowercase dotted 'i' is the same as the Latin. Therefore: + /// + /// ``` + /// let upper_i = 'i'.to_uppercase().to_string(); + /// ``` + /// + /// The value of `upper_i` here relies on the language of the text: if we're + /// in `en-US`, it should be `"I"`, but if we're in `tr_TR`, it should + /// be `"İ"`. `to_uppercase()` does not take this into account, and so: + /// + /// ``` + /// let upper_i = 'i'.to_uppercase().to_string(); + /// + /// assert_eq!(upper_i, "I"); + /// ``` + /// + /// holds across languages. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_uppercase(self) -> ToUppercase { + ToUppercase(CaseMappingIter::new(conversions::to_upper(self))) + } + + /// Checks if the value is within the ASCII range. + /// + /// # Examples + /// + /// ``` + /// let ascii = 'a'; + /// let non_ascii = '❤'; + /// + /// assert!(ascii.is_ascii()); + /// assert!(!non_ascii.is_ascii()); + /// ``` + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn is_ascii(&self) -> bool { + *self as u32 <= 0x7F + } + + /// Makes a copy of the value in its ASCII upper case equivalent. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To uppercase the value in-place, use [`make_ascii_uppercase`]. + /// + /// To uppercase ASCII characters in addition to non-ASCII characters, use + /// [`to_uppercase`]. + /// + /// # Examples + /// + /// ``` + /// let ascii = 'a'; + /// let non_ascii = '❤'; + /// + /// assert_eq!('A', ascii.to_ascii_uppercase()); + /// assert_eq!('❤', non_ascii.to_ascii_uppercase()); + /// ``` + /// + /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase + /// [`to_uppercase`]: #method.to_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn to_ascii_uppercase(&self) -> char { + if self.is_ascii() { + (*self as u8).to_ascii_uppercase() as char + } else { + *self + } + } + + /// Makes a copy of the value in its ASCII lower case equivalent. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To lowercase the value in-place, use [`make_ascii_lowercase`]. + /// + /// To lowercase ASCII characters in addition to non-ASCII characters, use + /// [`to_lowercase`]. + /// + /// # Examples + /// + /// ``` + /// let ascii = 'A'; + /// let non_ascii = '❤'; + /// + /// assert_eq!('a', ascii.to_ascii_lowercase()); + /// assert_eq!('❤', non_ascii.to_ascii_lowercase()); + /// ``` + /// + /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase + /// [`to_lowercase`]: #method.to_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn to_ascii_lowercase(&self) -> char { + if self.is_ascii() { + (*self as u8).to_ascii_lowercase() as char + } else { + *self + } + } + + /// Checks that two values are an ASCII case-insensitive match. + /// + /// Equivalent to `to_ascii_lowercase(a) == to_ascii_lowercase(b)`. + /// + /// # Examples + /// + /// ``` + /// let upper_a = 'A'; + /// let lower_a = 'a'; + /// let lower_z = 'z'; + /// + /// assert!(upper_a.eq_ignore_ascii_case(&lower_a)); + /// assert!(upper_a.eq_ignore_ascii_case(&upper_a)); + /// assert!(!upper_a.eq_ignore_ascii_case(&lower_z)); + /// ``` + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn eq_ignore_ascii_case(&self, other: &char) -> bool { + self.to_ascii_lowercase() == other.to_ascii_lowercase() + } + + /// Converts this type to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`to_ascii_uppercase`]. + /// + /// # Examples + /// + /// ``` + /// let mut ascii = 'a'; + /// + /// ascii.make_ascii_uppercase(); + /// + /// assert_eq!('A', ascii); + /// ``` + /// + /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn make_ascii_uppercase(&mut self) { + *self = self.to_ascii_uppercase(); + } + + /// Converts this type to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`to_ascii_lowercase`]. + /// + /// # Examples + /// + /// ``` + /// let mut ascii = 'A'; + /// + /// ascii.make_ascii_lowercase(); + /// + /// assert_eq!('a', ascii); + /// ``` + /// + /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn make_ascii_lowercase(&mut self) { + *self = self.to_ascii_lowercase(); + } + + /// Checks if the value is an ASCII alphabetic character: + /// + /// - U+0041 'A' ... U+005A 'Z', or + /// - U+0061 'a' ... U+007A 'z'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(uppercase_a.is_ascii_alphabetic()); + /// assert!(uppercase_g.is_ascii_alphabetic()); + /// assert!(a.is_ascii_alphabetic()); + /// assert!(g.is_ascii_alphabetic()); + /// assert!(!zero.is_ascii_alphabetic()); + /// assert!(!percent.is_ascii_alphabetic()); + /// assert!(!space.is_ascii_alphabetic()); + /// assert!(!lf.is_ascii_alphabetic()); + /// assert!(!esc.is_ascii_alphabetic()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_alphabetic(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_alphabetic() + } + + /// Checks if the value is an ASCII uppercase character: + /// U+0041 'A' ... U+005A 'Z'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(uppercase_a.is_ascii_uppercase()); + /// assert!(uppercase_g.is_ascii_uppercase()); + /// assert!(!a.is_ascii_uppercase()); + /// assert!(!g.is_ascii_uppercase()); + /// assert!(!zero.is_ascii_uppercase()); + /// assert!(!percent.is_ascii_uppercase()); + /// assert!(!space.is_ascii_uppercase()); + /// assert!(!lf.is_ascii_uppercase()); + /// assert!(!esc.is_ascii_uppercase()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_uppercase(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_uppercase() + } + + /// Checks if the value is an ASCII lowercase character: + /// U+0061 'a' ... U+007A 'z'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(!uppercase_a.is_ascii_lowercase()); + /// assert!(!uppercase_g.is_ascii_lowercase()); + /// assert!(a.is_ascii_lowercase()); + /// assert!(g.is_ascii_lowercase()); + /// assert!(!zero.is_ascii_lowercase()); + /// assert!(!percent.is_ascii_lowercase()); + /// assert!(!space.is_ascii_lowercase()); + /// assert!(!lf.is_ascii_lowercase()); + /// assert!(!esc.is_ascii_lowercase()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_lowercase(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_lowercase() + } + + /// Checks if the value is an ASCII alphanumeric character: + /// + /// - U+0041 'A' ... U+005A 'Z', or + /// - U+0061 'a' ... U+007A 'z', or + /// - U+0030 '0' ... U+0039 '9'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(uppercase_a.is_ascii_alphanumeric()); + /// assert!(uppercase_g.is_ascii_alphanumeric()); + /// assert!(a.is_ascii_alphanumeric()); + /// assert!(g.is_ascii_alphanumeric()); + /// assert!(zero.is_ascii_alphanumeric()); + /// assert!(!percent.is_ascii_alphanumeric()); + /// assert!(!space.is_ascii_alphanumeric()); + /// assert!(!lf.is_ascii_alphanumeric()); + /// assert!(!esc.is_ascii_alphanumeric()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_alphanumeric(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_alphanumeric() + } + + /// Checks if the value is an ASCII decimal digit: + /// U+0030 '0' ... U+0039 '9'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(!uppercase_a.is_ascii_digit()); + /// assert!(!uppercase_g.is_ascii_digit()); + /// assert!(!a.is_ascii_digit()); + /// assert!(!g.is_ascii_digit()); + /// assert!(zero.is_ascii_digit()); + /// assert!(!percent.is_ascii_digit()); + /// assert!(!space.is_ascii_digit()); + /// assert!(!lf.is_ascii_digit()); + /// assert!(!esc.is_ascii_digit()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_digit(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_digit() + } + + /// Checks if the value is an ASCII hexadecimal digit: + /// + /// - U+0030 '0' ... U+0039 '9', or + /// - U+0041 'A' ... U+0046 'F', or + /// - U+0061 'a' ... U+0066 'f'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(uppercase_a.is_ascii_hexdigit()); + /// assert!(!uppercase_g.is_ascii_hexdigit()); + /// assert!(a.is_ascii_hexdigit()); + /// assert!(!g.is_ascii_hexdigit()); + /// assert!(zero.is_ascii_hexdigit()); + /// assert!(!percent.is_ascii_hexdigit()); + /// assert!(!space.is_ascii_hexdigit()); + /// assert!(!lf.is_ascii_hexdigit()); + /// assert!(!esc.is_ascii_hexdigit()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_hexdigit(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_hexdigit() + } + + /// Checks if the value is an ASCII punctuation character: + /// + /// - U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`, or + /// - U+003A ... U+0040 `: ; < = > ? @`, or + /// - U+005B ... U+0060 ``[ \ ] ^ _ ` ``, or + /// - U+007B ... U+007E `{ | } ~` + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(!uppercase_a.is_ascii_punctuation()); + /// assert!(!uppercase_g.is_ascii_punctuation()); + /// assert!(!a.is_ascii_punctuation()); + /// assert!(!g.is_ascii_punctuation()); + /// assert!(!zero.is_ascii_punctuation()); + /// assert!(percent.is_ascii_punctuation()); + /// assert!(!space.is_ascii_punctuation()); + /// assert!(!lf.is_ascii_punctuation()); + /// assert!(!esc.is_ascii_punctuation()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_punctuation(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_punctuation() + } + + /// Checks if the value is an ASCII graphic character: + /// U+0021 '!' ... U+007E '~'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(uppercase_a.is_ascii_graphic()); + /// assert!(uppercase_g.is_ascii_graphic()); + /// assert!(a.is_ascii_graphic()); + /// assert!(g.is_ascii_graphic()); + /// assert!(zero.is_ascii_graphic()); + /// assert!(percent.is_ascii_graphic()); + /// assert!(!space.is_ascii_graphic()); + /// assert!(!lf.is_ascii_graphic()); + /// assert!(!esc.is_ascii_graphic()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_graphic(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_graphic() + } + + /// Checks if the value is an ASCII whitespace character: + /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED, + /// U+000C FORM FEED, or U+000D CARRIAGE RETURN. + /// + /// Rust uses the WhatWG Infra Standard's [definition of ASCII + /// whitespace][infra-aw]. There are several other definitions in + /// wide use. For instance, [the POSIX locale][pct] includes + /// U+000B VERTICAL TAB as well as all the above characters, + /// but—from the very same specification—[the default rule for + /// "field splitting" in the Bourne shell][bfs] considers *only* + /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace. + /// + /// If you are writing a program that will process an existing + /// file format, check what that format's definition of whitespace is + /// before using this function. + /// + /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace + /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 + /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(!uppercase_a.is_ascii_whitespace()); + /// assert!(!uppercase_g.is_ascii_whitespace()); + /// assert!(!a.is_ascii_whitespace()); + /// assert!(!g.is_ascii_whitespace()); + /// assert!(!zero.is_ascii_whitespace()); + /// assert!(!percent.is_ascii_whitespace()); + /// assert!(space.is_ascii_whitespace()); + /// assert!(lf.is_ascii_whitespace()); + /// assert!(!esc.is_ascii_whitespace()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_whitespace(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_whitespace() + } + + /// Checks if the value is an ASCII control character: + /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE. + /// Note that most ASCII whitespace characters are control + /// characters, but SPACE is not. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_ctype)] + /// + /// let uppercase_a = 'A'; + /// let uppercase_g = 'G'; + /// let a = 'a'; + /// let g = 'g'; + /// let zero = '0'; + /// let percent = '%'; + /// let space = ' '; + /// let lf = '\n'; + /// let esc: char = 0x1b_u8.into(); + /// + /// assert!(!uppercase_a.is_ascii_control()); + /// assert!(!uppercase_g.is_ascii_control()); + /// assert!(!a.is_ascii_control()); + /// assert!(!g.is_ascii_control()); + /// assert!(!zero.is_ascii_control()); + /// assert!(!percent.is_ascii_control()); + /// assert!(!space.is_ascii_control()); + /// assert!(lf.is_ascii_control()); + /// assert!(esc.is_ascii_control()); + /// ``` + #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] + #[inline] + pub fn is_ascii_control(&self) -> bool { + self.is_ascii() && (*self as u8).is_ascii_control() + } +} diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index 01a7b49ac74..7b4f0dc4548 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -8,15 +8,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Character manipulation. +//! A character type. //! -//! For more details, see ::core::unicode::char (a.k.a. std::char) +//! The `char` type represents a single character. More specifically, since +//! 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode +//! scalar value]', which is similar to, but not the same as, a '[Unicode code +//! point]'. +//! +//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value +//! [Unicode code point]: http://www.unicode.org/glossary/#code_point +//! +//! This module exists for technical reasons, the primary documentation for +//! `char` is directly on [the `char` primitive type](../../std/primitive.char.html) +//! itself. +//! +//! This module is the home of the iterator implementations for the iterators +//! implemented on `char`, as well as some useful constants and conversion +//! functions that convert various types to `char`. #![allow(non_snake_case)] #![stable(feature = "core_char", since = "1.2.0")] mod convert; mod decode; +mod methods; mod printable; // stable re-exports @@ -28,8 +43,6 @@ pub use self::convert::from_u32_unchecked; pub use self::convert::ParseCharError; #[stable(feature = "try_from", since = "1.26.0")] pub use self::convert::CharTryFromError; -#[stable(feature = "rust1", since = "1.0.0")] -pub use unicode::char::{ToLowercase, ToUppercase}; #[stable(feature = "decode_utf16", since = "1.9.0")] pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error}; @@ -41,10 +54,7 @@ pub use unicode::version::UnicodeVersion; #[unstable(feature = "decode_utf8", issue = "33906")] pub use self::decode::{decode_utf8, DecodeUtf8, InvalidSequence}; -use self::printable::is_printable; use fmt::{self, Write}; -use slice; -use str::from_utf8_unchecked_mut; use iter::FusedIterator; // UTF-8 ranges and tags for encoding characters @@ -137,149 +147,6 @@ pub trait CharExt { fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16]; } -#[stable(feature = "core", since = "1.6.0")] -impl CharExt for char { - #[inline] - fn is_digit(self, radix: u32) -> bool { - self.to_digit(radix).is_some() - } - - #[inline] - fn to_digit(self, radix: u32) -> Option { - if radix > 36 { - panic!("to_digit: radix is too high (maximum 36)"); - } - let val = match self { - '0' ... '9' => self as u32 - '0' as u32, - 'a' ... 'z' => self as u32 - 'a' as u32 + 10, - 'A' ... 'Z' => self as u32 - 'A' as u32 + 10, - _ => return None, - }; - if val < radix { Some(val) } - else { None } - } - - #[inline] - fn escape_unicode(self) -> EscapeUnicode { - let c = self as u32; - - // or-ing 1 ensures that for c==0 the code computes that one - // digit should be printed and (which is the same) avoids the - // (31 - 32) underflow - let msb = 31 - (c | 1).leading_zeros(); - - // the index of the most significant hex digit - let ms_hex_digit = msb / 4; - EscapeUnicode { - c: self, - state: EscapeUnicodeState::Backslash, - hex_digit_idx: ms_hex_digit as usize, - } - } - - #[inline] - fn escape_default(self) -> EscapeDefault { - let init_state = match self { - '\t' => EscapeDefaultState::Backslash('t'), - '\r' => EscapeDefaultState::Backslash('r'), - '\n' => EscapeDefaultState::Backslash('n'), - '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), - '\x20' ... '\x7e' => EscapeDefaultState::Char(self), - _ => EscapeDefaultState::Unicode(self.escape_unicode()) - }; - EscapeDefault { state: init_state } - } - - #[inline] - fn escape_debug(self) -> EscapeDebug { - let init_state = match self { - '\t' => EscapeDefaultState::Backslash('t'), - '\r' => EscapeDefaultState::Backslash('r'), - '\n' => EscapeDefaultState::Backslash('n'), - '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), - c if is_printable(c) => EscapeDefaultState::Char(c), - c => EscapeDefaultState::Unicode(c.escape_unicode()), - }; - EscapeDebug(EscapeDefault { state: init_state }) - } - - #[inline] - fn len_utf8(self) -> usize { - let code = self as u32; - if code < MAX_ONE_B { - 1 - } else if code < MAX_TWO_B { - 2 - } else if code < MAX_THREE_B { - 3 - } else { - 4 - } - } - - #[inline] - fn len_utf16(self) -> usize { - let ch = self as u32; - if (ch & 0xFFFF) == ch { 1 } else { 2 } - } - - #[inline] - fn encode_utf8(self, dst: &mut [u8]) -> &mut str { - let code = self as u32; - unsafe { - let len = - if code < MAX_ONE_B && !dst.is_empty() { - *dst.get_unchecked_mut(0) = code as u8; - 1 - } else if code < MAX_TWO_B && dst.len() >= 2 { - *dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; - *dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT; - 2 - } else if code < MAX_THREE_B && dst.len() >= 3 { - *dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; - *dst.get_unchecked_mut(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT; - 3 - } else if dst.len() >= 4 { - *dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; - *dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT; - 4 - } else { - panic!("encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", - from_u32_unchecked(code).len_utf8(), - code, - dst.len()) - }; - from_utf8_unchecked_mut(dst.get_unchecked_mut(..len)) - } - } - - #[inline] - fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { - let mut code = self as u32; - unsafe { - if (code & 0xFFFF) == code && !dst.is_empty() { - // The BMP falls through (assuming non-surrogate, as it should) - *dst.get_unchecked_mut(0) = code as u16; - slice::from_raw_parts_mut(dst.as_mut_ptr(), 1) - } else if dst.len() >= 2 { - // Supplementary planes break into surrogates. - code -= 0x1_0000; - *dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16); - *dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF); - slice::from_raw_parts_mut(dst.as_mut_ptr(), 2) - } else { - panic!("encode_utf16: need {} units to encode U+{:X}, but the buffer has {}", - from_u32_unchecked(code).len_utf16(), - code, - dst.len()) - } - } - } -} - /// Returns an iterator that yields the hexadecimal Unicode escape of a /// character, as `char`s. /// @@ -545,3 +412,124 @@ impl fmt::Display for EscapeDebug { fmt::Display::fmt(&self.0, f) } } + +/// Returns an iterator that yields the lowercase equivalent of a `char`. +/// +/// This `struct` is created by the [`to_lowercase`] method on [`char`]. See +/// its documentation for more. +/// +/// [`to_lowercase`]: ../../std/primitive.char.html#method.to_lowercase +/// [`char`]: ../../std/primitive.char.html +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug, Clone)] +pub struct ToLowercase(CaseMappingIter); + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for ToLowercase { + type Item = char; + fn next(&mut self) -> Option { + self.0.next() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for ToLowercase {} + +/// Returns an iterator that yields the uppercase equivalent of a `char`. +/// +/// This `struct` is created by the [`to_uppercase`] method on [`char`]. See +/// its documentation for more. +/// +/// [`to_uppercase`]: ../../std/primitive.char.html#method.to_uppercase +/// [`char`]: ../../std/primitive.char.html +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug, Clone)] +pub struct ToUppercase(CaseMappingIter); + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for ToUppercase { + type Item = char; + fn next(&mut self) -> Option { + self.0.next() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for ToUppercase {} + +#[derive(Debug, Clone)] +enum CaseMappingIter { + Three(char, char, char), + Two(char, char), + One(char), + Zero, +} + +impl CaseMappingIter { + fn new(chars: [char; 3]) -> CaseMappingIter { + if chars[2] == '\0' { + if chars[1] == '\0' { + CaseMappingIter::One(chars[0]) // Including if chars[0] == '\0' + } else { + CaseMappingIter::Two(chars[0], chars[1]) + } + } else { + CaseMappingIter::Three(chars[0], chars[1], chars[2]) + } + } +} + +impl Iterator for CaseMappingIter { + type Item = char; + fn next(&mut self) -> Option { + match *self { + CaseMappingIter::Three(a, b, c) => { + *self = CaseMappingIter::Two(b, c); + Some(a) + } + CaseMappingIter::Two(b, c) => { + *self = CaseMappingIter::One(c); + Some(b) + } + CaseMappingIter::One(c) => { + *self = CaseMappingIter::Zero; + Some(c) + } + CaseMappingIter::Zero => None, + } + } +} + +impl fmt::Display for CaseMappingIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + CaseMappingIter::Three(a, b, c) => { + f.write_char(a)?; + f.write_char(b)?; + f.write_char(c) + } + CaseMappingIter::Two(b, c) => { + f.write_char(b)?; + f.write_char(c) + } + CaseMappingIter::One(c) => { + f.write_char(c) + } + CaseMappingIter::Zero => Ok(()), + } + } +} + +#[stable(feature = "char_struct_display", since = "1.16.0")] +impl fmt::Display for ToLowercase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +#[stable(feature = "char_struct_display", since = "1.16.0")] +impl fmt::Display for ToUppercase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} diff --git a/src/libcore/unicode/char.rs b/src/libcore/unicode/char.rs deleted file mode 100644 index fda1914a50f..00000000000 --- a/src/libcore/unicode/char.rs +++ /dev/null @@ -1,1437 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A character type. -//! -//! The `char` type represents a single character. More specifically, since -//! 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode -//! scalar value]', which is similar to, but not the same as, a '[Unicode code -//! point]'. -//! -//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value -//! [Unicode code point]: http://www.unicode.org/glossary/#code_point -//! -//! This module exists for technical reasons, the primary documentation for -//! `char` is directly on [the `char` primitive type](../../std/primitive.char.html) -//! itself. -//! -//! This module is the home of the iterator implementations for the iterators -//! implemented on `char`, as well as some useful constants and conversion -//! functions that convert various types to `char`. - -#![stable(feature = "rust1", since = "1.0.0")] - -use char::*; -use char::CharExt as C; -use iter::FusedIterator; -use fmt::{self, Write}; -use unicode::tables::{conversions, derived_property, general_category, property}; - -/// Returns an iterator that yields the lowercase equivalent of a `char`. -/// -/// This `struct` is created by the [`to_lowercase`] method on [`char`]. See -/// its documentation for more. -/// -/// [`to_lowercase`]: ../../std/primitive.char.html#method.to_lowercase -/// [`char`]: ../../std/primitive.char.html -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug, Clone)] -pub struct ToLowercase(CaseMappingIter); - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for ToLowercase { - type Item = char; - fn next(&mut self) -> Option { - self.0.next() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for ToLowercase {} - -/// Returns an iterator that yields the uppercase equivalent of a `char`. -/// -/// This `struct` is created by the [`to_uppercase`] method on [`char`]. See -/// its documentation for more. -/// -/// [`to_uppercase`]: ../../std/primitive.char.html#method.to_uppercase -/// [`char`]: ../../std/primitive.char.html -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug, Clone)] -pub struct ToUppercase(CaseMappingIter); - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for ToUppercase { - type Item = char; - fn next(&mut self) -> Option { - self.0.next() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for ToUppercase {} - -#[derive(Debug, Clone)] -enum CaseMappingIter { - Three(char, char, char), - Two(char, char), - One(char), - Zero, -} - -impl CaseMappingIter { - fn new(chars: [char; 3]) -> CaseMappingIter { - if chars[2] == '\0' { - if chars[1] == '\0' { - CaseMappingIter::One(chars[0]) // Including if chars[0] == '\0' - } else { - CaseMappingIter::Two(chars[0], chars[1]) - } - } else { - CaseMappingIter::Three(chars[0], chars[1], chars[2]) - } - } -} - -impl Iterator for CaseMappingIter { - type Item = char; - fn next(&mut self) -> Option { - match *self { - CaseMappingIter::Three(a, b, c) => { - *self = CaseMappingIter::Two(b, c); - Some(a) - } - CaseMappingIter::Two(b, c) => { - *self = CaseMappingIter::One(c); - Some(b) - } - CaseMappingIter::One(c) => { - *self = CaseMappingIter::Zero; - Some(c) - } - CaseMappingIter::Zero => None, - } - } -} - -impl fmt::Display for CaseMappingIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - CaseMappingIter::Three(a, b, c) => { - f.write_char(a)?; - f.write_char(b)?; - f.write_char(c) - } - CaseMappingIter::Two(b, c) => { - f.write_char(b)?; - f.write_char(c) - } - CaseMappingIter::One(c) => { - f.write_char(c) - } - CaseMappingIter::Zero => Ok(()), - } - } -} - -#[stable(feature = "char_struct_display", since = "1.16.0")] -impl fmt::Display for ToLowercase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } -} - -#[stable(feature = "char_struct_display", since = "1.16.0")] -impl fmt::Display for ToUppercase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } -} - -#[lang = "char"] -impl char { - /// Checks if a `char` is a digit in the given radix. - /// - /// A 'radix' here is sometimes also called a 'base'. A radix of two - /// indicates a binary number, a radix of ten, decimal, and a radix of - /// sixteen, hexadecimal, to give some common values. Arbitrary - /// radices are supported. - /// - /// Compared to `is_numeric()`, this function only recognizes the characters - /// `0-9`, `a-z` and `A-Z`. - /// - /// 'Digit' is defined to be only the following characters: - /// - /// * `0-9` - /// * `a-z` - /// * `A-Z` - /// - /// For a more comprehensive understanding of 'digit', see [`is_numeric`][is_numeric]. - /// - /// [is_numeric]: #method.is_numeric - /// - /// # Panics - /// - /// Panics if given a radix larger than 36. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!('1'.is_digit(10)); - /// assert!('f'.is_digit(16)); - /// assert!(!'f'.is_digit(10)); - /// ``` - /// - /// Passing a large radix, causing a panic: - /// - /// ``` - /// use std::thread; - /// - /// let result = thread::spawn(|| { - /// // this panics - /// '1'.is_digit(37); - /// }).join(); - /// - /// assert!(result.is_err()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_digit(self, radix: u32) -> bool { - C::is_digit(self, radix) - } - - /// Converts a `char` to a digit in the given radix. - /// - /// A 'radix' here is sometimes also called a 'base'. A radix of two - /// indicates a binary number, a radix of ten, decimal, and a radix of - /// sixteen, hexadecimal, to give some common values. Arbitrary - /// radices are supported. - /// - /// 'Digit' is defined to be only the following characters: - /// - /// * `0-9` - /// * `a-z` - /// * `A-Z` - /// - /// # Errors - /// - /// Returns `None` if the `char` does not refer to a digit in the given radix. - /// - /// # Panics - /// - /// Panics if given a radix larger than 36. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!('1'.to_digit(10), Some(1)); - /// assert_eq!('f'.to_digit(16), Some(15)); - /// ``` - /// - /// Passing a non-digit results in failure: - /// - /// ``` - /// assert_eq!('f'.to_digit(10), None); - /// assert_eq!('z'.to_digit(16), None); - /// ``` - /// - /// Passing a large radix, causing a panic: - /// - /// ``` - /// use std::thread; - /// - /// let result = thread::spawn(|| { - /// '1'.to_digit(37); - /// }).join(); - /// - /// assert!(result.is_err()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_digit(self, radix: u32) -> Option { - C::to_digit(self, radix) - } - - /// Returns an iterator that yields the hexadecimal Unicode escape of a - /// character as `char`s. - /// - /// This will escape characters with the Rust syntax of the form - /// `\u{NNNNNN}` where `NNNNNN` is a hexadecimal representation. - /// - /// # Examples - /// - /// As an iterator: - /// - /// ``` - /// for c in '❤'.escape_unicode() { - /// print!("{}", c); - /// } - /// println!(); - /// ``` - /// - /// Using `println!` directly: - /// - /// ``` - /// println!("{}", '❤'.escape_unicode()); - /// ``` - /// - /// Both are equivalent to: - /// - /// ``` - /// println!("\\u{{2764}}"); - /// ``` - /// - /// Using `to_string`: - /// - /// ``` - /// assert_eq!('❤'.escape_unicode().to_string(), "\\u{2764}"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn escape_unicode(self) -> EscapeUnicode { - C::escape_unicode(self) - } - - /// Returns an iterator that yields the literal escape code of a character - /// as `char`s. - /// - /// This will escape the characters similar to the `Debug` implementations - /// of `str` or `char`. - /// - /// # Examples - /// - /// As an iterator: - /// - /// ``` - /// for c in '\n'.escape_debug() { - /// print!("{}", c); - /// } - /// println!(); - /// ``` - /// - /// Using `println!` directly: - /// - /// ``` - /// println!("{}", '\n'.escape_debug()); - /// ``` - /// - /// Both are equivalent to: - /// - /// ``` - /// println!("\\n"); - /// ``` - /// - /// Using `to_string`: - /// - /// ``` - /// assert_eq!('\n'.escape_debug().to_string(), "\\n"); - /// ``` - #[stable(feature = "char_escape_debug", since = "1.20.0")] - #[inline] - pub fn escape_debug(self) -> EscapeDebug { - C::escape_debug(self) - } - - /// Returns an iterator that yields the literal escape code of a character - /// as `char`s. - /// - /// The default is chosen with a bias toward producing literals that are - /// legal in a variety of languages, including C++11 and similar C-family - /// languages. The exact rules are: - /// - /// * Tab is escaped as `\t`. - /// * Carriage return is escaped as `\r`. - /// * Line feed is escaped as `\n`. - /// * Single quote is escaped as `\'`. - /// * Double quote is escaped as `\"`. - /// * Backslash is escaped as `\\`. - /// * Any character in the 'printable ASCII' range `0x20` .. `0x7e` - /// inclusive is not escaped. - /// * All other characters are given hexadecimal Unicode escapes; see - /// [`escape_unicode`][escape_unicode]. - /// - /// [escape_unicode]: #method.escape_unicode - /// - /// # Examples - /// - /// As an iterator: - /// - /// ``` - /// for c in '"'.escape_default() { - /// print!("{}", c); - /// } - /// println!(); - /// ``` - /// - /// Using `println!` directly: - /// - /// ``` - /// println!("{}", '"'.escape_default()); - /// ``` - /// - /// - /// Both are equivalent to: - /// - /// ``` - /// println!("\\\""); - /// ``` - /// - /// Using `to_string`: - /// - /// ``` - /// assert_eq!('"'.escape_default().to_string(), "\\\""); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn escape_default(self) -> EscapeDefault { - C::escape_default(self) - } - - /// Returns the number of bytes this `char` would need if encoded in UTF-8. - /// - /// That number of bytes is always between 1 and 4, inclusive. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let len = 'A'.len_utf8(); - /// assert_eq!(len, 1); - /// - /// let len = 'ß'.len_utf8(); - /// assert_eq!(len, 2); - /// - /// let len = 'ℝ'.len_utf8(); - /// assert_eq!(len, 3); - /// - /// let len = '💣'.len_utf8(); - /// assert_eq!(len, 4); - /// ``` - /// - /// The `&str` type guarantees that its contents are UTF-8, and so we can compare the length it - /// would take if each code point was represented as a `char` vs in the `&str` itself: - /// - /// ``` - /// // as chars - /// let eastern = '東'; - /// let capitol = '京'; - /// - /// // both can be represented as three bytes - /// assert_eq!(3, eastern.len_utf8()); - /// assert_eq!(3, capitol.len_utf8()); - /// - /// // as a &str, these two are encoded in UTF-8 - /// let tokyo = "東京"; - /// - /// let len = eastern.len_utf8() + capitol.len_utf8(); - /// - /// // we can see that they take six bytes total... - /// assert_eq!(6, tokyo.len()); - /// - /// // ... just like the &str - /// assert_eq!(len, tokyo.len()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn len_utf8(self) -> usize { - C::len_utf8(self) - } - - /// Returns the number of 16-bit code units this `char` would need if - /// encoded in UTF-16. - /// - /// See the documentation for [`len_utf8`] for more explanation of this - /// concept. This function is a mirror, but for UTF-16 instead of UTF-8. - /// - /// [`len_utf8`]: #method.len_utf8 - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 'ß'.len_utf16(); - /// assert_eq!(n, 1); - /// - /// let len = '💣'.len_utf16(); - /// assert_eq!(len, 2); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn len_utf16(self) -> usize { - C::len_utf16(self) - } - - /// Encodes this character as UTF-8 into the provided byte buffer, - /// and then returns the subslice of the buffer that contains the encoded character. - /// - /// # Panics - /// - /// Panics if the buffer is not large enough. - /// A buffer of length four is large enough to encode any `char`. - /// - /// # Examples - /// - /// In both of these examples, 'ß' takes two bytes to encode. - /// - /// ``` - /// let mut b = [0; 2]; - /// - /// let result = 'ß'.encode_utf8(&mut b); - /// - /// assert_eq!(result, "ß"); - /// - /// assert_eq!(result.len(), 2); - /// ``` - /// - /// A buffer that's too small: - /// - /// ``` - /// use std::thread; - /// - /// let result = thread::spawn(|| { - /// let mut b = [0; 1]; - /// - /// // this panics - /// 'ß'.encode_utf8(&mut b); - /// }).join(); - /// - /// assert!(result.is_err()); - /// ``` - #[stable(feature = "unicode_encode_char", since = "1.15.0")] - #[inline] - pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str { - C::encode_utf8(self, dst) - } - - /// Encodes this character as UTF-16 into the provided `u16` buffer, - /// and then returns the subslice of the buffer that contains the encoded character. - /// - /// # Panics - /// - /// Panics if the buffer is not large enough. - /// A buffer of length 2 is large enough to encode any `char`. - /// - /// # Examples - /// - /// In both of these examples, '𝕊' takes two `u16`s to encode. - /// - /// ``` - /// let mut b = [0; 2]; - /// - /// let result = '𝕊'.encode_utf16(&mut b); - /// - /// assert_eq!(result.len(), 2); - /// ``` - /// - /// A buffer that's too small: - /// - /// ``` - /// use std::thread; - /// - /// let result = thread::spawn(|| { - /// let mut b = [0; 1]; - /// - /// // this panics - /// '𝕊'.encode_utf16(&mut b); - /// }).join(); - /// - /// assert!(result.is_err()); - /// ``` - #[stable(feature = "unicode_encode_char", since = "1.15.0")] - #[inline] - pub fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { - C::encode_utf16(self, dst) - } - - /// Returns true if this `char` is an alphabetic code point, and false if not. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!('a'.is_alphabetic()); - /// assert!('京'.is_alphabetic()); - /// - /// let c = '💝'; - /// // love is many things, but it is not alphabetic - /// assert!(!c.is_alphabetic()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_alphabetic(self) -> bool { - match self { - 'a'...'z' | 'A'...'Z' => true, - c if c > '\x7f' => derived_property::Alphabetic(c), - _ => false, - } - } - - /// Returns true if this `char` satisfies the 'XID_Start' Unicode property, and false - /// otherwise. - /// - /// 'XID_Start' is a Unicode Derived Property specified in - /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), - /// mostly similar to `ID_Start` but modified for closure under `NFKx`. - #[unstable(feature = "rustc_private", - reason = "mainly needed for compiler internals", - issue = "27812")] - #[inline] - pub fn is_xid_start(self) -> bool { - derived_property::XID_Start(self) - } - - /// Returns true if this `char` satisfies the 'XID_Continue' Unicode property, and false - /// otherwise. - /// - /// 'XID_Continue' is a Unicode Derived Property specified in - /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), - /// mostly similar to 'ID_Continue' but modified for closure under NFKx. - #[unstable(feature = "rustc_private", - reason = "mainly needed for compiler internals", - issue = "27812")] - #[inline] - pub fn is_xid_continue(self) -> bool { - derived_property::XID_Continue(self) - } - - /// Returns true if this `char` is lowercase, and false otherwise. - /// - /// 'Lowercase' is defined according to the terms of the Unicode Derived Core - /// Property `Lowercase`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!('a'.is_lowercase()); - /// assert!('δ'.is_lowercase()); - /// assert!(!'A'.is_lowercase()); - /// assert!(!'Δ'.is_lowercase()); - /// - /// // The various Chinese scripts do not have case, and so: - /// assert!(!'中'.is_lowercase()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_lowercase(self) -> bool { - match self { - 'a'...'z' => true, - c if c > '\x7f' => derived_property::Lowercase(c), - _ => false, - } - } - - /// Returns true if this `char` is uppercase, and false otherwise. - /// - /// 'Uppercase' is defined according to the terms of the Unicode Derived Core - /// Property `Uppercase`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!(!'a'.is_uppercase()); - /// assert!(!'δ'.is_uppercase()); - /// assert!('A'.is_uppercase()); - /// assert!('Δ'.is_uppercase()); - /// - /// // The various Chinese scripts do not have case, and so: - /// assert!(!'中'.is_uppercase()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_uppercase(self) -> bool { - match self { - 'A'...'Z' => true, - c if c > '\x7f' => derived_property::Uppercase(c), - _ => false, - } - } - - /// Returns true if this `char` is whitespace, and false otherwise. - /// - /// 'Whitespace' is defined according to the terms of the Unicode Derived Core - /// Property `White_Space`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!(' '.is_whitespace()); - /// - /// // a non-breaking space - /// assert!('\u{A0}'.is_whitespace()); - /// - /// assert!(!'越'.is_whitespace()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_whitespace(self) -> bool { - match self { - ' ' | '\x09'...'\x0d' => true, - c if c > '\x7f' => property::White_Space(c), - _ => false, - } - } - - /// Returns true if this `char` is alphanumeric, and false otherwise. - /// - /// 'Alphanumeric'-ness is defined in terms of the Unicode General Categories - /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!('٣'.is_alphanumeric()); - /// assert!('7'.is_alphanumeric()); - /// assert!('৬'.is_alphanumeric()); - /// assert!('K'.is_alphanumeric()); - /// assert!('و'.is_alphanumeric()); - /// assert!('藏'.is_alphanumeric()); - /// assert!(!'¾'.is_alphanumeric()); - /// assert!(!'①'.is_alphanumeric()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_alphanumeric(self) -> bool { - self.is_alphabetic() || self.is_numeric() - } - - /// Returns true if this `char` is a control code point, and false otherwise. - /// - /// 'Control code point' is defined in terms of the Unicode General - /// Category `Cc`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // U+009C, STRING TERMINATOR - /// assert!('œ'.is_control()); - /// assert!(!'q'.is_control()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_control(self) -> bool { - general_category::Cc(self) - } - - /// Returns true if this `char` is numeric, and false otherwise. - /// - /// 'Numeric'-ness is defined in terms of the Unicode General Categories - /// 'Nd', 'Nl', 'No'. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!('٣'.is_numeric()); - /// assert!('7'.is_numeric()); - /// assert!('৬'.is_numeric()); - /// assert!(!'K'.is_numeric()); - /// assert!(!'و'.is_numeric()); - /// assert!(!'藏'.is_numeric()); - /// assert!(!'¾'.is_numeric()); - /// assert!(!'①'.is_numeric()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_numeric(self) -> bool { - match self { - '0'...'9' => true, - c if c > '\x7f' => general_category::N(c), - _ => false, - } - } - - /// Returns an iterator that yields the lowercase equivalent of a `char` - /// as one or more `char`s. - /// - /// If a character does not have a lowercase equivalent, the same character - /// will be returned back by the iterator. - /// - /// This performs complex unconditional mappings with no tailoring: it maps - /// one Unicode character to its lowercase equivalent according to the - /// [Unicode database] and the additional complex mappings - /// [`SpecialCasing.txt`]. Conditional mappings (based on context or - /// language) are not considered here. - /// - /// For a full reference, see [here][reference]. - /// - /// [Unicode database]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt - /// - /// [`SpecialCasing.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt - /// - /// [reference]: http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 - /// - /// # Examples - /// - /// As an iterator: - /// - /// ``` - /// for c in 'İ'.to_lowercase() { - /// print!("{}", c); - /// } - /// println!(); - /// ``` - /// - /// Using `println!` directly: - /// - /// ``` - /// println!("{}", 'İ'.to_lowercase()); - /// ``` - /// - /// Both are equivalent to: - /// - /// ``` - /// println!("i\u{307}"); - /// ``` - /// - /// Using `to_string`: - /// - /// ``` - /// assert_eq!('C'.to_lowercase().to_string(), "c"); - /// - /// // Sometimes the result is more than one character: - /// assert_eq!('İ'.to_lowercase().to_string(), "i\u{307}"); - /// - /// // Characters that do not have both uppercase and lowercase - /// // convert into themselves. - /// assert_eq!('山'.to_lowercase().to_string(), "山"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_lowercase(self) -> ToLowercase { - ToLowercase(CaseMappingIter::new(conversions::to_lower(self))) - } - - /// Returns an iterator that yields the uppercase equivalent of a `char` - /// as one or more `char`s. - /// - /// If a character does not have an uppercase equivalent, the same character - /// will be returned back by the iterator. - /// - /// This performs complex unconditional mappings with no tailoring: it maps - /// one Unicode character to its uppercase equivalent according to the - /// [Unicode database] and the additional complex mappings - /// [`SpecialCasing.txt`]. Conditional mappings (based on context or - /// language) are not considered here. - /// - /// For a full reference, see [here][reference]. - /// - /// [Unicode database]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt - /// - /// [`SpecialCasing.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt - /// - /// [reference]: http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 - /// - /// # Examples - /// - /// As an iterator: - /// - /// ``` - /// for c in 'ß'.to_uppercase() { - /// print!("{}", c); - /// } - /// println!(); - /// ``` - /// - /// Using `println!` directly: - /// - /// ``` - /// println!("{}", 'ß'.to_uppercase()); - /// ``` - /// - /// Both are equivalent to: - /// - /// ``` - /// println!("SS"); - /// ``` - /// - /// Using `to_string`: - /// - /// ``` - /// assert_eq!('c'.to_uppercase().to_string(), "C"); - /// - /// // Sometimes the result is more than one character: - /// assert_eq!('ß'.to_uppercase().to_string(), "SS"); - /// - /// // Characters that do not have both uppercase and lowercase - /// // convert into themselves. - /// assert_eq!('山'.to_uppercase().to_string(), "山"); - /// ``` - /// - /// # Note on locale - /// - /// In Turkish, the equivalent of 'i' in Latin has five forms instead of two: - /// - /// * 'Dotless': I / ı, sometimes written ï - /// * 'Dotted': İ / i - /// - /// Note that the lowercase dotted 'i' is the same as the Latin. Therefore: - /// - /// ``` - /// let upper_i = 'i'.to_uppercase().to_string(); - /// ``` - /// - /// The value of `upper_i` here relies on the language of the text: if we're - /// in `en-US`, it should be `"I"`, but if we're in `tr_TR`, it should - /// be `"İ"`. `to_uppercase()` does not take this into account, and so: - /// - /// ``` - /// let upper_i = 'i'.to_uppercase().to_string(); - /// - /// assert_eq!(upper_i, "I"); - /// ``` - /// - /// holds across languages. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_uppercase(self) -> ToUppercase { - ToUppercase(CaseMappingIter::new(conversions::to_upper(self))) - } - - /// Checks if the value is within the ASCII range. - /// - /// # Examples - /// - /// ``` - /// let ascii = 'a'; - /// let non_ascii = '❤'; - /// - /// assert!(ascii.is_ascii()); - /// assert!(!non_ascii.is_ascii()); - /// ``` - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn is_ascii(&self) -> bool { - *self as u32 <= 0x7F - } - - /// Makes a copy of the value in its ASCII upper case equivalent. - /// - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - /// - /// To uppercase the value in-place, use [`make_ascii_uppercase`]. - /// - /// To uppercase ASCII characters in addition to non-ASCII characters, use - /// [`to_uppercase`]. - /// - /// # Examples - /// - /// ``` - /// let ascii = 'a'; - /// let non_ascii = '❤'; - /// - /// assert_eq!('A', ascii.to_ascii_uppercase()); - /// assert_eq!('❤', non_ascii.to_ascii_uppercase()); - /// ``` - /// - /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase - /// [`to_uppercase`]: #method.to_uppercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn to_ascii_uppercase(&self) -> char { - if self.is_ascii() { - (*self as u8).to_ascii_uppercase() as char - } else { - *self - } - } - - /// Makes a copy of the value in its ASCII lower case equivalent. - /// - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - /// - /// To lowercase the value in-place, use [`make_ascii_lowercase`]. - /// - /// To lowercase ASCII characters in addition to non-ASCII characters, use - /// [`to_lowercase`]. - /// - /// # Examples - /// - /// ``` - /// let ascii = 'A'; - /// let non_ascii = '❤'; - /// - /// assert_eq!('a', ascii.to_ascii_lowercase()); - /// assert_eq!('❤', non_ascii.to_ascii_lowercase()); - /// ``` - /// - /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase - /// [`to_lowercase`]: #method.to_lowercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn to_ascii_lowercase(&self) -> char { - if self.is_ascii() { - (*self as u8).to_ascii_lowercase() as char - } else { - *self - } - } - - /// Checks that two values are an ASCII case-insensitive match. - /// - /// Equivalent to `to_ascii_lowercase(a) == to_ascii_lowercase(b)`. - /// - /// # Examples - /// - /// ``` - /// let upper_a = 'A'; - /// let lower_a = 'a'; - /// let lower_z = 'z'; - /// - /// assert!(upper_a.eq_ignore_ascii_case(&lower_a)); - /// assert!(upper_a.eq_ignore_ascii_case(&upper_a)); - /// assert!(!upper_a.eq_ignore_ascii_case(&lower_z)); - /// ``` - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn eq_ignore_ascii_case(&self, other: &char) -> bool { - self.to_ascii_lowercase() == other.to_ascii_lowercase() - } - - /// Converts this type to its ASCII upper case equivalent in-place. - /// - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new uppercased value without modifying the existing one, use - /// [`to_ascii_uppercase`]. - /// - /// # Examples - /// - /// ``` - /// let mut ascii = 'a'; - /// - /// ascii.make_ascii_uppercase(); - /// - /// assert_eq!('A', ascii); - /// ``` - /// - /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn make_ascii_uppercase(&mut self) { - *self = self.to_ascii_uppercase(); - } - - /// Converts this type to its ASCII lower case equivalent in-place. - /// - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new lowercased value without modifying the existing one, use - /// [`to_ascii_lowercase`]. - /// - /// # Examples - /// - /// ``` - /// let mut ascii = 'A'; - /// - /// ascii.make_ascii_lowercase(); - /// - /// assert_eq!('a', ascii); - /// ``` - /// - /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn make_ascii_lowercase(&mut self) { - *self = self.to_ascii_lowercase(); - } - - /// Checks if the value is an ASCII alphabetic character: - /// - /// - U+0041 'A' ... U+005A 'Z', or - /// - U+0061 'a' ... U+007A 'z'. - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(uppercase_a.is_ascii_alphabetic()); - /// assert!(uppercase_g.is_ascii_alphabetic()); - /// assert!(a.is_ascii_alphabetic()); - /// assert!(g.is_ascii_alphabetic()); - /// assert!(!zero.is_ascii_alphabetic()); - /// assert!(!percent.is_ascii_alphabetic()); - /// assert!(!space.is_ascii_alphabetic()); - /// assert!(!lf.is_ascii_alphabetic()); - /// assert!(!esc.is_ascii_alphabetic()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_alphabetic(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_alphabetic() - } - - /// Checks if the value is an ASCII uppercase character: - /// U+0041 'A' ... U+005A 'Z'. - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(uppercase_a.is_ascii_uppercase()); - /// assert!(uppercase_g.is_ascii_uppercase()); - /// assert!(!a.is_ascii_uppercase()); - /// assert!(!g.is_ascii_uppercase()); - /// assert!(!zero.is_ascii_uppercase()); - /// assert!(!percent.is_ascii_uppercase()); - /// assert!(!space.is_ascii_uppercase()); - /// assert!(!lf.is_ascii_uppercase()); - /// assert!(!esc.is_ascii_uppercase()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_uppercase(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_uppercase() - } - - /// Checks if the value is an ASCII lowercase character: - /// U+0061 'a' ... U+007A 'z'. - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(!uppercase_a.is_ascii_lowercase()); - /// assert!(!uppercase_g.is_ascii_lowercase()); - /// assert!(a.is_ascii_lowercase()); - /// assert!(g.is_ascii_lowercase()); - /// assert!(!zero.is_ascii_lowercase()); - /// assert!(!percent.is_ascii_lowercase()); - /// assert!(!space.is_ascii_lowercase()); - /// assert!(!lf.is_ascii_lowercase()); - /// assert!(!esc.is_ascii_lowercase()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_lowercase(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_lowercase() - } - - /// Checks if the value is an ASCII alphanumeric character: - /// - /// - U+0041 'A' ... U+005A 'Z', or - /// - U+0061 'a' ... U+007A 'z', or - /// - U+0030 '0' ... U+0039 '9'. - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(uppercase_a.is_ascii_alphanumeric()); - /// assert!(uppercase_g.is_ascii_alphanumeric()); - /// assert!(a.is_ascii_alphanumeric()); - /// assert!(g.is_ascii_alphanumeric()); - /// assert!(zero.is_ascii_alphanumeric()); - /// assert!(!percent.is_ascii_alphanumeric()); - /// assert!(!space.is_ascii_alphanumeric()); - /// assert!(!lf.is_ascii_alphanumeric()); - /// assert!(!esc.is_ascii_alphanumeric()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_alphanumeric(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_alphanumeric() - } - - /// Checks if the value is an ASCII decimal digit: - /// U+0030 '0' ... U+0039 '9'. - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(!uppercase_a.is_ascii_digit()); - /// assert!(!uppercase_g.is_ascii_digit()); - /// assert!(!a.is_ascii_digit()); - /// assert!(!g.is_ascii_digit()); - /// assert!(zero.is_ascii_digit()); - /// assert!(!percent.is_ascii_digit()); - /// assert!(!space.is_ascii_digit()); - /// assert!(!lf.is_ascii_digit()); - /// assert!(!esc.is_ascii_digit()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_digit(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_digit() - } - - /// Checks if the value is an ASCII hexadecimal digit: - /// - /// - U+0030 '0' ... U+0039 '9', or - /// - U+0041 'A' ... U+0046 'F', or - /// - U+0061 'a' ... U+0066 'f'. - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(uppercase_a.is_ascii_hexdigit()); - /// assert!(!uppercase_g.is_ascii_hexdigit()); - /// assert!(a.is_ascii_hexdigit()); - /// assert!(!g.is_ascii_hexdigit()); - /// assert!(zero.is_ascii_hexdigit()); - /// assert!(!percent.is_ascii_hexdigit()); - /// assert!(!space.is_ascii_hexdigit()); - /// assert!(!lf.is_ascii_hexdigit()); - /// assert!(!esc.is_ascii_hexdigit()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_hexdigit(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_hexdigit() - } - - /// Checks if the value is an ASCII punctuation character: - /// - /// - U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`, or - /// - U+003A ... U+0040 `: ; < = > ? @`, or - /// - U+005B ... U+0060 ``[ \ ] ^ _ ` ``, or - /// - U+007B ... U+007E `{ | } ~` - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(!uppercase_a.is_ascii_punctuation()); - /// assert!(!uppercase_g.is_ascii_punctuation()); - /// assert!(!a.is_ascii_punctuation()); - /// assert!(!g.is_ascii_punctuation()); - /// assert!(!zero.is_ascii_punctuation()); - /// assert!(percent.is_ascii_punctuation()); - /// assert!(!space.is_ascii_punctuation()); - /// assert!(!lf.is_ascii_punctuation()); - /// assert!(!esc.is_ascii_punctuation()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_punctuation(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_punctuation() - } - - /// Checks if the value is an ASCII graphic character: - /// U+0021 '!' ... U+007E '~'. - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(uppercase_a.is_ascii_graphic()); - /// assert!(uppercase_g.is_ascii_graphic()); - /// assert!(a.is_ascii_graphic()); - /// assert!(g.is_ascii_graphic()); - /// assert!(zero.is_ascii_graphic()); - /// assert!(percent.is_ascii_graphic()); - /// assert!(!space.is_ascii_graphic()); - /// assert!(!lf.is_ascii_graphic()); - /// assert!(!esc.is_ascii_graphic()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_graphic(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_graphic() - } - - /// Checks if the value is an ASCII whitespace character: - /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED, - /// U+000C FORM FEED, or U+000D CARRIAGE RETURN. - /// - /// Rust uses the WhatWG Infra Standard's [definition of ASCII - /// whitespace][infra-aw]. There are several other definitions in - /// wide use. For instance, [the POSIX locale][pct] includes - /// U+000B VERTICAL TAB as well as all the above characters, - /// but—from the very same specification—[the default rule for - /// "field splitting" in the Bourne shell][bfs] considers *only* - /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace. - /// - /// If you are writing a program that will process an existing - /// file format, check what that format's definition of whitespace is - /// before using this function. - /// - /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace - /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 - /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(!uppercase_a.is_ascii_whitespace()); - /// assert!(!uppercase_g.is_ascii_whitespace()); - /// assert!(!a.is_ascii_whitespace()); - /// assert!(!g.is_ascii_whitespace()); - /// assert!(!zero.is_ascii_whitespace()); - /// assert!(!percent.is_ascii_whitespace()); - /// assert!(space.is_ascii_whitespace()); - /// assert!(lf.is_ascii_whitespace()); - /// assert!(!esc.is_ascii_whitespace()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_whitespace(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_whitespace() - } - - /// Checks if the value is an ASCII control character: - /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE. - /// Note that most ASCII whitespace characters are control - /// characters, but SPACE is not. - /// - /// # Examples - /// - /// ``` - /// #![feature(ascii_ctype)] - /// - /// let uppercase_a = 'A'; - /// let uppercase_g = 'G'; - /// let a = 'a'; - /// let g = 'g'; - /// let zero = '0'; - /// let percent = '%'; - /// let space = ' '; - /// let lf = '\n'; - /// let esc: char = 0x1b_u8.into(); - /// - /// assert!(!uppercase_a.is_ascii_control()); - /// assert!(!uppercase_g.is_ascii_control()); - /// assert!(!a.is_ascii_control()); - /// assert!(!g.is_ascii_control()); - /// assert!(!zero.is_ascii_control()); - /// assert!(!percent.is_ascii_control()); - /// assert!(!space.is_ascii_control()); - /// assert!(lf.is_ascii_control()); - /// assert!(esc.is_ascii_control()); - /// ``` - #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")] - #[inline] - pub fn is_ascii_control(&self) -> bool { - self.is_ascii() && (*self as u8).is_ascii_control() - } -} diff --git a/src/libcore/unicode/mod.rs b/src/libcore/unicode/mod.rs index 0ea1aa12146..060c55286fe 100644 --- a/src/libcore/unicode/mod.rs +++ b/src/libcore/unicode/mod.rs @@ -16,7 +16,6 @@ pub(crate) mod tables; pub(crate) mod version; pub mod str; -pub(crate) mod char; // For use in liballoc, not re-exported in libstd. pub mod derived_property { -- cgit 1.4.1-3-g733a5 From 33358dc3c5c1f5d627544075de6ff37b9e328efa Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 5 Apr 2018 18:46:16 +0200 Subject: Remove the CharExt trait, now that libcore has inherent methods for char --- src/libcore/char/methods.rs | 257 +++++++++++++++++------------------------ src/libcore/char/mod.rs | 28 ----- src/libcore/prelude/v1.rs | 3 - src/libcore/unicode/str.rs | 5 +- src/libcore/unicode/tables.rs | 2 +- src/libcore/unicode/unicode.py | 2 +- 6 files changed, 107 insertions(+), 190 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 0958c67ea05..2c433a7ac9e 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -13,153 +13,9 @@ use slice; use str::from_utf8_unchecked_mut; use super::*; -use super::CharExt as C; use super::printable::is_printable; use unicode::tables::{conversions, derived_property, general_category, property}; -#[stable(feature = "core", since = "1.6.0")] -impl CharExt for char { - #[inline] - fn is_digit(self, radix: u32) -> bool { - self.to_digit(radix).is_some() - } - - #[inline] - fn to_digit(self, radix: u32) -> Option { - if radix > 36 { - panic!("to_digit: radix is too high (maximum 36)"); - } - let val = match self { - '0' ... '9' => self as u32 - '0' as u32, - 'a' ... 'z' => self as u32 - 'a' as u32 + 10, - 'A' ... 'Z' => self as u32 - 'A' as u32 + 10, - _ => return None, - }; - if val < radix { Some(val) } - else { None } - } - - #[inline] - fn escape_unicode(self) -> EscapeUnicode { - let c = self as u32; - - // or-ing 1 ensures that for c==0 the code computes that one - // digit should be printed and (which is the same) avoids the - // (31 - 32) underflow - let msb = 31 - (c | 1).leading_zeros(); - - // the index of the most significant hex digit - let ms_hex_digit = msb / 4; - EscapeUnicode { - c: self, - state: EscapeUnicodeState::Backslash, - hex_digit_idx: ms_hex_digit as usize, - } - } - - #[inline] - fn escape_default(self) -> EscapeDefault { - let init_state = match self { - '\t' => EscapeDefaultState::Backslash('t'), - '\r' => EscapeDefaultState::Backslash('r'), - '\n' => EscapeDefaultState::Backslash('n'), - '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), - '\x20' ... '\x7e' => EscapeDefaultState::Char(self), - _ => EscapeDefaultState::Unicode(self.escape_unicode()) - }; - EscapeDefault { state: init_state } - } - - #[inline] - fn escape_debug(self) -> EscapeDebug { - let init_state = match self { - '\t' => EscapeDefaultState::Backslash('t'), - '\r' => EscapeDefaultState::Backslash('r'), - '\n' => EscapeDefaultState::Backslash('n'), - '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), - c if is_printable(c) => EscapeDefaultState::Char(c), - c => EscapeDefaultState::Unicode(c.escape_unicode()), - }; - EscapeDebug(EscapeDefault { state: init_state }) - } - - #[inline] - fn len_utf8(self) -> usize { - let code = self as u32; - if code < MAX_ONE_B { - 1 - } else if code < MAX_TWO_B { - 2 - } else if code < MAX_THREE_B { - 3 - } else { - 4 - } - } - - #[inline] - fn len_utf16(self) -> usize { - let ch = self as u32; - if (ch & 0xFFFF) == ch { 1 } else { 2 } - } - - #[inline] - fn encode_utf8(self, dst: &mut [u8]) -> &mut str { - let code = self as u32; - unsafe { - let len = - if code < MAX_ONE_B && !dst.is_empty() { - *dst.get_unchecked_mut(0) = code as u8; - 1 - } else if code < MAX_TWO_B && dst.len() >= 2 { - *dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; - *dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT; - 2 - } else if code < MAX_THREE_B && dst.len() >= 3 { - *dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; - *dst.get_unchecked_mut(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT; - 3 - } else if dst.len() >= 4 { - *dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; - *dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT; - 4 - } else { - panic!("encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", - from_u32_unchecked(code).len_utf8(), - code, - dst.len()) - }; - from_utf8_unchecked_mut(dst.get_unchecked_mut(..len)) - } - } - - #[inline] - fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { - let mut code = self as u32; - unsafe { - if (code & 0xFFFF) == code && !dst.is_empty() { - // The BMP falls through (assuming non-surrogate, as it should) - *dst.get_unchecked_mut(0) = code as u16; - slice::from_raw_parts_mut(dst.as_mut_ptr(), 1) - } else if dst.len() >= 2 { - // Supplementary planes break into surrogates. - code -= 0x1_0000; - *dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16); - *dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF); - slice::from_raw_parts_mut(dst.as_mut_ptr(), 2) - } else { - panic!("encode_utf16: need {} units to encode U+{:X}, but the buffer has {}", - from_u32_unchecked(code).len_utf16(), - code, - dst.len()) - } - } - } -} - #[lang = "char"] impl char { /// Checks if a `char` is a digit in the given radix. @@ -211,7 +67,7 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_digit(self, radix: u32) -> bool { - C::is_digit(self, radix) + self.to_digit(radix).is_some() } /// Converts a `char` to a digit in the given radix. @@ -265,7 +121,17 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn to_digit(self, radix: u32) -> Option { - C::to_digit(self, radix) + if radix > 36 { + panic!("to_digit: radix is too high (maximum 36)"); + } + let val = match self { + '0' ... '9' => self as u32 - '0' as u32, + 'a' ... 'z' => self as u32 - 'a' as u32 + 10, + 'A' ... 'Z' => self as u32 - 'A' as u32 + 10, + _ => return None, + }; + if val < radix { Some(val) } + else { None } } /// Returns an iterator that yields the hexadecimal Unicode escape of a @@ -305,7 +171,20 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn escape_unicode(self) -> EscapeUnicode { - C::escape_unicode(self) + let c = self as u32; + + // or-ing 1 ensures that for c==0 the code computes that one + // digit should be printed and (which is the same) avoids the + // (31 - 32) underflow + let msb = 31 - (c | 1).leading_zeros(); + + // the index of the most significant hex digit + let ms_hex_digit = msb / 4; + EscapeUnicode { + c: self, + state: EscapeUnicodeState::Backslash, + hex_digit_idx: ms_hex_digit as usize, + } } /// Returns an iterator that yields the literal escape code of a character @@ -345,7 +224,15 @@ impl char { #[stable(feature = "char_escape_debug", since = "1.20.0")] #[inline] pub fn escape_debug(self) -> EscapeDebug { - C::escape_debug(self) + let init_state = match self { + '\t' => EscapeDefaultState::Backslash('t'), + '\r' => EscapeDefaultState::Backslash('r'), + '\n' => EscapeDefaultState::Backslash('n'), + '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), + c if is_printable(c) => EscapeDefaultState::Char(c), + c => EscapeDefaultState::Unicode(c.escape_unicode()), + }; + EscapeDebug(EscapeDefault { state: init_state }) } /// Returns an iterator that yields the literal escape code of a character @@ -400,7 +287,15 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn escape_default(self) -> EscapeDefault { - C::escape_default(self) + let init_state = match self { + '\t' => EscapeDefaultState::Backslash('t'), + '\r' => EscapeDefaultState::Backslash('r'), + '\n' => EscapeDefaultState::Backslash('n'), + '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), + '\x20' ... '\x7e' => EscapeDefaultState::Char(self), + _ => EscapeDefaultState::Unicode(self.escape_unicode()) + }; + EscapeDefault { state: init_state } } /// Returns the number of bytes this `char` would need if encoded in UTF-8. @@ -451,7 +346,16 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn len_utf8(self) -> usize { - C::len_utf8(self) + let code = self as u32; + if code < MAX_ONE_B { + 1 + } else if code < MAX_TWO_B { + 2 + } else if code < MAX_THREE_B { + 3 + } else { + 4 + } } /// Returns the number of 16-bit code units this `char` would need if @@ -476,7 +380,8 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn len_utf16(self) -> usize { - C::len_utf16(self) + let ch = self as u32; + if (ch & 0xFFFF) == ch { 1 } else { 2 } } /// Encodes this character as UTF-8 into the provided byte buffer, @@ -518,7 +423,35 @@ impl char { #[stable(feature = "unicode_encode_char", since = "1.15.0")] #[inline] pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str { - C::encode_utf8(self, dst) + let code = self as u32; + unsafe { + let len = + if code < MAX_ONE_B && !dst.is_empty() { + *dst.get_unchecked_mut(0) = code as u8; + 1 + } else if code < MAX_TWO_B && dst.len() >= 2 { + *dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; + *dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT; + 2 + } else if code < MAX_THREE_B && dst.len() >= 3 { + *dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; + *dst.get_unchecked_mut(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT; + 3 + } else if dst.len() >= 4 { + *dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; + *dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT; + *dst.get_unchecked_mut(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT; + 4 + } else { + panic!("encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", + from_u32_unchecked(code).len_utf8(), + code, + dst.len()) + }; + from_utf8_unchecked_mut(dst.get_unchecked_mut(..len)) + } } /// Encodes this character as UTF-16 into the provided `u16` buffer, @@ -558,7 +491,25 @@ impl char { #[stable(feature = "unicode_encode_char", since = "1.15.0")] #[inline] pub fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { - C::encode_utf16(self, dst) + let mut code = self as u32; + unsafe { + if (code & 0xFFFF) == code && !dst.is_empty() { + // The BMP falls through (assuming non-surrogate, as it should) + *dst.get_unchecked_mut(0) = code as u16; + slice::from_raw_parts_mut(dst.as_mut_ptr(), 1) + } else if dst.len() >= 2 { + // Supplementary planes break into surrogates. + code -= 0x1_0000; + *dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16); + *dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF); + slice::from_raw_parts_mut(dst.as_mut_ptr(), 2) + } else { + panic!("encode_utf16: need {} units to encode U+{:X}, but the buffer has {}", + from_u32_unchecked(code).len_utf16(), + code, + dst.len()) + } + } } /// Returns true if this `char` is an alphabetic code point, and false if not. diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index 7b4f0dc4548..c051a1ff8c8 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -119,34 +119,6 @@ pub const MAX: char = '\u{10ffff}'; #[stable(feature = "decode_utf16", since = "1.9.0")] pub const REPLACEMENT_CHARACTER: char = '\u{FFFD}'; -// NB: the stabilization and documentation for this trait is in -// unicode/char.rs, not here -#[allow(missing_docs)] // docs in libunicode/u_char.rs -#[doc(hidden)] -#[unstable(feature = "core_char_ext", - reason = "the stable interface is `impl char` in later crate", - issue = "32110")] -pub trait CharExt { - #[stable(feature = "core", since = "1.6.0")] - fn is_digit(self, radix: u32) -> bool; - #[stable(feature = "core", since = "1.6.0")] - fn to_digit(self, radix: u32) -> Option; - #[stable(feature = "core", since = "1.6.0")] - fn escape_unicode(self) -> EscapeUnicode; - #[stable(feature = "core", since = "1.6.0")] - fn escape_default(self) -> EscapeDefault; - #[stable(feature = "char_escape_debug", since = "1.20.0")] - fn escape_debug(self) -> EscapeDebug; - #[stable(feature = "core", since = "1.6.0")] - fn len_utf8(self) -> usize; - #[stable(feature = "core", since = "1.6.0")] - fn len_utf16(self) -> usize; - #[stable(feature = "unicode_encode_char", since = "1.15.0")] - fn encode_utf8(self, dst: &mut [u8]) -> &mut str; - #[stable(feature = "unicode_encode_char", since = "1.15.0")] - fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16]; -} - /// Returns an iterator that yields the hexadecimal Unicode escape of a /// character, as `char`s. /// diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index d43496c387c..cc3ad71117a 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -62,6 +62,3 @@ pub use slice::SliceExt; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use str::StrExt; -#[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] -pub use char::CharExt; diff --git a/src/libcore/unicode/str.rs b/src/libcore/unicode/str.rs index 18581bf4d58..0882984e077 100644 --- a/src/libcore/unicode/str.rs +++ b/src/libcore/unicode/str.rs @@ -9,9 +9,6 @@ // except according to those terms. //! Unicode-intensive string manipulations. -//! -//! This module provides functionality to `str` that requires the Unicode -//! methods provided by the unicode parts of the CharExt trait. use char; use iter::{Filter, FusedIterator}; @@ -109,7 +106,7 @@ impl Iterator for Utf16Encoder let mut buf = [0; 2]; self.chars.next().map(|ch| { - let n = CharExt::encode_utf16(ch, &mut buf).len(); + let n = ch.encode_utf16(&mut buf).len(); if n == 2 { self.extra = buf[1]; } diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs index 7e8e925bda3..1f7b1bde914 100644 --- a/src/libcore/unicode/tables.rs +++ b/src/libcore/unicode/tables.rs @@ -16,7 +16,7 @@ use unicode::version::UnicodeVersion; use unicode::bool_trie::{BoolTrie, SmallBoolTrie}; /// The version of [Unicode](http://www.unicode.org/) that the Unicode parts of -/// `CharExt` and `UnicodeStrPrelude` traits are based on. +/// `char` and `str` methods are based on. pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { major: 10, minor: 0, diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py index 39b68dc7d9b..82262cc7662 100755 --- a/src/libcore/unicode/unicode.py +++ b/src/libcore/unicode/unicode.py @@ -470,7 +470,7 @@ if __name__ == "__main__": unicode_version = re.search(pattern, readme.read()).groups() rf.write(""" /// The version of [Unicode](http://www.unicode.org/) that the Unicode parts of -/// `CharExt` and `UnicodeStrPrelude` traits are based on. +/// `char` and `str` methods are based on. pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { major: %s, minor: %s, -- cgit 1.4.1-3-g733a5 From 0d9afcd9b9f881545c8b722855f7e39361495d27 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 5 Apr 2018 19:00:48 +0200 Subject: Merge core::unicode::str into core::str And the UnicodeStr trait into StrExt --- src/liballoc/str.rs | 16 ++-- src/liballoc/tests/str.rs | 2 +- src/libcore/str/mod.rs | 116 +++++++++++++++++++++++++++- src/libcore/unicode/mod.rs | 60 ++++++++++++++- src/libcore/unicode/str.rs | 186 --------------------------------------------- 5 files changed, 182 insertions(+), 198 deletions(-) delete mode 100644 src/libcore/unicode/str.rs (limited to 'src/libcore') diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index eaca9eb49f9..0b961c2c186 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -45,7 +45,7 @@ use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; use core::ptr; use core::iter::FusedIterator; -use core::unicode::str::{UnicodeStr, Utf16Encoder}; +use core::unicode::Utf16Encoder; use vec_deque::VecDeque; use borrow::{Borrow, ToOwned}; @@ -74,7 +74,7 @@ pub use core::str::{from_utf8, from_utf8_mut, Chars, CharIndices, Bytes}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::unicode::str::SplitWhitespace; +pub use core::str::SplitWhitespace; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::pattern; @@ -800,7 +800,7 @@ impl str { #[stable(feature = "split_whitespace", since = "1.1.0")] #[inline] pub fn split_whitespace(&self) -> SplitWhitespace { - UnicodeStr::split_whitespace(self) + StrExt::split_whitespace(self) } /// An iterator over the lines of a string, as string slices. @@ -1570,7 +1570,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim(&self) -> &str { - UnicodeStr::trim(self) + StrExt::trim(self) } /// Returns a string slice with leading whitespace removed. @@ -1606,7 +1606,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim_left(&self) -> &str { - UnicodeStr::trim_left(self) + StrExt::trim_left(self) } /// Returns a string slice with trailing whitespace removed. @@ -1642,7 +1642,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim_right(&self) -> &str { - UnicodeStr::trim_right(self) + StrExt::trim_right(self) } /// Returns a string slice with all prefixes and suffixes that match a @@ -2141,7 +2141,7 @@ impl str { #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")] #[inline] pub fn is_whitespace(&self) -> bool { - UnicodeStr::is_whitespace(self) + StrExt::is_whitespace(self) } /// Returns true if this `str` is entirely alphanumeric, and false otherwise. @@ -2160,7 +2160,7 @@ impl str { #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")] #[inline] pub fn is_alphanumeric(&self) -> bool { - UnicodeStr::is_alphanumeric(self) + StrExt::is_alphanumeric(self) } /// Checks if all characters in this string are within the ASCII range. diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index 763dbe675b9..2df8ca63a3e 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -1204,7 +1204,7 @@ fn test_rev_split_char_iterator_no_trailing() { #[test] fn test_utf16_code_units() { - use core::unicode::str::Utf16Encoder; + use core::unicode::Utf16Encoder; assert_eq!(Utf16Encoder::new(vec!['é', '\u{1F4A9}'].into_iter()).collect::>(), [0xE9, 0xD83D, 0xDCA9]) } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 7a97d89dcf9..f1fe23092de 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -19,7 +19,7 @@ use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use char; use fmt; -use iter::{Map, Cloned, FusedIterator, TrustedLen}; +use iter::{Map, Cloned, FusedIterator, TrustedLen, Filter}; use iter_private::TrustedRandomAccess; use slice::{self, SliceIndex}; use mem; @@ -2216,6 +2216,18 @@ pub trait StrExt { fn is_empty(&self) -> bool; #[stable(feature = "core", since = "1.6.0")] fn parse(&self) -> Result; + #[stable(feature = "split_whitespace", since = "1.1.0")] + fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>; + #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")] + fn is_whitespace(&self) -> bool; + #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")] + fn is_alphanumeric(&self) -> bool; + #[stable(feature = "rust1", since = "1.0.0")] + fn trim(&self) -> &str; + #[stable(feature = "rust1", since = "1.0.0")] + fn trim_left(&self) -> &str; + #[stable(feature = "rust1", since = "1.0.0")] + fn trim_right(&self) -> &str; } // truncate `&str` to length at most equal to `max` @@ -2536,6 +2548,36 @@ impl StrExt for str { #[inline] fn parse(&self) -> Result { FromStr::from_str(self) } + + #[inline] + fn split_whitespace(&self) -> SplitWhitespace { + SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } + } + + #[inline] + fn is_whitespace(&self) -> bool { + self.chars().all(|c| c.is_whitespace()) + } + + #[inline] + fn is_alphanumeric(&self) -> bool { + self.chars().all(|c| c.is_alphanumeric()) + } + + #[inline] + fn trim(&self) -> &str { + self.trim_matches(|c: char| c.is_whitespace()) + } + + #[inline] + fn trim_left(&self) -> &str { + self.trim_left_matches(|c: char| c.is_whitespace()) + } + + #[inline] + fn trim_right(&self) -> &str { + self.trim_right_matches(|c: char| c.is_whitespace()) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -2551,3 +2593,75 @@ impl<'a> Default for &'a str { /// Creates an empty str fn default() -> &'a str { "" } } + +/// An iterator over the non-whitespace substrings of a string, +/// separated by any amount of whitespace. +/// +/// This struct is created by the [`split_whitespace`] method on [`str`]. +/// See its documentation for more. +/// +/// [`split_whitespace`]: ../../std/primitive.str.html#method.split_whitespace +/// [`str`]: ../../std/primitive.str.html +#[stable(feature = "split_whitespace", since = "1.1.0")] +#[derive(Clone, Debug)] +pub struct SplitWhitespace<'a> { + inner: Filter, IsNotEmpty>, +} + +#[derive(Clone)] +struct IsWhitespace; + +impl FnOnce<(char, )> for IsWhitespace { + type Output = bool; + + #[inline] + extern "rust-call" fn call_once(mut self, arg: (char, )) -> bool { + self.call_mut(arg) + } +} + +impl FnMut<(char, )> for IsWhitespace { + #[inline] + extern "rust-call" fn call_mut(&mut self, arg: (char, )) -> bool { + arg.0.is_whitespace() + } +} + +#[derive(Clone)] +struct IsNotEmpty; + +impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty { + type Output = bool; + + #[inline] + extern "rust-call" fn call_once(mut self, arg: (&&str, )) -> bool { + self.call_mut(arg) + } +} + +impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty { + #[inline] + extern "rust-call" fn call_mut(&mut self, arg: (&&str, )) -> bool { + !arg.0.is_empty() + } +} + + +#[stable(feature = "split_whitespace", since = "1.1.0")] +impl<'a> Iterator for SplitWhitespace<'a> { + type Item = &'a str; + + fn next(&mut self) -> Option<&'a str> { + self.inner.next() + } +} + +#[stable(feature = "split_whitespace", since = "1.1.0")] +impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { + fn next_back(&mut self) -> Option<&'a str> { + self.inner.next_back() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a> FusedIterator for SplitWhitespace<'a> {} diff --git a/src/libcore/unicode/mod.rs b/src/libcore/unicode/mod.rs index 060c55286fe..3413476fd22 100644 --- a/src/libcore/unicode/mod.rs +++ b/src/libcore/unicode/mod.rs @@ -15,8 +15,6 @@ mod bool_trie; pub(crate) mod tables; pub(crate) mod version; -pub mod str; - // For use in liballoc, not re-exported in libstd. pub mod derived_property { pub use unicode::tables::derived_property::{Case_Ignorable, Cased}; @@ -26,3 +24,61 @@ pub mod derived_property { pub mod property { pub use unicode::tables::property::Pattern_White_Space; } + +use iter::FusedIterator; + +/// Iterator adaptor for encoding `char`s to UTF-16. +#[derive(Clone)] +#[allow(missing_debug_implementations)] +pub struct Utf16Encoder { + chars: I, + extra: u16, +} + +impl Utf16Encoder { + /// Create a UTF-16 encoder from any `char` iterator. + pub fn new(chars: I) -> Utf16Encoder + where I: Iterator + { + Utf16Encoder { + chars, + extra: 0, + } + } +} + +impl Iterator for Utf16Encoder + where I: Iterator +{ + type Item = u16; + + #[inline] + fn next(&mut self) -> Option { + if self.extra != 0 { + let tmp = self.extra; + self.extra = 0; + return Some(tmp); + } + + let mut buf = [0; 2]; + self.chars.next().map(|ch| { + let n = ch.encode_utf16(&mut buf).len(); + if n == 2 { + self.extra = buf[1]; + } + buf[0] + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (low, high) = self.chars.size_hint(); + // every char gets either one u16 or two u16, + // so this iterator is between 1 or 2 times as + // long as the underlying iterator. + (low, high.and_then(|n| n.checked_mul(2))) + } +} + +impl FusedIterator for Utf16Encoder + where I: FusedIterator {} diff --git a/src/libcore/unicode/str.rs b/src/libcore/unicode/str.rs deleted file mode 100644 index 0882984e077..00000000000 --- a/src/libcore/unicode/str.rs +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unicode-intensive string manipulations. - -use char; -use iter::{Filter, FusedIterator}; -use str::Split; - -/// An iterator over the non-whitespace substrings of a string, -/// separated by any amount of whitespace. -/// -/// This struct is created by the [`split_whitespace`] method on [`str`]. -/// See its documentation for more. -/// -/// [`split_whitespace`]: ../../std/primitive.str.html#method.split_whitespace -/// [`str`]: ../../std/primitive.str.html -#[stable(feature = "split_whitespace", since = "1.1.0")] -#[derive(Clone, Debug)] -pub struct SplitWhitespace<'a> { - inner: Filter, IsNotEmpty>, -} - -/// Methods for Unicode string slices -#[allow(missing_docs)] // docs in liballoc -pub trait UnicodeStr { - fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>; - fn is_whitespace(&self) -> bool; - fn is_alphanumeric(&self) -> bool; - fn trim(&self) -> &str; - fn trim_left(&self) -> &str; - fn trim_right(&self) -> &str; -} - -impl UnicodeStr for str { - #[inline] - fn split_whitespace(&self) -> SplitWhitespace { - SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } - } - - #[inline] - fn is_whitespace(&self) -> bool { - self.chars().all(|c| c.is_whitespace()) - } - - #[inline] - fn is_alphanumeric(&self) -> bool { - self.chars().all(|c| c.is_alphanumeric()) - } - - #[inline] - fn trim(&self) -> &str { - self.trim_matches(|c: char| c.is_whitespace()) - } - - #[inline] - fn trim_left(&self) -> &str { - self.trim_left_matches(|c: char| c.is_whitespace()) - } - - #[inline] - fn trim_right(&self) -> &str { - self.trim_right_matches(|c: char| c.is_whitespace()) - } -} - -/// Iterator adaptor for encoding `char`s to UTF-16. -#[derive(Clone)] -#[allow(missing_debug_implementations)] -pub struct Utf16Encoder { - chars: I, - extra: u16, -} - -impl Utf16Encoder { - /// Create a UTF-16 encoder from any `char` iterator. - pub fn new(chars: I) -> Utf16Encoder - where I: Iterator - { - Utf16Encoder { - chars, - extra: 0, - } - } -} - -impl Iterator for Utf16Encoder - where I: Iterator -{ - type Item = u16; - - #[inline] - fn next(&mut self) -> Option { - if self.extra != 0 { - let tmp = self.extra; - self.extra = 0; - return Some(tmp); - } - - let mut buf = [0; 2]; - self.chars.next().map(|ch| { - let n = ch.encode_utf16(&mut buf).len(); - if n == 2 { - self.extra = buf[1]; - } - buf[0] - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (low, high) = self.chars.size_hint(); - // every char gets either one u16 or two u16, - // so this iterator is between 1 or 2 times as - // long as the underlying iterator. - (low, high.and_then(|n| n.checked_mul(2))) - } -} - -impl FusedIterator for Utf16Encoder - where I: FusedIterator {} - -#[derive(Clone)] -struct IsWhitespace; - -impl FnOnce<(char, )> for IsWhitespace { - type Output = bool; - - #[inline] - extern "rust-call" fn call_once(mut self, arg: (char, )) -> bool { - self.call_mut(arg) - } -} - -impl FnMut<(char, )> for IsWhitespace { - #[inline] - extern "rust-call" fn call_mut(&mut self, arg: (char, )) -> bool { - arg.0.is_whitespace() - } -} - -#[derive(Clone)] -struct IsNotEmpty; - -impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty { - type Output = bool; - - #[inline] - extern "rust-call" fn call_once(mut self, arg: (&&str, )) -> bool { - self.call_mut(arg) - } -} - -impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty { - #[inline] - extern "rust-call" fn call_mut(&mut self, arg: (&&str, )) -> bool { - !arg.0.is_empty() - } -} - - -#[stable(feature = "split_whitespace", since = "1.1.0")] -impl<'a> Iterator for SplitWhitespace<'a> { - type Item = &'a str; - - fn next(&mut self) -> Option<&'a str> { - self.inner.next() - } -} - -#[stable(feature = "split_whitespace", since = "1.1.0")] -impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { - fn next_back(&mut self) -> Option<&'a str> { - self.inner.next_back() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a> FusedIterator for SplitWhitespace<'a> {} -- cgit 1.4.1-3-g733a5 From d4ed1e6fa4978141408ef01d0d35c7bd142dd164 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 6 Apr 2018 10:24:01 +0200 Subject: Merge unstable Utf16Encoder into EncodeUtf16 --- src/liballoc/str.rs | 27 +++++++++++++++++---- src/liballoc/tests/str.rs | 3 +-- src/libcore/unicode/mod.rs | 58 ---------------------------------------------- 3 files changed, 23 insertions(+), 65 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 0b961c2c186..65df93bd3bb 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -45,7 +45,6 @@ use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; use core::ptr; use core::iter::FusedIterator; -use core::unicode::Utf16Encoder; use vec_deque::VecDeque; use borrow::{Borrow, ToOwned}; @@ -146,7 +145,8 @@ impl> SliceConcatExt for [S] { #[derive(Clone)] #[stable(feature = "encode_utf16", since = "1.8.0")] pub struct EncodeUtf16<'a> { - encoder: Utf16Encoder>, + chars: Chars<'a>, + extra: u16, } #[stable(feature = "collection_debug", since = "1.17.0")] @@ -162,12 +162,29 @@ impl<'a> Iterator for EncodeUtf16<'a> { #[inline] fn next(&mut self) -> Option { - self.encoder.next() + if self.extra != 0 { + let tmp = self.extra; + self.extra = 0; + return Some(tmp); + } + + let mut buf = [0; 2]; + self.chars.next().map(|ch| { + let n = ch.encode_utf16(&mut buf).len(); + if n == 2 { + self.extra = buf[1]; + } + buf[0] + }) } #[inline] fn size_hint(&self) -> (usize, Option) { - self.encoder.size_hint() + let (low, high) = self.chars.size_hint(); + // every char gets either one u16 or two u16, + // so this iterator is between 1 or 2 times as + // long as the underlying iterator. + (low, high.and_then(|n| n.checked_mul(2))) } } @@ -870,7 +887,7 @@ impl str { /// ``` #[stable(feature = "encode_utf16", since = "1.8.0")] pub fn encode_utf16(&self) -> EncodeUtf16 { - EncodeUtf16 { encoder: Utf16Encoder::new(self[..].chars()) } + EncodeUtf16 { chars: self[..].chars(), extra: 0 } } /// Returns `true` if the given pattern matches a sub-slice of diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index 2df8ca63a3e..a3f4c385fe2 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -1204,8 +1204,7 @@ fn test_rev_split_char_iterator_no_trailing() { #[test] fn test_utf16_code_units() { - use core::unicode::Utf16Encoder; - assert_eq!(Utf16Encoder::new(vec!['é', '\u{1F4A9}'].into_iter()).collect::>(), + assert_eq!("é\u{1F4A9}".encode_utf16().collect::>(), [0xE9, 0xD83D, 0xDCA9]) } diff --git a/src/libcore/unicode/mod.rs b/src/libcore/unicode/mod.rs index 3413476fd22..9ab8cb748b1 100644 --- a/src/libcore/unicode/mod.rs +++ b/src/libcore/unicode/mod.rs @@ -24,61 +24,3 @@ pub mod derived_property { pub mod property { pub use unicode::tables::property::Pattern_White_Space; } - -use iter::FusedIterator; - -/// Iterator adaptor for encoding `char`s to UTF-16. -#[derive(Clone)] -#[allow(missing_debug_implementations)] -pub struct Utf16Encoder { - chars: I, - extra: u16, -} - -impl Utf16Encoder { - /// Create a UTF-16 encoder from any `char` iterator. - pub fn new(chars: I) -> Utf16Encoder - where I: Iterator - { - Utf16Encoder { - chars, - extra: 0, - } - } -} - -impl Iterator for Utf16Encoder - where I: Iterator -{ - type Item = u16; - - #[inline] - fn next(&mut self) -> Option { - if self.extra != 0 { - let tmp = self.extra; - self.extra = 0; - return Some(tmp); - } - - let mut buf = [0; 2]; - self.chars.next().map(|ch| { - let n = ch.encode_utf16(&mut buf).len(); - if n == 2 { - self.extra = buf[1]; - } - buf[0] - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (low, high) = self.chars.size_hint(); - // every char gets either one u16 or two u16, - // so this iterator is between 1 or 2 times as - // long as the underlying iterator. - (low, high.and_then(|n| n.checked_mul(2))) - } -} - -impl FusedIterator for Utf16Encoder - where I: FusedIterator {} -- cgit 1.4.1-3-g733a5 From 670e85339a5014ad6fde02beb0603d2e12027a89 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 6 Apr 2018 10:26:57 +0200 Subject: Move core::char::printable to core::unicode::printable --- src/libcore/char/methods.rs | 2 +- src/libcore/char/mod.rs | 1 - src/libcore/char/printable.py | 254 ------------------- src/libcore/char/printable.rs | 531 --------------------------------------- src/libcore/unicode/mod.rs | 1 + src/libcore/unicode/printable.py | 254 +++++++++++++++++++ src/libcore/unicode/printable.rs | 531 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 787 insertions(+), 787 deletions(-) delete mode 100644 src/libcore/char/printable.py delete mode 100644 src/libcore/char/printable.rs create mode 100644 src/libcore/unicode/printable.py create mode 100644 src/libcore/unicode/printable.rs (limited to 'src/libcore') diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 2c433a7ac9e..374adafef64 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -13,7 +13,7 @@ use slice; use str::from_utf8_unchecked_mut; use super::*; -use super::printable::is_printable; +use unicode::printable::is_printable; use unicode::tables::{conversions, derived_property, general_category, property}; #[lang = "char"] diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index c051a1ff8c8..b2af95eb5ba 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -32,7 +32,6 @@ mod convert; mod decode; mod methods; -mod printable; // stable re-exports #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/char/printable.py b/src/libcore/char/printable.py deleted file mode 100644 index 484822e10aa..00000000000 --- a/src/libcore/char/printable.py +++ /dev/null @@ -1,254 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2011-2016 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -# This script uses the following Unicode tables: -# - UnicodeData.txt - - -from collections import namedtuple -import csv -import os -import subprocess - -NUM_CODEPOINTS=0x110000 - -def to_ranges(iter): - current = None - for i in iter: - if current is None or i != current[1] or i in (0x10000, 0x20000): - if current is not None: - yield tuple(current) - current = [i, i + 1] - else: - current[1] += 1 - if current is not None: - yield tuple(current) - -def get_escaped(codepoints): - for c in codepoints: - if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord(' '): - yield c.value - -def get_file(f): - try: - return open(os.path.basename(f)) - except FileNotFoundError: - subprocess.run(["curl", "-O", f], check=True) - return open(os.path.basename(f)) - -Codepoint = namedtuple('Codepoint', 'value class_') - -def get_codepoints(f): - r = csv.reader(f, delimiter=";") - prev_codepoint = 0 - class_first = None - for row in r: - codepoint = int(row[0], 16) - name = row[1] - class_ = row[2] - - if class_first is not None: - if not name.endswith("Last>"): - raise ValueError("Missing Last after First") - - for c in range(prev_codepoint + 1, codepoint): - yield Codepoint(c, class_first) - - class_first = None - if name.endswith("First>"): - class_first = class_ - - yield Codepoint(codepoint, class_) - prev_codepoint = codepoint - - if class_first != None: - raise ValueError("Missing Last after First") - - for c in range(prev_codepoint + 1, NUM_CODEPOINTS): - yield Codepoint(c, None) - -def compress_singletons(singletons): - uppers = [] # (upper, # items in lowers) - lowers = [] - - for i in singletons: - upper = i >> 8 - lower = i & 0xff - if len(uppers) == 0 or uppers[-1][0] != upper: - uppers.append((upper, 1)) - else: - upper, count = uppers[-1] - uppers[-1] = upper, count + 1 - lowers.append(lower) - - return uppers, lowers - -def compress_normal(normal): - # lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f - # lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff - compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)] - - prev_start = 0 - for start, count in normal: - truelen = start - prev_start - falselen = count - prev_start = start + count - - assert truelen < 0x8000 and falselen < 0x8000 - entry = [] - if truelen > 0x7f: - entry.append(0x80 | (truelen >> 8)) - entry.append(truelen & 0xff) - else: - entry.append(truelen & 0x7f) - if falselen > 0x7f: - entry.append(0x80 | (falselen >> 8)) - entry.append(falselen & 0xff) - else: - entry.append(falselen & 0x7f) - - compressed.append(entry) - - return compressed - -def print_singletons(uppers, lowers, uppersname, lowersname): - print("const {}: &'static [(u8, u8)] = &[".format(uppersname)) - for u, c in uppers: - print(" ({:#04x}, {}),".format(u, c)) - print("];") - print("const {}: &'static [u8] = &[".format(lowersname)) - for i in range(0, len(lowers), 8): - print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8]))) - print("];") - -def print_normal(normal, normalname): - print("const {}: &'static [u8] = &[".format(normalname)) - for v in normal: - print(" {}".format(" ".join("{:#04x},".format(i) for i in v))) - print("];") - -def main(): - file = get_file("http://www.unicode.org/Public/UNIDATA/UnicodeData.txt") - - codepoints = get_codepoints(file) - - CUTOFF=0x10000 - singletons0 = [] - singletons1 = [] - normal0 = [] - normal1 = [] - extra = [] - - for a, b in to_ranges(get_escaped(codepoints)): - if a > 2 * CUTOFF: - extra.append((a, b - a)) - elif a == b - 1: - if a & CUTOFF: - singletons1.append(a & ~CUTOFF) - else: - singletons0.append(a) - elif a == b - 2: - if a & CUTOFF: - singletons1.append(a & ~CUTOFF) - singletons1.append((a + 1) & ~CUTOFF) - else: - singletons0.append(a) - singletons0.append(a + 1) - else: - if a >= 2 * CUTOFF: - extra.append((a, b - a)) - elif a & CUTOFF: - normal1.append((a & ~CUTOFF, b - a)) - else: - normal0.append((a, b - a)) - - singletons0u, singletons0l = compress_singletons(singletons0) - singletons1u, singletons1l = compress_singletons(singletons1) - normal0 = compress_normal(normal0) - normal1 = compress_normal(normal1) - - print("""\ -// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// NOTE: The following code was generated by "src/libcore/char/printable.py", -// do not edit directly! - -fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], - normal: &[u8]) -> bool { - let xupper = (x >> 8) as u8; - let mut lowerstart = 0; - for &(upper, lowercount) in singletonuppers { - let lowerend = lowerstart + lowercount as usize; - if xupper == upper { - for &lower in &singletonlowers[lowerstart..lowerend] { - if lower == x as u8 { - return false; - } - } - } else if xupper < upper { - break; - } - lowerstart = lowerend; - } - - let mut x = x as i32; - let mut normal = normal.iter().cloned(); - let mut current = true; - while let Some(v) = normal.next() { - let len = if v & 0x80 != 0 { - ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32 - } else { - v as i32 - }; - x -= len; - if x < 0 { - break; - } - current = !current; - } - current -} - -pub(crate) fn is_printable(x: char) -> bool { - let x = x as u32; - let lower = x as u16; - if x < 0x10000 { - check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) - } else if x < 0x20000 { - check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) - } else {\ -""") - for a, b in extra: - print(" if 0x{:x} <= x && x < 0x{:x} {{".format(a, a + b)) - print(" return false;") - print(" }") - print("""\ - true - } -}\ -""") - print() - print_singletons(singletons0u, singletons0l, 'SINGLETONS0U', 'SINGLETONS0L') - print_singletons(singletons1u, singletons1l, 'SINGLETONS1U', 'SINGLETONS1L') - print_normal(normal0, 'NORMAL0') - print_normal(normal1, 'NORMAL1') - -if __name__ == '__main__': - main() diff --git a/src/libcore/char/printable.rs b/src/libcore/char/printable.rs deleted file mode 100644 index ce011fab187..00000000000 --- a/src/libcore/char/printable.rs +++ /dev/null @@ -1,531 +0,0 @@ -// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// NOTE: The following code was generated by "src/libcore/char/printable.py", -// do not edit directly! - -fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], - normal: &[u8]) -> bool { - let xupper = (x >> 8) as u8; - let mut lowerstart = 0; - for &(upper, lowercount) in singletonuppers { - let lowerend = lowerstart + lowercount as usize; - if xupper == upper { - for &lower in &singletonlowers[lowerstart..lowerend] { - if lower == x as u8 { - return false; - } - } - } else if xupper < upper { - break; - } - lowerstart = lowerend; - } - - let mut x = x as i32; - let mut normal = normal.iter().cloned(); - let mut current = true; - while let Some(v) = normal.next() { - let len = if v & 0x80 != 0 { - ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32 - } else { - v as i32 - }; - x -= len; - if x < 0 { - break; - } - current = !current; - } - current -} - -pub(crate) fn is_printable(x: char) -> bool { - let x = x as u32; - let lower = x as u16; - if x < 0x10000 { - check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) - } else if x < 0x20000 { - check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) - } else { - if 0x2a6d7 <= x && x < 0x2a700 { - return false; - } - if 0x2b735 <= x && x < 0x2b740 { - return false; - } - if 0x2b81e <= x && x < 0x2b820 { - return false; - } - if 0x2cea2 <= x && x < 0x2ceb0 { - return false; - } - if 0x2ebe1 <= x && x < 0x2f800 { - return false; - } - if 0x2fa1e <= x && x < 0xe0100 { - return false; - } - if 0xe01f0 <= x && x < 0x110000 { - return false; - } - true - } -} - -const SINGLETONS0U: &'static [(u8, u8)] = &[ - (0x00, 1), - (0x03, 5), - (0x05, 8), - (0x06, 3), - (0x07, 4), - (0x08, 8), - (0x09, 16), - (0x0a, 27), - (0x0b, 25), - (0x0c, 22), - (0x0d, 18), - (0x0e, 22), - (0x0f, 4), - (0x10, 3), - (0x12, 18), - (0x13, 9), - (0x16, 1), - (0x17, 5), - (0x18, 2), - (0x19, 3), - (0x1a, 7), - (0x1d, 1), - (0x1f, 22), - (0x20, 3), - (0x2b, 5), - (0x2c, 2), - (0x2d, 11), - (0x2e, 1), - (0x30, 3), - (0x31, 3), - (0x32, 2), - (0xa7, 1), - (0xa8, 2), - (0xa9, 2), - (0xaa, 4), - (0xab, 8), - (0xfa, 2), - (0xfb, 5), - (0xfd, 4), - (0xfe, 3), - (0xff, 9), -]; -const SINGLETONS0L: &'static [u8] = &[ - 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, - 0x58, 0x60, 0x88, 0x8b, 0x8c, 0x90, 0x1c, 0x1d, - 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0x2e, 0x2f, 0x3f, - 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, - 0x91, 0x92, 0xa9, 0xb1, 0xba, 0xbb, 0xc5, 0xc6, - 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0x04, 0x11, 0x12, - 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, - 0x4a, 0x5d, 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, - 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, 0xe4, 0xe5, - 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, - 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, - 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, 0xc9, 0xce, - 0xcf, 0x04, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, - 0x64, 0x65, 0x84, 0x8d, 0x91, 0xa9, 0xb4, 0xba, - 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x04, - 0x0d, 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x81, - 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, 0xd7, 0xf0, - 0xf1, 0x83, 0x85, 0x86, 0x89, 0x8b, 0x8c, 0x98, - 0xa0, 0xa4, 0xa6, 0xa8, 0xa9, 0xac, 0xba, 0xbe, - 0xbf, 0xc5, 0xc7, 0xce, 0xcf, 0xda, 0xdb, 0x48, - 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, 0x4e, - 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, - 0xb1, 0xb6, 0xb7, 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, - 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe, - 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, - 0x0f, 0x1f, 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, - 0x7e, 0xae, 0xaf, 0xfa, 0x16, 0x17, 0x1e, 0x1f, - 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, - 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, - 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0x74, 0x75, 0x96, - 0x97, 0xc9, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, - 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, - 0x40, 0x97, 0x98, 0x2f, 0x30, 0x8f, 0x1f, 0xff, - 0xaf, 0xfe, 0xff, 0xce, 0xff, 0x4e, 0x4f, 0x5a, - 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, - 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, - 0x90, 0x91, 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, - 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff, -]; -const SINGLETONS1U: &'static [(u8, u8)] = &[ - (0x00, 6), - (0x01, 1), - (0x03, 1), - (0x04, 2), - (0x08, 8), - (0x09, 2), - (0x0a, 3), - (0x0b, 2), - (0x10, 1), - (0x11, 4), - (0x12, 5), - (0x13, 18), - (0x14, 2), - (0x15, 2), - (0x1a, 3), - (0x1c, 5), - (0x1d, 4), - (0x24, 1), - (0x6a, 3), - (0x6b, 2), - (0xbc, 2), - (0xd1, 2), - (0xd4, 12), - (0xd5, 9), - (0xd6, 2), - (0xd7, 2), - (0xda, 1), - (0xe0, 5), - (0xe8, 2), - (0xee, 32), - (0xf0, 4), - (0xf1, 1), - (0xf9, 1), -]; -const SINGLETONS1L: &'static [u8] = &[ - 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, - 0x9e, 0x9f, 0x06, 0x07, 0x09, 0x36, 0x3d, 0x3e, - 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x56, - 0x57, 0xbd, 0x35, 0xce, 0xcf, 0xe0, 0x12, 0x87, - 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, - 0x29, 0x31, 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, - 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5a, 0x5c, 0xb6, - 0xb7, 0x84, 0x85, 0x9d, 0x09, 0x37, 0x90, 0x91, - 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x6f, 0x5f, 0xee, - 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, 0x28, 0x55, - 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, - 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, - 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, 0xcd, - 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0xc5, 0xc6, - 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, - 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53, 0x55, 0x56, - 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, - 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, - 0xaf, 0xb0, 0xc0, 0xd0, 0x2f, 0x3f, -]; -const NORMAL0: &'static [u8] = &[ - 0x00, 0x20, - 0x5f, 0x22, - 0x82, 0xdf, 0x04, - 0x82, 0x44, 0x08, - 0x1b, 0x05, - 0x05, 0x11, - 0x81, 0xac, 0x0e, - 0x3b, 0x05, - 0x6b, 0x35, - 0x1e, 0x16, - 0x80, 0xdf, 0x03, - 0x19, 0x08, - 0x01, 0x04, - 0x22, 0x03, - 0x0a, 0x04, - 0x34, 0x04, - 0x07, 0x03, - 0x01, 0x07, - 0x06, 0x07, - 0x10, 0x0b, - 0x50, 0x0f, - 0x12, 0x07, - 0x55, 0x08, - 0x02, 0x04, - 0x1c, 0x0a, - 0x09, 0x03, - 0x08, 0x03, - 0x07, 0x03, - 0x02, 0x03, - 0x03, 0x03, - 0x0c, 0x04, - 0x05, 0x03, - 0x0b, 0x06, - 0x01, 0x0e, - 0x15, 0x05, - 0x3a, 0x03, - 0x11, 0x07, - 0x06, 0x05, - 0x10, 0x08, - 0x56, 0x07, - 0x02, 0x07, - 0x15, 0x0d, - 0x50, 0x04, - 0x43, 0x03, - 0x2d, 0x03, - 0x01, 0x04, - 0x11, 0x06, - 0x0f, 0x0c, - 0x3a, 0x04, - 0x1d, 0x25, - 0x0d, 0x06, - 0x4c, 0x20, - 0x6d, 0x04, - 0x6a, 0x25, - 0x80, 0xc8, 0x05, - 0x82, 0xb0, 0x03, - 0x1a, 0x06, - 0x82, 0xfd, 0x03, - 0x59, 0x07, - 0x15, 0x0b, - 0x17, 0x09, - 0x14, 0x0c, - 0x14, 0x0c, - 0x6a, 0x06, - 0x0a, 0x06, - 0x1a, 0x06, - 0x58, 0x08, - 0x2b, 0x05, - 0x46, 0x0a, - 0x2c, 0x04, - 0x0c, 0x04, - 0x01, 0x03, - 0x31, 0x0b, - 0x2c, 0x04, - 0x1a, 0x06, - 0x0b, 0x03, - 0x80, 0xac, 0x06, - 0x0a, 0x06, - 0x1f, 0x41, - 0x4c, 0x04, - 0x2d, 0x03, - 0x74, 0x08, - 0x3c, 0x03, - 0x0f, 0x03, - 0x3c, 0x37, - 0x08, 0x08, - 0x2a, 0x06, - 0x82, 0xff, 0x11, - 0x18, 0x08, - 0x2f, 0x11, - 0x2d, 0x03, - 0x20, 0x10, - 0x21, 0x0f, - 0x80, 0x8c, 0x04, - 0x82, 0x97, 0x19, - 0x0b, 0x15, - 0x87, 0x5a, 0x03, - 0x16, 0x19, - 0x04, 0x10, - 0x80, 0xf4, 0x05, - 0x2f, 0x05, - 0x3b, 0x07, - 0x02, 0x0e, - 0x18, 0x09, - 0x80, 0xaa, 0x36, - 0x74, 0x0c, - 0x80, 0xd6, 0x1a, - 0x0c, 0x05, - 0x80, 0xff, 0x05, - 0x80, 0xb6, 0x05, - 0x24, 0x0c, - 0x9b, 0xc6, 0x0a, - 0xd2, 0x2b, 0x15, - 0x84, 0x8d, 0x03, - 0x37, 0x09, - 0x81, 0x5c, 0x14, - 0x80, 0xb8, 0x08, - 0x80, 0xb8, 0x3f, - 0x35, 0x04, - 0x0a, 0x06, - 0x38, 0x08, - 0x46, 0x08, - 0x0c, 0x06, - 0x74, 0x0b, - 0x1e, 0x03, - 0x5a, 0x04, - 0x59, 0x09, - 0x80, 0x83, 0x18, - 0x1c, 0x0a, - 0x16, 0x09, - 0x46, 0x0a, - 0x80, 0x8a, 0x06, - 0xab, 0xa4, 0x0c, - 0x17, 0x04, - 0x31, 0xa1, 0x04, - 0x81, 0xda, 0x26, - 0x07, 0x0c, - 0x05, 0x05, - 0x80, 0xa5, 0x11, - 0x81, 0x6d, 0x10, - 0x78, 0x28, - 0x2a, 0x06, - 0x4c, 0x04, - 0x80, 0x8d, 0x04, - 0x80, 0xbe, 0x03, - 0x1b, 0x03, - 0x0f, 0x0d, -]; -const NORMAL1: &'static [u8] = &[ - 0x5e, 0x22, - 0x7b, 0x05, - 0x03, 0x04, - 0x2d, 0x03, - 0x65, 0x04, - 0x01, 0x2f, - 0x2e, 0x80, 0x82, - 0x1d, 0x03, - 0x31, 0x0f, - 0x1c, 0x04, - 0x24, 0x09, - 0x1e, 0x05, - 0x2b, 0x05, - 0x44, 0x04, - 0x0e, 0x2a, - 0x80, 0xaa, 0x06, - 0x24, 0x04, - 0x24, 0x04, - 0x28, 0x08, - 0x34, 0x0b, - 0x01, 0x80, 0x90, - 0x81, 0x37, 0x09, - 0x16, 0x0a, - 0x08, 0x80, 0x98, - 0x39, 0x03, - 0x63, 0x08, - 0x09, 0x30, - 0x16, 0x05, - 0x21, 0x03, - 0x1b, 0x05, - 0x01, 0x40, - 0x38, 0x04, - 0x4b, 0x05, - 0x28, 0x04, - 0x03, 0x04, - 0x09, 0x08, - 0x09, 0x07, - 0x40, 0x20, - 0x27, 0x04, - 0x0c, 0x09, - 0x36, 0x03, - 0x3a, 0x05, - 0x1a, 0x07, - 0x04, 0x0c, - 0x07, 0x50, - 0x49, 0x37, - 0x33, 0x0d, - 0x33, 0x07, - 0x06, 0x81, 0x60, - 0x1f, 0x81, 0x81, - 0x4e, 0x04, - 0x1e, 0x0f, - 0x43, 0x0e, - 0x19, 0x07, - 0x0a, 0x06, - 0x44, 0x0c, - 0x27, 0x09, - 0x75, 0x0b, - 0x3f, 0x41, - 0x2a, 0x06, - 0x3b, 0x05, - 0x0a, 0x06, - 0x51, 0x06, - 0x01, 0x05, - 0x10, 0x03, - 0x05, 0x80, 0x8b, - 0x5e, 0x22, - 0x48, 0x08, - 0x0a, 0x80, 0xa6, - 0x5e, 0x22, - 0x45, 0x0b, - 0x0a, 0x06, - 0x0d, 0x13, - 0x38, 0x08, - 0x0a, 0x36, - 0x1a, 0x03, - 0x0f, 0x04, - 0x10, 0x81, 0x60, - 0x53, 0x0c, - 0x01, 0x81, 0x00, - 0x48, 0x08, - 0x53, 0x1d, - 0x39, 0x81, 0x07, - 0x46, 0x0a, - 0x1d, 0x03, - 0x47, 0x49, - 0x37, 0x03, - 0x0e, 0x08, - 0x0a, 0x82, 0xa6, - 0x83, 0x9a, 0x66, - 0x75, 0x0b, - 0x80, 0xc4, 0x8a, 0xbc, - 0x84, 0x2f, 0x8f, 0xd1, - 0x82, 0x47, 0xa1, 0xb9, - 0x82, 0x39, 0x07, - 0x2a, 0x04, - 0x02, 0x60, - 0x26, 0x0a, - 0x46, 0x0a, - 0x28, 0x05, - 0x13, 0x83, 0x70, - 0x45, 0x0b, - 0x2f, 0x10, - 0x11, 0x40, - 0x02, 0x1e, - 0x97, 0xed, 0x13, - 0x82, 0xf3, 0xa5, 0x0d, - 0x81, 0x1f, 0x51, - 0x81, 0x8c, 0x89, 0x04, - 0x6b, 0x05, - 0x0d, 0x03, - 0x09, 0x07, - 0x10, 0x93, 0x60, - 0x80, 0xf6, 0x0a, - 0x73, 0x08, - 0x6e, 0x17, - 0x46, 0x80, 0xba, - 0x57, 0x09, - 0x12, 0x80, 0x8e, - 0x81, 0x47, 0x03, - 0x85, 0x42, 0x0f, - 0x15, 0x85, 0x50, - 0x2b, 0x87, 0xd5, - 0x80, 0xd7, 0x29, - 0x4b, 0x05, - 0x0a, 0x04, - 0x02, 0x84, 0xa0, - 0x3c, 0x06, - 0x01, 0x04, - 0x55, 0x05, - 0x1b, 0x34, - 0x02, 0x81, 0x0e, - 0x2c, 0x04, - 0x64, 0x0c, - 0x56, 0x0a, - 0x0d, 0x03, - 0x5c, 0x04, - 0x3d, 0x39, - 0x1d, 0x0d, - 0x2c, 0x04, - 0x09, 0x07, - 0x02, 0x0e, - 0x06, 0x80, 0x9a, - 0x83, 0xd5, 0x0b, - 0x0d, 0x03, - 0x09, 0x07, - 0x74, 0x0c, - 0x55, 0x2b, - 0x0c, 0x04, - 0x38, 0x08, - 0x0a, 0x06, - 0x28, 0x08, - 0x1e, 0x52, - 0x0c, 0x04, - 0x3d, 0x03, - 0x1c, 0x14, - 0x18, 0x28, - 0x01, 0x0f, - 0x17, 0x86, 0x19, -]; diff --git a/src/libcore/unicode/mod.rs b/src/libcore/unicode/mod.rs index 9ab8cb748b1..0fbc4dcd175 100644 --- a/src/libcore/unicode/mod.rs +++ b/src/libcore/unicode/mod.rs @@ -12,6 +12,7 @@ #![allow(missing_docs)] mod bool_trie; +pub(crate) mod printable; pub(crate) mod tables; pub(crate) mod version; diff --git a/src/libcore/unicode/printable.py b/src/libcore/unicode/printable.py new file mode 100644 index 00000000000..9410dafbbc3 --- /dev/null +++ b/src/libcore/unicode/printable.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python +# +# Copyright 2011-2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +# This script uses the following Unicode tables: +# - UnicodeData.txt + + +from collections import namedtuple +import csv +import os +import subprocess + +NUM_CODEPOINTS=0x110000 + +def to_ranges(iter): + current = None + for i in iter: + if current is None or i != current[1] or i in (0x10000, 0x20000): + if current is not None: + yield tuple(current) + current = [i, i + 1] + else: + current[1] += 1 + if current is not None: + yield tuple(current) + +def get_escaped(codepoints): + for c in codepoints: + if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord(' '): + yield c.value + +def get_file(f): + try: + return open(os.path.basename(f)) + except FileNotFoundError: + subprocess.run(["curl", "-O", f], check=True) + return open(os.path.basename(f)) + +Codepoint = namedtuple('Codepoint', 'value class_') + +def get_codepoints(f): + r = csv.reader(f, delimiter=";") + prev_codepoint = 0 + class_first = None + for row in r: + codepoint = int(row[0], 16) + name = row[1] + class_ = row[2] + + if class_first is not None: + if not name.endswith("Last>"): + raise ValueError("Missing Last after First") + + for c in range(prev_codepoint + 1, codepoint): + yield Codepoint(c, class_first) + + class_first = None + if name.endswith("First>"): + class_first = class_ + + yield Codepoint(codepoint, class_) + prev_codepoint = codepoint + + if class_first != None: + raise ValueError("Missing Last after First") + + for c in range(prev_codepoint + 1, NUM_CODEPOINTS): + yield Codepoint(c, None) + +def compress_singletons(singletons): + uppers = [] # (upper, # items in lowers) + lowers = [] + + for i in singletons: + upper = i >> 8 + lower = i & 0xff + if len(uppers) == 0 or uppers[-1][0] != upper: + uppers.append((upper, 1)) + else: + upper, count = uppers[-1] + uppers[-1] = upper, count + 1 + lowers.append(lower) + + return uppers, lowers + +def compress_normal(normal): + # lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f + # lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff + compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)] + + prev_start = 0 + for start, count in normal: + truelen = start - prev_start + falselen = count + prev_start = start + count + + assert truelen < 0x8000 and falselen < 0x8000 + entry = [] + if truelen > 0x7f: + entry.append(0x80 | (truelen >> 8)) + entry.append(truelen & 0xff) + else: + entry.append(truelen & 0x7f) + if falselen > 0x7f: + entry.append(0x80 | (falselen >> 8)) + entry.append(falselen & 0xff) + else: + entry.append(falselen & 0x7f) + + compressed.append(entry) + + return compressed + +def print_singletons(uppers, lowers, uppersname, lowersname): + print("const {}: &'static [(u8, u8)] = &[".format(uppersname)) + for u, c in uppers: + print(" ({:#04x}, {}),".format(u, c)) + print("];") + print("const {}: &'static [u8] = &[".format(lowersname)) + for i in range(0, len(lowers), 8): + print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8]))) + print("];") + +def print_normal(normal, normalname): + print("const {}: &'static [u8] = &[".format(normalname)) + for v in normal: + print(" {}".format(" ".join("{:#04x},".format(i) for i in v))) + print("];") + +def main(): + file = get_file("http://www.unicode.org/Public/UNIDATA/UnicodeData.txt") + + codepoints = get_codepoints(file) + + CUTOFF=0x10000 + singletons0 = [] + singletons1 = [] + normal0 = [] + normal1 = [] + extra = [] + + for a, b in to_ranges(get_escaped(codepoints)): + if a > 2 * CUTOFF: + extra.append((a, b - a)) + elif a == b - 1: + if a & CUTOFF: + singletons1.append(a & ~CUTOFF) + else: + singletons0.append(a) + elif a == b - 2: + if a & CUTOFF: + singletons1.append(a & ~CUTOFF) + singletons1.append((a + 1) & ~CUTOFF) + else: + singletons0.append(a) + singletons0.append(a + 1) + else: + if a >= 2 * CUTOFF: + extra.append((a, b - a)) + elif a & CUTOFF: + normal1.append((a & ~CUTOFF, b - a)) + else: + normal0.append((a, b - a)) + + singletons0u, singletons0l = compress_singletons(singletons0) + singletons1u, singletons1l = compress_singletons(singletons1) + normal0 = compress_normal(normal0) + normal1 = compress_normal(normal1) + + print("""\ +// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "src/libcore/unicode/printable.py", +// do not edit directly! + +fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], + normal: &[u8]) -> bool { + let xupper = (x >> 8) as u8; + let mut lowerstart = 0; + for &(upper, lowercount) in singletonuppers { + let lowerend = lowerstart + lowercount as usize; + if xupper == upper { + for &lower in &singletonlowers[lowerstart..lowerend] { + if lower == x as u8 { + return false; + } + } + } else if xupper < upper { + break; + } + lowerstart = lowerend; + } + + let mut x = x as i32; + let mut normal = normal.iter().cloned(); + let mut current = true; + while let Some(v) = normal.next() { + let len = if v & 0x80 != 0 { + ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32 + } else { + v as i32 + }; + x -= len; + if x < 0 { + break; + } + current = !current; + } + current +} + +pub(crate) fn is_printable(x: char) -> bool { + let x = x as u32; + let lower = x as u16; + if x < 0x10000 { + check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) + } else if x < 0x20000 { + check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) + } else {\ +""") + for a, b in extra: + print(" if 0x{:x} <= x && x < 0x{:x} {{".format(a, a + b)) + print(" return false;") + print(" }") + print("""\ + true + } +}\ +""") + print() + print_singletons(singletons0u, singletons0l, 'SINGLETONS0U', 'SINGLETONS0L') + print_singletons(singletons1u, singletons1l, 'SINGLETONS1U', 'SINGLETONS1L') + print_normal(normal0, 'NORMAL0') + print_normal(normal1, 'NORMAL1') + +if __name__ == '__main__': + main() diff --git a/src/libcore/unicode/printable.rs b/src/libcore/unicode/printable.rs new file mode 100644 index 00000000000..4426c32eebc --- /dev/null +++ b/src/libcore/unicode/printable.rs @@ -0,0 +1,531 @@ +// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "src/libcore/unicode/printable.py", +// do not edit directly! + +fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], + normal: &[u8]) -> bool { + let xupper = (x >> 8) as u8; + let mut lowerstart = 0; + for &(upper, lowercount) in singletonuppers { + let lowerend = lowerstart + lowercount as usize; + if xupper == upper { + for &lower in &singletonlowers[lowerstart..lowerend] { + if lower == x as u8 { + return false; + } + } + } else if xupper < upper { + break; + } + lowerstart = lowerend; + } + + let mut x = x as i32; + let mut normal = normal.iter().cloned(); + let mut current = true; + while let Some(v) = normal.next() { + let len = if v & 0x80 != 0 { + ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32 + } else { + v as i32 + }; + x -= len; + if x < 0 { + break; + } + current = !current; + } + current +} + +pub(crate) fn is_printable(x: char) -> bool { + let x = x as u32; + let lower = x as u16; + if x < 0x10000 { + check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) + } else if x < 0x20000 { + check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) + } else { + if 0x2a6d7 <= x && x < 0x2a700 { + return false; + } + if 0x2b735 <= x && x < 0x2b740 { + return false; + } + if 0x2b81e <= x && x < 0x2b820 { + return false; + } + if 0x2cea2 <= x && x < 0x2ceb0 { + return false; + } + if 0x2ebe1 <= x && x < 0x2f800 { + return false; + } + if 0x2fa1e <= x && x < 0xe0100 { + return false; + } + if 0xe01f0 <= x && x < 0x110000 { + return false; + } + true + } +} + +const SINGLETONS0U: &'static [(u8, u8)] = &[ + (0x00, 1), + (0x03, 5), + (0x05, 8), + (0x06, 3), + (0x07, 4), + (0x08, 8), + (0x09, 16), + (0x0a, 27), + (0x0b, 25), + (0x0c, 22), + (0x0d, 18), + (0x0e, 22), + (0x0f, 4), + (0x10, 3), + (0x12, 18), + (0x13, 9), + (0x16, 1), + (0x17, 5), + (0x18, 2), + (0x19, 3), + (0x1a, 7), + (0x1d, 1), + (0x1f, 22), + (0x20, 3), + (0x2b, 5), + (0x2c, 2), + (0x2d, 11), + (0x2e, 1), + (0x30, 3), + (0x31, 3), + (0x32, 2), + (0xa7, 1), + (0xa8, 2), + (0xa9, 2), + (0xaa, 4), + (0xab, 8), + (0xfa, 2), + (0xfb, 5), + (0xfd, 4), + (0xfe, 3), + (0xff, 9), +]; +const SINGLETONS0L: &'static [u8] = &[ + 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, + 0x58, 0x60, 0x88, 0x8b, 0x8c, 0x90, 0x1c, 0x1d, + 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0x2e, 0x2f, 0x3f, + 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, + 0x91, 0x92, 0xa9, 0xb1, 0xba, 0xbb, 0xc5, 0xc6, + 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0x04, 0x11, 0x12, + 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, + 0x4a, 0x5d, 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, + 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, 0xe4, 0xe5, + 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, + 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, + 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, 0xc9, 0xce, + 0xcf, 0x04, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, + 0x64, 0x65, 0x84, 0x8d, 0x91, 0xa9, 0xb4, 0xba, + 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x04, + 0x0d, 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x81, + 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, 0xd7, 0xf0, + 0xf1, 0x83, 0x85, 0x86, 0x89, 0x8b, 0x8c, 0x98, + 0xa0, 0xa4, 0xa6, 0xa8, 0xa9, 0xac, 0xba, 0xbe, + 0xbf, 0xc5, 0xc7, 0xce, 0xcf, 0xda, 0xdb, 0x48, + 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, 0x4e, + 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, + 0xb1, 0xb6, 0xb7, 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, + 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe, + 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, + 0x0f, 0x1f, 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, + 0x7e, 0xae, 0xaf, 0xfa, 0x16, 0x17, 0x1e, 0x1f, + 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, + 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, + 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0x74, 0x75, 0x96, + 0x97, 0xc9, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, + 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, + 0x40, 0x97, 0x98, 0x2f, 0x30, 0x8f, 0x1f, 0xff, + 0xaf, 0xfe, 0xff, 0xce, 0xff, 0x4e, 0x4f, 0x5a, + 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, + 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, + 0x90, 0x91, 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, + 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff, +]; +const SINGLETONS1U: &'static [(u8, u8)] = &[ + (0x00, 6), + (0x01, 1), + (0x03, 1), + (0x04, 2), + (0x08, 8), + (0x09, 2), + (0x0a, 3), + (0x0b, 2), + (0x10, 1), + (0x11, 4), + (0x12, 5), + (0x13, 18), + (0x14, 2), + (0x15, 2), + (0x1a, 3), + (0x1c, 5), + (0x1d, 4), + (0x24, 1), + (0x6a, 3), + (0x6b, 2), + (0xbc, 2), + (0xd1, 2), + (0xd4, 12), + (0xd5, 9), + (0xd6, 2), + (0xd7, 2), + (0xda, 1), + (0xe0, 5), + (0xe8, 2), + (0xee, 32), + (0xf0, 4), + (0xf1, 1), + (0xf9, 1), +]; +const SINGLETONS1L: &'static [u8] = &[ + 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, + 0x9e, 0x9f, 0x06, 0x07, 0x09, 0x36, 0x3d, 0x3e, + 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x56, + 0x57, 0xbd, 0x35, 0xce, 0xcf, 0xe0, 0x12, 0x87, + 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, + 0x29, 0x31, 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, + 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5a, 0x5c, 0xb6, + 0xb7, 0x84, 0x85, 0x9d, 0x09, 0x37, 0x90, 0x91, + 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x6f, 0x5f, 0xee, + 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, 0x28, 0x55, + 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, + 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, + 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, 0xcd, + 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0xc5, 0xc6, + 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, + 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53, 0x55, 0x56, + 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, + 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, + 0xaf, 0xb0, 0xc0, 0xd0, 0x2f, 0x3f, +]; +const NORMAL0: &'static [u8] = &[ + 0x00, 0x20, + 0x5f, 0x22, + 0x82, 0xdf, 0x04, + 0x82, 0x44, 0x08, + 0x1b, 0x05, + 0x05, 0x11, + 0x81, 0xac, 0x0e, + 0x3b, 0x05, + 0x6b, 0x35, + 0x1e, 0x16, + 0x80, 0xdf, 0x03, + 0x19, 0x08, + 0x01, 0x04, + 0x22, 0x03, + 0x0a, 0x04, + 0x34, 0x04, + 0x07, 0x03, + 0x01, 0x07, + 0x06, 0x07, + 0x10, 0x0b, + 0x50, 0x0f, + 0x12, 0x07, + 0x55, 0x08, + 0x02, 0x04, + 0x1c, 0x0a, + 0x09, 0x03, + 0x08, 0x03, + 0x07, 0x03, + 0x02, 0x03, + 0x03, 0x03, + 0x0c, 0x04, + 0x05, 0x03, + 0x0b, 0x06, + 0x01, 0x0e, + 0x15, 0x05, + 0x3a, 0x03, + 0x11, 0x07, + 0x06, 0x05, + 0x10, 0x08, + 0x56, 0x07, + 0x02, 0x07, + 0x15, 0x0d, + 0x50, 0x04, + 0x43, 0x03, + 0x2d, 0x03, + 0x01, 0x04, + 0x11, 0x06, + 0x0f, 0x0c, + 0x3a, 0x04, + 0x1d, 0x25, + 0x0d, 0x06, + 0x4c, 0x20, + 0x6d, 0x04, + 0x6a, 0x25, + 0x80, 0xc8, 0x05, + 0x82, 0xb0, 0x03, + 0x1a, 0x06, + 0x82, 0xfd, 0x03, + 0x59, 0x07, + 0x15, 0x0b, + 0x17, 0x09, + 0x14, 0x0c, + 0x14, 0x0c, + 0x6a, 0x06, + 0x0a, 0x06, + 0x1a, 0x06, + 0x58, 0x08, + 0x2b, 0x05, + 0x46, 0x0a, + 0x2c, 0x04, + 0x0c, 0x04, + 0x01, 0x03, + 0x31, 0x0b, + 0x2c, 0x04, + 0x1a, 0x06, + 0x0b, 0x03, + 0x80, 0xac, 0x06, + 0x0a, 0x06, + 0x1f, 0x41, + 0x4c, 0x04, + 0x2d, 0x03, + 0x74, 0x08, + 0x3c, 0x03, + 0x0f, 0x03, + 0x3c, 0x37, + 0x08, 0x08, + 0x2a, 0x06, + 0x82, 0xff, 0x11, + 0x18, 0x08, + 0x2f, 0x11, + 0x2d, 0x03, + 0x20, 0x10, + 0x21, 0x0f, + 0x80, 0x8c, 0x04, + 0x82, 0x97, 0x19, + 0x0b, 0x15, + 0x87, 0x5a, 0x03, + 0x16, 0x19, + 0x04, 0x10, + 0x80, 0xf4, 0x05, + 0x2f, 0x05, + 0x3b, 0x07, + 0x02, 0x0e, + 0x18, 0x09, + 0x80, 0xaa, 0x36, + 0x74, 0x0c, + 0x80, 0xd6, 0x1a, + 0x0c, 0x05, + 0x80, 0xff, 0x05, + 0x80, 0xb6, 0x05, + 0x24, 0x0c, + 0x9b, 0xc6, 0x0a, + 0xd2, 0x2b, 0x15, + 0x84, 0x8d, 0x03, + 0x37, 0x09, + 0x81, 0x5c, 0x14, + 0x80, 0xb8, 0x08, + 0x80, 0xb8, 0x3f, + 0x35, 0x04, + 0x0a, 0x06, + 0x38, 0x08, + 0x46, 0x08, + 0x0c, 0x06, + 0x74, 0x0b, + 0x1e, 0x03, + 0x5a, 0x04, + 0x59, 0x09, + 0x80, 0x83, 0x18, + 0x1c, 0x0a, + 0x16, 0x09, + 0x46, 0x0a, + 0x80, 0x8a, 0x06, + 0xab, 0xa4, 0x0c, + 0x17, 0x04, + 0x31, 0xa1, 0x04, + 0x81, 0xda, 0x26, + 0x07, 0x0c, + 0x05, 0x05, + 0x80, 0xa5, 0x11, + 0x81, 0x6d, 0x10, + 0x78, 0x28, + 0x2a, 0x06, + 0x4c, 0x04, + 0x80, 0x8d, 0x04, + 0x80, 0xbe, 0x03, + 0x1b, 0x03, + 0x0f, 0x0d, +]; +const NORMAL1: &'static [u8] = &[ + 0x5e, 0x22, + 0x7b, 0x05, + 0x03, 0x04, + 0x2d, 0x03, + 0x65, 0x04, + 0x01, 0x2f, + 0x2e, 0x80, 0x82, + 0x1d, 0x03, + 0x31, 0x0f, + 0x1c, 0x04, + 0x24, 0x09, + 0x1e, 0x05, + 0x2b, 0x05, + 0x44, 0x04, + 0x0e, 0x2a, + 0x80, 0xaa, 0x06, + 0x24, 0x04, + 0x24, 0x04, + 0x28, 0x08, + 0x34, 0x0b, + 0x01, 0x80, 0x90, + 0x81, 0x37, 0x09, + 0x16, 0x0a, + 0x08, 0x80, 0x98, + 0x39, 0x03, + 0x63, 0x08, + 0x09, 0x30, + 0x16, 0x05, + 0x21, 0x03, + 0x1b, 0x05, + 0x01, 0x40, + 0x38, 0x04, + 0x4b, 0x05, + 0x28, 0x04, + 0x03, 0x04, + 0x09, 0x08, + 0x09, 0x07, + 0x40, 0x20, + 0x27, 0x04, + 0x0c, 0x09, + 0x36, 0x03, + 0x3a, 0x05, + 0x1a, 0x07, + 0x04, 0x0c, + 0x07, 0x50, + 0x49, 0x37, + 0x33, 0x0d, + 0x33, 0x07, + 0x06, 0x81, 0x60, + 0x1f, 0x81, 0x81, + 0x4e, 0x04, + 0x1e, 0x0f, + 0x43, 0x0e, + 0x19, 0x07, + 0x0a, 0x06, + 0x44, 0x0c, + 0x27, 0x09, + 0x75, 0x0b, + 0x3f, 0x41, + 0x2a, 0x06, + 0x3b, 0x05, + 0x0a, 0x06, + 0x51, 0x06, + 0x01, 0x05, + 0x10, 0x03, + 0x05, 0x80, 0x8b, + 0x5e, 0x22, + 0x48, 0x08, + 0x0a, 0x80, 0xa6, + 0x5e, 0x22, + 0x45, 0x0b, + 0x0a, 0x06, + 0x0d, 0x13, + 0x38, 0x08, + 0x0a, 0x36, + 0x1a, 0x03, + 0x0f, 0x04, + 0x10, 0x81, 0x60, + 0x53, 0x0c, + 0x01, 0x81, 0x00, + 0x48, 0x08, + 0x53, 0x1d, + 0x39, 0x81, 0x07, + 0x46, 0x0a, + 0x1d, 0x03, + 0x47, 0x49, + 0x37, 0x03, + 0x0e, 0x08, + 0x0a, 0x82, 0xa6, + 0x83, 0x9a, 0x66, + 0x75, 0x0b, + 0x80, 0xc4, 0x8a, 0xbc, + 0x84, 0x2f, 0x8f, 0xd1, + 0x82, 0x47, 0xa1, 0xb9, + 0x82, 0x39, 0x07, + 0x2a, 0x04, + 0x02, 0x60, + 0x26, 0x0a, + 0x46, 0x0a, + 0x28, 0x05, + 0x13, 0x83, 0x70, + 0x45, 0x0b, + 0x2f, 0x10, + 0x11, 0x40, + 0x02, 0x1e, + 0x97, 0xed, 0x13, + 0x82, 0xf3, 0xa5, 0x0d, + 0x81, 0x1f, 0x51, + 0x81, 0x8c, 0x89, 0x04, + 0x6b, 0x05, + 0x0d, 0x03, + 0x09, 0x07, + 0x10, 0x93, 0x60, + 0x80, 0xf6, 0x0a, + 0x73, 0x08, + 0x6e, 0x17, + 0x46, 0x80, 0xba, + 0x57, 0x09, + 0x12, 0x80, 0x8e, + 0x81, 0x47, 0x03, + 0x85, 0x42, 0x0f, + 0x15, 0x85, 0x50, + 0x2b, 0x87, 0xd5, + 0x80, 0xd7, 0x29, + 0x4b, 0x05, + 0x0a, 0x04, + 0x02, 0x84, 0xa0, + 0x3c, 0x06, + 0x01, 0x04, + 0x55, 0x05, + 0x1b, 0x34, + 0x02, 0x81, 0x0e, + 0x2c, 0x04, + 0x64, 0x0c, + 0x56, 0x0a, + 0x0d, 0x03, + 0x5c, 0x04, + 0x3d, 0x39, + 0x1d, 0x0d, + 0x2c, 0x04, + 0x09, 0x07, + 0x02, 0x0e, + 0x06, 0x80, 0x9a, + 0x83, 0xd5, 0x0b, + 0x0d, 0x03, + 0x09, 0x07, + 0x74, 0x0c, + 0x55, 0x2b, + 0x0c, 0x04, + 0x38, 0x08, + 0x0a, 0x06, + 0x28, 0x08, + 0x1e, 0x52, + 0x0c, 0x04, + 0x3d, 0x03, + 0x1c, 0x14, + 0x18, 0x28, + 0x01, 0x0f, + 0x17, 0x86, 0x19, +]; -- cgit 1.4.1-3-g733a5 From 1ca2905cda99dd395347b46c3ce225f58b4d3844 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 6 Apr 2018 14:18:28 +0200 Subject: Dedicated tracking issue for UnicodeVersion and UNICODE_VERSION. --- src/libcore/char/mod.rs | 6 +++--- src/libcore/unicode/tables.rs | 1 + src/libcore/unicode/unicode.py | 1 + src/libcore/unicode/version.rs | 1 + src/test/run-pass/char_unicode.rs | 4 +--- 5 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index b2af95eb5ba..9edc0c88756 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -46,9 +46,9 @@ pub use self::convert::CharTryFromError; pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error}; // unstable re-exports -#[unstable(feature = "unicode", issue = "27783")] -pub use unicode::tables::{UNICODE_VERSION}; -#[unstable(feature = "unicode", issue = "27783")] +#[unstable(feature = "unicode_version", issue = "49726")] +pub use unicode::tables::UNICODE_VERSION; +#[unstable(feature = "unicode_version", issue = "49726")] pub use unicode::version::UnicodeVersion; #[unstable(feature = "decode_utf8", issue = "33906")] pub use self::decode::{decode_utf8, DecodeUtf8, InvalidSequence}; diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs index 1f7b1bde914..3fbbc011bc4 100644 --- a/src/libcore/unicode/tables.rs +++ b/src/libcore/unicode/tables.rs @@ -17,6 +17,7 @@ use unicode::bool_trie::{BoolTrie, SmallBoolTrie}; /// The version of [Unicode](http://www.unicode.org/) that the Unicode parts of /// `char` and `str` methods are based on. +#[unstable(feature = "unicode_version", issue = "49726")] pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { major: 10, minor: 0, diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py index 82262cc7662..75ec01944bf 100755 --- a/src/libcore/unicode/unicode.py +++ b/src/libcore/unicode/unicode.py @@ -471,6 +471,7 @@ if __name__ == "__main__": rf.write(""" /// The version of [Unicode](http://www.unicode.org/) that the Unicode parts of /// `char` and `str` methods are based on. +#[unstable(feature = "unicode_version", issue = "49726")] pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { major: %s, minor: %s, diff --git a/src/libcore/unicode/version.rs b/src/libcore/unicode/version.rs index d82a749d917..59ebf5f5012 100644 --- a/src/libcore/unicode/version.rs +++ b/src/libcore/unicode/version.rs @@ -12,6 +12,7 @@ /// /// See also: #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[unstable(feature = "unicode_version", issue = "49726")] pub struct UnicodeVersion { /// Major version. pub major: u32, diff --git a/src/test/run-pass/char_unicode.rs b/src/test/run-pass/char_unicode.rs index b4884acdd07..bfc7faac06e 100644 --- a/src/test/run-pass/char_unicode.rs +++ b/src/test/run-pass/char_unicode.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(unicode)] - +#![feature(unicode_version)] /// Tests access to the internal Unicode Version type and value. pub fn main() { -- cgit 1.4.1-3-g733a5 From ef41788cf37074e44f70257508c97efd539a7f29 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 6 Apr 2018 14:23:00 +0200 Subject: Mark the rest of the `unicode` feature flag as perma-unstable. --- src/liballoc/lib.rs | 2 +- src/liballoc/tests/lib.rs | 1 - src/libcore/unicode/mod.rs | 2 +- src/librustdoc/lib.rs | 1 - src/libstd/lib.rs | 1 - src/libstd_unicode/lib.rs | 2 +- src/libsyntax/lib.rs | 2 +- 7 files changed, 4 insertions(+), 7 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index d1a91ab4a9c..69fc007ab7c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -113,7 +113,7 @@ #![feature(trusted_len)] #![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(unicode)] +#![feature(unicode_internals)] #![feature(unsize)] #![feature(allocator_internals)] #![feature(on_unimplemented)] diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index fddf341d0d1..32272169307 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -24,7 +24,6 @@ #![feature(string_retain)] #![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(unicode)] #![feature(exact_chunks)] #![feature(inclusive_range_fields)] diff --git a/src/libcore/unicode/mod.rs b/src/libcore/unicode/mod.rs index 0fbc4dcd175..b6b033adc04 100644 --- a/src/libcore/unicode/mod.rs +++ b/src/libcore/unicode/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![unstable(feature = "unicode", issue = "27783")] +#![unstable(feature = "unicode_internals", issue = "0")] #![allow(missing_docs)] mod bool_trie; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 9ac034869ac..4a062e9a55b 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -20,7 +20,6 @@ #![feature(fs_read_write)] #![feature(set_stdio)] #![feature(test)] -#![feature(unicode)] #![feature(vec_remove_item)] #![feature(entry_and_modify)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 94e48732c26..c82d600e4a1 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -307,7 +307,6 @@ #![feature(toowned_clone_into)] #![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(unicode)] #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(vec_push_all)] diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index 29de017c64d..c0d47f1fcb4 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -29,7 +29,7 @@ test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] #![no_std] -#![feature(unicode)] +#![feature(unicode_internals)] #![feature(staged_api)] #![rustc_deprecated(since = "1.27.0", reason = "moved into libcore")] diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 9de905c01d6..4e1e9fa2b46 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -19,7 +19,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![feature(unicode)] +#![feature(unicode_internals)] #![feature(rustc_diagnostic_macros)] #![feature(non_exhaustive)] #![feature(const_atomic_usize_new)] -- cgit 1.4.1-3-g733a5 From 2f603413ab4764898f63f532c7c26291409e0aa7 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 12 Apr 2018 22:48:48 +0200 Subject: improve Atomic*::fetch_update docs --- src/libcore/sync/atomic.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index d336934ec72..62e0979c5fe 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -1425,8 +1425,8 @@ assert_eq!(foo.load(Ordering::SeqCst), 0b011110); doc_comment! { concat!("Fetches the value, and applies a function to it that returns an optional -new value. Returns a `Result` (`Ok(_)` if the function returned `Some(_)`, else `Err(_)`) of the -previous value. +new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else +`Err(previous_value)`. Note: This may call the function multiple times if the value has been changed from other threads in the meantime, as long as the function returns `Some(_)`, but the function will have been applied -- cgit 1.4.1-3-g733a5 From 9b068867f0ac0851ff0b23381e5b1b1c09b4002e Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 2 Apr 2018 11:26:16 +0200 Subject: Add a core::heap::Void extern type. --- src/libcore/heap.rs | 20 ++++++++++++++++++++ src/libcore/lib.rs | 1 + 2 files changed, 21 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/heap.rs b/src/libcore/heap.rs index fe19c923a58..80eedb5bff2 100644 --- a/src/libcore/heap.rs +++ b/src/libcore/heap.rs @@ -21,6 +21,26 @@ use mem; use usize; use ptr::{self, NonNull}; +extern { + /// An opaque, unsized type. Used for pointers to allocated memory. + /// + /// This type can only be used behind a pointer like `*mut Void` or `ptr::NonNull`. + /// Such pointers are similar to C’s `void*` type. + pub type Void; +} + +impl Void { + /// Similar to `std::ptr::null`, which requires `T: Sized`. + pub fn null() -> *const Self { + 0 as _ + } + + /// Similar to `std::ptr::null_mut`, which requires `T: Sized`. + pub fn null_mut() -> *mut Self { + 0 as _ + } +} + /// Represents the combination of a starting address and /// a total capacity of the returned block. #[derive(Debug)] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 9ff8465bc0f..722a9de215c 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -75,6 +75,7 @@ #![feature(custom_attribute)] #![feature(doc_cfg)] #![feature(doc_spotlight)] +#![feature(extern_types)] #![feature(fn_must_use)] #![feature(fundamental)] #![feature(intrinsics)] -- cgit 1.4.1-3-g733a5 From c660cedc02e125fe47d90075837c5d8adeb4c097 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 3 Apr 2018 14:07:06 +0200 Subject: Add a GlobalAlloc trait --- src/libcore/heap.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/heap.rs b/src/libcore/heap.rs index 80eedb5bff2..5c51bb2b51b 100644 --- a/src/libcore/heap.rs +++ b/src/libcore/heap.rs @@ -404,6 +404,36 @@ impl From for CollectionAllocErr { } } +// FIXME: docs +pub unsafe trait GlobalAlloc { + unsafe fn alloc(&self, layout: Layout) -> *mut Void; + + unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout); + + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { + let size = layout.size(); + let ptr = self.alloc(layout); + if !ptr.is_null() { + ptr::write_bytes(ptr as *mut u8, 0, size); + } + ptr + } + + unsafe fn realloc(&self, ptr: *mut Void, old_layout: Layout, new_size: usize) -> *mut Void { + let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); + let new_ptr = self.alloc(new_layout); + if !new_ptr.is_null() { + ptr::copy_nonoverlapping( + ptr as *const u8, + new_ptr as *mut u8, + cmp::min(old_layout.size(), new_size), + ); + self.dealloc(ptr, old_layout); + } + new_ptr + } +} + /// An implementation of `Alloc` can allocate, reallocate, and /// deallocate arbitrary blocks of data described via `Layout`. /// -- cgit 1.4.1-3-g733a5 From 09e8db1e4f33ec82316e1eeaaedad94fe6e1acb5 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 3 Apr 2018 14:41:15 +0200 Subject: Rename `heap` modules in the core, alloc, and std crates to `alloc` --- src/liballoc/alloc.rs | 291 +++++++++++++ src/liballoc/heap.rs | 291 ------------- src/liballoc/lib.rs | 8 +- src/libcore/alloc.rs | 1125 +++++++++++++++++++++++++++++++++++++++++++++++++ src/libcore/heap.rs | 1125 ------------------------------------------------- src/libcore/lib.rs | 6 +- src/libstd/alloc.rs | 176 ++++++++ src/libstd/heap.rs | 176 -------- src/libstd/lib.rs | 6 +- 9 files changed, 1608 insertions(+), 1596 deletions(-) create mode 100644 src/liballoc/alloc.rs delete mode 100644 src/liballoc/heap.rs create mode 100644 src/libcore/alloc.rs delete mode 100644 src/libcore/heap.rs create mode 100644 src/libstd/alloc.rs delete mode 100644 src/libstd/heap.rs (limited to 'src/libcore') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs new file mode 100644 index 00000000000..000c0123d9f --- /dev/null +++ b/src/liballoc/alloc.rs @@ -0,0 +1,291 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "allocator_api", + reason = "the precise API and guarantees it provides may be tweaked \ + slightly, especially to possibly take into account the \ + types being stored to make room for a future \ + tracing garbage collector", + issue = "32838")] + +use core::intrinsics::{min_align_of_val, size_of_val}; +use core::mem::{self, ManuallyDrop}; +use core::usize; + +#[doc(inline)] +pub use core::heap::*; + +#[doc(hidden)] +pub mod __core { + pub use core::*; +} + +extern "Rust" { + #[allocator] + #[rustc_allocator_nounwind] + fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8; + #[cold] + #[rustc_allocator_nounwind] + fn __rust_oom(err: *const u8) -> !; + #[rustc_allocator_nounwind] + fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); + #[rustc_allocator_nounwind] + fn __rust_usable_size(layout: *const u8, + min: *mut usize, + max: *mut usize); + #[rustc_allocator_nounwind] + fn __rust_realloc(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize, + err: *mut u8) -> *mut u8; + #[rustc_allocator_nounwind] + fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8; + #[rustc_allocator_nounwind] + fn __rust_alloc_excess(size: usize, + align: usize, + excess: *mut usize, + err: *mut u8) -> *mut u8; + #[rustc_allocator_nounwind] + fn __rust_realloc_excess(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize, + excess: *mut usize, + err: *mut u8) -> *mut u8; + #[rustc_allocator_nounwind] + fn __rust_grow_in_place(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize) -> u8; + #[rustc_allocator_nounwind] + fn __rust_shrink_in_place(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize) -> u8; +} + +#[derive(Copy, Clone, Default, Debug)] +pub struct Heap; + +unsafe impl Alloc for Heap { + #[inline] + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + let mut err = ManuallyDrop::new(mem::uninitialized::()); + let ptr = __rust_alloc(layout.size(), + layout.align(), + &mut *err as *mut AllocErr as *mut u8); + if ptr.is_null() { + Err(ManuallyDrop::into_inner(err)) + } else { + Ok(ptr) + } + } + + #[inline] + #[cold] + fn oom(&mut self, err: AllocErr) -> ! { + unsafe { + __rust_oom(&err as *const AllocErr as *const u8) + } + } + + #[inline] + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + __rust_dealloc(ptr, layout.size(), layout.align()) + } + + #[inline] + fn usable_size(&self, layout: &Layout) -> (usize, usize) { + let mut min = 0; + let mut max = 0; + unsafe { + __rust_usable_size(layout as *const Layout as *const u8, + &mut min, + &mut max); + } + (min, max) + } + + #[inline] + unsafe fn realloc(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) + -> Result<*mut u8, AllocErr> + { + let mut err = ManuallyDrop::new(mem::uninitialized::()); + let ptr = __rust_realloc(ptr, + layout.size(), + layout.align(), + new_layout.size(), + new_layout.align(), + &mut *err as *mut AllocErr as *mut u8); + if ptr.is_null() { + Err(ManuallyDrop::into_inner(err)) + } else { + mem::forget(err); + Ok(ptr) + } + } + + #[inline] + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + let mut err = ManuallyDrop::new(mem::uninitialized::()); + let ptr = __rust_alloc_zeroed(layout.size(), + layout.align(), + &mut *err as *mut AllocErr as *mut u8); + if ptr.is_null() { + Err(ManuallyDrop::into_inner(err)) + } else { + Ok(ptr) + } + } + + #[inline] + unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { + let mut err = ManuallyDrop::new(mem::uninitialized::()); + let mut size = 0; + let ptr = __rust_alloc_excess(layout.size(), + layout.align(), + &mut size, + &mut *err as *mut AllocErr as *mut u8); + if ptr.is_null() { + Err(ManuallyDrop::into_inner(err)) + } else { + Ok(Excess(ptr, size)) + } + } + + #[inline] + unsafe fn realloc_excess(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result { + let mut err = ManuallyDrop::new(mem::uninitialized::()); + let mut size = 0; + let ptr = __rust_realloc_excess(ptr, + layout.size(), + layout.align(), + new_layout.size(), + new_layout.align(), + &mut size, + &mut *err as *mut AllocErr as *mut u8); + if ptr.is_null() { + Err(ManuallyDrop::into_inner(err)) + } else { + Ok(Excess(ptr, size)) + } + } + + #[inline] + unsafe fn grow_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) + -> Result<(), CannotReallocInPlace> + { + debug_assert!(new_layout.size() >= layout.size()); + debug_assert!(new_layout.align() == layout.align()); + let ret = __rust_grow_in_place(ptr, + layout.size(), + layout.align(), + new_layout.size(), + new_layout.align()); + if ret != 0 { + Ok(()) + } else { + Err(CannotReallocInPlace) + } + } + + #[inline] + unsafe fn shrink_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + debug_assert!(new_layout.size() <= layout.size()); + debug_assert!(new_layout.align() == layout.align()); + let ret = __rust_shrink_in_place(ptr, + layout.size(), + layout.align(), + new_layout.size(), + new_layout.align()); + if ret != 0 { + Ok(()) + } else { + Err(CannotReallocInPlace) + } + } +} + +/// The allocator for unique pointers. +// This function must not unwind. If it does, MIR trans will fail. +#[cfg(not(test))] +#[lang = "exchange_malloc"] +#[inline] +unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { + if size == 0 { + align as *mut u8 + } else { + let layout = Layout::from_size_align_unchecked(size, align); + Heap.alloc(layout).unwrap_or_else(|err| { + Heap.oom(err) + }) + } +} + +#[cfg_attr(not(test), lang = "box_free")] +#[inline] +pub(crate) unsafe fn box_free(ptr: *mut T) { + let size = size_of_val(&*ptr); + let align = min_align_of_val(&*ptr); + // We do not allocate for Box when T is ZST, so deallocation is also not necessary. + if size != 0 { + let layout = Layout::from_size_align_unchecked(size, align); + Heap.dealloc(ptr as *mut u8, layout); + } +} + +#[cfg(test)] +mod tests { + extern crate test; + use self::test::Bencher; + use boxed::Box; + use heap::{Heap, Alloc, Layout}; + + #[test] + fn allocate_zeroed() { + unsafe { + let layout = Layout::from_size_align(1024, 1).unwrap(); + let ptr = Heap.alloc_zeroed(layout.clone()) + .unwrap_or_else(|e| Heap.oom(e)); + + let end = ptr.offset(layout.size() as isize); + let mut i = ptr; + while i < end { + assert_eq!(*i, 0); + i = i.offset(1); + } + Heap.dealloc(ptr, layout); + } + } + + #[bench] + fn alloc_owned_small(b: &mut Bencher) { + b.iter(|| { + let _: Box<_> = box 10; + }) + } +} diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs deleted file mode 100644 index 000c0123d9f..00000000000 --- a/src/liballoc/heap.rs +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked \ - slightly, especially to possibly take into account the \ - types being stored to make room for a future \ - tracing garbage collector", - issue = "32838")] - -use core::intrinsics::{min_align_of_val, size_of_val}; -use core::mem::{self, ManuallyDrop}; -use core::usize; - -#[doc(inline)] -pub use core::heap::*; - -#[doc(hidden)] -pub mod __core { - pub use core::*; -} - -extern "Rust" { - #[allocator] - #[rustc_allocator_nounwind] - fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8; - #[cold] - #[rustc_allocator_nounwind] - fn __rust_oom(err: *const u8) -> !; - #[rustc_allocator_nounwind] - fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); - #[rustc_allocator_nounwind] - fn __rust_usable_size(layout: *const u8, - min: *mut usize, - max: *mut usize); - #[rustc_allocator_nounwind] - fn __rust_realloc(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - err: *mut u8) -> *mut u8; - #[rustc_allocator_nounwind] - fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8; - #[rustc_allocator_nounwind] - fn __rust_alloc_excess(size: usize, - align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8; - #[rustc_allocator_nounwind] - fn __rust_realloc_excess(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8; - #[rustc_allocator_nounwind] - fn __rust_grow_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8; - #[rustc_allocator_nounwind] - fn __rust_shrink_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8; -} - -#[derive(Copy, Clone, Default, Debug)] -pub struct Heap; - -unsafe impl Alloc for Heap { - #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let mut err = ManuallyDrop::new(mem::uninitialized::()); - let ptr = __rust_alloc(layout.size(), - layout.align(), - &mut *err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) - } else { - Ok(ptr) - } - } - - #[inline] - #[cold] - fn oom(&mut self, err: AllocErr) -> ! { - unsafe { - __rust_oom(&err as *const AllocErr as *const u8) - } - } - - #[inline] - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - __rust_dealloc(ptr, layout.size(), layout.align()) - } - - #[inline] - fn usable_size(&self, layout: &Layout) -> (usize, usize) { - let mut min = 0; - let mut max = 0; - unsafe { - __rust_usable_size(layout as *const Layout as *const u8, - &mut min, - &mut max); - } - (min, max) - } - - #[inline] - unsafe fn realloc(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) - -> Result<*mut u8, AllocErr> - { - let mut err = ManuallyDrop::new(mem::uninitialized::()); - let ptr = __rust_realloc(ptr, - layout.size(), - layout.align(), - new_layout.size(), - new_layout.align(), - &mut *err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) - } else { - mem::forget(err); - Ok(ptr) - } - } - - #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let mut err = ManuallyDrop::new(mem::uninitialized::()); - let ptr = __rust_alloc_zeroed(layout.size(), - layout.align(), - &mut *err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) - } else { - Ok(ptr) - } - } - - #[inline] - unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { - let mut err = ManuallyDrop::new(mem::uninitialized::()); - let mut size = 0; - let ptr = __rust_alloc_excess(layout.size(), - layout.align(), - &mut size, - &mut *err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) - } else { - Ok(Excess(ptr, size)) - } - } - - #[inline] - unsafe fn realloc_excess(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result { - let mut err = ManuallyDrop::new(mem::uninitialized::()); - let mut size = 0; - let ptr = __rust_realloc_excess(ptr, - layout.size(), - layout.align(), - new_layout.size(), - new_layout.align(), - &mut size, - &mut *err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) - } else { - Ok(Excess(ptr, size)) - } - } - - #[inline] - unsafe fn grow_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) - -> Result<(), CannotReallocInPlace> - { - debug_assert!(new_layout.size() >= layout.size()); - debug_assert!(new_layout.align() == layout.align()); - let ret = __rust_grow_in_place(ptr, - layout.size(), - layout.align(), - new_layout.size(), - new_layout.align()); - if ret != 0 { - Ok(()) - } else { - Err(CannotReallocInPlace) - } - } - - #[inline] - unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - debug_assert!(new_layout.size() <= layout.size()); - debug_assert!(new_layout.align() == layout.align()); - let ret = __rust_shrink_in_place(ptr, - layout.size(), - layout.align(), - new_layout.size(), - new_layout.align()); - if ret != 0 { - Ok(()) - } else { - Err(CannotReallocInPlace) - } - } -} - -/// The allocator for unique pointers. -// This function must not unwind. If it does, MIR trans will fail. -#[cfg(not(test))] -#[lang = "exchange_malloc"] -#[inline] -unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { - if size == 0 { - align as *mut u8 - } else { - let layout = Layout::from_size_align_unchecked(size, align); - Heap.alloc(layout).unwrap_or_else(|err| { - Heap.oom(err) - }) - } -} - -#[cfg_attr(not(test), lang = "box_free")] -#[inline] -pub(crate) unsafe fn box_free(ptr: *mut T) { - let size = size_of_val(&*ptr); - let align = min_align_of_val(&*ptr); - // We do not allocate for Box when T is ZST, so deallocation is also not necessary. - if size != 0 { - let layout = Layout::from_size_align_unchecked(size, align); - Heap.dealloc(ptr as *mut u8, layout); - } -} - -#[cfg(test)] -mod tests { - extern crate test; - use self::test::Bencher; - use boxed::Box; - use heap::{Heap, Alloc, Layout}; - - #[test] - fn allocate_zeroed() { - unsafe { - let layout = Layout::from_size_align(1024, 1).unwrap(); - let ptr = Heap.alloc_zeroed(layout.clone()) - .unwrap_or_else(|e| Heap.oom(e)); - - let end = ptr.offset(layout.size() as isize); - let mut i = ptr; - while i < end { - assert_eq!(*i, 0); - i = i.offset(1); - } - Heap.dealloc(ptr, layout); - } - } - - #[bench] - fn alloc_owned_small(b: &mut Bencher) { - b.iter(|| { - let _: Box<_> = box 10; - }) - } -} diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 5ca39442342..617bc5c52b3 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -57,7 +57,7 @@ //! //! ## Heap interfaces //! -//! The [`heap`](heap/index.html) module defines the low-level interface to the +//! The [`alloc`](alloc/index.html) module defines the low-level interface to the //! default global allocator. It is not compatible with the libc allocator API. #![allow(unused_attributes)] @@ -145,7 +145,11 @@ pub use core::heap as allocator; // Heaps provided for low-level allocation strategies -pub mod heap; +pub mod alloc; + +#[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] +pub use alloc as heap; // Primitive types using the heaps above diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs new file mode 100644 index 00000000000..5c51bb2b51b --- /dev/null +++ b/src/libcore/alloc.rs @@ -0,0 +1,1125 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "allocator_api", + reason = "the precise API and guarantees it provides may be tweaked \ + slightly, especially to possibly take into account the \ + types being stored to make room for a future \ + tracing garbage collector", + issue = "32838")] + +use cmp; +use fmt; +use mem; +use usize; +use ptr::{self, NonNull}; + +extern { + /// An opaque, unsized type. Used for pointers to allocated memory. + /// + /// This type can only be used behind a pointer like `*mut Void` or `ptr::NonNull`. + /// Such pointers are similar to C’s `void*` type. + pub type Void; +} + +impl Void { + /// Similar to `std::ptr::null`, which requires `T: Sized`. + pub fn null() -> *const Self { + 0 as _ + } + + /// Similar to `std::ptr::null_mut`, which requires `T: Sized`. + pub fn null_mut() -> *mut Self { + 0 as _ + } +} + +/// Represents the combination of a starting address and +/// a total capacity of the returned block. +#[derive(Debug)] +pub struct Excess(pub *mut u8, pub usize); + +fn size_align() -> (usize, usize) { + (mem::size_of::(), mem::align_of::()) +} + +/// Layout of a block of memory. +/// +/// An instance of `Layout` describes a particular layout of memory. +/// You build a `Layout` up as an input to give to an allocator. +/// +/// All layouts have an associated non-negative size and a +/// power-of-two alignment. +/// +/// (Note however that layouts are *not* required to have positive +/// size, even though many allocators require that all memory +/// requests have positive size. A caller to the `Alloc::alloc` +/// method must either ensure that conditions like this are met, or +/// use specific allocators with looser requirements.) +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Layout { + // size of the requested block of memory, measured in bytes. + size: usize, + + // alignment of the requested block of memory, measured in bytes. + // we ensure that this is always a power-of-two, because API's + // like `posix_memalign` require it and it is a reasonable + // constraint to impose on Layout constructors. + // + // (However, we do not analogously require `align >= sizeof(void*)`, + // even though that is *also* a requirement of `posix_memalign`.) + align: usize, +} + + +// FIXME: audit default implementations for overflow errors, +// (potentially switching to overflowing_add and +// overflowing_mul as necessary). + +impl Layout { + /// Constructs a `Layout` from a given `size` and `align`, + /// or returns `None` if either of the following conditions + /// are not met: + /// + /// * `align` must be a power of two, + /// + /// * `size`, when rounded up to the nearest multiple of `align`, + /// must not overflow (i.e. the rounded value must be less than + /// `usize::MAX`). + #[inline] + pub fn from_size_align(size: usize, align: usize) -> Option { + if !align.is_power_of_two() { + return None; + } + + // (power-of-two implies align != 0.) + + // Rounded up size is: + // size_rounded_up = (size + align - 1) & !(align - 1); + // + // We know from above that align != 0. If adding (align - 1) + // does not overflow, then rounding up will be fine. + // + // Conversely, &-masking with !(align - 1) will subtract off + // only low-order-bits. Thus if overflow occurs with the sum, + // the &-mask cannot subtract enough to undo that overflow. + // + // Above implies that checking for summation overflow is both + // necessary and sufficient. + if size > usize::MAX - (align - 1) { + return None; + } + + unsafe { + Some(Layout::from_size_align_unchecked(size, align)) + } + } + + /// Creates a layout, bypassing all checks. + /// + /// # Safety + /// + /// This function is unsafe as it does not verify that `align` is + /// a power-of-two nor `size` aligned to `align` fits within the + /// address space (i.e. the `Layout::from_size_align` preconditions). + #[inline] + pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout { + Layout { size: size, align: align } + } + + /// The minimum size in bytes for a memory block of this layout. + #[inline] + pub fn size(&self) -> usize { self.size } + + /// The minimum byte alignment for a memory block of this layout. + #[inline] + pub fn align(&self) -> usize { self.align } + + /// Constructs a `Layout` suitable for holding a value of type `T`. + pub fn new() -> Self { + let (size, align) = size_align::(); + Layout::from_size_align(size, align).unwrap() + } + + /// Produces layout describing a record that could be used to + /// allocate backing structure for `T` (which could be a trait + /// or other unsized type like a slice). + pub fn for_value(t: &T) -> Self { + let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); + Layout::from_size_align(size, align).unwrap() + } + + /// Creates a layout describing the record that can hold a value + /// of the same layout as `self`, but that also is aligned to + /// alignment `align` (measured in bytes). + /// + /// If `self` already meets the prescribed alignment, then returns + /// `self`. + /// + /// Note that this method does not add any padding to the overall + /// size, regardless of whether the returned layout has a different + /// alignment. In other words, if `K` has size 16, `K.align_to(32)` + /// will *still* have size 16. + /// + /// # Panics + /// + /// Panics if the combination of `self.size` and the given `align` + /// violates the conditions listed in `from_size_align`. + #[inline] + pub fn align_to(&self, align: usize) -> Self { + Layout::from_size_align(self.size, cmp::max(self.align, align)).unwrap() + } + + /// Returns the amount of padding we must insert after `self` + /// to ensure that the following address will satisfy `align` + /// (measured in bytes). + /// + /// E.g. if `self.size` is 9, then `self.padding_needed_for(4)` + /// returns 3, because that is the minimum number of bytes of + /// padding required to get a 4-aligned address (assuming that the + /// corresponding memory block starts at a 4-aligned address). + /// + /// The return value of this function has no meaning if `align` is + /// not a power-of-two. + /// + /// Note that the utility of the returned value requires `align` + /// to be less than or equal to the alignment of the starting + /// address for the whole allocated block of memory. One way to + /// satisfy this constraint is to ensure `align <= self.align`. + #[inline] + pub fn padding_needed_for(&self, align: usize) -> usize { + let len = self.size(); + + // Rounded up value is: + // len_rounded_up = (len + align - 1) & !(align - 1); + // and then we return the padding difference: `len_rounded_up - len`. + // + // We use modular arithmetic throughout: + // + // 1. align is guaranteed to be > 0, so align - 1 is always + // valid. + // + // 2. `len + align - 1` can overflow by at most `align - 1`, + // so the &-mask wth `!(align - 1)` will ensure that in the + // case of overflow, `len_rounded_up` will itself be 0. + // Thus the returned padding, when added to `len`, yields 0, + // which trivially satisfies the alignment `align`. + // + // (Of course, attempts to allocate blocks of memory whose + // size and padding overflow in the above manner should cause + // the allocator to yield an error anyway.) + + let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); + return len_rounded_up.wrapping_sub(len); + } + + /// Creates a layout describing the record for `n` instances of + /// `self`, with a suitable amount of padding between each to + /// ensure that each instance is given its requested size and + /// alignment. On success, returns `(k, offs)` where `k` is the + /// layout of the array and `offs` is the distance between the start + /// of each element in the array. + /// + /// On arithmetic overflow, returns `None`. + #[inline] + pub fn repeat(&self, n: usize) -> Option<(Self, usize)> { + let padded_size = self.size.checked_add(self.padding_needed_for(self.align))?; + let alloc_size = padded_size.checked_mul(n)?; + + // We can assume that `self.align` is a power-of-two. + // Furthermore, `alloc_size` has already been rounded up + // to a multiple of `self.align`; therefore, the call to + // `Layout::from_size_align` below should never panic. + Some((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) + } + + /// Creates a layout describing the record for `self` followed by + /// `next`, including any necessary padding to ensure that `next` + /// will be properly aligned. Note that the result layout will + /// satisfy the alignment properties of both `self` and `next`. + /// + /// Returns `Some((k, offset))`, where `k` is layout of the concatenated + /// record and `offset` is the relative location, in bytes, of the + /// start of the `next` embedded within the concatenated record + /// (assuming that the record itself starts at offset 0). + /// + /// On arithmetic overflow, returns `None`. + pub fn extend(&self, next: Self) -> Option<(Self, usize)> { + let new_align = cmp::max(self.align, next.align); + let realigned = Layout::from_size_align(self.size, new_align)?; + + let pad = realigned.padding_needed_for(next.align); + + let offset = self.size.checked_add(pad)?; + let new_size = offset.checked_add(next.size)?; + + let layout = Layout::from_size_align(new_size, new_align)?; + Some((layout, offset)) + } + + /// Creates a layout describing the record for `n` instances of + /// `self`, with no padding between each instance. + /// + /// Note that, unlike `repeat`, `repeat_packed` does not guarantee + /// that the repeated instances of `self` will be properly + /// aligned, even if a given instance of `self` is properly + /// aligned. In other words, if the layout returned by + /// `repeat_packed` is used to allocate an array, it is not + /// guaranteed that all elements in the array will be properly + /// aligned. + /// + /// On arithmetic overflow, returns `None`. + pub fn repeat_packed(&self, n: usize) -> Option { + let size = self.size().checked_mul(n)?; + Layout::from_size_align(size, self.align) + } + + /// Creates a layout describing the record for `self` followed by + /// `next` with no additional padding between the two. Since no + /// padding is inserted, the alignment of `next` is irrelevant, + /// and is not incorporated *at all* into the resulting layout. + /// + /// Returns `(k, offset)`, where `k` is layout of the concatenated + /// record and `offset` is the relative location, in bytes, of the + /// start of the `next` embedded within the concatenated record + /// (assuming that the record itself starts at offset 0). + /// + /// (The `offset` is always the same as `self.size()`; we use this + /// signature out of convenience in matching the signature of + /// `extend`.) + /// + /// On arithmetic overflow, returns `None`. + pub fn extend_packed(&self, next: Self) -> Option<(Self, usize)> { + let new_size = self.size().checked_add(next.size())?; + let layout = Layout::from_size_align(new_size, self.align)?; + Some((layout, self.size())) + } + + /// Creates a layout describing the record for a `[T; n]`. + /// + /// On arithmetic overflow, returns `None`. + pub fn array(n: usize) -> Option { + Layout::new::() + .repeat(n) + .map(|(k, offs)| { + debug_assert!(offs == mem::size_of::()); + k + }) + } +} + +/// The `AllocErr` error specifies whether an allocation failure is +/// specifically due to resource exhaustion or if it is due to +/// something wrong when combining the given input arguments with this +/// allocator. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum AllocErr { + /// Error due to hitting some resource limit or otherwise running + /// out of memory. This condition strongly implies that *some* + /// series of deallocations would allow a subsequent reissuing of + /// the original allocation request to succeed. + Exhausted { request: Layout }, + + /// Error due to allocator being fundamentally incapable of + /// satisfying the original request. This condition implies that + /// such an allocation request will never succeed on the given + /// allocator, regardless of environment, memory pressure, or + /// other contextual conditions. + /// + /// For example, an allocator that does not support requests for + /// large memory blocks might return this error variant. + Unsupported { details: &'static str }, +} + +impl AllocErr { + #[inline] + pub fn invalid_input(details: &'static str) -> Self { + AllocErr::Unsupported { details: details } + } + #[inline] + pub fn is_memory_exhausted(&self) -> bool { + if let AllocErr::Exhausted { .. } = *self { true } else { false } + } + #[inline] + pub fn is_request_unsupported(&self) -> bool { + if let AllocErr::Unsupported { .. } = *self { true } else { false } + } + #[inline] + pub fn description(&self) -> &str { + match *self { + AllocErr::Exhausted { .. } => "allocator memory exhausted", + AllocErr::Unsupported { .. } => "unsupported allocator request", + } + } +} + +// (we need this for downstream impl of trait Error) +impl fmt::Display for AllocErr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +/// The `CannotReallocInPlace` error is used when `grow_in_place` or +/// `shrink_in_place` were unable to reuse the given memory block for +/// a requested layout. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct CannotReallocInPlace; + +impl CannotReallocInPlace { + pub fn description(&self) -> &str { + "cannot reallocate allocator's memory in place" + } +} + +// (we need this for downstream impl of trait Error) +impl fmt::Display for CannotReallocInPlace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +/// Augments `AllocErr` with a CapacityOverflow variant. +#[derive(Clone, PartialEq, Eq, Debug)] +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +pub enum CollectionAllocErr { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + /// Error due to the allocator (see the `AllocErr` type's docs). + AllocErr(AllocErr), +} + +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +impl From for CollectionAllocErr { + fn from(err: AllocErr) -> Self { + CollectionAllocErr::AllocErr(err) + } +} + +// FIXME: docs +pub unsafe trait GlobalAlloc { + unsafe fn alloc(&self, layout: Layout) -> *mut Void; + + unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout); + + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { + let size = layout.size(); + let ptr = self.alloc(layout); + if !ptr.is_null() { + ptr::write_bytes(ptr as *mut u8, 0, size); + } + ptr + } + + unsafe fn realloc(&self, ptr: *mut Void, old_layout: Layout, new_size: usize) -> *mut Void { + let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); + let new_ptr = self.alloc(new_layout); + if !new_ptr.is_null() { + ptr::copy_nonoverlapping( + ptr as *const u8, + new_ptr as *mut u8, + cmp::min(old_layout.size(), new_size), + ); + self.dealloc(ptr, old_layout); + } + new_ptr + } +} + +/// An implementation of `Alloc` can allocate, reallocate, and +/// deallocate arbitrary blocks of data described via `Layout`. +/// +/// Some of the methods require that a memory block be *currently +/// allocated* via an allocator. This means that: +/// +/// * the starting address for that memory block was previously +/// returned by a previous call to an allocation method (`alloc`, +/// `alloc_zeroed`, `alloc_excess`, `alloc_one`, `alloc_array`) or +/// reallocation method (`realloc`, `realloc_excess`, or +/// `realloc_array`), and +/// +/// * the memory block has not been subsequently deallocated, where +/// blocks are deallocated either by being passed to a deallocation +/// method (`dealloc`, `dealloc_one`, `dealloc_array`) or by being +/// passed to a reallocation method (see above) that returns `Ok`. +/// +/// A note regarding zero-sized types and zero-sized layouts: many +/// methods in the `Alloc` trait state that allocation requests +/// must be non-zero size, or else undefined behavior can result. +/// +/// * However, some higher-level allocation methods (`alloc_one`, +/// `alloc_array`) are well-defined on zero-sized types and can +/// optionally support them: it is left up to the implementor +/// whether to return `Err`, or to return `Ok` with some pointer. +/// +/// * If an `Alloc` implementation chooses to return `Ok` in this +/// case (i.e. the pointer denotes a zero-sized inaccessible block) +/// then that returned pointer must be considered "currently +/// allocated". On such an allocator, *all* methods that take +/// currently-allocated pointers as inputs must accept these +/// zero-sized pointers, *without* causing undefined behavior. +/// +/// * In other words, if a zero-sized pointer can flow out of an +/// allocator, then that allocator must likewise accept that pointer +/// flowing back into its deallocation and reallocation methods. +/// +/// Some of the methods require that a layout *fit* a memory block. +/// What it means for a layout to "fit" a memory block means (or +/// equivalently, for a memory block to "fit" a layout) is that the +/// following two conditions must hold: +/// +/// 1. The block's starting address must be aligned to `layout.align()`. +/// +/// 2. The block's size must fall in the range `[use_min, use_max]`, where: +/// +/// * `use_min` is `self.usable_size(layout).0`, and +/// +/// * `use_max` is the capacity that was (or would have been) +/// returned when (if) the block was allocated via a call to +/// `alloc_excess` or `realloc_excess`. +/// +/// Note that: +/// +/// * the size of the layout most recently used to allocate the block +/// is guaranteed to be in the range `[use_min, use_max]`, and +/// +/// * a lower-bound on `use_max` can be safely approximated by a call to +/// `usable_size`. +/// +/// * if a layout `k` fits a memory block (denoted by `ptr`) +/// currently allocated via an allocator `a`, then it is legal to +/// use that layout to deallocate it, i.e. `a.dealloc(ptr, k);`. +/// +/// # Unsafety +/// +/// The `Alloc` trait is an `unsafe` trait for a number of reasons, and +/// implementors must ensure that they adhere to these contracts: +/// +/// * Pointers returned from allocation functions must point to valid memory and +/// retain their validity until at least the instance of `Alloc` is dropped +/// itself. +/// +/// * It's undefined behavior if global allocators unwind. This restriction may +/// be lifted in the future, but currently a panic from any of these +/// functions may lead to memory unsafety. Note that as of the time of this +/// writing allocators *not* intending to be global allocators can still panic +/// in their implementation without violating memory safety. +/// +/// * `Layout` queries and calculations in general must be correct. Callers of +/// this trait are allowed to rely on the contracts defined on each method, +/// and implementors must ensure such contracts remain true. +/// +/// Note that this list may get tweaked over time as clarifications are made in +/// the future. Additionally global allocators may gain unique requirements for +/// how to safely implement one in the future as well. +pub unsafe trait Alloc { + + // (Note: existing allocators have unspecified but well-defined + // behavior in response to a zero size allocation request ; + // e.g. in C, `malloc` of 0 will either return a null pointer or a + // unique pointer, but will not have arbitrary undefined + // behavior. Rust should consider revising the alloc::heap crate + // to reflect this reality.) + + /// Returns a pointer meeting the size and alignment guarantees of + /// `layout`. + /// + /// If this method returns an `Ok(addr)`, then the `addr` returned + /// will be non-null address pointing to a block of storage + /// suitable for holding an instance of `layout`. + /// + /// The returned block of storage may or may not have its contents + /// initialized. (Extension subtraits might restrict this + /// behavior, e.g. to ensure initialization to particular sets of + /// bit patterns.) + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure that `layout` has non-zero size. + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints. + /// + /// Implementations are encouraged to return `Err` on memory + /// exhaustion rather than panicking or aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; + + /// Deallocate the memory referenced by `ptr`. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must denote a block of memory currently allocated via + /// this allocator, + /// + /// * `layout` must *fit* that block of memory, + /// + /// * In addition to fitting the block of memory `layout`, the + /// alignment of the `layout` must match the alignment used + /// to allocate that block of memory. + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); + + /// Allocator-specific method for signaling an out-of-memory + /// condition. + /// + /// `oom` aborts the thread or process, optionally performing + /// cleanup or logging diagnostic information before panicking or + /// aborting. + /// + /// `oom` is meant to be used by clients unable to cope with an + /// unsatisfied allocation request (signaled by an error such as + /// `AllocErr::Exhausted`), and wish to abandon computation rather + /// than attempt to recover locally. Such clients should pass the + /// signaling error value back into `oom`, where the allocator + /// may incorporate that error value into its diagnostic report + /// before aborting. + /// + /// Implementations of the `oom` method are discouraged from + /// infinitely regressing in nested calls to `oom`. In + /// practice this means implementors should eschew allocating, + /// especially from `self` (directly or indirectly). + /// + /// Implementations of the allocation and reallocation methods + /// (e.g. `alloc`, `alloc_one`, `realloc`) are discouraged from + /// panicking (or aborting) in the event of memory exhaustion; + /// instead they should return an appropriate error from the + /// invoked method, and let the client decide whether to invoke + /// this `oom` method in response. + fn oom(&mut self, _: AllocErr) -> ! { + unsafe { ::intrinsics::abort() } + } + + // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS == + // usable_size + + /// Returns bounds on the guaranteed usable size of a successful + /// allocation created with the specified `layout`. + /// + /// In particular, if one has a memory block allocated via a given + /// allocator `a` and layout `k` where `a.usable_size(k)` returns + /// `(l, u)`, then one can pass that block to `a.dealloc()` with a + /// layout in the size range [l, u]. + /// + /// (All implementors of `usable_size` must ensure that + /// `l <= k.size() <= u`) + /// + /// Both the lower- and upper-bounds (`l` and `u` respectively) + /// are provided, because an allocator based on size classes could + /// misbehave if one attempts to deallocate a block without + /// providing a correct value for its size (i.e., one within the + /// range `[l, u]`). + /// + /// Clients who wish to make use of excess capacity are encouraged + /// to use the `alloc_excess` and `realloc_excess` instead, as + /// this method is constrained to report conservative values that + /// serve as valid bounds for *all possible* allocation method + /// calls. + /// + /// However, for clients that do not wish to track the capacity + /// returned by `alloc_excess` locally, this method is likely to + /// produce useful results. + #[inline] + fn usable_size(&self, layout: &Layout) -> (usize, usize) { + (layout.size(), layout.size()) + } + + // == METHODS FOR MEMORY REUSE == + // realloc. alloc_excess, realloc_excess + + /// Returns a pointer suitable for holding data described by + /// `new_layout`, meeting its size and alignment guarantees. To + /// accomplish this, this may extend or shrink the allocation + /// referenced by `ptr` to fit `new_layout`. + /// + /// If this returns `Ok`, then ownership of the memory block + /// referenced by `ptr` has been transferred to this + /// allocator. The memory may or may not have been freed, and + /// should be considered unusable (unless of course it was + /// transferred back to the caller again via the return value of + /// this method). + /// + /// If this method returns `Err`, then ownership of the memory + /// block has not been transferred to this allocator, and the + /// contents of the memory block are unaltered. + /// + /// For best results, `new_layout` should not impose a different + /// alignment constraint than `layout`. (In other words, + /// `new_layout.align()` should equal `layout.align()`.) However, + /// behavior is well-defined (though underspecified) when this + /// constraint is violated; further discussion below. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above). (The `new_layout` + /// argument need not fit it.) + /// + /// * `new_layout` must have size greater than zero. + /// + /// * the alignment of `new_layout` is non-zero. + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// # Errors + /// + /// Returns `Err` only if `new_layout` does not match the + /// alignment of `layout`, or does not meet the allocator's size + /// and alignment constraints of the allocator, or if reallocation + /// otherwise fails. + /// + /// (Note the previous sentence did not say "if and only if" -- in + /// particular, an implementation of this method *can* return `Ok` + /// if `new_layout.align() != old_layout.align()`; or it can + /// return `Err` in that scenario, depending on whether this + /// allocator can dynamically adjust the alignment constraint for + /// the block.) + /// + /// Implementations are encouraged to return `Err` on memory + /// exhaustion rather than panicking or aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an + /// reallocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn realloc(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<*mut u8, AllocErr> { + let new_size = new_layout.size(); + let old_size = layout.size(); + let aligns_match = layout.align == new_layout.align; + + if new_size >= old_size && aligns_match { + if let Ok(()) = self.grow_in_place(ptr, layout.clone(), new_layout.clone()) { + return Ok(ptr); + } + } else if new_size < old_size && aligns_match { + if let Ok(()) = self.shrink_in_place(ptr, layout.clone(), new_layout.clone()) { + return Ok(ptr); + } + } + + // otherwise, fall back on alloc + copy + dealloc. + let result = self.alloc(new_layout); + if let Ok(new_ptr) = result { + ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size)); + self.dealloc(ptr, layout); + } + result + } + + /// Behaves like `alloc`, but also ensures that the contents + /// are set to zero before being returned. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `alloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `alloc`. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + let size = layout.size(); + let p = self.alloc(layout); + if let Ok(p) = p { + ptr::write_bytes(p, 0, size); + } + p + } + + /// Behaves like `alloc`, but also returns the whole size of + /// the returned block. For some `layout` inputs, like arrays, this + /// may include extra storage usable for additional data. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `alloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `alloc`. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { + let usable_size = self.usable_size(&layout); + self.alloc(layout).map(|p| Excess(p, usable_size.1)) + } + + /// Behaves like `realloc`, but also returns the whole size of + /// the returned block. For some `layout` inputs, like arrays, this + /// may include extra storage usable for additional data. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `realloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `realloc`. + /// + /// Clients wishing to abort computation in response to an + /// reallocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn realloc_excess(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result { + let usable_size = self.usable_size(&new_layout); + self.realloc(ptr, layout, new_layout) + .map(|p| Excess(p, usable_size.1)) + } + + /// Attempts to extend the allocation referenced by `ptr` to fit `new_layout`. + /// + /// If this returns `Ok`, then the allocator has asserted that the + /// memory block referenced by `ptr` now fits `new_layout`, and thus can + /// be used to carry data of that layout. (The allocator is allowed to + /// expend effort to accomplish this, such as extending the memory block to + /// include successor blocks, or virtual memory tricks.) + /// + /// Regardless of what this method returns, ownership of the + /// memory block referenced by `ptr` has not been transferred, and + /// the contents of the memory block are unaltered. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above); note the + /// `new_layout` argument need not fit it, + /// + /// * `new_layout.size()` must not be less than `layout.size()`, + /// + /// * `new_layout.align()` must equal `layout.align()`. + /// + /// # Errors + /// + /// Returns `Err(CannotReallocInPlace)` when the allocator is + /// unable to assert that the memory block referenced by `ptr` + /// could fit `layout`. + /// + /// Note that one cannot pass `CannotReallocInPlace` to the `oom` + /// method; clients are expected either to be able to recover from + /// `grow_in_place` failures without aborting, or to fall back on + /// another reallocation method before resorting to an abort. + unsafe fn grow_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + let _ = ptr; // this default implementation doesn't care about the actual address. + debug_assert!(new_layout.size >= layout.size); + debug_assert!(new_layout.align == layout.align); + let (_l, u) = self.usable_size(&layout); + // _l <= layout.size() [guaranteed by usable_size()] + // layout.size() <= new_layout.size() [required by this method] + if new_layout.size <= u { + return Ok(()); + } else { + return Err(CannotReallocInPlace); + } + } + + /// Attempts to shrink the allocation referenced by `ptr` to fit `new_layout`. + /// + /// If this returns `Ok`, then the allocator has asserted that the + /// memory block referenced by `ptr` now fits `new_layout`, and + /// thus can only be used to carry data of that smaller + /// layout. (The allocator is allowed to take advantage of this, + /// carving off portions of the block for reuse elsewhere.) The + /// truncated contents of the block within the smaller layout are + /// unaltered, and ownership of block has not been transferred. + /// + /// If this returns `Err`, then the memory block is considered to + /// still represent the original (larger) `layout`. None of the + /// block has been carved off for reuse elsewhere, ownership of + /// the memory block has not been transferred, and the contents of + /// the memory block are unaltered. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above); note the + /// `new_layout` argument need not fit it, + /// + /// * `new_layout.size()` must not be greater than `layout.size()` + /// (and must be greater than zero), + /// + /// * `new_layout.align()` must equal `layout.align()`. + /// + /// # Errors + /// + /// Returns `Err(CannotReallocInPlace)` when the allocator is + /// unable to assert that the memory block referenced by `ptr` + /// could fit `layout`. + /// + /// Note that one cannot pass `CannotReallocInPlace` to the `oom` + /// method; clients are expected either to be able to recover from + /// `shrink_in_place` failures without aborting, or to fall back + /// on another reallocation method before resorting to an abort. + unsafe fn shrink_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + let _ = ptr; // this default implementation doesn't care about the actual address. + debug_assert!(new_layout.size <= layout.size); + debug_assert!(new_layout.align == layout.align); + let (l, _u) = self.usable_size(&layout); + // layout.size() <= _u [guaranteed by usable_size()] + // new_layout.size() <= layout.size() [required by this method] + if l <= new_layout.size { + return Ok(()); + } else { + return Err(CannotReallocInPlace); + } + } + + + // == COMMON USAGE PATTERNS == + // alloc_one, dealloc_one, alloc_array, realloc_array. dealloc_array + + /// Allocates a block suitable for holding an instance of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` + /// must be considered "currently allocated" and must be + /// acceptable input to methods such as `realloc` or `dealloc`, + /// *even if* `T` is a zero-sized type. In other words, if your + /// `Alloc` implementation overrides this method in a manner + /// that can return a zero-sized `ptr`, then all reallocation and + /// deallocation methods need to be similarly overridden to accept + /// such values as input. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `T` does not meet allocator's size or alignment constraints. + /// + /// For zero-sized `T`, may return either of `Ok` or `Err`, but + /// will *not* yield undefined behavior. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + fn alloc_one(&mut self) -> Result, AllocErr> + where Self: Sized + { + let k = Layout::new::(); + if k.size() > 0 { + unsafe { self.alloc(k).map(|p| NonNull::new_unchecked(p as *mut T)) } + } else { + Err(AllocErr::invalid_input("zero-sized type invalid for alloc_one")) + } + } + + /// Deallocates a block suitable for holding an instance of `T`. + /// + /// The given block must have been produced by this allocator, + /// and must be suitable for storing a `T` (in terms of alignment + /// as well as minimum and maximum size); otherwise yields + /// undefined behavior. + /// + /// Captures a common usage pattern for allocators. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure both: + /// + /// * `ptr` must denote a block of memory currently allocated via this allocator + /// + /// * the layout of `T` must *fit* that block of memory. + unsafe fn dealloc_one(&mut self, ptr: NonNull) + where Self: Sized + { + let raw_ptr = ptr.as_ptr() as *mut u8; + let k = Layout::new::(); + if k.size() > 0 { + self.dealloc(raw_ptr, k); + } + } + + /// Allocates a block suitable for holding `n` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` + /// must be considered "currently allocated" and must be + /// acceptable input to methods such as `realloc` or `dealloc`, + /// *even if* `T` is a zero-sized type. In other words, if your + /// `Alloc` implementation overrides this method in a manner + /// that can return a zero-sized `ptr`, then all reallocation and + /// deallocation methods need to be similarly overridden to accept + /// such values as input. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `[T; n]` does not meet allocator's size or alignment + /// constraints. + /// + /// For zero-sized `T` or `n == 0`, may return either of `Ok` or + /// `Err`, but will *not* yield undefined behavior. + /// + /// Always returns `Err` on arithmetic overflow. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + fn alloc_array(&mut self, n: usize) -> Result, AllocErr> + where Self: Sized + { + match Layout::array::(n) { + Some(ref layout) if layout.size() > 0 => { + unsafe { + self.alloc(layout.clone()) + .map(|p| { + NonNull::new_unchecked(p as *mut T) + }) + } + } + _ => Err(AllocErr::invalid_input("invalid layout for alloc_array")), + } + } + + /// Reallocates a block previously suitable for holding `n_old` + /// instances of `T`, returning a block suitable for holding + /// `n_new` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * the layout of `[T; n_old]` must *fit* that block of memory. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `[T; n_new]` does not meet allocator's size or alignment + /// constraints. + /// + /// For zero-sized `T` or `n_new == 0`, may return either of `Ok` or + /// `Err`, but will *not* yield undefined behavior. + /// + /// Always returns `Err` on arithmetic overflow. + /// + /// Clients wishing to abort computation in response to an + /// reallocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn realloc_array(&mut self, + ptr: NonNull, + n_old: usize, + n_new: usize) -> Result, AllocErr> + where Self: Sized + { + match (Layout::array::(n_old), Layout::array::(n_new), ptr.as_ptr()) { + (Some(ref k_old), Some(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { + self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone()) + .map(|p| NonNull::new_unchecked(p as *mut T)) + } + _ => { + Err(AllocErr::invalid_input("invalid layout for realloc_array")) + } + } + } + + /// Deallocates a block suitable for holding `n` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure both: + /// + /// * `ptr` must denote a block of memory currently allocated via this allocator + /// + /// * the layout of `[T; n]` must *fit* that block of memory. + /// + /// # Errors + /// + /// Returning `Err` indicates that either `[T; n]` or the given + /// memory block does not meet allocator's size or alignment + /// constraints. + /// + /// Always returns `Err` on arithmetic overflow. + unsafe fn dealloc_array(&mut self, ptr: NonNull, n: usize) -> Result<(), AllocErr> + where Self: Sized + { + let raw_ptr = ptr.as_ptr() as *mut u8; + match Layout::array::(n) { + Some(ref k) if k.size() > 0 => { + Ok(self.dealloc(raw_ptr, k.clone())) + } + _ => { + Err(AllocErr::invalid_input("invalid layout for dealloc_array")) + } + } + } +} diff --git a/src/libcore/heap.rs b/src/libcore/heap.rs deleted file mode 100644 index 5c51bb2b51b..00000000000 --- a/src/libcore/heap.rs +++ /dev/null @@ -1,1125 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked \ - slightly, especially to possibly take into account the \ - types being stored to make room for a future \ - tracing garbage collector", - issue = "32838")] - -use cmp; -use fmt; -use mem; -use usize; -use ptr::{self, NonNull}; - -extern { - /// An opaque, unsized type. Used for pointers to allocated memory. - /// - /// This type can only be used behind a pointer like `*mut Void` or `ptr::NonNull`. - /// Such pointers are similar to C’s `void*` type. - pub type Void; -} - -impl Void { - /// Similar to `std::ptr::null`, which requires `T: Sized`. - pub fn null() -> *const Self { - 0 as _ - } - - /// Similar to `std::ptr::null_mut`, which requires `T: Sized`. - pub fn null_mut() -> *mut Self { - 0 as _ - } -} - -/// Represents the combination of a starting address and -/// a total capacity of the returned block. -#[derive(Debug)] -pub struct Excess(pub *mut u8, pub usize); - -fn size_align() -> (usize, usize) { - (mem::size_of::(), mem::align_of::()) -} - -/// Layout of a block of memory. -/// -/// An instance of `Layout` describes a particular layout of memory. -/// You build a `Layout` up as an input to give to an allocator. -/// -/// All layouts have an associated non-negative size and a -/// power-of-two alignment. -/// -/// (Note however that layouts are *not* required to have positive -/// size, even though many allocators require that all memory -/// requests have positive size. A caller to the `Alloc::alloc` -/// method must either ensure that conditions like this are met, or -/// use specific allocators with looser requirements.) -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Layout { - // size of the requested block of memory, measured in bytes. - size: usize, - - // alignment of the requested block of memory, measured in bytes. - // we ensure that this is always a power-of-two, because API's - // like `posix_memalign` require it and it is a reasonable - // constraint to impose on Layout constructors. - // - // (However, we do not analogously require `align >= sizeof(void*)`, - // even though that is *also* a requirement of `posix_memalign`.) - align: usize, -} - - -// FIXME: audit default implementations for overflow errors, -// (potentially switching to overflowing_add and -// overflowing_mul as necessary). - -impl Layout { - /// Constructs a `Layout` from a given `size` and `align`, - /// or returns `None` if either of the following conditions - /// are not met: - /// - /// * `align` must be a power of two, - /// - /// * `size`, when rounded up to the nearest multiple of `align`, - /// must not overflow (i.e. the rounded value must be less than - /// `usize::MAX`). - #[inline] - pub fn from_size_align(size: usize, align: usize) -> Option { - if !align.is_power_of_two() { - return None; - } - - // (power-of-two implies align != 0.) - - // Rounded up size is: - // size_rounded_up = (size + align - 1) & !(align - 1); - // - // We know from above that align != 0. If adding (align - 1) - // does not overflow, then rounding up will be fine. - // - // Conversely, &-masking with !(align - 1) will subtract off - // only low-order-bits. Thus if overflow occurs with the sum, - // the &-mask cannot subtract enough to undo that overflow. - // - // Above implies that checking for summation overflow is both - // necessary and sufficient. - if size > usize::MAX - (align - 1) { - return None; - } - - unsafe { - Some(Layout::from_size_align_unchecked(size, align)) - } - } - - /// Creates a layout, bypassing all checks. - /// - /// # Safety - /// - /// This function is unsafe as it does not verify that `align` is - /// a power-of-two nor `size` aligned to `align` fits within the - /// address space (i.e. the `Layout::from_size_align` preconditions). - #[inline] - pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout { - Layout { size: size, align: align } - } - - /// The minimum size in bytes for a memory block of this layout. - #[inline] - pub fn size(&self) -> usize { self.size } - - /// The minimum byte alignment for a memory block of this layout. - #[inline] - pub fn align(&self) -> usize { self.align } - - /// Constructs a `Layout` suitable for holding a value of type `T`. - pub fn new() -> Self { - let (size, align) = size_align::(); - Layout::from_size_align(size, align).unwrap() - } - - /// Produces layout describing a record that could be used to - /// allocate backing structure for `T` (which could be a trait - /// or other unsized type like a slice). - pub fn for_value(t: &T) -> Self { - let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); - Layout::from_size_align(size, align).unwrap() - } - - /// Creates a layout describing the record that can hold a value - /// of the same layout as `self`, but that also is aligned to - /// alignment `align` (measured in bytes). - /// - /// If `self` already meets the prescribed alignment, then returns - /// `self`. - /// - /// Note that this method does not add any padding to the overall - /// size, regardless of whether the returned layout has a different - /// alignment. In other words, if `K` has size 16, `K.align_to(32)` - /// will *still* have size 16. - /// - /// # Panics - /// - /// Panics if the combination of `self.size` and the given `align` - /// violates the conditions listed in `from_size_align`. - #[inline] - pub fn align_to(&self, align: usize) -> Self { - Layout::from_size_align(self.size, cmp::max(self.align, align)).unwrap() - } - - /// Returns the amount of padding we must insert after `self` - /// to ensure that the following address will satisfy `align` - /// (measured in bytes). - /// - /// E.g. if `self.size` is 9, then `self.padding_needed_for(4)` - /// returns 3, because that is the minimum number of bytes of - /// padding required to get a 4-aligned address (assuming that the - /// corresponding memory block starts at a 4-aligned address). - /// - /// The return value of this function has no meaning if `align` is - /// not a power-of-two. - /// - /// Note that the utility of the returned value requires `align` - /// to be less than or equal to the alignment of the starting - /// address for the whole allocated block of memory. One way to - /// satisfy this constraint is to ensure `align <= self.align`. - #[inline] - pub fn padding_needed_for(&self, align: usize) -> usize { - let len = self.size(); - - // Rounded up value is: - // len_rounded_up = (len + align - 1) & !(align - 1); - // and then we return the padding difference: `len_rounded_up - len`. - // - // We use modular arithmetic throughout: - // - // 1. align is guaranteed to be > 0, so align - 1 is always - // valid. - // - // 2. `len + align - 1` can overflow by at most `align - 1`, - // so the &-mask wth `!(align - 1)` will ensure that in the - // case of overflow, `len_rounded_up` will itself be 0. - // Thus the returned padding, when added to `len`, yields 0, - // which trivially satisfies the alignment `align`. - // - // (Of course, attempts to allocate blocks of memory whose - // size and padding overflow in the above manner should cause - // the allocator to yield an error anyway.) - - let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); - return len_rounded_up.wrapping_sub(len); - } - - /// Creates a layout describing the record for `n` instances of - /// `self`, with a suitable amount of padding between each to - /// ensure that each instance is given its requested size and - /// alignment. On success, returns `(k, offs)` where `k` is the - /// layout of the array and `offs` is the distance between the start - /// of each element in the array. - /// - /// On arithmetic overflow, returns `None`. - #[inline] - pub fn repeat(&self, n: usize) -> Option<(Self, usize)> { - let padded_size = self.size.checked_add(self.padding_needed_for(self.align))?; - let alloc_size = padded_size.checked_mul(n)?; - - // We can assume that `self.align` is a power-of-two. - // Furthermore, `alloc_size` has already been rounded up - // to a multiple of `self.align`; therefore, the call to - // `Layout::from_size_align` below should never panic. - Some((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) - } - - /// Creates a layout describing the record for `self` followed by - /// `next`, including any necessary padding to ensure that `next` - /// will be properly aligned. Note that the result layout will - /// satisfy the alignment properties of both `self` and `next`. - /// - /// Returns `Some((k, offset))`, where `k` is layout of the concatenated - /// record and `offset` is the relative location, in bytes, of the - /// start of the `next` embedded within the concatenated record - /// (assuming that the record itself starts at offset 0). - /// - /// On arithmetic overflow, returns `None`. - pub fn extend(&self, next: Self) -> Option<(Self, usize)> { - let new_align = cmp::max(self.align, next.align); - let realigned = Layout::from_size_align(self.size, new_align)?; - - let pad = realigned.padding_needed_for(next.align); - - let offset = self.size.checked_add(pad)?; - let new_size = offset.checked_add(next.size)?; - - let layout = Layout::from_size_align(new_size, new_align)?; - Some((layout, offset)) - } - - /// Creates a layout describing the record for `n` instances of - /// `self`, with no padding between each instance. - /// - /// Note that, unlike `repeat`, `repeat_packed` does not guarantee - /// that the repeated instances of `self` will be properly - /// aligned, even if a given instance of `self` is properly - /// aligned. In other words, if the layout returned by - /// `repeat_packed` is used to allocate an array, it is not - /// guaranteed that all elements in the array will be properly - /// aligned. - /// - /// On arithmetic overflow, returns `None`. - pub fn repeat_packed(&self, n: usize) -> Option { - let size = self.size().checked_mul(n)?; - Layout::from_size_align(size, self.align) - } - - /// Creates a layout describing the record for `self` followed by - /// `next` with no additional padding between the two. Since no - /// padding is inserted, the alignment of `next` is irrelevant, - /// and is not incorporated *at all* into the resulting layout. - /// - /// Returns `(k, offset)`, where `k` is layout of the concatenated - /// record and `offset` is the relative location, in bytes, of the - /// start of the `next` embedded within the concatenated record - /// (assuming that the record itself starts at offset 0). - /// - /// (The `offset` is always the same as `self.size()`; we use this - /// signature out of convenience in matching the signature of - /// `extend`.) - /// - /// On arithmetic overflow, returns `None`. - pub fn extend_packed(&self, next: Self) -> Option<(Self, usize)> { - let new_size = self.size().checked_add(next.size())?; - let layout = Layout::from_size_align(new_size, self.align)?; - Some((layout, self.size())) - } - - /// Creates a layout describing the record for a `[T; n]`. - /// - /// On arithmetic overflow, returns `None`. - pub fn array(n: usize) -> Option { - Layout::new::() - .repeat(n) - .map(|(k, offs)| { - debug_assert!(offs == mem::size_of::()); - k - }) - } -} - -/// The `AllocErr` error specifies whether an allocation failure is -/// specifically due to resource exhaustion or if it is due to -/// something wrong when combining the given input arguments with this -/// allocator. -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum AllocErr { - /// Error due to hitting some resource limit or otherwise running - /// out of memory. This condition strongly implies that *some* - /// series of deallocations would allow a subsequent reissuing of - /// the original allocation request to succeed. - Exhausted { request: Layout }, - - /// Error due to allocator being fundamentally incapable of - /// satisfying the original request. This condition implies that - /// such an allocation request will never succeed on the given - /// allocator, regardless of environment, memory pressure, or - /// other contextual conditions. - /// - /// For example, an allocator that does not support requests for - /// large memory blocks might return this error variant. - Unsupported { details: &'static str }, -} - -impl AllocErr { - #[inline] - pub fn invalid_input(details: &'static str) -> Self { - AllocErr::Unsupported { details: details } - } - #[inline] - pub fn is_memory_exhausted(&self) -> bool { - if let AllocErr::Exhausted { .. } = *self { true } else { false } - } - #[inline] - pub fn is_request_unsupported(&self) -> bool { - if let AllocErr::Unsupported { .. } = *self { true } else { false } - } - #[inline] - pub fn description(&self) -> &str { - match *self { - AllocErr::Exhausted { .. } => "allocator memory exhausted", - AllocErr::Unsupported { .. } => "unsupported allocator request", - } - } -} - -// (we need this for downstream impl of trait Error) -impl fmt::Display for AllocErr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.description()) - } -} - -/// The `CannotReallocInPlace` error is used when `grow_in_place` or -/// `shrink_in_place` were unable to reuse the given memory block for -/// a requested layout. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct CannotReallocInPlace; - -impl CannotReallocInPlace { - pub fn description(&self) -> &str { - "cannot reallocate allocator's memory in place" - } -} - -// (we need this for downstream impl of trait Error) -impl fmt::Display for CannotReallocInPlace { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.description()) - } -} - -/// Augments `AllocErr` with a CapacityOverflow variant. -#[derive(Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub enum CollectionAllocErr { - /// Error due to the computed capacity exceeding the collection's maximum - /// (usually `isize::MAX` bytes). - CapacityOverflow, - /// Error due to the allocator (see the `AllocErr` type's docs). - AllocErr(AllocErr), -} - -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -impl From for CollectionAllocErr { - fn from(err: AllocErr) -> Self { - CollectionAllocErr::AllocErr(err) - } -} - -// FIXME: docs -pub unsafe trait GlobalAlloc { - unsafe fn alloc(&self, layout: Layout) -> *mut Void; - - unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout); - - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { - let size = layout.size(); - let ptr = self.alloc(layout); - if !ptr.is_null() { - ptr::write_bytes(ptr as *mut u8, 0, size); - } - ptr - } - - unsafe fn realloc(&self, ptr: *mut Void, old_layout: Layout, new_size: usize) -> *mut Void { - let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); - let new_ptr = self.alloc(new_layout); - if !new_ptr.is_null() { - ptr::copy_nonoverlapping( - ptr as *const u8, - new_ptr as *mut u8, - cmp::min(old_layout.size(), new_size), - ); - self.dealloc(ptr, old_layout); - } - new_ptr - } -} - -/// An implementation of `Alloc` can allocate, reallocate, and -/// deallocate arbitrary blocks of data described via `Layout`. -/// -/// Some of the methods require that a memory block be *currently -/// allocated* via an allocator. This means that: -/// -/// * the starting address for that memory block was previously -/// returned by a previous call to an allocation method (`alloc`, -/// `alloc_zeroed`, `alloc_excess`, `alloc_one`, `alloc_array`) or -/// reallocation method (`realloc`, `realloc_excess`, or -/// `realloc_array`), and -/// -/// * the memory block has not been subsequently deallocated, where -/// blocks are deallocated either by being passed to a deallocation -/// method (`dealloc`, `dealloc_one`, `dealloc_array`) or by being -/// passed to a reallocation method (see above) that returns `Ok`. -/// -/// A note regarding zero-sized types and zero-sized layouts: many -/// methods in the `Alloc` trait state that allocation requests -/// must be non-zero size, or else undefined behavior can result. -/// -/// * However, some higher-level allocation methods (`alloc_one`, -/// `alloc_array`) are well-defined on zero-sized types and can -/// optionally support them: it is left up to the implementor -/// whether to return `Err`, or to return `Ok` with some pointer. -/// -/// * If an `Alloc` implementation chooses to return `Ok` in this -/// case (i.e. the pointer denotes a zero-sized inaccessible block) -/// then that returned pointer must be considered "currently -/// allocated". On such an allocator, *all* methods that take -/// currently-allocated pointers as inputs must accept these -/// zero-sized pointers, *without* causing undefined behavior. -/// -/// * In other words, if a zero-sized pointer can flow out of an -/// allocator, then that allocator must likewise accept that pointer -/// flowing back into its deallocation and reallocation methods. -/// -/// Some of the methods require that a layout *fit* a memory block. -/// What it means for a layout to "fit" a memory block means (or -/// equivalently, for a memory block to "fit" a layout) is that the -/// following two conditions must hold: -/// -/// 1. The block's starting address must be aligned to `layout.align()`. -/// -/// 2. The block's size must fall in the range `[use_min, use_max]`, where: -/// -/// * `use_min` is `self.usable_size(layout).0`, and -/// -/// * `use_max` is the capacity that was (or would have been) -/// returned when (if) the block was allocated via a call to -/// `alloc_excess` or `realloc_excess`. -/// -/// Note that: -/// -/// * the size of the layout most recently used to allocate the block -/// is guaranteed to be in the range `[use_min, use_max]`, and -/// -/// * a lower-bound on `use_max` can be safely approximated by a call to -/// `usable_size`. -/// -/// * if a layout `k` fits a memory block (denoted by `ptr`) -/// currently allocated via an allocator `a`, then it is legal to -/// use that layout to deallocate it, i.e. `a.dealloc(ptr, k);`. -/// -/// # Unsafety -/// -/// The `Alloc` trait is an `unsafe` trait for a number of reasons, and -/// implementors must ensure that they adhere to these contracts: -/// -/// * Pointers returned from allocation functions must point to valid memory and -/// retain their validity until at least the instance of `Alloc` is dropped -/// itself. -/// -/// * It's undefined behavior if global allocators unwind. This restriction may -/// be lifted in the future, but currently a panic from any of these -/// functions may lead to memory unsafety. Note that as of the time of this -/// writing allocators *not* intending to be global allocators can still panic -/// in their implementation without violating memory safety. -/// -/// * `Layout` queries and calculations in general must be correct. Callers of -/// this trait are allowed to rely on the contracts defined on each method, -/// and implementors must ensure such contracts remain true. -/// -/// Note that this list may get tweaked over time as clarifications are made in -/// the future. Additionally global allocators may gain unique requirements for -/// how to safely implement one in the future as well. -pub unsafe trait Alloc { - - // (Note: existing allocators have unspecified but well-defined - // behavior in response to a zero size allocation request ; - // e.g. in C, `malloc` of 0 will either return a null pointer or a - // unique pointer, but will not have arbitrary undefined - // behavior. Rust should consider revising the alloc::heap crate - // to reflect this reality.) - - /// Returns a pointer meeting the size and alignment guarantees of - /// `layout`. - /// - /// If this method returns an `Ok(addr)`, then the `addr` returned - /// will be non-null address pointing to a block of storage - /// suitable for holding an instance of `layout`. - /// - /// The returned block of storage may or may not have its contents - /// initialized. (Extension subtraits might restrict this - /// behavior, e.g. to ensure initialization to particular sets of - /// bit patterns.) - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure that `layout` has non-zero size. - /// - /// (Extension subtraits might provide more specific bounds on - /// behavior, e.g. guarantee a sentinel address or a null pointer - /// in response to a zero-size allocation request.) - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `layout` does not meet allocator's size or alignment - /// constraints. - /// - /// Implementations are encouraged to return `Err` on memory - /// exhaustion rather than panicking or aborting, but this is not - /// a strict requirement. (Specifically: it is *legal* to - /// implement this trait atop an underlying native allocation - /// library that aborts on memory exhaustion.) - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; - - /// Deallocate the memory referenced by `ptr`. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must denote a block of memory currently allocated via - /// this allocator, - /// - /// * `layout` must *fit* that block of memory, - /// - /// * In addition to fitting the block of memory `layout`, the - /// alignment of the `layout` must match the alignment used - /// to allocate that block of memory. - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); - - /// Allocator-specific method for signaling an out-of-memory - /// condition. - /// - /// `oom` aborts the thread or process, optionally performing - /// cleanup or logging diagnostic information before panicking or - /// aborting. - /// - /// `oom` is meant to be used by clients unable to cope with an - /// unsatisfied allocation request (signaled by an error such as - /// `AllocErr::Exhausted`), and wish to abandon computation rather - /// than attempt to recover locally. Such clients should pass the - /// signaling error value back into `oom`, where the allocator - /// may incorporate that error value into its diagnostic report - /// before aborting. - /// - /// Implementations of the `oom` method are discouraged from - /// infinitely regressing in nested calls to `oom`. In - /// practice this means implementors should eschew allocating, - /// especially from `self` (directly or indirectly). - /// - /// Implementations of the allocation and reallocation methods - /// (e.g. `alloc`, `alloc_one`, `realloc`) are discouraged from - /// panicking (or aborting) in the event of memory exhaustion; - /// instead they should return an appropriate error from the - /// invoked method, and let the client decide whether to invoke - /// this `oom` method in response. - fn oom(&mut self, _: AllocErr) -> ! { - unsafe { ::intrinsics::abort() } - } - - // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS == - // usable_size - - /// Returns bounds on the guaranteed usable size of a successful - /// allocation created with the specified `layout`. - /// - /// In particular, if one has a memory block allocated via a given - /// allocator `a` and layout `k` where `a.usable_size(k)` returns - /// `(l, u)`, then one can pass that block to `a.dealloc()` with a - /// layout in the size range [l, u]. - /// - /// (All implementors of `usable_size` must ensure that - /// `l <= k.size() <= u`) - /// - /// Both the lower- and upper-bounds (`l` and `u` respectively) - /// are provided, because an allocator based on size classes could - /// misbehave if one attempts to deallocate a block without - /// providing a correct value for its size (i.e., one within the - /// range `[l, u]`). - /// - /// Clients who wish to make use of excess capacity are encouraged - /// to use the `alloc_excess` and `realloc_excess` instead, as - /// this method is constrained to report conservative values that - /// serve as valid bounds for *all possible* allocation method - /// calls. - /// - /// However, for clients that do not wish to track the capacity - /// returned by `alloc_excess` locally, this method is likely to - /// produce useful results. - #[inline] - fn usable_size(&self, layout: &Layout) -> (usize, usize) { - (layout.size(), layout.size()) - } - - // == METHODS FOR MEMORY REUSE == - // realloc. alloc_excess, realloc_excess - - /// Returns a pointer suitable for holding data described by - /// `new_layout`, meeting its size and alignment guarantees. To - /// accomplish this, this may extend or shrink the allocation - /// referenced by `ptr` to fit `new_layout`. - /// - /// If this returns `Ok`, then ownership of the memory block - /// referenced by `ptr` has been transferred to this - /// allocator. The memory may or may not have been freed, and - /// should be considered unusable (unless of course it was - /// transferred back to the caller again via the return value of - /// this method). - /// - /// If this method returns `Err`, then ownership of the memory - /// block has not been transferred to this allocator, and the - /// contents of the memory block are unaltered. - /// - /// For best results, `new_layout` should not impose a different - /// alignment constraint than `layout`. (In other words, - /// `new_layout.align()` should equal `layout.align()`.) However, - /// behavior is well-defined (though underspecified) when this - /// constraint is violated; further discussion below. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must be currently allocated via this allocator, - /// - /// * `layout` must *fit* the `ptr` (see above). (The `new_layout` - /// argument need not fit it.) - /// - /// * `new_layout` must have size greater than zero. - /// - /// * the alignment of `new_layout` is non-zero. - /// - /// (Extension subtraits might provide more specific bounds on - /// behavior, e.g. guarantee a sentinel address or a null pointer - /// in response to a zero-size allocation request.) - /// - /// # Errors - /// - /// Returns `Err` only if `new_layout` does not match the - /// alignment of `layout`, or does not meet the allocator's size - /// and alignment constraints of the allocator, or if reallocation - /// otherwise fails. - /// - /// (Note the previous sentence did not say "if and only if" -- in - /// particular, an implementation of this method *can* return `Ok` - /// if `new_layout.align() != old_layout.align()`; or it can - /// return `Err` in that scenario, depending on whether this - /// allocator can dynamically adjust the alignment constraint for - /// the block.) - /// - /// Implementations are encouraged to return `Err` on memory - /// exhaustion rather than panicking or aborting, but this is not - /// a strict requirement. (Specifically: it is *legal* to - /// implement this trait atop an underlying native allocation - /// library that aborts on memory exhaustion.) - /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn realloc(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - let new_size = new_layout.size(); - let old_size = layout.size(); - let aligns_match = layout.align == new_layout.align; - - if new_size >= old_size && aligns_match { - if let Ok(()) = self.grow_in_place(ptr, layout.clone(), new_layout.clone()) { - return Ok(ptr); - } - } else if new_size < old_size && aligns_match { - if let Ok(()) = self.shrink_in_place(ptr, layout.clone(), new_layout.clone()) { - return Ok(ptr); - } - } - - // otherwise, fall back on alloc + copy + dealloc. - let result = self.alloc(new_layout); - if let Ok(new_ptr) = result { - ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size)); - self.dealloc(ptr, layout); - } - result - } - - /// Behaves like `alloc`, but also ensures that the contents - /// are set to zero before being returned. - /// - /// # Safety - /// - /// This function is unsafe for the same reasons that `alloc` is. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `layout` does not meet allocator's size or alignment - /// constraints, just as in `alloc`. - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let size = layout.size(); - let p = self.alloc(layout); - if let Ok(p) = p { - ptr::write_bytes(p, 0, size); - } - p - } - - /// Behaves like `alloc`, but also returns the whole size of - /// the returned block. For some `layout` inputs, like arrays, this - /// may include extra storage usable for additional data. - /// - /// # Safety - /// - /// This function is unsafe for the same reasons that `alloc` is. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `layout` does not meet allocator's size or alignment - /// constraints, just as in `alloc`. - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { - let usable_size = self.usable_size(&layout); - self.alloc(layout).map(|p| Excess(p, usable_size.1)) - } - - /// Behaves like `realloc`, but also returns the whole size of - /// the returned block. For some `layout` inputs, like arrays, this - /// may include extra storage usable for additional data. - /// - /// # Safety - /// - /// This function is unsafe for the same reasons that `realloc` is. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `layout` does not meet allocator's size or alignment - /// constraints, just as in `realloc`. - /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn realloc_excess(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result { - let usable_size = self.usable_size(&new_layout); - self.realloc(ptr, layout, new_layout) - .map(|p| Excess(p, usable_size.1)) - } - - /// Attempts to extend the allocation referenced by `ptr` to fit `new_layout`. - /// - /// If this returns `Ok`, then the allocator has asserted that the - /// memory block referenced by `ptr` now fits `new_layout`, and thus can - /// be used to carry data of that layout. (The allocator is allowed to - /// expend effort to accomplish this, such as extending the memory block to - /// include successor blocks, or virtual memory tricks.) - /// - /// Regardless of what this method returns, ownership of the - /// memory block referenced by `ptr` has not been transferred, and - /// the contents of the memory block are unaltered. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must be currently allocated via this allocator, - /// - /// * `layout` must *fit* the `ptr` (see above); note the - /// `new_layout` argument need not fit it, - /// - /// * `new_layout.size()` must not be less than `layout.size()`, - /// - /// * `new_layout.align()` must equal `layout.align()`. - /// - /// # Errors - /// - /// Returns `Err(CannotReallocInPlace)` when the allocator is - /// unable to assert that the memory block referenced by `ptr` - /// could fit `layout`. - /// - /// Note that one cannot pass `CannotReallocInPlace` to the `oom` - /// method; clients are expected either to be able to recover from - /// `grow_in_place` failures without aborting, or to fall back on - /// another reallocation method before resorting to an abort. - unsafe fn grow_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let _ = ptr; // this default implementation doesn't care about the actual address. - debug_assert!(new_layout.size >= layout.size); - debug_assert!(new_layout.align == layout.align); - let (_l, u) = self.usable_size(&layout); - // _l <= layout.size() [guaranteed by usable_size()] - // layout.size() <= new_layout.size() [required by this method] - if new_layout.size <= u { - return Ok(()); - } else { - return Err(CannotReallocInPlace); - } - } - - /// Attempts to shrink the allocation referenced by `ptr` to fit `new_layout`. - /// - /// If this returns `Ok`, then the allocator has asserted that the - /// memory block referenced by `ptr` now fits `new_layout`, and - /// thus can only be used to carry data of that smaller - /// layout. (The allocator is allowed to take advantage of this, - /// carving off portions of the block for reuse elsewhere.) The - /// truncated contents of the block within the smaller layout are - /// unaltered, and ownership of block has not been transferred. - /// - /// If this returns `Err`, then the memory block is considered to - /// still represent the original (larger) `layout`. None of the - /// block has been carved off for reuse elsewhere, ownership of - /// the memory block has not been transferred, and the contents of - /// the memory block are unaltered. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must be currently allocated via this allocator, - /// - /// * `layout` must *fit* the `ptr` (see above); note the - /// `new_layout` argument need not fit it, - /// - /// * `new_layout.size()` must not be greater than `layout.size()` - /// (and must be greater than zero), - /// - /// * `new_layout.align()` must equal `layout.align()`. - /// - /// # Errors - /// - /// Returns `Err(CannotReallocInPlace)` when the allocator is - /// unable to assert that the memory block referenced by `ptr` - /// could fit `layout`. - /// - /// Note that one cannot pass `CannotReallocInPlace` to the `oom` - /// method; clients are expected either to be able to recover from - /// `shrink_in_place` failures without aborting, or to fall back - /// on another reallocation method before resorting to an abort. - unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let _ = ptr; // this default implementation doesn't care about the actual address. - debug_assert!(new_layout.size <= layout.size); - debug_assert!(new_layout.align == layout.align); - let (l, _u) = self.usable_size(&layout); - // layout.size() <= _u [guaranteed by usable_size()] - // new_layout.size() <= layout.size() [required by this method] - if l <= new_layout.size { - return Ok(()); - } else { - return Err(CannotReallocInPlace); - } - } - - - // == COMMON USAGE PATTERNS == - // alloc_one, dealloc_one, alloc_array, realloc_array. dealloc_array - - /// Allocates a block suitable for holding an instance of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// The returned block is suitable for passing to the - /// `alloc`/`realloc` methods of this allocator. - /// - /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` - /// must be considered "currently allocated" and must be - /// acceptable input to methods such as `realloc` or `dealloc`, - /// *even if* `T` is a zero-sized type. In other words, if your - /// `Alloc` implementation overrides this method in a manner - /// that can return a zero-sized `ptr`, then all reallocation and - /// deallocation methods need to be similarly overridden to accept - /// such values as input. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `T` does not meet allocator's size or alignment constraints. - /// - /// For zero-sized `T`, may return either of `Ok` or `Err`, but - /// will *not* yield undefined behavior. - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - fn alloc_one(&mut self) -> Result, AllocErr> - where Self: Sized - { - let k = Layout::new::(); - if k.size() > 0 { - unsafe { self.alloc(k).map(|p| NonNull::new_unchecked(p as *mut T)) } - } else { - Err(AllocErr::invalid_input("zero-sized type invalid for alloc_one")) - } - } - - /// Deallocates a block suitable for holding an instance of `T`. - /// - /// The given block must have been produced by this allocator, - /// and must be suitable for storing a `T` (in terms of alignment - /// as well as minimum and maximum size); otherwise yields - /// undefined behavior. - /// - /// Captures a common usage pattern for allocators. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure both: - /// - /// * `ptr` must denote a block of memory currently allocated via this allocator - /// - /// * the layout of `T` must *fit* that block of memory. - unsafe fn dealloc_one(&mut self, ptr: NonNull) - where Self: Sized - { - let raw_ptr = ptr.as_ptr() as *mut u8; - let k = Layout::new::(); - if k.size() > 0 { - self.dealloc(raw_ptr, k); - } - } - - /// Allocates a block suitable for holding `n` instances of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// The returned block is suitable for passing to the - /// `alloc`/`realloc` methods of this allocator. - /// - /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` - /// must be considered "currently allocated" and must be - /// acceptable input to methods such as `realloc` or `dealloc`, - /// *even if* `T` is a zero-sized type. In other words, if your - /// `Alloc` implementation overrides this method in a manner - /// that can return a zero-sized `ptr`, then all reallocation and - /// deallocation methods need to be similarly overridden to accept - /// such values as input. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `[T; n]` does not meet allocator's size or alignment - /// constraints. - /// - /// For zero-sized `T` or `n == 0`, may return either of `Ok` or - /// `Err`, but will *not* yield undefined behavior. - /// - /// Always returns `Err` on arithmetic overflow. - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - fn alloc_array(&mut self, n: usize) -> Result, AllocErr> - where Self: Sized - { - match Layout::array::(n) { - Some(ref layout) if layout.size() > 0 => { - unsafe { - self.alloc(layout.clone()) - .map(|p| { - NonNull::new_unchecked(p as *mut T) - }) - } - } - _ => Err(AllocErr::invalid_input("invalid layout for alloc_array")), - } - } - - /// Reallocates a block previously suitable for holding `n_old` - /// instances of `T`, returning a block suitable for holding - /// `n_new` instances of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// The returned block is suitable for passing to the - /// `alloc`/`realloc` methods of this allocator. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must be currently allocated via this allocator, - /// - /// * the layout of `[T; n_old]` must *fit* that block of memory. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `[T; n_new]` does not meet allocator's size or alignment - /// constraints. - /// - /// For zero-sized `T` or `n_new == 0`, may return either of `Ok` or - /// `Err`, but will *not* yield undefined behavior. - /// - /// Always returns `Err` on arithmetic overflow. - /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn realloc_array(&mut self, - ptr: NonNull, - n_old: usize, - n_new: usize) -> Result, AllocErr> - where Self: Sized - { - match (Layout::array::(n_old), Layout::array::(n_new), ptr.as_ptr()) { - (Some(ref k_old), Some(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { - self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone()) - .map(|p| NonNull::new_unchecked(p as *mut T)) - } - _ => { - Err(AllocErr::invalid_input("invalid layout for realloc_array")) - } - } - } - - /// Deallocates a block suitable for holding `n` instances of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure both: - /// - /// * `ptr` must denote a block of memory currently allocated via this allocator - /// - /// * the layout of `[T; n]` must *fit* that block of memory. - /// - /// # Errors - /// - /// Returning `Err` indicates that either `[T; n]` or the given - /// memory block does not meet allocator's size or alignment - /// constraints. - /// - /// Always returns `Err` on arithmetic overflow. - unsafe fn dealloc_array(&mut self, ptr: NonNull, n: usize) -> Result<(), AllocErr> - where Self: Sized - { - let raw_ptr = ptr.as_ptr() as *mut u8; - match Layout::array::(n) { - Some(ref k) if k.size() > 0 => { - Ok(self.dealloc(raw_ptr, k.clone())) - } - _ => { - Err(AllocErr::invalid_input("invalid layout for dealloc_array")) - } - } - } -} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 722a9de215c..56d4e65d3ac 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -185,7 +185,11 @@ pub mod unicode; /* Heap memory allocator trait */ #[allow(missing_docs)] -pub mod heap; +pub mod alloc; + +#[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] +pub use alloc as heap; // note: does not need to be public mod iter_private; diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs new file mode 100644 index 00000000000..b42a1052c49 --- /dev/null +++ b/src/libstd/alloc.rs @@ -0,0 +1,176 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! dox + +#![unstable(issue = "32838", feature = "allocator_api")] + +pub use alloc_crate::heap::Heap; +pub use alloc_system::System; +#[doc(inline)] pub use core::heap::*; + +#[cfg(not(test))] +#[doc(hidden)] +#[allow(unused_attributes)] +pub mod __default_lib_allocator { + use super::{System, Layout, Alloc, AllocErr}; + use ptr; + + // for symbol names src/librustc/middle/allocator.rs + // for signatures src/librustc_allocator/lib.rs + + // linkage directives are provided as part of the current compiler allocator + // ABI + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_alloc(size: usize, + align: usize, + err: *mut u8) -> *mut u8 { + let layout = Layout::from_size_align_unchecked(size, align); + match System.alloc(layout) { + Ok(p) => p, + Err(e) => { + ptr::write(err as *mut AllocErr, e); + 0 as *mut u8 + } + } + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_oom(err: *const u8) -> ! { + System.oom((*(err as *const AllocErr)).clone()) + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, + size: usize, + align: usize) { + System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_usable_size(layout: *const u8, + min: *mut usize, + max: *mut usize) { + let pair = System.usable_size(&*(layout as *const Layout)); + *min = pair.0; + *max = pair.1; + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_realloc(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize, + err: *mut u8) -> *mut u8 { + let old_layout = Layout::from_size_align_unchecked(old_size, old_align); + let new_layout = Layout::from_size_align_unchecked(new_size, new_align); + match System.realloc(ptr, old_layout, new_layout) { + Ok(p) => p, + Err(e) => { + ptr::write(err as *mut AllocErr, e); + 0 as *mut u8 + } + } + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_alloc_zeroed(size: usize, + align: usize, + err: *mut u8) -> *mut u8 { + let layout = Layout::from_size_align_unchecked(size, align); + match System.alloc_zeroed(layout) { + Ok(p) => p, + Err(e) => { + ptr::write(err as *mut AllocErr, e); + 0 as *mut u8 + } + } + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_alloc_excess(size: usize, + align: usize, + excess: *mut usize, + err: *mut u8) -> *mut u8 { + let layout = Layout::from_size_align_unchecked(size, align); + match System.alloc_excess(layout) { + Ok(p) => { + *excess = p.1; + p.0 + } + Err(e) => { + ptr::write(err as *mut AllocErr, e); + 0 as *mut u8 + } + } + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_realloc_excess(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize, + excess: *mut usize, + err: *mut u8) -> *mut u8 { + let old_layout = Layout::from_size_align_unchecked(old_size, old_align); + let new_layout = Layout::from_size_align_unchecked(new_size, new_align); + match System.realloc_excess(ptr, old_layout, new_layout) { + Ok(p) => { + *excess = p.1; + p.0 + } + Err(e) => { + ptr::write(err as *mut AllocErr, e); + 0 as *mut u8 + } + } + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_grow_in_place(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize) -> u8 { + let old_layout = Layout::from_size_align_unchecked(old_size, old_align); + let new_layout = Layout::from_size_align_unchecked(new_size, new_align); + match System.grow_in_place(ptr, old_layout, new_layout) { + Ok(()) => 1, + Err(_) => 0, + } + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_shrink_in_place(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize) -> u8 { + let old_layout = Layout::from_size_align_unchecked(old_size, old_align); + let new_layout = Layout::from_size_align_unchecked(new_size, new_align); + match System.shrink_in_place(ptr, old_layout, new_layout) { + Ok(()) => 1, + Err(_) => 0, + } + } +} diff --git a/src/libstd/heap.rs b/src/libstd/heap.rs deleted file mode 100644 index b42a1052c49..00000000000 --- a/src/libstd/heap.rs +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! dox - -#![unstable(issue = "32838", feature = "allocator_api")] - -pub use alloc_crate::heap::Heap; -pub use alloc_system::System; -#[doc(inline)] pub use core::heap::*; - -#[cfg(not(test))] -#[doc(hidden)] -#[allow(unused_attributes)] -pub mod __default_lib_allocator { - use super::{System, Layout, Alloc, AllocErr}; - use ptr; - - // for symbol names src/librustc/middle/allocator.rs - // for signatures src/librustc_allocator/lib.rs - - // linkage directives are provided as part of the current compiler allocator - // ABI - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc(size: usize, - align: usize, - err: *mut u8) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); - match System.alloc(layout) { - Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_oom(err: *const u8) -> ! { - System.oom((*(err as *const AllocErr)).clone()) - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, - size: usize, - align: usize) { - System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_usable_size(layout: *const u8, - min: *mut usize, - max: *mut usize) { - let pair = System.usable_size(&*(layout as *const Layout)); - *min = pair.0; - *max = pair.1; - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_realloc(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - err: *mut u8) -> *mut u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.realloc(ptr, old_layout, new_layout) { - Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc_zeroed(size: usize, - align: usize, - err: *mut u8) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); - match System.alloc_zeroed(layout) { - Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc_excess(size: usize, - align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); - match System.alloc_excess(layout) { - Ok(p) => { - *excess = p.1; - p.0 - } - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_realloc_excess(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.realloc_excess(ptr, old_layout, new_layout) { - Ok(p) => { - *excess = p.1; - p.0 - } - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_grow_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.grow_in_place(ptr, old_layout, new_layout) { - Ok(()) => 1, - Err(_) => 0, - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_shrink_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.shrink_in_place(ptr, old_layout, new_layout) { - Ok(()) => 1, - Err(_) => 0, - } - } -} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index ef4205e7a62..3a99e845a16 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -477,7 +477,11 @@ pub mod path; pub mod process; pub mod sync; pub mod time; -pub mod heap; +pub mod alloc; + +#[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] +pub use alloc as heap; // Platform-abstraction modules #[macro_use] -- cgit 1.4.1-3-g733a5 From 743c29bdc5b0a75c648e1317aa5d1d816007f176 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 3 Apr 2018 21:05:10 +0200 Subject: Actually deprecate heap modules. --- src/liballoc/alloc.rs | 2 +- src/liballoc/lib.rs | 10 ++++++++-- src/libcore/lib.rs | 5 ++++- src/libstd/alloc.rs | 6 +++--- src/libstd/lib.rs | 5 ++++- 5 files changed, 20 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 000c0123d9f..2477166966e 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -20,7 +20,7 @@ use core::mem::{self, ManuallyDrop}; use core::usize; #[doc(inline)] -pub use core::heap::*; +pub use core::alloc::*; #[doc(hidden)] pub mod __core { diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 617bc5c52b3..066698a71df 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -141,7 +141,10 @@ mod macros; #[rustc_deprecated(since = "1.27.0", reason = "use the heap module in core, alloc, or std instead")] #[unstable(feature = "allocator_api", issue = "32838")] -pub use core::heap as allocator; +/// Use the `alloc` module instead. +pub mod allocator { + pub use alloc::*; +} // Heaps provided for low-level allocation strategies @@ -149,7 +152,10 @@ pub mod alloc; #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -pub use alloc as heap; +/// Use the `alloc` module instead. +pub mod heap { + pub use alloc::*; +} // Primitive types using the heaps above diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 56d4e65d3ac..5ebd9e4334c 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -189,7 +189,10 @@ pub mod alloc; #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -pub use alloc as heap; +/// Use the `alloc` module instead. +pub mod heap { + pub use alloc::*; +} // note: does not need to be public mod iter_private; diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index b42a1052c49..77be3e52d76 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -12,9 +12,9 @@ #![unstable(issue = "32838", feature = "allocator_api")] -pub use alloc_crate::heap::Heap; -pub use alloc_system::System; -#[doc(inline)] pub use core::heap::*; +#[doc(inline)] pub use alloc_crate::alloc::Heap; +#[doc(inline)] pub use alloc_system::System; +#[doc(inline)] pub use core::alloc::*; #[cfg(not(test))] #[doc(hidden)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3a99e845a16..25ba75fd35e 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -481,7 +481,10 @@ pub mod alloc; #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -pub use alloc as heap; +/// Use the `alloc` module instead. +pub mod heap { + pub use alloc::*; +} // Platform-abstraction modules #[macro_use] -- cgit 1.4.1-3-g733a5 From ba7081a033de4981ccad1e1525c8b5191ce02208 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 3 Apr 2018 15:41:09 +0200 Subject: Make AllocErr a zero-size unit struct --- src/liballoc/alloc.rs | 32 ++++++++++++------------ src/liballoc/raw_vec.rs | 2 +- src/liballoc_jemalloc/lib.rs | 25 +++---------------- src/liballoc_system/lib.rs | 24 +++++++----------- src/libcore/alloc.rs | 58 ++++++-------------------------------------- src/libstd/alloc.rs | 43 ++++++++++---------------------- src/libstd/error.rs | 2 +- 7 files changed, 51 insertions(+), 135 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 00a8b2c0e25..b975ff6be58 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -16,7 +16,7 @@ issue = "32838")] use core::intrinsics::{min_align_of_val, size_of_val}; -use core::mem::{self, ManuallyDrop}; +use core::mem; use core::usize; #[doc(inline)] @@ -86,12 +86,12 @@ pub const Heap: Global = Global; unsafe impl Alloc for Global { #[inline] unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let mut err = ManuallyDrop::new(mem::uninitialized::()); + let mut err = AllocErr; let ptr = __rust_alloc(layout.size(), layout.align(), - &mut *err as *mut AllocErr as *mut u8); + &mut err as *mut AllocErr as *mut u8); if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) + Err(AllocErr) } else { Ok(ptr) } @@ -129,15 +129,15 @@ unsafe impl Alloc for Global { new_layout: Layout) -> Result<*mut u8, AllocErr> { - let mut err = ManuallyDrop::new(mem::uninitialized::()); + let mut err = AllocErr; let ptr = __rust_realloc(ptr, layout.size(), layout.align(), new_layout.size(), new_layout.align(), - &mut *err as *mut AllocErr as *mut u8); + &mut err as *mut AllocErr as *mut u8); if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) + Err(AllocErr) } else { mem::forget(err); Ok(ptr) @@ -146,12 +146,12 @@ unsafe impl Alloc for Global { #[inline] unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let mut err = ManuallyDrop::new(mem::uninitialized::()); + let mut err = AllocErr; let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), - &mut *err as *mut AllocErr as *mut u8); + &mut err as *mut AllocErr as *mut u8); if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) + Err(AllocErr) } else { Ok(ptr) } @@ -159,14 +159,14 @@ unsafe impl Alloc for Global { #[inline] unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { - let mut err = ManuallyDrop::new(mem::uninitialized::()); + let mut err = AllocErr; let mut size = 0; let ptr = __rust_alloc_excess(layout.size(), layout.align(), &mut size, - &mut *err as *mut AllocErr as *mut u8); + &mut err as *mut AllocErr as *mut u8); if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) + Err(AllocErr) } else { Ok(Excess(ptr, size)) } @@ -177,7 +177,7 @@ unsafe impl Alloc for Global { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result { - let mut err = ManuallyDrop::new(mem::uninitialized::()); + let mut err = AllocErr; let mut size = 0; let ptr = __rust_realloc_excess(ptr, layout.size(), @@ -185,9 +185,9 @@ unsafe impl Alloc for Global { new_layout.size(), new_layout.align(), &mut size, - &mut *err as *mut AllocErr as *mut u8); + &mut err as *mut AllocErr as *mut u8); if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) + Err(AllocErr) } else { Ok(Excess(ptr, size)) } diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 51f39dc6cc7..caedb971ddc 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -760,7 +760,7 @@ mod tests { unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { let size = layout.size(); if size > self.fuel { - return Err(AllocErr::Unsupported { details: "fuel exhausted" }); + return Err(AllocErr); } match Global.alloc(layout) { ok @ Ok(_) => { self.fuel -= size; ok } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 616181d99bc..59a7e87e1ec 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -30,8 +30,6 @@ extern crate libc; pub use contents::*; #[cfg(not(dummy_jemalloc))] mod contents { - use core::ptr; - use core::alloc::{Alloc, AllocErr, Layout}; use alloc_system::System; use libc::{c_int, c_void, size_t}; @@ -106,14 +104,9 @@ mod contents { #[rustc_std_internal_symbol] pub unsafe extern fn __rde_alloc(size: usize, align: usize, - err: *mut u8) -> *mut u8 { + _err: *mut u8) -> *mut u8 { let flags = align_to_flags(align, size); let ptr = mallocx(size as size_t, flags) as *mut u8; - if ptr.is_null() { - let layout = Layout::from_size_align_unchecked(size, align); - ptr::write(err as *mut AllocErr, - AllocErr::Exhausted { request: layout }); - } ptr } @@ -155,20 +148,13 @@ mod contents { old_align: usize, new_size: usize, new_align: usize, - err: *mut u8) -> *mut u8 { + _err: *mut u8) -> *mut u8 { if new_align != old_align { - ptr::write(err as *mut AllocErr, - AllocErr::Unsupported { details: "can't change alignments" }); return 0 as *mut u8 } let flags = align_to_flags(new_align, new_size); let ptr = rallocx(ptr as *mut c_void, new_size, flags) as *mut u8; - if ptr.is_null() { - let layout = Layout::from_size_align_unchecked(new_size, new_align); - ptr::write(err as *mut AllocErr, - AllocErr::Exhausted { request: layout }); - } ptr } @@ -176,18 +162,13 @@ mod contents { #[rustc_std_internal_symbol] pub unsafe extern fn __rde_alloc_zeroed(size: usize, align: usize, - err: *mut u8) -> *mut u8 { + _err: *mut u8) -> *mut u8 { let ptr = if align <= MIN_ALIGN && align <= size { calloc(size as size_t, 1) as *mut u8 } else { let flags = align_to_flags(align, size) | MALLOCX_ZERO; mallocx(size as size_t, flags) as *mut u8 }; - if ptr.is_null() { - let layout = Layout::from_size_align_unchecked(size, align); - ptr::write(err as *mut AllocErr, - AllocErr::Exhausted { request: layout }); - } ptr } diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 6f928287ef2..5dca05cf085 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -133,9 +133,7 @@ mod platform { #[cfg(target_os = "macos")] { if layout.align() > (1 << 31) { - return Err(AllocErr::Unsupported { - details: "requested alignment too large" - }) + return Err(AllocErr) } } aligned_malloc(&layout) @@ -143,7 +141,7 @@ mod platform { if !ptr.is_null() { Ok(ptr) } else { - Err(AllocErr::Exhausted { request: layout }) + Err(AllocErr) } } @@ -156,7 +154,7 @@ mod platform { if !ptr.is_null() { Ok(ptr) } else { - Err(AllocErr::Exhausted { request: layout }) + Err(AllocErr) } } else { let ret = self.alloc(layout.clone()); @@ -178,9 +176,7 @@ mod platform { old_layout: Layout, new_layout: Layout) -> Result<*mut u8, AllocErr> { if old_layout.align() != new_layout.align() { - return Err(AllocErr::Unsupported { - details: "cannot change alignment on `realloc`", - }) + return Err(AllocErr) } if new_layout.align() <= MIN_ALIGN && new_layout.align() <= new_layout.size(){ @@ -188,7 +184,7 @@ mod platform { if !ptr.is_null() { Ok(ptr as *mut u8) } else { - Err(AllocErr::Exhausted { request: new_layout }) + Err(AllocErr) } } else { let res = self.alloc(new_layout.clone()); @@ -342,7 +338,7 @@ mod platform { } }; if ptr.is_null() { - Err(AllocErr::Exhausted { request: layout }) + Err(AllocErr) } else { Ok(ptr as *mut u8) } @@ -382,9 +378,7 @@ mod platform { old_layout: Layout, new_layout: Layout) -> Result<*mut u8, AllocErr> { if old_layout.align() != new_layout.align() { - return Err(AllocErr::Unsupported { - details: "cannot change alignment on `realloc`", - }) + return Err(AllocErr) } if new_layout.align() <= MIN_ALIGN { @@ -395,7 +389,7 @@ mod platform { if !ptr.is_null() { Ok(ptr as *mut u8) } else { - Err(AllocErr::Exhausted { request: new_layout }) + Err(AllocErr) } } else { let res = self.alloc(new_layout.clone()); @@ -505,7 +499,7 @@ mod platform { if !ptr.is_null() { Ok(ptr) } else { - Err(AllocErr::Unsupported { details: "" }) + Err(AllocErr) } } diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 5c51bb2b51b..b6626ff9f26 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -320,50 +320,12 @@ impl Layout { /// something wrong when combining the given input arguments with this /// allocator. #[derive(Clone, PartialEq, Eq, Debug)] -pub enum AllocErr { - /// Error due to hitting some resource limit or otherwise running - /// out of memory. This condition strongly implies that *some* - /// series of deallocations would allow a subsequent reissuing of - /// the original allocation request to succeed. - Exhausted { request: Layout }, - - /// Error due to allocator being fundamentally incapable of - /// satisfying the original request. This condition implies that - /// such an allocation request will never succeed on the given - /// allocator, regardless of environment, memory pressure, or - /// other contextual conditions. - /// - /// For example, an allocator that does not support requests for - /// large memory blocks might return this error variant. - Unsupported { details: &'static str }, -} - -impl AllocErr { - #[inline] - pub fn invalid_input(details: &'static str) -> Self { - AllocErr::Unsupported { details: details } - } - #[inline] - pub fn is_memory_exhausted(&self) -> bool { - if let AllocErr::Exhausted { .. } = *self { true } else { false } - } - #[inline] - pub fn is_request_unsupported(&self) -> bool { - if let AllocErr::Unsupported { .. } = *self { true } else { false } - } - #[inline] - pub fn description(&self) -> &str { - match *self { - AllocErr::Exhausted { .. } => "allocator memory exhausted", - AllocErr::Unsupported { .. } => "unsupported allocator request", - } - } -} +pub struct AllocErr; // (we need this for downstream impl of trait Error) impl fmt::Display for AllocErr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.description()) + f.write_str("memory allocation failed") } } @@ -592,12 +554,8 @@ pub unsafe trait Alloc { /// aborting. /// /// `oom` is meant to be used by clients unable to cope with an - /// unsatisfied allocation request (signaled by an error such as - /// `AllocErr::Exhausted`), and wish to abandon computation rather - /// than attempt to recover locally. Such clients should pass the - /// signaling error value back into `oom`, where the allocator - /// may incorporate that error value into its diagnostic report - /// before aborting. + /// unsatisfied allocation request, and wish to abandon + /// computation rather than attempt to recover locally. /// /// Implementations of the `oom` method are discouraged from /// infinitely regressing in nested calls to `oom`. In @@ -963,7 +921,7 @@ pub unsafe trait Alloc { if k.size() > 0 { unsafe { self.alloc(k).map(|p| NonNull::new_unchecked(p as *mut T)) } } else { - Err(AllocErr::invalid_input("zero-sized type invalid for alloc_one")) + Err(AllocErr) } } @@ -1036,7 +994,7 @@ pub unsafe trait Alloc { }) } } - _ => Err(AllocErr::invalid_input("invalid layout for alloc_array")), + _ => Err(AllocErr), } } @@ -1084,7 +1042,7 @@ pub unsafe trait Alloc { .map(|p| NonNull::new_unchecked(p as *mut T)) } _ => { - Err(AllocErr::invalid_input("invalid layout for realloc_array")) + Err(AllocErr) } } } @@ -1118,7 +1076,7 @@ pub unsafe trait Alloc { Ok(self.dealloc(raw_ptr, k.clone())) } _ => { - Err(AllocErr::invalid_input("invalid layout for dealloc_array")) + Err(AllocErr) } } } diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index eb0c960732d..533ad3ad473 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -21,9 +21,7 @@ #[doc(hidden)] #[allow(unused_attributes)] pub mod __default_lib_allocator { - use super::{System, Layout, Alloc, AllocErr}; - use ptr; - + use super::{System, Layout, Alloc, AllocErr, CannotReallocInPlace}; // for symbol names src/librustc/middle/allocator.rs // for signatures src/librustc_allocator/lib.rs @@ -34,14 +32,11 @@ pub mod __default_lib_allocator { #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_alloc(size: usize, align: usize, - err: *mut u8) -> *mut u8 { + _err: *mut u8) -> *mut u8 { let layout = Layout::from_size_align_unchecked(size, align); match System.alloc(layout) { Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } + Err(AllocErr) => 0 as *mut u8, } } @@ -76,15 +71,12 @@ pub mod __default_lib_allocator { old_align: usize, new_size: usize, new_align: usize, - err: *mut u8) -> *mut u8 { + _err: *mut u8) -> *mut u8 { let old_layout = Layout::from_size_align_unchecked(old_size, old_align); let new_layout = Layout::from_size_align_unchecked(new_size, new_align); match System.realloc(ptr, old_layout, new_layout) { Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } + Err(AllocErr) => 0 as *mut u8, } } @@ -92,14 +84,11 @@ pub mod __default_lib_allocator { #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize, - err: *mut u8) -> *mut u8 { + _err: *mut u8) -> *mut u8 { let layout = Layout::from_size_align_unchecked(size, align); match System.alloc_zeroed(layout) { Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } + Err(AllocErr) => 0 as *mut u8, } } @@ -108,17 +97,14 @@ pub mod __default_lib_allocator { pub unsafe extern fn __rdl_alloc_excess(size: usize, align: usize, excess: *mut usize, - err: *mut u8) -> *mut u8 { + _err: *mut u8) -> *mut u8 { let layout = Layout::from_size_align_unchecked(size, align); match System.alloc_excess(layout) { Ok(p) => { *excess = p.1; p.0 } - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } + Err(AllocErr) => 0 as *mut u8, } } @@ -130,7 +116,7 @@ pub mod __default_lib_allocator { new_size: usize, new_align: usize, excess: *mut usize, - err: *mut u8) -> *mut u8 { + _err: *mut u8) -> *mut u8 { let old_layout = Layout::from_size_align_unchecked(old_size, old_align); let new_layout = Layout::from_size_align_unchecked(new_size, new_align); match System.realloc_excess(ptr, old_layout, new_layout) { @@ -138,10 +124,7 @@ pub mod __default_lib_allocator { *excess = p.1; p.0 } - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } + Err(AllocErr) => 0 as *mut u8, } } @@ -156,7 +139,7 @@ pub mod __default_lib_allocator { let new_layout = Layout::from_size_align_unchecked(new_size, new_align); match System.grow_in_place(ptr, old_layout, new_layout) { Ok(()) => 1, - Err(_) => 0, + Err(CannotReallocInPlace) => 0, } } @@ -171,7 +154,7 @@ pub mod __default_lib_allocator { let new_layout = Layout::from_size_align_unchecked(new_size, new_align); match System.shrink_in_place(ptr, old_layout, new_layout) { Ok(()) => 1, - Err(_) => 0, + Err(CannotReallocInPlace) => 0, } } } diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 4edb897350e..ec55a3c021a 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -243,7 +243,7 @@ impl Error for ! { issue = "32838")] impl Error for AllocErr { fn description(&self) -> &str { - AllocErr::description(self) + "memory allocation failed" } } -- cgit 1.4.1-3-g733a5 From eb69593f73be1e41d9e2ef065010a47478c14924 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 3 Apr 2018 17:51:03 +0200 Subject: Implement GlobalAlloc for System --- src/liballoc_system/lib.rs | 269 ++++++++++++++++++++++++--------------------- src/libcore/alloc.rs | 4 + 2 files changed, 145 insertions(+), 128 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 5dca05cf085..0480be8d913 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -50,19 +50,19 @@ pub struct System; unsafe impl Alloc for System { #[inline] unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - (&*self).alloc(layout) + Alloc::alloc(&mut &*self, layout) } #[inline] unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - (&*self).alloc_zeroed(layout) + Alloc::alloc_zeroed(&mut &*self, layout) } #[inline] unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - (&*self).dealloc(ptr, layout) + Alloc::dealloc(&mut &*self, ptr, layout) } #[inline] @@ -70,21 +70,21 @@ unsafe impl Alloc for System { ptr: *mut u8, old_layout: Layout, new_layout: Layout) -> Result<*mut u8, AllocErr> { - (&*self).realloc(ptr, old_layout, new_layout) + Alloc::realloc(&mut &*self, ptr, old_layout, new_layout) } fn oom(&mut self, err: AllocErr) -> ! { - (&*self).oom(err) + Alloc::oom(&mut &*self, err) } #[inline] fn usable_size(&self, layout: &Layout) -> (usize, usize) { - (&self).usable_size(layout) + Alloc::usable_size(&mut &*self, layout) } #[inline] unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { - (&*self).alloc_excess(layout) + Alloc::alloc_excess(&mut &*self, layout) } #[inline] @@ -92,7 +92,7 @@ unsafe impl Alloc for System { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result { - (&*self).realloc_excess(ptr, layout, new_layout) + Alloc::realloc_excess(&mut &*self, ptr, layout, new_layout) } #[inline] @@ -100,7 +100,7 @@ unsafe impl Alloc for System { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { - (&*self).grow_in_place(ptr, layout, new_layout) + Alloc::grow_in_place(&mut &*self, ptr, layout, new_layout) } #[inline] @@ -108,7 +108,76 @@ unsafe impl Alloc for System { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { - (&*self).shrink_in_place(ptr, layout, new_layout) + Alloc::shrink_in_place(&mut &*self, ptr, layout, new_layout) + } +} + +#[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))] +mod realloc_fallback { + use core::alloc::{GlobalAlloc, Void, Layout}; + use core::cmp; + use core::ptr; + + impl super::System { + pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut Void, old_layout: Layout, + new_size: usize) -> *mut Void { + // Docs for GlobalAlloc::realloc require this to be valid: + let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); + + let new_ptr = GlobalAlloc::alloc(self, new_layout); + if !new_ptr.is_null() { + let size = cmp::min(old_layout.size(), new_size); + ptr::copy_nonoverlapping(ptr as *mut u8, new_ptr as *mut u8, size); + GlobalAlloc::dealloc(self, ptr, old_layout); + } + new_ptr + } + } +} + +macro_rules! alloc_methods_based_on_global_alloc { + () => { + #[inline] + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + let ptr = GlobalAlloc::alloc(*self, layout); + if !ptr.is_null() { + Ok(ptr as *mut u8) + } else { + Err(AllocErr) + } + } + + #[inline] + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + let ptr = GlobalAlloc::alloc_zeroed(*self, layout); + if !ptr.is_null() { + Ok(ptr as *mut u8) + } else { + Err(AllocErr) + } + } + + #[inline] + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + GlobalAlloc::dealloc(*self, ptr as *mut Void, layout) + } + + #[inline] + unsafe fn realloc(&mut self, + ptr: *mut u8, + old_layout: Layout, + new_layout: Layout) -> Result<*mut u8, AllocErr> { + if old_layout.align() != new_layout.align() { + return Err(AllocErr) + } + + let ptr = GlobalAlloc::realloc(*self, ptr as *mut Void, old_layout, new_layout.size()); + if !ptr.is_null() { + Ok(ptr as *mut u8) + } else { + Err(AllocErr) + } + } } } @@ -116,86 +185,62 @@ unsafe impl Alloc for System { mod platform { extern crate libc; - use core::cmp; use core::ptr; use MIN_ALIGN; use System; - use core::alloc::{Alloc, AllocErr, Layout}; + use core::alloc::{GlobalAlloc, Alloc, AllocErr, Layout, Void}; #[unstable(feature = "allocator_api", issue = "32838")] - unsafe impl<'a> Alloc for &'a System { + unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let ptr = if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::malloc(layout.size()) as *mut u8 + unsafe fn alloc(&self, layout: Layout) -> *mut Void { + if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { + libc::malloc(layout.size()) as *mut Void } else { #[cfg(target_os = "macos")] { if layout.align() > (1 << 31) { - return Err(AllocErr) + // FIXME: use Void::null_mut https://github.com/rust-lang/rust/issues/49659 + return 0 as *mut Void } } aligned_malloc(&layout) - }; - if !ptr.is_null() { - Ok(ptr) - } else { - Err(AllocErr) } } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) - -> Result<*mut u8, AllocErr> - { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - let ptr = libc::calloc(layout.size(), 1) as *mut u8; - if !ptr.is_null() { - Ok(ptr) - } else { - Err(AllocErr) - } + libc::calloc(layout.size(), 1) as *mut Void } else { - let ret = self.alloc(layout.clone()); - if let Ok(ptr) = ret { - ptr::write_bytes(ptr, 0, layout.size()); + let ptr = self.alloc(layout.clone()); + if !ptr.is_null() { + ptr::write_bytes(ptr as *mut u8, 0, layout.size()); } - ret + ptr } } #[inline] - unsafe fn dealloc(&mut self, ptr: *mut u8, _layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Void, _layout: Layout) { libc::free(ptr as *mut libc::c_void) } #[inline] - unsafe fn realloc(&mut self, - ptr: *mut u8, - old_layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - if old_layout.align() != new_layout.align() { - return Err(AllocErr) - } - - if new_layout.align() <= MIN_ALIGN && new_layout.align() <= new_layout.size(){ - let ptr = libc::realloc(ptr as *mut libc::c_void, new_layout.size()); - if !ptr.is_null() { - Ok(ptr as *mut u8) - } else { - Err(AllocErr) - } + unsafe fn realloc(&self, ptr: *mut Void, old_layout: Layout, new_size: usize) -> *mut Void { + let align = old_layout.align(); + if align <= MIN_ALIGN && align <= new_size { + libc::realloc(ptr as *mut libc::c_void, new_size) as *mut Void } else { - let res = self.alloc(new_layout.clone()); - if let Ok(new_ptr) = res { - let size = cmp::min(old_layout.size(), new_layout.size()); - ptr::copy_nonoverlapping(ptr, new_ptr, size); - self.dealloc(ptr, old_layout); - } - res + self.realloc_fallback(ptr, old_layout, new_size) } } + } + + #[unstable(feature = "allocator_api", issue = "32838")] + unsafe impl<'a> Alloc for &'a System { + alloc_methods_based_on_global_alloc!(); fn oom(&mut self, err: AllocErr) -> ! { use core::fmt::{self, Write}; @@ -237,7 +282,7 @@ mod platform { #[cfg(any(target_os = "android", target_os = "redox", target_os = "solaris"))] #[inline] - unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + unsafe fn aligned_malloc(layout: &Layout) -> *mut Void { // On android we currently target API level 9 which unfortunately // doesn't have the `posix_memalign` API used below. Instead we use // `memalign`, but this unfortunately has the property on some systems @@ -255,18 +300,18 @@ mod platform { // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ // /memory/aligned_memory.cc - libc::memalign(layout.align(), layout.size()) as *mut u8 + libc::memalign(layout.align(), layout.size()) as *mut Void } #[cfg(not(any(target_os = "android", target_os = "redox", target_os = "solaris")))] #[inline] - unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + unsafe fn aligned_malloc(layout: &Layout) -> *mut Void { let mut out = ptr::null_mut(); let ret = libc::posix_memalign(&mut out, layout.align(), layout.size()); if ret != 0 { - ptr::null_mut() + 0 as *mut Void } else { - out as *mut u8 + out as *mut Void } } } @@ -274,12 +319,11 @@ mod platform { #[cfg(windows)] #[allow(bad_style)] mod platform { - use core::cmp; use core::ptr; use MIN_ALIGN; use System; - use core::alloc::{Alloc, AllocErr, Layout, CannotReallocInPlace}; + use core::alloc::{GlobalAlloc, Alloc, Void, AllocErr, Layout, CannotReallocInPlace}; type LPVOID = *mut u8; type HANDLE = LPVOID; @@ -323,9 +367,7 @@ mod platform { } #[inline] - unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) - -> Result<*mut u8, AllocErr> - { + unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut Void { let ptr = if layout.align() <= MIN_ALIGN { HeapAlloc(GetProcessHeap(), flags, layout.size()) } else { @@ -337,35 +379,29 @@ mod platform { align_ptr(ptr, layout.align()) } }; - if ptr.is_null() { - Err(AllocErr) - } else { - Ok(ptr as *mut u8) - } + ptr as *mut Void } #[unstable(feature = "allocator_api", issue = "32838")] - unsafe impl<'a> Alloc for &'a System { + unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc(&self, layout: Layout) -> *mut Void { allocate_with_flags(layout, 0) } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) - -> Result<*mut u8, AllocErr> - { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { allocate_with_flags(layout, HEAP_ZERO_MEMORY) } #[inline] - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { if layout.align() <= MIN_ALIGN { let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID); debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); } else { - let header = get_header(ptr); + let header = get_header(ptr as *mut u8); let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID); debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); @@ -373,34 +409,19 @@ mod platform { } #[inline] - unsafe fn realloc(&mut self, - ptr: *mut u8, - old_layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - if old_layout.align() != new_layout.align() { - return Err(AllocErr) - } - - if new_layout.align() <= MIN_ALIGN { - let ptr = HeapReAlloc(GetProcessHeap(), - 0, - ptr as LPVOID, - new_layout.size()); - if !ptr.is_null() { - Ok(ptr as *mut u8) - } else { - Err(AllocErr) - } + unsafe fn realloc(&self, ptr: *mut Void, old_layout: Layout, new_size: usize) -> *mut Void { + let align = old_layout.align(); + if align <= MIN_ALIGN { + HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut Void } else { - let res = self.alloc(new_layout.clone()); - if let Ok(new_ptr) = res { - let size = cmp::min(old_layout.size(), new_layout.size()); - ptr::copy_nonoverlapping(ptr, new_ptr, size); - self.dealloc(ptr, old_layout); - } - res + self.realloc_fallback(ptr, old_layout, new_size) } } + } + + #[unstable(feature = "allocator_api", issue = "32838")] + unsafe impl<'a> Alloc for &'a System { + alloc_methods_based_on_global_alloc!(); #[inline] unsafe fn grow_in_place(&mut self, @@ -489,45 +510,37 @@ mod platform { mod platform { extern crate dlmalloc; - use core::alloc::{Alloc, AllocErr, Layout}; + use core::alloc::{GlobalAlloc, Alloc, AllocErr, Layout, Void}; use System; // No need for synchronization here as wasm is currently single-threaded static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT; - fn to_result(ptr: *mut u8) -> Result<*mut u8, AllocErr> { - if !ptr.is_null() { - Ok(ptr) - } else { - Err(AllocErr) - } - } - #[unstable(feature = "allocator_api", issue = "32838")] - unsafe impl<'a> Alloc for &'a System { + unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - to_result(DLMALLOC.malloc(layout.size(), layout.align())) + unsafe fn alloc(&self, layout: Layout) -> *mut Void { + DLMALLOC.malloc(layout.size(), layout.align()) as *mut Void } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - to_result(DLMALLOC.calloc(layout.size(), layout.align())) + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { + DLMALLOC.calloc(layout.size(), layout.align()) as *mut Void } #[inline] - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - DLMALLOC.free(ptr, layout.size(), layout.align()) + unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { + DLMALLOC.free(ptr as *mut u8, layout.size(), layout.align()) } #[inline] - unsafe fn realloc(&mut self, - ptr: *mut u8, - old_layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - to_result(DLMALLOC.realloc( - ptr, old_layout.size(), old_layout.align(), new_layout.size(), - )) + unsafe fn realloc(&self, ptr: *mut Void, layout: Layout, new_size: usize) -> *mut Void { + DLMALLOC.realloc(ptr as *mut u8, layout.size(), layout.align(), new_size) as *mut Void } } + + #[unstable(feature = "allocator_api", issue = "32838")] + unsafe impl<'a> Alloc for &'a System { + alloc_methods_based_on_global_alloc!(); + } } diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index b6626ff9f26..1c764dab000 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -381,6 +381,10 @@ pub unsafe trait GlobalAlloc { ptr } + /// # Safety + /// + /// `new_size`, when rounded up to the nearest multiple of `old_layout.align()`, + /// must not overflow (i.e. the rounded value must be less than `usize::MAX`). unsafe fn realloc(&self, ptr: *mut Void, old_layout: Layout, new_size: usize) -> *mut Void { let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); let new_ptr = self.alloc(new_layout); -- cgit 1.4.1-3-g733a5 From 157ff8cd0562eefdd7aa296395c38a7bc259a4b9 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 3 Apr 2018 16:00:04 +0200 Subject: Remove the now-unit-struct AllocErr parameter of oom() --- src/liballoc/alloc.rs | 6 +++--- src/liballoc/arc.rs | 2 +- src/liballoc/heap.rs | 4 ++-- src/liballoc/raw_vec.rs | 12 ++++++------ src/liballoc/rc.rs | 2 +- src/liballoc_system/lib.rs | 12 ++++++------ src/libcore/alloc.rs | 2 +- src/libstd/collections/hash/map.rs | 2 +- src/libstd/collections/hash/table.rs | 4 ++-- src/test/run-pass/allocator-alloc-one.rs | 4 ++-- src/test/run-pass/realloc-16687.rs | 4 ++-- src/test/run-pass/regions-mock-trans.rs | 2 +- 12 files changed, 28 insertions(+), 28 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 73bc78eb8a2..a7b5864016c 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -136,8 +136,8 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { align as *mut u8 } else { let layout = Layout::from_size_align_unchecked(size, align); - Global.alloc(layout).unwrap_or_else(|err| { - Global.oom(err) + Global.alloc(layout).unwrap_or_else(|_| { + Global.oom() }) } } @@ -166,7 +166,7 @@ mod tests { unsafe { let layout = Layout::from_size_align(1024, 1).unwrap(); let ptr = Global.alloc_zeroed(layout.clone()) - .unwrap_or_else(|e| Global.oom(e)); + .unwrap_or_else(|_| Global.oom()); let end = ptr.offset(layout.size() as isize); let mut i = ptr; diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index d63ed24aa4f..f0a325530ba 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -555,7 +555,7 @@ impl Arc { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|e| Global.oom(e)); + .unwrap_or_else(|_| Global.oom()); // Initialize the real ArcInner let inner = set_data_ptr(ptr as *mut T, mem) as *mut ArcInner; diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index a44ff04bd1b..765fb8458d1 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -52,8 +52,8 @@ unsafe impl Alloc for T where T: CoreAlloc { CoreAlloc::dealloc(self, ptr, layout) } - fn oom(&mut self, err: AllocErr) -> ! { - CoreAlloc::oom(self, err) + fn oom(&mut self, _: AllocErr) -> ! { + CoreAlloc::oom(self) } fn usable_size(&self, layout: &Layout) -> (usize, usize) { diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index caedb971ddc..25d759764a5 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -100,7 +100,7 @@ impl RawVec { }; match result { Ok(ptr) => ptr, - Err(err) => a.oom(err), + Err(_) => a.oom(), } }; @@ -316,7 +316,7 @@ impl RawVec { new_layout); match ptr_res { Ok(ptr) => (new_cap, Unique::new_unchecked(ptr as *mut T)), - Err(e) => self.a.oom(e), + Err(_) => self.a.oom(), } } None => { @@ -325,7 +325,7 @@ impl RawVec { let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; match self.a.alloc_array::(new_cap) { Ok(ptr) => (new_cap, ptr.into()), - Err(e) => self.a.oom(e), + Err(_) => self.a.oom(), } } }; @@ -444,7 +444,7 @@ impl RawVec { pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) { match self.try_reserve_exact(used_cap, needed_extra_cap) { Err(CapacityOverflow) => panic!("capacity overflow"), - Err(AllocErr(e)) => self.a.oom(e), + Err(AllocErr(_)) => self.a.oom(), Ok(()) => { /* yay */ } } } @@ -554,7 +554,7 @@ impl RawVec { pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) { match self.try_reserve(used_cap, needed_extra_cap) { Err(CapacityOverflow) => panic!("capacity overflow"), - Err(AllocErr(e)) => self.a.oom(e), + Err(AllocErr(_)) => self.a.oom(), Ok(()) => { /* yay */ } } } @@ -669,7 +669,7 @@ impl RawVec { old_layout, new_layout) { Ok(p) => self.ptr = Unique::new_unchecked(p as *mut T), - Err(err) => self.a.oom(err), + Err(_) => self.a.oom(), } } self.cap = amount; diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index c134b181158..3c0b11bfe74 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -668,7 +668,7 @@ impl Rc { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|e| Global.oom(e)); + .unwrap_or_else(|_| Global.oom()); // Initialize the real RcBox let inner = set_data_ptr(ptr as *mut T, mem) as *mut RcBox; diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 0480be8d913..5e6b3b5ca11 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -73,8 +73,8 @@ unsafe impl Alloc for System { Alloc::realloc(&mut &*self, ptr, old_layout, new_layout) } - fn oom(&mut self, err: AllocErr) -> ! { - Alloc::oom(&mut &*self, err) + fn oom(&mut self) -> ! { + Alloc::oom(&mut &*self) } #[inline] @@ -242,7 +242,7 @@ mod platform { unsafe impl<'a> Alloc for &'a System { alloc_methods_based_on_global_alloc!(); - fn oom(&mut self, err: AllocErr) -> ! { + fn oom(&mut self) -> ! { use core::fmt::{self, Write}; // Print a message to stderr before aborting to assist with @@ -250,7 +250,7 @@ mod platform { // memory since we are in an OOM situation. Any errors are ignored // while printing since there's nothing we can do about them and we // are about to exit anyways. - drop(writeln!(Stderr, "fatal runtime error: {}", err)); + drop(writeln!(Stderr, "fatal runtime error: {}", AllocErr)); unsafe { ::core::intrinsics::abort(); } @@ -459,11 +459,11 @@ mod platform { } } - fn oom(&mut self, err: AllocErr) -> ! { + fn oom(&mut self) -> ! { use core::fmt::{self, Write}; // Same as with unix we ignore all errors here - drop(writeln!(Stderr, "fatal runtime error: {}", err)); + drop(writeln!(Stderr, "fatal runtime error: {}", AllocErr)); unsafe { ::core::intrinsics::abort(); } diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 1c764dab000..1ba4c641065 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -572,7 +572,7 @@ pub unsafe trait Alloc { /// instead they should return an appropriate error from the /// invoked method, and let the client decide whether to invoke /// this `oom` method in response. - fn oom(&mut self, _: AllocErr) -> ! { + fn oom(&mut self) -> ! { unsafe { ::intrinsics::abort() } } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index c4ef9e62577..2a00241afc6 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -784,7 +784,7 @@ impl HashMap pub fn reserve(&mut self, additional: usize) { match self.try_reserve(additional) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(e)) => Global.oom(e), + Err(CollectionAllocErr::AllocErr(_)) => Global.oom(), Ok(()) => { /* yay */ } } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 10bab5df8b5..fcc2eb8fef2 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -772,7 +772,7 @@ impl RawTable { unsafe fn new_uninitialized(capacity: usize) -> RawTable { match Self::try_new_uninitialized(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(e)) => Global.oom(e), + Err(CollectionAllocErr::AllocErr(_)) => Global.oom(), Ok(table) => { table } } } @@ -811,7 +811,7 @@ impl RawTable { pub fn new(capacity: usize) -> RawTable { match Self::try_new(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(e)) => Global.oom(e), + Err(CollectionAllocErr::AllocErr(_)) => Global.oom(), Ok(table) => { table } } } diff --git a/src/test/run-pass/allocator-alloc-one.rs b/src/test/run-pass/allocator-alloc-one.rs index eaa5bc90805..38b8ab50cc7 100644 --- a/src/test/run-pass/allocator-alloc-one.rs +++ b/src/test/run-pass/allocator-alloc-one.rs @@ -14,8 +14,8 @@ use std::heap::{Heap, Alloc}; fn main() { unsafe { - let ptr = Heap.alloc_one::().unwrap_or_else(|e| { - Heap.oom(e) + let ptr = Heap.alloc_one::().unwrap_or_else(|_| { + Heap.oom() }); *ptr.as_ptr() = 4; assert_eq!(*ptr.as_ptr(), 4); diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index eddcd5a584a..a562165d21b 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -50,7 +50,7 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?})", layout); } - let ret = Heap.alloc(layout.clone()).unwrap_or_else(|e| Heap.oom(e)); + let ret = Heap.alloc(layout.clone()).unwrap_or_else(|_| Heap.oom()); if PRINT { println!("allocate({:?}) = {:?}", layout, ret); @@ -73,7 +73,7 @@ unsafe fn test_triangle() -> bool { } let ret = Heap.realloc(ptr, old.clone(), new.clone()) - .unwrap_or_else(|e| Heap.oom(e)); + .unwrap_or_else(|_| Heap.oom()); if PRINT { println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", diff --git a/src/test/run-pass/regions-mock-trans.rs b/src/test/run-pass/regions-mock-trans.rs index 8f278a315d1..7d34b8fd00f 100644 --- a/src/test/run-pass/regions-mock-trans.rs +++ b/src/test/run-pass/regions-mock-trans.rs @@ -32,7 +32,7 @@ struct Ccx { fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> { unsafe { let ptr = Heap.alloc(Layout::new::()) - .unwrap_or_else(|e| Heap.oom(e)); + .unwrap_or_else(|_| Heap.oom()); &*(ptr as *const _) } } -- cgit 1.4.1-3-g733a5 From 93a9ad4897e560ccd5ebc3397afb7d83d990ef42 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 3 Apr 2018 16:01:29 +0200 Subject: Remove the now-unit-struct AllocErr field inside CollectionAllocErr --- src/liballoc/raw_vec.rs | 4 ++-- src/liballoc/tests/string.rs | 12 ++++++------ src/liballoc/tests/vec.rs | 16 ++++++++-------- src/liballoc/tests/vec_deque.rs | 12 ++++++------ src/libcore/alloc.rs | 6 +++--- src/libstd/collections/hash/map.rs | 4 ++-- src/libstd/collections/hash/table.rs | 4 ++-- 7 files changed, 29 insertions(+), 29 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 25d759764a5..d7c30925f1a 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -444,7 +444,7 @@ impl RawVec { pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) { match self.try_reserve_exact(used_cap, needed_extra_cap) { Err(CapacityOverflow) => panic!("capacity overflow"), - Err(AllocErr(_)) => self.a.oom(), + Err(AllocErr) => self.a.oom(), Ok(()) => { /* yay */ } } } @@ -554,7 +554,7 @@ impl RawVec { pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) { match self.try_reserve(used_cap, needed_extra_cap) { Err(CapacityOverflow) => panic!("capacity overflow"), - Err(AllocErr(_)) => self.a.oom(), + Err(AllocErr) => self.a.oom(), Ok(()) => { /* yay */ } } } diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index 17d53e4cf3e..befb36baeef 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -575,11 +575,11 @@ fn test_try_reserve() { } else { panic!("usize::MAX should trigger an overflow!") } } else { // Check isize::MAX + 1 is an OOM - if let Err(AllocErr(_)) = empty_string.try_reserve(MAX_CAP + 1) { + if let Err(AllocErr) = empty_string.try_reserve(MAX_CAP + 1) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } // Check usize::MAX is an OOM - if let Err(AllocErr(_)) = empty_string.try_reserve(MAX_USIZE) { + if let Err(AllocErr) = empty_string.try_reserve(MAX_USIZE) { } else { panic!("usize::MAX should trigger an OOM!") } } } @@ -599,7 +599,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should always overflow in the add-to-len @@ -637,10 +637,10 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_USIZE) { } else { panic!("usize::MAX should trigger an overflow!") } } else { - if let Err(AllocErr(_)) = empty_string.try_reserve_exact(MAX_CAP + 1) { + if let Err(AllocErr) = empty_string.try_reserve_exact(MAX_CAP + 1) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } - if let Err(AllocErr(_)) = empty_string.try_reserve_exact(MAX_USIZE) { + if let Err(AllocErr) = empty_string.try_reserve_exact(MAX_USIZE) { } else { panic!("usize::MAX should trigger an OOM!") } } } @@ -659,7 +659,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 2895c53009d..e329b45a617 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -1016,11 +1016,11 @@ fn test_try_reserve() { } else { panic!("usize::MAX should trigger an overflow!") } } else { // Check isize::MAX + 1 is an OOM - if let Err(AllocErr(_)) = empty_bytes.try_reserve(MAX_CAP + 1) { + if let Err(AllocErr) = empty_bytes.try_reserve(MAX_CAP + 1) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } // Check usize::MAX is an OOM - if let Err(AllocErr(_)) = empty_bytes.try_reserve(MAX_USIZE) { + if let Err(AllocErr) = empty_bytes.try_reserve(MAX_USIZE) { } else { panic!("usize::MAX should trigger an OOM!") } } } @@ -1040,7 +1040,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should always overflow in the add-to-len @@ -1063,7 +1063,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { + if let Err(AllocErr) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should fail in the mul-by-size @@ -1103,10 +1103,10 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_USIZE) { } else { panic!("usize::MAX should trigger an overflow!") } } else { - if let Err(AllocErr(_)) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { + if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } - if let Err(AllocErr(_)) = empty_bytes.try_reserve_exact(MAX_USIZE) { + if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_USIZE) { } else { panic!("usize::MAX should trigger an OOM!") } } } @@ -1125,7 +1125,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { @@ -1146,7 +1146,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { + if let Err(AllocErr) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index 75d3f01f8b6..4d55584e2f4 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -1073,7 +1073,7 @@ fn test_try_reserve() { // VecDeque starts with capacity 7, always adds 1 to the capacity // and also rounds the number to next power of 2 so this is the // furthest we can go without triggering CapacityOverflow - if let Err(AllocErr(_)) = empty_bytes.try_reserve(MAX_CAP) { + if let Err(AllocErr) = empty_bytes.try_reserve(MAX_CAP) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } } @@ -1093,7 +1093,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should always overflow in the add-to-len @@ -1116,7 +1116,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { + if let Err(AllocErr) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should fail in the mul-by-size @@ -1160,7 +1160,7 @@ fn test_try_reserve_exact() { // VecDeque starts with capacity 7, always adds 1 to the capacity // and also rounds the number to next power of 2 so this is the // furthest we can go without triggering CapacityOverflow - if let Err(AllocErr(_)) = empty_bytes.try_reserve_exact(MAX_CAP) { + if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_CAP) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } } @@ -1179,7 +1179,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { @@ -1200,7 +1200,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { + if let Err(AllocErr) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 1ba4c641065..23532c61721 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -356,13 +356,13 @@ pub enum CollectionAllocErr { /// (usually `isize::MAX` bytes). CapacityOverflow, /// Error due to the allocator (see the `AllocErr` type's docs). - AllocErr(AllocErr), + AllocErr, } #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] impl From for CollectionAllocErr { - fn from(err: AllocErr) -> Self { - CollectionAllocErr::AllocErr(err) + fn from(AllocErr: AllocErr) -> Self { + CollectionAllocErr::AllocErr } } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 2a00241afc6..20a4f9b508d 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -784,7 +784,7 @@ impl HashMap pub fn reserve(&mut self, additional: usize) { match self.try_reserve(additional) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(_)) => Global.oom(), + Err(CollectionAllocErr::AllocErr) => Global.oom(), Ok(()) => { /* yay */ } } } @@ -3634,7 +3634,7 @@ mod test_map { if let Err(CapacityOverflow) = empty_bytes.try_reserve(max_no_ovf) { } else { panic!("isize::MAX + 1 should trigger a CapacityOverflow!") } } else { - if let Err(AllocErr(_)) = empty_bytes.try_reserve(max_no_ovf) { + if let Err(AllocErr) = empty_bytes.try_reserve(max_no_ovf) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index fcc2eb8fef2..e9bdd4e7d07 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -772,7 +772,7 @@ impl RawTable { unsafe fn new_uninitialized(capacity: usize) -> RawTable { match Self::try_new_uninitialized(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(_)) => Global.oom(), + Err(CollectionAllocErr::AllocErr) => Global.oom(), Ok(table) => { table } } } @@ -811,7 +811,7 @@ impl RawTable { pub fn new(capacity: usize) -> RawTable { match Self::try_new(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(_)) => Global.oom(), + Err(CollectionAllocErr::AllocErr) => Global.oom(), Ok(table) => { table } } } -- cgit 1.4.1-3-g733a5 From b017742136a5d02b6ba0f2080e97d18a8bfeba4b Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 4 Apr 2018 16:03:46 +0200 Subject: Return Result instead of Option in alloc::Layout constructors --- src/liballoc/raw_vec.rs | 4 +-- src/libcore/alloc.rs | 63 +++++++++++++++++++++++------------- src/libstd/collections/hash/table.rs | 2 +- src/libstd/error.rs | 11 ++++++- 4 files changed, 54 insertions(+), 26 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index d7c30925f1a..18aaf1de08e 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -422,7 +422,7 @@ impl RawVec { // Nothing we can really do about these checks :( let new_cap = used_cap.checked_add(needed_extra_cap).ok_or(CapacityOverflow)?; - let new_layout = Layout::array::(new_cap).ok_or(CapacityOverflow)?; + let new_layout = Layout::array::(new_cap).map_err(|_| CapacityOverflow)?; alloc_guard(new_layout.size())?; @@ -530,7 +530,7 @@ impl RawVec { } let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)?; - let new_layout = Layout::array::(new_cap).ok_or(CapacityOverflow)?; + let new_layout = Layout::array::(new_cap).map_err(|_| CapacityOverflow)?; // FIXME: may crash and burn on over-reserve alloc_guard(new_layout.size())?; diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 23532c61721..0acaf54e0d9 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -94,9 +94,9 @@ impl Layout { /// must not overflow (i.e. the rounded value must be less than /// `usize::MAX`). #[inline] - pub fn from_size_align(size: usize, align: usize) -> Option { + pub fn from_size_align(size: usize, align: usize) -> Result { if !align.is_power_of_two() { - return None; + return Err(LayoutErr { private: () }); } // (power-of-two implies align != 0.) @@ -114,11 +114,11 @@ impl Layout { // Above implies that checking for summation overflow is both // necessary and sufficient. if size > usize::MAX - (align - 1) { - return None; + return Err(LayoutErr { private: () }); } unsafe { - Some(Layout::from_size_align_unchecked(size, align)) + Ok(Layout::from_size_align_unchecked(size, align)) } } @@ -130,7 +130,7 @@ impl Layout { /// a power-of-two nor `size` aligned to `align` fits within the /// address space (i.e. the `Layout::from_size_align` preconditions). #[inline] - pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout { + pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { Layout { size: size, align: align } } @@ -229,15 +229,17 @@ impl Layout { /// /// On arithmetic overflow, returns `None`. #[inline] - pub fn repeat(&self, n: usize) -> Option<(Self, usize)> { - let padded_size = self.size.checked_add(self.padding_needed_for(self.align))?; - let alloc_size = padded_size.checked_mul(n)?; + pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> { + let padded_size = self.size.checked_add(self.padding_needed_for(self.align)) + .ok_or(LayoutErr { private: () })?; + let alloc_size = padded_size.checked_mul(n) + .ok_or(LayoutErr { private: () })?; // We can assume that `self.align` is a power-of-two. // Furthermore, `alloc_size` has already been rounded up // to a multiple of `self.align`; therefore, the call to // `Layout::from_size_align` below should never panic. - Some((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) + Ok((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) } /// Creates a layout describing the record for `self` followed by @@ -251,17 +253,19 @@ impl Layout { /// (assuming that the record itself starts at offset 0). /// /// On arithmetic overflow, returns `None`. - pub fn extend(&self, next: Self) -> Option<(Self, usize)> { + pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> { let new_align = cmp::max(self.align, next.align); let realigned = Layout::from_size_align(self.size, new_align)?; let pad = realigned.padding_needed_for(next.align); - let offset = self.size.checked_add(pad)?; - let new_size = offset.checked_add(next.size)?; + let offset = self.size.checked_add(pad) + .ok_or(LayoutErr { private: () })?; + let new_size = offset.checked_add(next.size) + .ok_or(LayoutErr { private: () })?; let layout = Layout::from_size_align(new_size, new_align)?; - Some((layout, offset)) + Ok((layout, offset)) } /// Creates a layout describing the record for `n` instances of @@ -276,8 +280,8 @@ impl Layout { /// aligned. /// /// On arithmetic overflow, returns `None`. - pub fn repeat_packed(&self, n: usize) -> Option { - let size = self.size().checked_mul(n)?; + pub fn repeat_packed(&self, n: usize) -> Result { + let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?; Layout::from_size_align(size, self.align) } @@ -296,16 +300,17 @@ impl Layout { /// `extend`.) /// /// On arithmetic overflow, returns `None`. - pub fn extend_packed(&self, next: Self) -> Option<(Self, usize)> { - let new_size = self.size().checked_add(next.size())?; + pub fn extend_packed(&self, next: Self) -> Result<(Self, usize), LayoutErr> { + let new_size = self.size().checked_add(next.size()) + .ok_or(LayoutErr { private: () })?; let layout = Layout::from_size_align(new_size, self.align)?; - Some((layout, self.size())) + Ok((layout, self.size())) } /// Creates a layout describing the record for a `[T; n]`. /// /// On arithmetic overflow, returns `None`. - pub fn array(n: usize) -> Option { + pub fn array(n: usize) -> Result { Layout::new::() .repeat(n) .map(|(k, offs)| { @@ -315,6 +320,20 @@ impl Layout { } } +/// The parameters given to `Layout::from_size_align` do not satisfy +/// its documented constraints. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct LayoutErr { + private: () +} + +// (we need this for downstream impl of trait Error) +impl fmt::Display for LayoutErr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("invalid parameters to Layout::from_size_align") + } +} + /// The `AllocErr` error specifies whether an allocation failure is /// specifically due to resource exhaustion or if it is due to /// something wrong when combining the given input arguments with this @@ -990,7 +1009,7 @@ pub unsafe trait Alloc { where Self: Sized { match Layout::array::(n) { - Some(ref layout) if layout.size() > 0 => { + Ok(ref layout) if layout.size() > 0 => { unsafe { self.alloc(layout.clone()) .map(|p| { @@ -1041,7 +1060,7 @@ pub unsafe trait Alloc { where Self: Sized { match (Layout::array::(n_old), Layout::array::(n_new), ptr.as_ptr()) { - (Some(ref k_old), Some(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { + (Ok(ref k_old), Ok(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone()) .map(|p| NonNull::new_unchecked(p as *mut T)) } @@ -1076,7 +1095,7 @@ pub unsafe trait Alloc { { let raw_ptr = ptr.as_ptr() as *mut u8; match Layout::array::(n) { - Some(ref k) if k.size() > 0 => { + Ok(ref k) if k.size() > 0 => { Ok(self.dealloc(raw_ptr, k.clone())) } _ => { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index e9bdd4e7d07..50263705143 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -755,7 +755,7 @@ impl RawTable { } let buffer = Global.alloc(Layout::from_size_align(size, alignment) - .ok_or(CollectionAllocErr::CapacityOverflow)?)?; + .map_err(|_| CollectionAllocErr::CapacityOverflow)?)?; let hashes = buffer as *mut HashUint; diff --git a/src/libstd/error.rs b/src/libstd/error.rs index ec55a3c021a..3c209928d43 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -57,7 +57,7 @@ use cell; use char; use core::array; use fmt::{self, Debug, Display}; -use heap::{AllocErr, CannotReallocInPlace}; +use heap::{AllocErr, LayoutErr, CannotReallocInPlace}; use mem::transmute; use num; use str; @@ -247,6 +247,15 @@ impl Error for AllocErr { } } +#[unstable(feature = "allocator_api", + reason = "the precise API and guarantees it provides may be tweaked.", + issue = "32838")] +impl Error for LayoutErr { + fn description(&self) -> &str { + "invalid parameters to Layout::from_size_align" + } +} + #[unstable(feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked.", issue = "32838")] -- cgit 1.4.1-3-g733a5 From c957e99b305ecee113442a7ce0edd6b565200ca9 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 4 Apr 2018 17:19:16 +0200 Subject: realloc with a new size only, not a full new layout. Changing the alignment with realloc is not supported. --- src/liballoc/alloc.rs | 22 +++++------- src/liballoc/heap.rs | 8 ++--- src/liballoc/raw_vec.rs | 17 +++++---- src/liballoc_system/lib.rs | 42 +++++++++------------- src/libcore/alloc.rs | 87 +++++++++++++++++++--------------------------- 5 files changed, 74 insertions(+), 102 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index a7b5864016c..a6fc8d5004c 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -91,21 +91,17 @@ unsafe impl Alloc for Global { unsafe fn realloc(&mut self, ptr: *mut u8, layout: Layout, - new_layout: Layout) + new_size: usize) -> Result<*mut u8, AllocErr> { - if layout.align() == new_layout.align() { - #[cfg(not(stage0))] - let ptr = __rust_realloc(ptr, layout.size(), layout.align(), new_layout.size()); - #[cfg(stage0)] - let ptr = __rust_realloc(ptr, layout.size(), layout.align(), - new_layout.size(), new_layout.align(), &mut 0); - - if !ptr.is_null() { - Ok(ptr) - } else { - Err(AllocErr) - } + #[cfg(not(stage0))] + let ptr = __rust_realloc(ptr, layout.size(), layout.align(), new_size); + #[cfg(stage0)] + let ptr = __rust_realloc(ptr, layout.size(), layout.align(), + new_size, layout.align(), &mut 0); + + if !ptr.is_null() { + Ok(ptr) } else { Err(AllocErr) } diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 765fb8458d1..e79383331e1 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -64,7 +64,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<*mut u8, AllocErr> { - CoreAlloc::realloc(self, ptr, layout, new_layout) + CoreAlloc::realloc(self, ptr, layout, new_layout.size()) } unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { @@ -79,20 +79,20 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result { - CoreAlloc::realloc_excess(self, ptr, layout, new_layout) + CoreAlloc::realloc_excess(self, ptr, layout, new_layout.size()) } unsafe fn grow_in_place(&mut self, ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { - CoreAlloc::grow_in_place(self, ptr, layout, new_layout) + CoreAlloc::grow_in_place(self, ptr, layout, new_layout.size()) } unsafe fn shrink_in_place(&mut self, ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { - CoreAlloc::shrink_in_place(self, ptr, layout, new_layout) + CoreAlloc::shrink_in_place(self, ptr, layout, new_layout.size()) } } diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 18aaf1de08e..80b816878fb 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -309,11 +309,10 @@ impl RawVec { // `from_size_align_unchecked`. let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; - let new_layout = Layout::from_size_align_unchecked(new_size, cur.align()); alloc_guard(new_size).expect("capacity overflow"); let ptr_res = self.a.realloc(self.ptr.as_ptr() as *mut u8, cur, - new_layout); + new_size); match ptr_res { Ok(ptr) => (new_cap, Unique::new_unchecked(ptr as *mut T)), Err(_) => self.a.oom(), @@ -371,8 +370,7 @@ impl RawVec { let new_size = new_cap * elem_size; alloc_guard(new_size).expect("capacity overflow"); let ptr = self.ptr() as *mut _; - let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); - match self.a.grow_in_place(ptr, old_layout, new_layout) { + match self.a.grow_in_place(ptr, old_layout, new_size) { Ok(_) => { // We can't directly divide `size`. self.cap = new_cap; @@ -428,8 +426,9 @@ impl RawVec { let res = match self.current_layout() { Some(layout) => { + debug_assert!(new_layout.align() == layout.align()); let old_ptr = self.ptr.as_ptr() as *mut u8; - self.a.realloc(old_ptr, layout, new_layout) + self.a.realloc(old_ptr, layout, new_layout.size()) } None => self.a.alloc(new_layout), }; @@ -537,8 +536,9 @@ impl RawVec { let res = match self.current_layout() { Some(layout) => { + debug_assert!(new_layout.align() == layout.align()); let old_ptr = self.ptr.as_ptr() as *mut u8; - self.a.realloc(old_ptr, layout, new_layout) + self.a.realloc(old_ptr, layout, new_layout.size()) } None => self.a.alloc(new_layout), }; @@ -604,7 +604,7 @@ impl RawVec { let new_layout = Layout::new::().repeat(new_cap).unwrap().0; // FIXME: may crash and burn on over-reserve alloc_guard(new_layout.size()).expect("capacity overflow"); - match self.a.grow_in_place(ptr, old_layout, new_layout) { + match self.a.grow_in_place(ptr, old_layout, new_layout.size()) { Ok(_) => { self.cap = new_cap; true @@ -664,10 +664,9 @@ impl RawVec { let new_size = elem_size * amount; let align = mem::align_of::(); let old_layout = Layout::from_size_align_unchecked(old_size, align); - let new_layout = Layout::from_size_align_unchecked(new_size, align); match self.a.realloc(self.ptr.as_ptr() as *mut u8, old_layout, - new_layout) { + new_size) { Ok(p) => self.ptr = Unique::new_unchecked(p as *mut T), Err(_) => self.a.oom(), } diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 48a6c1e150a..7b788a5f989 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -69,8 +69,8 @@ unsafe impl Alloc for System { unsafe fn realloc(&mut self, ptr: *mut u8, old_layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - Alloc::realloc(&mut &*self, ptr, old_layout, new_layout) + new_size: usize) -> Result<*mut u8, AllocErr> { + Alloc::realloc(&mut &*self, ptr, old_layout, new_size) } fn oom(&mut self) -> ! { @@ -91,24 +91,24 @@ unsafe impl Alloc for System { unsafe fn realloc_excess(&mut self, ptr: *mut u8, layout: Layout, - new_layout: Layout) -> Result { - Alloc::realloc_excess(&mut &*self, ptr, layout, new_layout) + new_size: usize) -> Result { + Alloc::realloc_excess(&mut &*self, ptr, layout, new_size) } #[inline] unsafe fn grow_in_place(&mut self, ptr: *mut u8, layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - Alloc::grow_in_place(&mut &*self, ptr, layout, new_layout) + new_size: usize) -> Result<(), CannotReallocInPlace> { + Alloc::grow_in_place(&mut &*self, ptr, layout, new_size) } #[inline] unsafe fn shrink_in_place(&mut self, ptr: *mut u8, layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - Alloc::shrink_in_place(&mut &*self, ptr, layout, new_layout) + new_size: usize) -> Result<(), CannotReallocInPlace> { + Alloc::shrink_in_place(&mut &*self, ptr, layout, new_size) } } @@ -166,12 +166,8 @@ macro_rules! alloc_methods_based_on_global_alloc { unsafe fn realloc(&mut self, ptr: *mut u8, old_layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - if old_layout.align() != new_layout.align() { - return Err(AllocErr) - } - - let ptr = GlobalAlloc::realloc(*self, ptr as *mut Void, old_layout, new_layout.size()); + new_size: usize) -> Result<*mut u8, AllocErr> { + let ptr = GlobalAlloc::realloc(*self, ptr as *mut Void, old_layout, new_size); if !ptr.is_null() { Ok(ptr as *mut u8) } else { @@ -428,30 +424,26 @@ mod platform { unsafe fn grow_in_place(&mut self, ptr: *mut u8, layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - self.shrink_in_place(ptr, layout, new_layout) + new_size: usize) -> Result<(), CannotReallocInPlace> { + self.shrink_in_place(ptr, layout, new_size) } #[inline] unsafe fn shrink_in_place(&mut self, ptr: *mut u8, - old_layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - if old_layout.align() != new_layout.align() { - return Err(CannotReallocInPlace) - } - - let new = if new_layout.align() <= MIN_ALIGN { + layout: Layout, + new_size: usize) -> Result<(), CannotReallocInPlace> { + let new = if layout.align() <= MIN_ALIGN { HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, ptr as LPVOID, - new_layout.size()) + new_size) } else { let header = get_header(ptr); HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, header.0 as LPVOID, - new_layout.size() + new_layout.align()) + new_size + layout.align()) }; if new.is_null() { Err(CannotReallocInPlace) diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 0acaf54e0d9..757f06e731f 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -633,9 +633,10 @@ pub unsafe trait Alloc { // realloc. alloc_excess, realloc_excess /// Returns a pointer suitable for holding data described by - /// `new_layout`, meeting its size and alignment guarantees. To + /// a new layout with `layout`’s alginment and a size given + /// by `new_size`. To /// accomplish this, this may extend or shrink the allocation - /// referenced by `ptr` to fit `new_layout`. + /// referenced by `ptr` to fit the new layout. /// /// If this returns `Ok`, then ownership of the memory block /// referenced by `ptr` has been transferred to this @@ -648,12 +649,6 @@ pub unsafe trait Alloc { /// block has not been transferred to this allocator, and the /// contents of the memory block are unaltered. /// - /// For best results, `new_layout` should not impose a different - /// alignment constraint than `layout`. (In other words, - /// `new_layout.align()` should equal `layout.align()`.) However, - /// behavior is well-defined (though underspecified) when this - /// constraint is violated; further discussion below. - /// /// # Safety /// /// This function is unsafe because undefined behavior can result @@ -661,12 +656,13 @@ pub unsafe trait Alloc { /// /// * `ptr` must be currently allocated via this allocator, /// - /// * `layout` must *fit* the `ptr` (see above). (The `new_layout` + /// * `layout` must *fit* the `ptr` (see above). (The `new_size` /// argument need not fit it.) /// - /// * `new_layout` must have size greater than zero. + /// * `new_size` must be greater than zero. /// - /// * the alignment of `new_layout` is non-zero. + /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, + /// must not overflow (i.e. the rounded value must be less than `usize::MAX`). /// /// (Extension subtraits might provide more specific bounds on /// behavior, e.g. guarantee a sentinel address or a null pointer @@ -674,18 +670,11 @@ pub unsafe trait Alloc { /// /// # Errors /// - /// Returns `Err` only if `new_layout` does not match the - /// alignment of `layout`, or does not meet the allocator's size + /// Returns `Err` only if the new layout + /// does not meet the allocator's size /// and alignment constraints of the allocator, or if reallocation /// otherwise fails. /// - /// (Note the previous sentence did not say "if and only if" -- in - /// particular, an implementation of this method *can* return `Ok` - /// if `new_layout.align() != old_layout.align()`; or it can - /// return `Err` in that scenario, depending on whether this - /// allocator can dynamically adjust the alignment constraint for - /// the block.) - /// /// Implementations are encouraged to return `Err` on memory /// exhaustion rather than panicking or aborting, but this is not /// a strict requirement. (Specifically: it is *legal* to @@ -698,22 +687,21 @@ pub unsafe trait Alloc { unsafe fn realloc(&mut self, ptr: *mut u8, layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - let new_size = new_layout.size(); + new_size: usize) -> Result<*mut u8, AllocErr> { let old_size = layout.size(); - let aligns_match = layout.align == new_layout.align; - if new_size >= old_size && aligns_match { - if let Ok(()) = self.grow_in_place(ptr, layout.clone(), new_layout.clone()) { + if new_size >= old_size { + if let Ok(()) = self.grow_in_place(ptr, layout.clone(), new_size) { return Ok(ptr); } - } else if new_size < old_size && aligns_match { - if let Ok(()) = self.shrink_in_place(ptr, layout.clone(), new_layout.clone()) { + } else if new_size < old_size { + if let Ok(()) = self.shrink_in_place(ptr, layout.clone(), new_size) { return Ok(ptr); } } // otherwise, fall back on alloc + copy + dealloc. + let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let result = self.alloc(new_layout); if let Ok(new_ptr) = result { ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size)); @@ -789,17 +777,19 @@ pub unsafe trait Alloc { unsafe fn realloc_excess(&mut self, ptr: *mut u8, layout: Layout, - new_layout: Layout) -> Result { + new_size: usize) -> Result { + let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let usable_size = self.usable_size(&new_layout); - self.realloc(ptr, layout, new_layout) + self.realloc(ptr, layout, new_size) .map(|p| Excess(p, usable_size.1)) } - /// Attempts to extend the allocation referenced by `ptr` to fit `new_layout`. + /// Attempts to extend the allocation referenced by `ptr` to fit `new_size`. /// /// If this returns `Ok`, then the allocator has asserted that the - /// memory block referenced by `ptr` now fits `new_layout`, and thus can - /// be used to carry data of that layout. (The allocator is allowed to + /// memory block referenced by `ptr` now fits `new_size`, and thus can + /// be used to carry data of a layout of that size and same alignment as + /// `layout`. (The allocator is allowed to /// expend effort to accomplish this, such as extending the memory block to /// include successor blocks, or virtual memory tricks.) /// @@ -815,11 +805,9 @@ pub unsafe trait Alloc { /// * `ptr` must be currently allocated via this allocator, /// /// * `layout` must *fit* the `ptr` (see above); note the - /// `new_layout` argument need not fit it, + /// `new_size` argument need not fit it, /// - /// * `new_layout.size()` must not be less than `layout.size()`, - /// - /// * `new_layout.align()` must equal `layout.align()`. + /// * `new_size` must not be less than `layout.size()`, /// /// # Errors /// @@ -834,24 +822,23 @@ pub unsafe trait Alloc { unsafe fn grow_in_place(&mut self, ptr: *mut u8, layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { + new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. - debug_assert!(new_layout.size >= layout.size); - debug_assert!(new_layout.align == layout.align); + debug_assert!(new_size >= layout.size); let (_l, u) = self.usable_size(&layout); // _l <= layout.size() [guaranteed by usable_size()] // layout.size() <= new_layout.size() [required by this method] - if new_layout.size <= u { + if new_size <= u { return Ok(()); } else { return Err(CannotReallocInPlace); } } - /// Attempts to shrink the allocation referenced by `ptr` to fit `new_layout`. + /// Attempts to shrink the allocation referenced by `ptr` to fit `new_size`. /// /// If this returns `Ok`, then the allocator has asserted that the - /// memory block referenced by `ptr` now fits `new_layout`, and + /// memory block referenced by `ptr` now fits `new_size`, and /// thus can only be used to carry data of that smaller /// layout. (The allocator is allowed to take advantage of this, /// carving off portions of the block for reuse elsewhere.) The @@ -872,13 +859,11 @@ pub unsafe trait Alloc { /// * `ptr` must be currently allocated via this allocator, /// /// * `layout` must *fit* the `ptr` (see above); note the - /// `new_layout` argument need not fit it, + /// `new_size` argument need not fit it, /// - /// * `new_layout.size()` must not be greater than `layout.size()` + /// * `new_size` must not be greater than `layout.size()` /// (and must be greater than zero), /// - /// * `new_layout.align()` must equal `layout.align()`. - /// /// # Errors /// /// Returns `Err(CannotReallocInPlace)` when the allocator is @@ -892,14 +877,13 @@ pub unsafe trait Alloc { unsafe fn shrink_in_place(&mut self, ptr: *mut u8, layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { + new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. - debug_assert!(new_layout.size <= layout.size); - debug_assert!(new_layout.align == layout.align); + debug_assert!(new_size <= layout.size); let (l, _u) = self.usable_size(&layout); // layout.size() <= _u [guaranteed by usable_size()] // new_layout.size() <= layout.size() [required by this method] - if l <= new_layout.size { + if l <= new_size { return Ok(()); } else { return Err(CannotReallocInPlace); @@ -1061,7 +1045,8 @@ pub unsafe trait Alloc { { match (Layout::array::(n_old), Layout::array::(n_new), ptr.as_ptr()) { (Ok(ref k_old), Ok(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { - self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone()) + debug_assert!(k_old.align() == k_new.align()); + self.realloc(ptr as *mut u8, k_old.clone(), k_new.size()) .map(|p| NonNull::new_unchecked(p as *mut T)) } _ => { -- cgit 1.4.1-3-g733a5 From 747cc749430d66bd2fca8e81fd8a1c994e36dcf1 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 4 Apr 2018 18:09:39 +0200 Subject: Conversions between Result<*mut u8, AllocErr>> and *mut Void --- src/liballoc_system/lib.rs | 21 +++------------------ src/libcore/alloc.rs | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 18 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 7b788a5f989..6ffbd029281 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -139,22 +139,12 @@ macro_rules! alloc_methods_based_on_global_alloc { () => { #[inline] unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let ptr = GlobalAlloc::alloc(*self, layout); - if !ptr.is_null() { - Ok(ptr as *mut u8) - } else { - Err(AllocErr) - } + GlobalAlloc::alloc(*self, layout).into() } #[inline] unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let ptr = GlobalAlloc::alloc_zeroed(*self, layout); - if !ptr.is_null() { - Ok(ptr as *mut u8) - } else { - Err(AllocErr) - } + GlobalAlloc::alloc_zeroed(*self, layout).into() } #[inline] @@ -167,12 +157,7 @@ macro_rules! alloc_methods_based_on_global_alloc { ptr: *mut u8, old_layout: Layout, new_size: usize) -> Result<*mut u8, AllocErr> { - let ptr = GlobalAlloc::realloc(*self, ptr as *mut Void, old_layout, new_size); - if !ptr.is_null() { - Ok(ptr as *mut u8) - } else { - Err(AllocErr) - } + GlobalAlloc::realloc(*self, ptr as *mut Void, old_layout, new_size).into() } } } diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 757f06e731f..cfa7df06a40 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -41,6 +41,27 @@ impl Void { } } +/// Convert from a return value of GlobalAlloc::alloc to that of Alloc::alloc +impl From<*mut Void> for Result<*mut u8, AllocErr> { + fn from(ptr: *mut Void) -> Self { + if !ptr.is_null() { + Ok(ptr as *mut u8) + } else { + Err(AllocErr) + } + } +} + +/// Convert from a return value of Alloc::alloc to that of GlobalAlloc::alloc +impl From> for *mut Void { + fn from(result: Result<*mut u8, AllocErr>) -> Self { + match result { + Ok(ptr) => ptr as *mut Void, + Err(_) => Void::null_mut(), + } + } +} + /// Represents the combination of a starting address and /// a total capacity of the returned block. #[derive(Debug)] -- cgit 1.4.1-3-g733a5 From eae0d468932660ca383e35bb9d8b0cb4943a82ae Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 4 Apr 2018 18:57:48 +0200 Subject: Restore Global.oom() functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … now that #[global_allocator] does not define a symbol for it --- src/Cargo.lock | 1 + src/liballoc/alloc.rs | 16 ++++++++++++++++ src/liballoc/lib.rs | 1 + src/liballoc_jemalloc/Cargo.toml | 1 + src/liballoc_jemalloc/lib.rs | 10 ++++++++++ src/liballoc_system/lib.rs | 4 ++++ src/libcore/alloc.rs | 4 ++++ src/librustc_allocator/expand.rs | 5 +++++ src/librustc_allocator/lib.rs | 6 ++++++ src/librustc_trans/allocator.rs | 2 ++ src/libstd/alloc.rs | 6 ++++++ src/test/compile-fail/allocator/not-an-allocator.rs | 1 + 12 files changed, 57 insertions(+) (limited to 'src/libcore') diff --git a/src/Cargo.lock b/src/Cargo.lock index 2e969f4ec2b..e5297d1482e 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -19,6 +19,7 @@ dependencies = [ name = "alloc_jemalloc" version = "0.0.0" dependencies = [ + "alloc_system 0.0.0", "build_helper 0.1.0", "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index a6fc8d5004c..beae52726a6 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -26,6 +26,9 @@ extern "Rust" { #[allocator] #[rustc_allocator_nounwind] fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8; + #[cold] + #[rustc_allocator_nounwind] + fn __rust_oom(err: *const u8) -> !; #[rustc_allocator_nounwind] fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); #[rustc_allocator_nounwind] @@ -44,6 +47,9 @@ extern "Rust" { #[allocator] #[rustc_allocator_nounwind] fn __rust_alloc(size: usize, align: usize) -> *mut u8; + #[cold] + #[rustc_allocator_nounwind] + fn __rust_oom() -> !; #[rustc_allocator_nounwind] fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); #[rustc_allocator_nounwind] @@ -120,6 +126,16 @@ unsafe impl Alloc for Global { Err(AllocErr) } } + + #[inline] + fn oom(&mut self) -> ! { + unsafe { + #[cfg(not(stage0))] + __rust_oom(); + #[cfg(stage0)] + __rust_oom(&mut 0); + } + } } /// The allocator for unique pointers. diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index f6598fe5e89..a10820ebefd 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -97,6 +97,7 @@ #![feature(from_ref)] #![feature(fundamental)] #![feature(lang_items)] +#![feature(libc)] #![feature(needs_allocator)] #![feature(nonzero)] #![feature(optin_builtin_traits)] diff --git a/src/liballoc_jemalloc/Cargo.toml b/src/liballoc_jemalloc/Cargo.toml index 7986d5dd2eb..02435170374 100644 --- a/src/liballoc_jemalloc/Cargo.toml +++ b/src/liballoc_jemalloc/Cargo.toml @@ -12,6 +12,7 @@ test = false doc = false [dependencies] +alloc_system = { path = "../liballoc_system" } core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 661d7ab78da..2b66c293f21 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -14,6 +14,7 @@ reason = "this library is unlikely to be stabilized in its current \ form or name", issue = "27783")] +#![feature(alloc_system)] #![feature(libc)] #![feature(linkage)] #![feature(staged_api)] @@ -22,12 +23,15 @@ #![cfg_attr(not(dummy_jemalloc), feature(allocator_api))] #![rustc_alloc_kind = "exe"] +extern crate alloc_system; extern crate libc; #[cfg(not(dummy_jemalloc))] pub use contents::*; #[cfg(not(dummy_jemalloc))] mod contents { + use core::alloc::GlobalAlloc; + use alloc_system::System; use libc::{c_int, c_void, size_t}; // Note that the symbols here are prefixed by default on macOS and Windows (we @@ -96,6 +100,12 @@ mod contents { ptr } + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rde_oom() -> ! { + System.oom() + } + #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rde_dealloc(ptr: *mut u8, diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 4516664e97c..c6507282b24 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -367,6 +367,7 @@ mod platform { } } +#[inline] fn oom() -> ! { write_to_stderr("fatal runtime error: memory allocation failed"); unsafe { @@ -375,6 +376,7 @@ fn oom() -> ! { } #[cfg(any(unix, target_os = "redox"))] +#[inline] fn write_to_stderr(s: &str) { extern crate libc; @@ -386,6 +388,7 @@ fn write_to_stderr(s: &str) { } #[cfg(windows)] +#[inline] fn write_to_stderr(s: &str) { use core::ptr; @@ -421,4 +424,5 @@ fn write_to_stderr(s: &str) { } #[cfg(not(any(windows, unix, target_os = "redox")))] +#[inline] fn write_to_stderr(_: &str) {} diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index cfa7df06a40..7334f986f2b 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -438,6 +438,10 @@ pub unsafe trait GlobalAlloc { } new_ptr } + + fn oom(&self) -> ! { + unsafe { ::intrinsics::abort() } + } } /// An implementation of `Alloc` can allocate, reallocate, and diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index ce41fe1f3bc..58d4c7f289c 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -231,6 +231,7 @@ impl<'a> AllocFnFactory<'a> { } AllocatorTy::ResultPtr | + AllocatorTy::Bang | AllocatorTy::Unit => { panic!("can't convert AllocatorTy to an argument") } @@ -248,6 +249,10 @@ impl<'a> AllocFnFactory<'a> { (self.ptr_u8(), expr) } + AllocatorTy::Bang => { + (self.cx.ty(self.span, TyKind::Never), expr) + } + AllocatorTy::Unit => { (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr) } diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index 969086815de..706eab72d44 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -23,6 +23,11 @@ pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ inputs: &[AllocatorTy::Layout], output: AllocatorTy::ResultPtr, }, + AllocatorMethod { + name: "oom", + inputs: &[], + output: AllocatorTy::Bang, + }, AllocatorMethod { name: "dealloc", inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout], @@ -47,6 +52,7 @@ pub struct AllocatorMethod { } pub enum AllocatorTy { + Bang, Layout, Ptr, ResultPtr, diff --git a/src/librustc_trans/allocator.rs b/src/librustc_trans/allocator.rs index ffebb959ebf..f2dd2ed8460 100644 --- a/src/librustc_trans/allocator.rs +++ b/src/librustc_trans/allocator.rs @@ -43,11 +43,13 @@ pub(crate) unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) AllocatorTy::Ptr => args.push(i8p), AllocatorTy::Usize => args.push(usize), + AllocatorTy::Bang | AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"), } } let output = match method.output { + AllocatorTy::Bang => None, AllocatorTy::ResultPtr => Some(i8p), AllocatorTy::Unit => None, diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 335dc7e0412..4e728df010a 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -35,6 +35,12 @@ pub mod __default_lib_allocator { System.alloc(layout) as *mut u8 } + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_oom() -> ! { + System.oom() + } + #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, diff --git a/src/test/compile-fail/allocator/not-an-allocator.rs b/src/test/compile-fail/allocator/not-an-allocator.rs index 140cad22f34..1479d0b6264 100644 --- a/src/test/compile-fail/allocator/not-an-allocator.rs +++ b/src/test/compile-fail/allocator/not-an-allocator.rs @@ -16,5 +16,6 @@ static A: usize = 0; //~| the trait bound `usize: //~| the trait bound `usize: //~| the trait bound `usize: +//~| the trait bound `usize: fn main() {} -- cgit 1.4.1-3-g733a5 From fddf51ee0b9765484fc316dbf3d4feb8ceea715d Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Tue, 3 Apr 2018 08:51:02 +0900 Subject: Use NonNull instead of *mut u8 in the Alloc trait Fixes #49608 --- src/doc/nomicon | 2 +- .../src/language-features/global-allocator.md | 1 + src/liballoc/alloc.rs | 19 +++---- src/liballoc/arc.rs | 16 +++--- src/liballoc/btree/node.rs | 16 +++--- src/liballoc/heap.rs | 22 ++++++-- src/liballoc/lib.rs | 1 + src/liballoc/raw_vec.rs | 40 +++++++-------- src/liballoc/rc.rs | 18 +++---- src/liballoc/tests/heap.rs | 3 +- src/liballoc_system/lib.rs | 29 +++++------ src/libcore/alloc.rs | 58 ++++++++++------------ src/libcore/ptr.rs | 8 +++ src/libstd/collections/hash/table.rs | 6 +-- src/libstd/lib.rs | 1 + src/test/run-pass/allocator/xcrate-use2.rs | 2 +- src/test/run-pass/realloc-16687.rs | 18 +++---- src/test/run-pass/regions-mock-trans.rs | 5 +- 18 files changed, 136 insertions(+), 129 deletions(-) (limited to 'src/libcore') diff --git a/src/doc/nomicon b/src/doc/nomicon index 6a8f0a27e9a..498ac299742 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 6a8f0a27e9a58c55c89d07bc43a176fdae5e051c +Subproject commit 498ac2997420f7b25f7cd0a3f8202950d8ad93ec diff --git a/src/doc/unstable-book/src/language-features/global-allocator.md b/src/doc/unstable-book/src/language-features/global-allocator.md index 6ce12ba684d..a3f3ee65bf0 100644 --- a/src/doc/unstable-book/src/language-features/global-allocator.md +++ b/src/doc/unstable-book/src/language-features/global-allocator.md @@ -30,6 +30,7 @@ looks like: #![feature(global_allocator, allocator_api, heap_api)] use std::alloc::{GlobalAlloc, System, Layout, Void}; +use std::ptr::NonNull; struct MyAllocator; diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 063f0543ec4..af48aa7961e 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -16,6 +16,7 @@ issue = "32838")] use core::intrinsics::{min_align_of_val, size_of_val}; +use core::ptr::NonNull; use core::usize; #[doc(inline)] @@ -120,27 +121,27 @@ unsafe impl GlobalAlloc for Global { unsafe impl Alloc for Global { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { GlobalAlloc::alloc(self, layout).into() } #[inline] - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - GlobalAlloc::dealloc(self, ptr as *mut Void, layout) + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: *mut u8, + ptr: NonNull, layout: Layout, new_size: usize) - -> Result<*mut u8, AllocErr> + -> Result, AllocErr> { - GlobalAlloc::realloc(self, ptr as *mut Void, layout, new_size).into() + GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size).into() } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { GlobalAlloc::alloc_zeroed(self, layout).into() } @@ -195,8 +196,8 @@ mod tests { let ptr = Global.alloc_zeroed(layout.clone()) .unwrap_or_else(|_| Global.oom()); - let end = ptr.offset(layout.size() as isize); - let mut i = ptr; + let mut i = ptr.cast::().as_ptr(); + let end = i.offset(layout.size() as isize); while i < end { assert_eq!(*i, 0); i = i.offset(1); diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index f0a325530ba..88754ace3ce 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -512,15 +512,13 @@ impl Arc { // Non-inlined part of `drop`. #[inline(never)] unsafe fn drop_slow(&mut self) { - let ptr = self.ptr.as_ptr(); - // Destroy the data at this time, even though we may not free the box // allocation itself (there may still be weak pointers lying around). ptr::drop_in_place(&mut self.ptr.as_mut().data); if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); - Global.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)) + Global.dealloc(self.ptr.as_void(), Layout::for_value(self.ptr.as_ref())) } } @@ -558,7 +556,7 @@ impl Arc { .unwrap_or_else(|_| Global.oom()); // Initialize the real ArcInner - let inner = set_data_ptr(ptr as *mut T, mem) as *mut ArcInner; + let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner; ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1)); ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1)); @@ -625,7 +623,7 @@ impl ArcFromSlice for Arc<[T]> { // In the event of a panic, elements that have been written // into the new ArcInner will be dropped, then the memory freed. struct Guard { - mem: *mut u8, + mem: NonNull, elems: *mut T, layout: Layout, n_elems: usize, @@ -639,7 +637,7 @@ impl ArcFromSlice for Arc<[T]> { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Global.dealloc(self.mem, self.layout.clone()); + Global.dealloc(self.mem.as_void(), self.layout.clone()); } } } @@ -655,7 +653,7 @@ impl ArcFromSlice for Arc<[T]> { let elems = &mut (*ptr).data as *mut [T] as *mut T; let mut guard = Guard{ - mem: mem, + mem: NonNull::new_unchecked(mem), elems: elems, layout: layout, n_elems: 0, @@ -1147,8 +1145,6 @@ impl Drop for Weak { /// assert!(other_weak_foo.upgrade().is_none()); /// ``` fn drop(&mut self) { - let ptr = self.ptr.as_ptr(); - // If we find out that we were the last weak pointer, then its time to // deallocate the data entirely. See the discussion in Arc::drop() about // the memory orderings @@ -1160,7 +1156,7 @@ impl Drop for Weak { if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); unsafe { - Global.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)) + Global.dealloc(self.ptr.as_void(), Layout::for_value(self.ptr.as_ref())) } } } diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs index 8e23228bd28..64aa40ac166 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -236,7 +236,7 @@ impl Root { pub fn pop_level(&mut self) { debug_assert!(self.height > 0); - let top = self.node.ptr.as_ptr() as *mut u8; + let top = self.node.ptr; self.node = unsafe { BoxedNode::from_ptr(self.as_mut() @@ -249,7 +249,7 @@ impl Root { self.as_mut().as_leaf_mut().parent = ptr::null(); unsafe { - Global.dealloc(top, Layout::new::>()); + Global.dealloc(NonNull::from(top).as_void(), Layout::new::>()); } } } @@ -433,9 +433,9 @@ impl NodeRef { marker::Edge > > { - let ptr = self.as_leaf() as *const LeafNode as *const u8 as *mut u8; + let node = self.node; let ret = self.ascend().ok(); - Global.dealloc(ptr, Layout::new::>()); + Global.dealloc(node.as_void(), Layout::new::>()); ret } } @@ -454,9 +454,9 @@ impl NodeRef { marker::Edge > > { - let ptr = self.as_internal() as *const InternalNode as *const u8 as *mut u8; + let node = self.node; let ret = self.ascend().ok(); - Global.dealloc(ptr, Layout::new::>()); + Global.dealloc(node.as_void(), Layout::new::>()); ret } } @@ -1239,12 +1239,12 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: } Global.dealloc( - right_node.node.as_ptr() as *mut u8, + right_node.node.as_void(), Layout::new::>(), ); } else { Global.dealloc( - right_node.node.as_ptr() as *mut u8, + right_node.node.as_void(), Layout::new::>(), ); } diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index e79383331e1..cfb6504e743 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -8,14 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use alloc::{Excess, Layout, AllocErr, CannotReallocInPlace}; +#![allow(deprecated)] + +pub use alloc::{Layout, AllocErr, CannotReallocInPlace, Void}; use core::alloc::Alloc as CoreAlloc; +use core::ptr::NonNull; #[doc(hidden)] pub mod __core { pub use core::*; } +#[derive(Debug)] +pub struct Excess(pub *mut u8, pub usize); + /// Compatibility with older versions of #[global_allocator] during bootstrap pub unsafe trait Alloc { unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; @@ -42,13 +48,13 @@ pub unsafe trait Alloc { new_layout: Layout) -> Result<(), CannotReallocInPlace>; } -#[allow(deprecated)] unsafe impl Alloc for T where T: CoreAlloc { unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - CoreAlloc::alloc(self, layout) + CoreAlloc::alloc(self, layout).map(|ptr| ptr.cast().as_ptr()) } unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + let ptr = NonNull::new_unchecked(ptr as *mut Void); CoreAlloc::dealloc(self, ptr, layout) } @@ -64,28 +70,33 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<*mut u8, AllocErr> { - CoreAlloc::realloc(self, ptr, layout, new_layout.size()) + let ptr = NonNull::new_unchecked(ptr as *mut Void); + CoreAlloc::realloc(self, ptr, layout, new_layout.size()).map(|ptr| ptr.cast().as_ptr()) } unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - CoreAlloc::alloc_zeroed(self, layout) + CoreAlloc::alloc_zeroed(self, layout).map(|ptr| ptr.cast().as_ptr()) } unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { CoreAlloc::alloc_excess(self, layout) + .map(|e| Excess(e.0 .cast().as_ptr(), e.1)) } unsafe fn realloc_excess(&mut self, ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result { + let ptr = NonNull::new_unchecked(ptr as *mut Void); CoreAlloc::realloc_excess(self, ptr, layout, new_layout.size()) + .map(|e| Excess(e.0 .cast().as_ptr(), e.1)) } unsafe fn grow_in_place(&mut self, ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { + let ptr = NonNull::new_unchecked(ptr as *mut Void); CoreAlloc::grow_in_place(self, ptr, layout, new_layout.size()) } @@ -93,6 +104,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { + let ptr = NonNull::new_unchecked(ptr as *mut Void); CoreAlloc::shrink_in_place(self, ptr, layout, new_layout.size()) } } diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index a10820ebefd..3a106a2ff5c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -99,6 +99,7 @@ #![feature(lang_items)] #![feature(libc)] #![feature(needs_allocator)] +#![feature(nonnull_cast)] #![feature(nonzero)] #![feature(optin_builtin_traits)] #![feature(pattern)] diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 80b816878fb..d72301f5ad6 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -12,7 +12,7 @@ use alloc::{Alloc, Layout, Global}; use core::cmp; use core::mem; use core::ops::Drop; -use core::ptr::{self, Unique}; +use core::ptr::{self, NonNull, Unique}; use core::slice; use super::boxed::Box; use super::allocator::CollectionAllocErr; @@ -90,7 +90,7 @@ impl RawVec { // handles ZSTs and `cap = 0` alike let ptr = if alloc_size == 0 { - mem::align_of::() as *mut u8 + NonNull::::dangling().as_void() } else { let align = mem::align_of::(); let result = if zeroed { @@ -105,7 +105,7 @@ impl RawVec { }; RawVec { - ptr: Unique::new_unchecked(ptr as *mut _), + ptr: ptr.cast().into(), cap, a, } @@ -310,11 +310,11 @@ impl RawVec { let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; alloc_guard(new_size).expect("capacity overflow"); - let ptr_res = self.a.realloc(self.ptr.as_ptr() as *mut u8, + let ptr_res = self.a.realloc(NonNull::from(self.ptr).as_void(), cur, new_size); match ptr_res { - Ok(ptr) => (new_cap, Unique::new_unchecked(ptr as *mut T)), + Ok(ptr) => (new_cap, ptr.cast().into()), Err(_) => self.a.oom(), } } @@ -369,8 +369,7 @@ impl RawVec { let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; alloc_guard(new_size).expect("capacity overflow"); - let ptr = self.ptr() as *mut _; - match self.a.grow_in_place(ptr, old_layout, new_size) { + match self.a.grow_in_place(NonNull::from(self.ptr).as_void(), old_layout, new_size) { Ok(_) => { // We can't directly divide `size`. self.cap = new_cap; @@ -427,13 +426,12 @@ impl RawVec { let res = match self.current_layout() { Some(layout) => { debug_assert!(new_layout.align() == layout.align()); - let old_ptr = self.ptr.as_ptr() as *mut u8; - self.a.realloc(old_ptr, layout, new_layout.size()) + self.a.realloc(NonNull::from(self.ptr).as_void(), layout, new_layout.size()) } None => self.a.alloc(new_layout), }; - self.ptr = Unique::new_unchecked(res? as *mut T); + self.ptr = res?.cast().into(); self.cap = new_cap; Ok(()) @@ -537,13 +535,12 @@ impl RawVec { let res = match self.current_layout() { Some(layout) => { debug_assert!(new_layout.align() == layout.align()); - let old_ptr = self.ptr.as_ptr() as *mut u8; - self.a.realloc(old_ptr, layout, new_layout.size()) + self.a.realloc(NonNull::from(self.ptr).as_void(), layout, new_layout.size()) } None => self.a.alloc(new_layout), }; - self.ptr = Unique::new_unchecked(res? as *mut T); + self.ptr = res?.cast().into(); self.cap = new_cap; Ok(()) @@ -600,11 +597,12 @@ impl RawVec { // (regardless of whether `self.cap - used_cap` wrapped). // Therefore we can safely call grow_in_place. - let ptr = self.ptr() as *mut _; let new_layout = Layout::new::().repeat(new_cap).unwrap().0; // FIXME: may crash and burn on over-reserve alloc_guard(new_layout.size()).expect("capacity overflow"); - match self.a.grow_in_place(ptr, old_layout, new_layout.size()) { + match self.a.grow_in_place( + NonNull::from(self.ptr).as_void(), old_layout, new_layout.size(), + ) { Ok(_) => { self.cap = new_cap; true @@ -664,10 +662,10 @@ impl RawVec { let new_size = elem_size * amount; let align = mem::align_of::(); let old_layout = Layout::from_size_align_unchecked(old_size, align); - match self.a.realloc(self.ptr.as_ptr() as *mut u8, + match self.a.realloc(NonNull::from(self.ptr).as_void(), old_layout, new_size) { - Ok(p) => self.ptr = Unique::new_unchecked(p as *mut T), + Ok(p) => self.ptr = p.cast().into(), Err(_) => self.a.oom(), } } @@ -700,8 +698,7 @@ impl RawVec { let elem_size = mem::size_of::(); if elem_size != 0 { if let Some(layout) = self.current_layout() { - let ptr = self.ptr() as *mut u8; - self.a.dealloc(ptr, layout); + self.a.dealloc(NonNull::from(self.ptr).as_void(), layout); } } } @@ -737,6 +734,7 @@ fn alloc_guard(alloc_size: usize) -> Result<(), CollectionAllocErr> { #[cfg(test)] mod tests { use super::*; + use alloc::Void; #[test] fn allocator_param() { @@ -756,7 +754,7 @@ mod tests { // before allocation attempts start failing. struct BoundedAlloc { fuel: usize } unsafe impl Alloc for BoundedAlloc { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); if size > self.fuel { return Err(AllocErr); @@ -766,7 +764,7 @@ mod tests { err @ Err(_) => err, } } - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { Global.dealloc(ptr, layout) } } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 3c0b11bfe74..1c835fe50de 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -259,7 +259,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, NonNull}; use core::convert::From; -use alloc::{Global, Alloc, Layout, box_free}; +use alloc::{Global, Alloc, Layout, Void, box_free}; use string::String; use vec::Vec; @@ -671,7 +671,7 @@ impl Rc { .unwrap_or_else(|_| Global.oom()); // Initialize the real RcBox - let inner = set_data_ptr(ptr as *mut T, mem) as *mut RcBox; + let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut RcBox; ptr::write(&mut (*inner).strong, Cell::new(1)); ptr::write(&mut (*inner).weak, Cell::new(1)); @@ -737,7 +737,7 @@ impl RcFromSlice for Rc<[T]> { // In the event of a panic, elements that have been written // into the new RcBox will be dropped, then the memory freed. struct Guard { - mem: *mut u8, + mem: NonNull, elems: *mut T, layout: Layout, n_elems: usize, @@ -760,14 +760,14 @@ impl RcFromSlice for Rc<[T]> { let v_ptr = v as *const [T]; let ptr = Self::allocate_for_ptr(v_ptr); - let mem = ptr as *mut _ as *mut u8; + let mem = ptr as *mut _ as *mut Void; let layout = Layout::for_value(&*ptr); // Pointer to first element let elems = &mut (*ptr).value as *mut [T] as *mut T; let mut guard = Guard{ - mem: mem, + mem: NonNull::new_unchecked(mem), elems: elems, layout: layout, n_elems: 0, @@ -834,8 +834,6 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { /// ``` fn drop(&mut self) { unsafe { - let ptr = self.ptr.as_ptr(); - self.dec_strong(); if self.strong() == 0 { // destroy the contained object @@ -846,7 +844,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { self.dec_weak(); if self.weak() == 0 { - Global.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)); + Global.dealloc(self.ptr.as_void(), Layout::for_value(self.ptr.as_ref())); } } } @@ -1266,13 +1264,11 @@ impl Drop for Weak { /// ``` fn drop(&mut self) { unsafe { - let ptr = self.ptr.as_ptr(); - self.dec_weak(); // the weak count starts at 1, and will only go to zero if all // the strong pointers have disappeared. if self.weak() == 0 { - Global.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)); + Global.dealloc(self.ptr.as_void(), Layout::for_value(self.ptr.as_ref())); } } } diff --git a/src/liballoc/tests/heap.rs b/src/liballoc/tests/heap.rs index 328131e2fef..6fa88ce969a 100644 --- a/src/liballoc/tests/heap.rs +++ b/src/liballoc/tests/heap.rs @@ -34,7 +34,8 @@ fn check_overalign_requests(mut allocator: T) { allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() }).collect(); for &ptr in &pointers { - assert_eq!((ptr as usize) % align, 0, "Got a pointer less aligned than requested") + assert_eq!((ptr.as_ptr() as usize) % align, 0, + "Got a pointer less aligned than requested") } // Clean up diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index c6507282b24..bf27e972177 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -42,6 +42,7 @@ const MIN_ALIGN: usize = 8; const MIN_ALIGN: usize = 16; use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout, Void}; +use core::ptr::NonNull; #[unstable(feature = "allocator_api", issue = "32838")] pub struct System; @@ -49,26 +50,26 @@ pub struct System; #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl Alloc for System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { GlobalAlloc::alloc(self, layout).into() } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { GlobalAlloc::alloc_zeroed(self, layout).into() } #[inline] - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - GlobalAlloc::dealloc(self, ptr as *mut Void, layout) + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: *mut u8, + ptr: NonNull, old_layout: Layout, - new_size: usize) -> Result<*mut u8, AllocErr> { - GlobalAlloc::realloc(self, ptr as *mut Void, old_layout, new_size).into() + new_size: usize) -> Result, AllocErr> { + GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size).into() } #[inline] @@ -81,26 +82,26 @@ unsafe impl Alloc for System { #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl<'a> Alloc for &'a System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { GlobalAlloc::alloc(*self, layout).into() } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { GlobalAlloc::alloc_zeroed(*self, layout).into() } #[inline] - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - GlobalAlloc::dealloc(*self, ptr as *mut Void, layout) + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + GlobalAlloc::dealloc(*self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: *mut u8, + ptr: NonNull, old_layout: Layout, - new_size: usize) -> Result<*mut u8, AllocErr> { - GlobalAlloc::realloc(*self, ptr as *mut Void, old_layout, new_size).into() + new_size: usize) -> Result, AllocErr> { + GlobalAlloc::realloc(*self, ptr.as_ptr(), old_layout, new_size).into() } #[inline] diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 7334f986f2b..632eed96049 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -42,21 +42,17 @@ impl Void { } /// Convert from a return value of GlobalAlloc::alloc to that of Alloc::alloc -impl From<*mut Void> for Result<*mut u8, AllocErr> { +impl From<*mut Void> for Result, AllocErr> { fn from(ptr: *mut Void) -> Self { - if !ptr.is_null() { - Ok(ptr as *mut u8) - } else { - Err(AllocErr) - } + NonNull::new(ptr).ok_or(AllocErr) } } /// Convert from a return value of Alloc::alloc to that of GlobalAlloc::alloc -impl From> for *mut Void { - fn from(result: Result<*mut u8, AllocErr>) -> Self { +impl From, AllocErr>> for *mut Void { + fn from(result: Result, AllocErr>) -> Self { match result { - Ok(ptr) => ptr as *mut Void, + Ok(ptr) => ptr.as_ptr(), Err(_) => Void::null_mut(), } } @@ -65,7 +61,7 @@ impl From> for *mut Void { /// Represents the combination of a starting address and /// a total capacity of the returned block. #[derive(Debug)] -pub struct Excess(pub *mut u8, pub usize); +pub struct Excess(pub NonNull, pub usize); fn size_align() -> (usize, usize) { (mem::size_of::(), mem::align_of::()) @@ -575,7 +571,7 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; /// Deallocate the memory referenced by `ptr`. /// @@ -592,7 +588,7 @@ pub unsafe trait Alloc { /// * In addition to fitting the block of memory `layout`, the /// alignment of the `layout` must match the alignment used /// to allocate that block of memory. - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); /// Allocator-specific method for signaling an out-of-memory /// condition. @@ -710,9 +706,9 @@ pub unsafe trait Alloc { /// reallocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. unsafe fn realloc(&mut self, - ptr: *mut u8, + ptr: NonNull, layout: Layout, - new_size: usize) -> Result<*mut u8, AllocErr> { + new_size: usize) -> Result, AllocErr> { let old_size = layout.size(); if new_size >= old_size { @@ -729,7 +725,9 @@ pub unsafe trait Alloc { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let result = self.alloc(new_layout); if let Ok(new_ptr) = result { - ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size)); + ptr::copy_nonoverlapping(ptr.as_ptr() as *const u8, + new_ptr.as_ptr() as *mut u8, + cmp::min(old_size, new_size)); self.dealloc(ptr, layout); } result @@ -751,11 +749,11 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); let p = self.alloc(layout); if let Ok(p) = p { - ptr::write_bytes(p, 0, size); + ptr::write_bytes(p.as_ptr() as *mut u8, 0, size); } p } @@ -800,7 +798,7 @@ pub unsafe trait Alloc { /// reallocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. unsafe fn realloc_excess(&mut self, - ptr: *mut u8, + ptr: NonNull, layout: Layout, new_size: usize) -> Result { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); @@ -845,7 +843,7 @@ pub unsafe trait Alloc { /// `grow_in_place` failures without aborting, or to fall back on /// another reallocation method before resorting to an abort. unsafe fn grow_in_place(&mut self, - ptr: *mut u8, + ptr: NonNull, layout: Layout, new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. @@ -900,7 +898,7 @@ pub unsafe trait Alloc { /// `shrink_in_place` failures without aborting, or to fall back /// on another reallocation method before resorting to an abort. unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, + ptr: NonNull, layout: Layout, new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. @@ -951,7 +949,7 @@ pub unsafe trait Alloc { { let k = Layout::new::(); if k.size() > 0 { - unsafe { self.alloc(k).map(|p| NonNull::new_unchecked(p as *mut T)) } + unsafe { self.alloc(k).map(|p| p.cast()) } } else { Err(AllocErr) } @@ -977,10 +975,9 @@ pub unsafe trait Alloc { unsafe fn dealloc_one(&mut self, ptr: NonNull) where Self: Sized { - let raw_ptr = ptr.as_ptr() as *mut u8; let k = Layout::new::(); if k.size() > 0 { - self.dealloc(raw_ptr, k); + self.dealloc(ptr.as_void(), k); } } @@ -1020,10 +1017,7 @@ pub unsafe trait Alloc { match Layout::array::(n) { Ok(ref layout) if layout.size() > 0 => { unsafe { - self.alloc(layout.clone()) - .map(|p| { - NonNull::new_unchecked(p as *mut T) - }) + self.alloc(layout.clone()).map(|p| p.cast()) } } _ => Err(AllocErr), @@ -1068,11 +1062,10 @@ pub unsafe trait Alloc { n_new: usize) -> Result, AllocErr> where Self: Sized { - match (Layout::array::(n_old), Layout::array::(n_new), ptr.as_ptr()) { - (Ok(ref k_old), Ok(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { + match (Layout::array::(n_old), Layout::array::(n_new)) { + (Ok(ref k_old), Ok(ref k_new)) if k_old.size() > 0 && k_new.size() > 0 => { debug_assert!(k_old.align() == k_new.align()); - self.realloc(ptr as *mut u8, k_old.clone(), k_new.size()) - .map(|p| NonNull::new_unchecked(p as *mut T)) + self.realloc(ptr.as_void(), k_old.clone(), k_new.size()).map(NonNull::cast) } _ => { Err(AllocErr) @@ -1103,10 +1096,9 @@ pub unsafe trait Alloc { unsafe fn dealloc_array(&mut self, ptr: NonNull, n: usize) -> Result<(), AllocErr> where Self: Sized { - let raw_ptr = ptr.as_ptr() as *mut u8; match Layout::array::(n) { Ok(ref k) if k.size() > 0 => { - Ok(self.dealloc(raw_ptr, k.clone())) + Ok(self.dealloc(ptr.as_void(), k.clone())) } _ => { Err(AllocErr) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index c1e150e9fb9..f4e668328ce 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2750,6 +2750,14 @@ impl NonNull { NonNull::new_unchecked(self.as_ptr() as *mut U) } } + + /// Cast to a `Void` pointer + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn as_void(self) -> NonNull<::alloc::Void> { + unsafe { + NonNull::new_unchecked(self.as_ptr() as _) + } + } } #[stable(feature = "nonnull", since = "1.25.0")] diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 50263705143..38c99373788 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -757,12 +757,10 @@ impl RawTable { let buffer = Global.alloc(Layout::from_size_align(size, alignment) .map_err(|_| CollectionAllocErr::CapacityOverflow)?)?; - let hashes = buffer as *mut HashUint; - Ok(RawTable { capacity_mask: capacity.wrapping_sub(1), size: 0, - hashes: TaggedHashUintPtr::new(hashes), + hashes: TaggedHashUintPtr::new(buffer.cast().as_ptr()), marker: marker::PhantomData, }) } @@ -1185,7 +1183,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { debug_assert!(!oflo, "should be impossible"); unsafe { - Global.dealloc(self.hashes.ptr() as *mut u8, + Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_void(), Layout::from_size_align(size, align).unwrap()); // Remember how everything was allocated out of one buffer // during initialization? We only need one call to free here. diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 25ba75fd35e..a34fcb5a7f9 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -275,6 +275,7 @@ #![feature(macro_reexport)] #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] +#![feature(nonnull_cast)] #![feature(exhaustive_patterns)] #![feature(nonzero)] #![feature(num_bits_bytes)] diff --git a/src/test/run-pass/allocator/xcrate-use2.rs b/src/test/run-pass/allocator/xcrate-use2.rs index 52eb963efdb..b8e844522dc 100644 --- a/src/test/run-pass/allocator/xcrate-use2.rs +++ b/src/test/run-pass/allocator/xcrate-use2.rs @@ -30,7 +30,7 @@ fn main() { let layout = Layout::from_size_align(4, 2).unwrap(); // Global allocator routes to the `custom_as_global` global - let ptr = Global.alloc(layout.clone()).unwrap(); + let ptr = Global.alloc(layout.clone()); helper::work_with(&ptr); assert_eq!(custom_as_global::get(), n + 1); Global.dealloc(ptr, layout.clone()); diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index a562165d21b..49ab0ee3310 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -13,10 +13,10 @@ // Ideally this would be revised to use no_std, but for now it serves // well enough to reproduce (and illustrate) the bug from #16687. -#![feature(heap_api, allocator_api)] +#![feature(heap_api, allocator_api, nonnull_cast)] -use std::heap::{Heap, Alloc, Layout}; -use std::ptr; +use std::alloc::{Global, Alloc, Layout}; +use std::ptr::{self, NonNull}; fn main() { unsafe { @@ -50,13 +50,13 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?})", layout); } - let ret = Heap.alloc(layout.clone()).unwrap_or_else(|_| Heap.oom()); + let ret = Global.alloc(layout.clone()).unwrap_or_else(|_| Global.oom()); if PRINT { println!("allocate({:?}) = {:?}", layout, ret); } - ret + ret.cast().as_ptr() } unsafe fn deallocate(ptr: *mut u8, layout: Layout) { @@ -64,7 +64,7 @@ unsafe fn test_triangle() -> bool { println!("deallocate({:?}, {:?}", ptr, layout); } - Heap.dealloc(ptr, layout); + Global.dealloc(NonNull::new_unchecked(ptr).as_void(), layout); } unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 { @@ -72,14 +72,14 @@ unsafe fn test_triangle() -> bool { println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new); } - let ret = Heap.realloc(ptr, old.clone(), new.clone()) - .unwrap_or_else(|_| Heap.oom()); + let ret = Global.realloc(NonNull::new_unchecked(ptr).as_void(), old.clone(), new.size()) + .unwrap_or_else(|_| Global.oom()); if PRINT { println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", ptr, old, new, ret); } - ret + ret.cast().as_ptr() } fn idx_to_size(i: usize) -> usize { (i+1) * 10 } diff --git a/src/test/run-pass/regions-mock-trans.rs b/src/test/run-pass/regions-mock-trans.rs index 7d34b8fd00f..3c37243c8b9 100644 --- a/src/test/run-pass/regions-mock-trans.rs +++ b/src/test/run-pass/regions-mock-trans.rs @@ -13,6 +13,7 @@ #![feature(allocator_api)] use std::heap::{Alloc, Heap, Layout}; +use std::ptr::NonNull; struct arena(()); @@ -33,7 +34,7 @@ fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> { unsafe { let ptr = Heap.alloc(Layout::new::()) .unwrap_or_else(|_| Heap.oom()); - &*(ptr as *const _) + &*(ptr.as_ptr() as *const _) } } @@ -45,7 +46,7 @@ fn g(fcx : &Fcx) { let bcx = Bcx { fcx: fcx }; let bcx2 = h(&bcx); unsafe { - Heap.dealloc(bcx2 as *const _ as *mut _, Layout::new::()); + Heap.dealloc(NonNull::new_unchecked(bcx2 as *const _ as *mut _), Layout::new::()); } } -- cgit 1.4.1-3-g733a5 From ed297777599081d11c4a337cf19c9b1a1112136b Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 11 Apr 2018 16:28:37 +0200 Subject: Remove conversions for allocated pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One was now unused, and `NonNull::new(…).ok_or(AllocErr)` feels short enough for the few cases that need the other conversion. --- src/liballoc/alloc.rs | 6 +++--- src/liballoc_system/lib.rs | 16 ++++++++-------- src/libcore/alloc.rs | 17 ----------------- 3 files changed, 11 insertions(+), 28 deletions(-) (limited to 'src/libcore') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index af48aa7961e..031babe5f6d 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -122,7 +122,7 @@ unsafe impl GlobalAlloc for Global { unsafe impl Alloc for Global { #[inline] unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { - GlobalAlloc::alloc(self, layout).into() + NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) } #[inline] @@ -137,12 +137,12 @@ unsafe impl Alloc for Global { new_size: usize) -> Result, AllocErr> { - GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size).into() + NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } #[inline] unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { - GlobalAlloc::alloc_zeroed(self, layout).into() + NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) } #[inline] diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index bf27e972177..7fea6061169 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -51,12 +51,12 @@ pub struct System; unsafe impl Alloc for System { #[inline] unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { - GlobalAlloc::alloc(self, layout).into() + NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) } #[inline] unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { - GlobalAlloc::alloc_zeroed(self, layout).into() + NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) } #[inline] @@ -67,9 +67,9 @@ unsafe impl Alloc for System { #[inline] unsafe fn realloc(&mut self, ptr: NonNull, - old_layout: Layout, + layout: Layout, new_size: usize) -> Result, AllocErr> { - GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size).into() + NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } #[inline] @@ -83,12 +83,12 @@ unsafe impl Alloc for System { unsafe impl<'a> Alloc for &'a System { #[inline] unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { - GlobalAlloc::alloc(*self, layout).into() + NonNull::new(GlobalAlloc::alloc(*self, layout)).ok_or(AllocErr) } #[inline] unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { - GlobalAlloc::alloc_zeroed(*self, layout).into() + NonNull::new(GlobalAlloc::alloc_zeroed(*self, layout)).ok_or(AllocErr) } #[inline] @@ -99,9 +99,9 @@ unsafe impl<'a> Alloc for &'a System { #[inline] unsafe fn realloc(&mut self, ptr: NonNull, - old_layout: Layout, + layout: Layout, new_size: usize) -> Result, AllocErr> { - GlobalAlloc::realloc(*self, ptr.as_ptr(), old_layout, new_size).into() + NonNull::new(GlobalAlloc::realloc(*self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } #[inline] diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 632eed96049..97a49703baf 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -41,23 +41,6 @@ impl Void { } } -/// Convert from a return value of GlobalAlloc::alloc to that of Alloc::alloc -impl From<*mut Void> for Result, AllocErr> { - fn from(ptr: *mut Void) -> Self { - NonNull::new(ptr).ok_or(AllocErr) - } -} - -/// Convert from a return value of Alloc::alloc to that of GlobalAlloc::alloc -impl From, AllocErr>> for *mut Void { - fn from(result: Result, AllocErr>) -> Self { - match result { - Ok(ptr) => ptr.as_ptr(), - Err(_) => Void::null_mut(), - } - } -} - /// Represents the combination of a starting address and /// a total capacity of the returned block. #[derive(Debug)] -- cgit 1.4.1-3-g733a5 From f607a3872addf380846cae28661a777ec3e3c9a2 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 11 Apr 2018 17:19:48 +0200 Subject: Rename alloc::Void to alloc::Opaque --- src/doc/nomicon | 2 +- .../src/language-features/global-allocator.md | 6 +- src/liballoc/alloc.rs | 26 +++--- src/liballoc/arc.rs | 6 +- src/liballoc/btree/node.rs | 10 +- src/liballoc/heap.rs | 12 +-- src/liballoc/raw_vec.rs | 22 ++--- src/liballoc/rc.rs | 10 +- src/liballoc_system/lib.rs | 103 ++++++++++----------- src/libcore/alloc.rs | 38 ++++---- src/libcore/ptr.rs | 4 +- src/librustc_allocator/expand.rs | 12 +-- src/libstd/alloc.rs | 6 +- src/libstd/collections/hash/table.rs | 2 +- src/test/run-make-fulldeps/std-core-cycle/bar.rs | 4 +- src/test/run-pass/allocator/auxiliary/custom.rs | 6 +- src/test/run-pass/allocator/custom.rs | 6 +- src/test/run-pass/realloc-16687.rs | 4 +- 18 files changed, 139 insertions(+), 140 deletions(-) (limited to 'src/libcore') diff --git a/src/doc/nomicon b/src/doc/nomicon index 498ac299742..3c56329d1bd 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 498ac2997420f7b25f7cd0a3f8202950d8ad93ec +Subproject commit 3c56329d1bd9038e5341f1962bcd8d043312a712 diff --git a/src/doc/unstable-book/src/language-features/global-allocator.md b/src/doc/unstable-book/src/language-features/global-allocator.md index a3f3ee65bf0..031b6347445 100644 --- a/src/doc/unstable-book/src/language-features/global-allocator.md +++ b/src/doc/unstable-book/src/language-features/global-allocator.md @@ -29,17 +29,17 @@ looks like: ```rust #![feature(global_allocator, allocator_api, heap_api)] -use std::alloc::{GlobalAlloc, System, Layout, Void}; +use std::alloc::{GlobalAlloc, System, Layout, Opaque}; use std::ptr::NonNull; struct MyAllocator; unsafe impl GlobalAlloc for MyAllocator { - unsafe fn alloc(&self, layout: Layout) -> *mut Void { + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { System.alloc(layout) } - unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { System.dealloc(ptr, layout) } } diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 031babe5f6d..68a617e0ffe 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -76,36 +76,36 @@ pub const Heap: Global = Global; unsafe impl GlobalAlloc for Global { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Void { + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { #[cfg(not(stage0))] let ptr = __rust_alloc(layout.size(), layout.align()); #[cfg(stage0)] let ptr = __rust_alloc(layout.size(), layout.align(), &mut 0); - ptr as *mut Void + ptr as *mut Opaque } #[inline] - unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { __rust_dealloc(ptr as *mut u8, layout.size(), layout.align()) } #[inline] - unsafe fn realloc(&self, ptr: *mut Void, layout: Layout, new_size: usize) -> *mut Void { + unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { #[cfg(not(stage0))] let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), new_size); #[cfg(stage0)] let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), new_size, layout.align(), &mut 0); - ptr as *mut Void + ptr as *mut Opaque } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { #[cfg(not(stage0))] let ptr = __rust_alloc_zeroed(layout.size(), layout.align()); #[cfg(stage0)] let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), &mut 0); - ptr as *mut Void + ptr as *mut Opaque } #[inline] @@ -121,27 +121,27 @@ unsafe impl GlobalAlloc for Global { unsafe impl Alloc for Global { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) - -> Result, AllocErr> + -> Result, AllocErr> { NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) } @@ -178,7 +178,7 @@ pub(crate) unsafe fn box_free(ptr: *mut T) { // We do not allocate for Box when T is ZST, so deallocation is also not necessary. if size != 0 { let layout = Layout::from_size_align_unchecked(size, align); - Global.dealloc(ptr as *mut Void, layout); + Global.dealloc(ptr as *mut Opaque, layout); } } diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 88754ace3ce..225b055d8ee 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -518,7 +518,7 @@ impl Arc { if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); - Global.dealloc(self.ptr.as_void(), Layout::for_value(self.ptr.as_ref())) + Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())) } } @@ -637,7 +637,7 @@ impl ArcFromSlice for Arc<[T]> { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Global.dealloc(self.mem.as_void(), self.layout.clone()); + Global.dealloc(self.mem.as_opaque(), self.layout.clone()); } } } @@ -1156,7 +1156,7 @@ impl Drop for Weak { if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); unsafe { - Global.dealloc(self.ptr.as_void(), Layout::for_value(self.ptr.as_ref())) + Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())) } } } diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs index 64aa40ac166..d6346662314 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -249,7 +249,7 @@ impl Root { self.as_mut().as_leaf_mut().parent = ptr::null(); unsafe { - Global.dealloc(NonNull::from(top).as_void(), Layout::new::>()); + Global.dealloc(NonNull::from(top).as_opaque(), Layout::new::>()); } } } @@ -435,7 +435,7 @@ impl NodeRef { > { let node = self.node; let ret = self.ascend().ok(); - Global.dealloc(node.as_void(), Layout::new::>()); + Global.dealloc(node.as_opaque(), Layout::new::>()); ret } } @@ -456,7 +456,7 @@ impl NodeRef { > { let node = self.node; let ret = self.ascend().ok(); - Global.dealloc(node.as_void(), Layout::new::>()); + Global.dealloc(node.as_opaque(), Layout::new::>()); ret } } @@ -1239,12 +1239,12 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: } Global.dealloc( - right_node.node.as_void(), + right_node.node.as_opaque(), Layout::new::>(), ); } else { Global.dealloc( - right_node.node.as_void(), + right_node.node.as_opaque(), Layout::new::>(), ); } diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index cfb6504e743..faac38ca7ce 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -10,7 +10,7 @@ #![allow(deprecated)] -pub use alloc::{Layout, AllocErr, CannotReallocInPlace, Void}; +pub use alloc::{Layout, AllocErr, CannotReallocInPlace, Opaque}; use core::alloc::Alloc as CoreAlloc; use core::ptr::NonNull; @@ -54,7 +54,7 @@ unsafe impl Alloc for T where T: CoreAlloc { } unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - let ptr = NonNull::new_unchecked(ptr as *mut Void); + let ptr = NonNull::new_unchecked(ptr as *mut Opaque); CoreAlloc::dealloc(self, ptr, layout) } @@ -70,7 +70,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<*mut u8, AllocErr> { - let ptr = NonNull::new_unchecked(ptr as *mut Void); + let ptr = NonNull::new_unchecked(ptr as *mut Opaque); CoreAlloc::realloc(self, ptr, layout, new_layout.size()).map(|ptr| ptr.cast().as_ptr()) } @@ -87,7 +87,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result { - let ptr = NonNull::new_unchecked(ptr as *mut Void); + let ptr = NonNull::new_unchecked(ptr as *mut Opaque); CoreAlloc::realloc_excess(self, ptr, layout, new_layout.size()) .map(|e| Excess(e.0 .cast().as_ptr(), e.1)) } @@ -96,7 +96,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let ptr = NonNull::new_unchecked(ptr as *mut Void); + let ptr = NonNull::new_unchecked(ptr as *mut Opaque); CoreAlloc::grow_in_place(self, ptr, layout, new_layout.size()) } @@ -104,7 +104,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let ptr = NonNull::new_unchecked(ptr as *mut Void); + let ptr = NonNull::new_unchecked(ptr as *mut Opaque); CoreAlloc::shrink_in_place(self, ptr, layout, new_layout.size()) } } diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index d72301f5ad6..214cc7d7d0c 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -90,7 +90,7 @@ impl RawVec { // handles ZSTs and `cap = 0` alike let ptr = if alloc_size == 0 { - NonNull::::dangling().as_void() + NonNull::::dangling().as_opaque() } else { let align = mem::align_of::(); let result = if zeroed { @@ -310,7 +310,7 @@ impl RawVec { let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; alloc_guard(new_size).expect("capacity overflow"); - let ptr_res = self.a.realloc(NonNull::from(self.ptr).as_void(), + let ptr_res = self.a.realloc(NonNull::from(self.ptr).as_opaque(), cur, new_size); match ptr_res { @@ -369,7 +369,7 @@ impl RawVec { let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; alloc_guard(new_size).expect("capacity overflow"); - match self.a.grow_in_place(NonNull::from(self.ptr).as_void(), old_layout, new_size) { + match self.a.grow_in_place(NonNull::from(self.ptr).as_opaque(), old_layout, new_size) { Ok(_) => { // We can't directly divide `size`. self.cap = new_cap; @@ -426,7 +426,7 @@ impl RawVec { let res = match self.current_layout() { Some(layout) => { debug_assert!(new_layout.align() == layout.align()); - self.a.realloc(NonNull::from(self.ptr).as_void(), layout, new_layout.size()) + self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size()) } None => self.a.alloc(new_layout), }; @@ -535,7 +535,7 @@ impl RawVec { let res = match self.current_layout() { Some(layout) => { debug_assert!(new_layout.align() == layout.align()); - self.a.realloc(NonNull::from(self.ptr).as_void(), layout, new_layout.size()) + self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size()) } None => self.a.alloc(new_layout), }; @@ -601,7 +601,7 @@ impl RawVec { // FIXME: may crash and burn on over-reserve alloc_guard(new_layout.size()).expect("capacity overflow"); match self.a.grow_in_place( - NonNull::from(self.ptr).as_void(), old_layout, new_layout.size(), + NonNull::from(self.ptr).as_opaque(), old_layout, new_layout.size(), ) { Ok(_) => { self.cap = new_cap; @@ -662,7 +662,7 @@ impl RawVec { let new_size = elem_size * amount; let align = mem::align_of::(); let old_layout = Layout::from_size_align_unchecked(old_size, align); - match self.a.realloc(NonNull::from(self.ptr).as_void(), + match self.a.realloc(NonNull::from(self.ptr).as_opaque(), old_layout, new_size) { Ok(p) => self.ptr = p.cast().into(), @@ -698,7 +698,7 @@ impl RawVec { let elem_size = mem::size_of::(); if elem_size != 0 { if let Some(layout) = self.current_layout() { - self.a.dealloc(NonNull::from(self.ptr).as_void(), layout); + self.a.dealloc(NonNull::from(self.ptr).as_opaque(), layout); } } } @@ -734,7 +734,7 @@ fn alloc_guard(alloc_size: usize) -> Result<(), CollectionAllocErr> { #[cfg(test)] mod tests { use super::*; - use alloc::Void; + use alloc::Opaque; #[test] fn allocator_param() { @@ -754,7 +754,7 @@ mod tests { // before allocation attempts start failing. struct BoundedAlloc { fuel: usize } unsafe impl Alloc for BoundedAlloc { - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); if size > self.fuel { return Err(AllocErr); @@ -764,7 +764,7 @@ mod tests { err @ Err(_) => err, } } - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { Global.dealloc(ptr, layout) } } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 1c835fe50de..de0422d82bb 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -259,7 +259,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, NonNull}; use core::convert::From; -use alloc::{Global, Alloc, Layout, Void, box_free}; +use alloc::{Global, Alloc, Layout, Opaque, box_free}; use string::String; use vec::Vec; @@ -737,7 +737,7 @@ impl RcFromSlice for Rc<[T]> { // In the event of a panic, elements that have been written // into the new RcBox will be dropped, then the memory freed. struct Guard { - mem: NonNull, + mem: NonNull, elems: *mut T, layout: Layout, n_elems: usize, @@ -760,7 +760,7 @@ impl RcFromSlice for Rc<[T]> { let v_ptr = v as *const [T]; let ptr = Self::allocate_for_ptr(v_ptr); - let mem = ptr as *mut _ as *mut Void; + let mem = ptr as *mut _ as *mut Opaque; let layout = Layout::for_value(&*ptr); // Pointer to first element @@ -844,7 +844,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { self.dec_weak(); if self.weak() == 0 { - Global.dealloc(self.ptr.as_void(), Layout::for_value(self.ptr.as_ref())); + Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())); } } } @@ -1268,7 +1268,7 @@ impl Drop for Weak { // the weak count starts at 1, and will only go to zero if all // the strong pointers have disappeared. if self.weak() == 0 { - Global.dealloc(self.ptr.as_void(), Layout::for_value(self.ptr.as_ref())); + Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())); } } } diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 7fea6061169..fd8109e2a4a 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -41,7 +41,7 @@ const MIN_ALIGN: usize = 8; #[allow(dead_code)] const MIN_ALIGN: usize = 16; -use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout, Void}; +use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout, Opaque}; use core::ptr::NonNull; #[unstable(feature = "allocator_api", issue = "32838")] @@ -50,25 +50,25 @@ pub struct System; #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl Alloc for System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, - new_size: usize) -> Result, AllocErr> { + new_size: usize) -> Result, AllocErr> { NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } @@ -82,25 +82,25 @@ unsafe impl Alloc for System { #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl<'a> Alloc for &'a System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc(*self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc_zeroed(*self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { GlobalAlloc::dealloc(*self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, - new_size: usize) -> Result, AllocErr> { + new_size: usize) -> Result, AllocErr> { NonNull::new(GlobalAlloc::realloc(*self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } @@ -112,13 +112,13 @@ unsafe impl<'a> Alloc for &'a System { #[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))] mod realloc_fallback { - use core::alloc::{GlobalAlloc, Void, Layout}; + use core::alloc::{GlobalAlloc, Opaque, Layout}; use core::cmp; use core::ptr; impl super::System { - pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut Void, old_layout: Layout, - new_size: usize) -> *mut Void { + pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut Opaque, old_layout: Layout, + new_size: usize) -> *mut Opaque { // Docs for GlobalAlloc::realloc require this to be valid: let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); @@ -141,20 +141,21 @@ mod platform { use MIN_ALIGN; use System; - use core::alloc::{GlobalAlloc, Layout, Void}; + use core::alloc::{GlobalAlloc, Layout, Opaque}; #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Void { + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::malloc(layout.size()) as *mut Void + libc::malloc(layout.size()) as *mut Opaque } else { #[cfg(target_os = "macos")] { if layout.align() > (1 << 31) { - // FIXME: use Void::null_mut https://github.com/rust-lang/rust/issues/49659 - return 0 as *mut Void + // FIXME: use Opaque::null_mut + // https://github.com/rust-lang/rust/issues/49659 + return 0 as *mut Opaque } } aligned_malloc(&layout) @@ -162,9 +163,9 @@ mod platform { } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::calloc(layout.size(), 1) as *mut Void + libc::calloc(layout.size(), 1) as *mut Opaque } else { let ptr = self.alloc(layout.clone()); if !ptr.is_null() { @@ -175,24 +176,23 @@ mod platform { } #[inline] - unsafe fn dealloc(&self, ptr: *mut Void, _layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, _layout: Layout) { libc::free(ptr as *mut libc::c_void) } #[inline] - unsafe fn realloc(&self, ptr: *mut Void, old_layout: Layout, new_size: usize) -> *mut Void { - let align = old_layout.align(); - if align <= MIN_ALIGN && align <= new_size { - libc::realloc(ptr as *mut libc::c_void, new_size) as *mut Void + unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + if layout.align() <= MIN_ALIGN && layout.align() <= new_size { + libc::realloc(ptr as *mut libc::c_void, new_size) as *mut Opaque } else { - self.realloc_fallback(ptr, old_layout, new_size) + self.realloc_fallback(ptr, layout, new_size) } } } #[cfg(any(target_os = "android", target_os = "redox", target_os = "solaris"))] #[inline] - unsafe fn aligned_malloc(layout: &Layout) -> *mut Void { + unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque { // On android we currently target API level 9 which unfortunately // doesn't have the `posix_memalign` API used below. Instead we use // `memalign`, but this unfortunately has the property on some systems @@ -210,19 +210,19 @@ mod platform { // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ // /memory/aligned_memory.cc - libc::memalign(layout.align(), layout.size()) as *mut Void + libc::memalign(layout.align(), layout.size()) as *mut Opaque } #[cfg(not(any(target_os = "android", target_os = "redox", target_os = "solaris")))] #[inline] - unsafe fn aligned_malloc(layout: &Layout) -> *mut Void { + unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque { let mut out = ptr::null_mut(); let ret = libc::posix_memalign(&mut out, layout.align(), layout.size()); if ret != 0 { - // FIXME: use Void::null_mut https://github.com/rust-lang/rust/issues/49659 - 0 as *mut Void + // FIXME: use Opaque::null_mut https://github.com/rust-lang/rust/issues/49659 + 0 as *mut Opaque } else { - out as *mut Void + out as *mut Opaque } } } @@ -232,7 +232,7 @@ mod platform { mod platform { use MIN_ALIGN; use System; - use core::alloc::{GlobalAlloc, Void, Layout}; + use core::alloc::{GlobalAlloc, Opaque, Layout}; type LPVOID = *mut u8; type HANDLE = LPVOID; @@ -264,7 +264,7 @@ mod platform { } #[inline] - unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut Void { + unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut Opaque { let ptr = if layout.align() <= MIN_ALIGN { HeapAlloc(GetProcessHeap(), flags, layout.size()) } else { @@ -276,23 +276,23 @@ mod platform { align_ptr(ptr, layout.align()) } }; - ptr as *mut Void + ptr as *mut Opaque } #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Void { + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { allocate_with_flags(layout, 0) } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { allocate_with_flags(layout, HEAP_ZERO_MEMORY) } #[inline] - unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { if layout.align() <= MIN_ALIGN { let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID); debug_assert!(err != 0, "Failed to free heap memory: {}", @@ -306,12 +306,11 @@ mod platform { } #[inline] - unsafe fn realloc(&self, ptr: *mut Void, old_layout: Layout, new_size: usize) -> *mut Void { - let align = old_layout.align(); - if align <= MIN_ALIGN { - HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut Void + unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + if layout.align() <= MIN_ALIGN { + HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut Opaque } else { - self.realloc_fallback(ptr, old_layout, new_size) + self.realloc_fallback(ptr, layout, new_size) } } } @@ -338,7 +337,7 @@ mod platform { mod platform { extern crate dlmalloc; - use core::alloc::{GlobalAlloc, Layout, Void}; + use core::alloc::{GlobalAlloc, Layout, Opaque}; use System; // No need for synchronization here as wasm is currently single-threaded @@ -347,23 +346,23 @@ mod platform { #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Void { - DLMALLOC.malloc(layout.size(), layout.align()) as *mut Void + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + DLMALLOC.malloc(layout.size(), layout.align()) as *mut Opaque } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { - DLMALLOC.calloc(layout.size(), layout.align()) as *mut Void + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { + DLMALLOC.calloc(layout.size(), layout.align()) as *mut Opaque } #[inline] - unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { DLMALLOC.free(ptr as *mut u8, layout.size(), layout.align()) } #[inline] - unsafe fn realloc(&self, ptr: *mut Void, layout: Layout, new_size: usize) -> *mut Void { - DLMALLOC.realloc(ptr as *mut u8, layout.size(), layout.align(), new_size) as *mut Void + unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + DLMALLOC.realloc(ptr as *mut u8, layout.size(), layout.align(), new_size) as *mut Opaque } } } diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 97a49703baf..fdba91bec80 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -24,12 +24,12 @@ use ptr::{self, NonNull}; extern { /// An opaque, unsized type. Used for pointers to allocated memory. /// - /// This type can only be used behind a pointer like `*mut Void` or `ptr::NonNull`. + /// This type can only be used behind a pointer like `*mut Opaque` or `ptr::NonNull`. /// Such pointers are similar to C’s `void*` type. - pub type Void; + pub type Opaque; } -impl Void { +impl Opaque { /// Similar to `std::ptr::null`, which requires `T: Sized`. pub fn null() -> *const Self { 0 as _ @@ -44,7 +44,7 @@ impl Void { /// Represents the combination of a starting address and /// a total capacity of the returned block. #[derive(Debug)] -pub struct Excess(pub NonNull, pub usize); +pub struct Excess(pub NonNull, pub usize); fn size_align() -> (usize, usize) { (mem::size_of::(), mem::align_of::()) @@ -387,11 +387,11 @@ impl From for CollectionAllocErr { // FIXME: docs pub unsafe trait GlobalAlloc { - unsafe fn alloc(&self, layout: Layout) -> *mut Void; + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque; - unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout); + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout); - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { let size = layout.size(); let ptr = self.alloc(layout); if !ptr.is_null() { @@ -404,7 +404,7 @@ pub unsafe trait GlobalAlloc { /// /// `new_size`, when rounded up to the nearest multiple of `old_layout.align()`, /// must not overflow (i.e. the rounded value must be less than `usize::MAX`). - unsafe fn realloc(&self, ptr: *mut Void, old_layout: Layout, new_size: usize) -> *mut Void { + unsafe fn realloc(&self, ptr: *mut Opaque, old_layout: Layout, new_size: usize) -> *mut Opaque { let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); let new_ptr = self.alloc(new_layout); if !new_ptr.is_null() { @@ -554,7 +554,7 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; /// Deallocate the memory referenced by `ptr`. /// @@ -571,7 +571,7 @@ pub unsafe trait Alloc { /// * In addition to fitting the block of memory `layout`, the /// alignment of the `layout` must match the alignment used /// to allocate that block of memory. - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); /// Allocator-specific method for signaling an out-of-memory /// condition. @@ -689,9 +689,9 @@ pub unsafe trait Alloc { /// reallocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, - new_size: usize) -> Result, AllocErr> { + new_size: usize) -> Result, AllocErr> { let old_size = layout.size(); if new_size >= old_size { @@ -732,7 +732,7 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); let p = self.alloc(layout); if let Ok(p) = p { @@ -781,7 +781,7 @@ pub unsafe trait Alloc { /// reallocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. unsafe fn realloc_excess(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) -> Result { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); @@ -826,7 +826,7 @@ pub unsafe trait Alloc { /// `grow_in_place` failures without aborting, or to fall back on /// another reallocation method before resorting to an abort. unsafe fn grow_in_place(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. @@ -881,7 +881,7 @@ pub unsafe trait Alloc { /// `shrink_in_place` failures without aborting, or to fall back /// on another reallocation method before resorting to an abort. unsafe fn shrink_in_place(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. @@ -960,7 +960,7 @@ pub unsafe trait Alloc { { let k = Layout::new::(); if k.size() > 0 { - self.dealloc(ptr.as_void(), k); + self.dealloc(ptr.as_opaque(), k); } } @@ -1048,7 +1048,7 @@ pub unsafe trait Alloc { match (Layout::array::(n_old), Layout::array::(n_new)) { (Ok(ref k_old), Ok(ref k_new)) if k_old.size() > 0 && k_new.size() > 0 => { debug_assert!(k_old.align() == k_new.align()); - self.realloc(ptr.as_void(), k_old.clone(), k_new.size()).map(NonNull::cast) + self.realloc(ptr.as_opaque(), k_old.clone(), k_new.size()).map(NonNull::cast) } _ => { Err(AllocErr) @@ -1081,7 +1081,7 @@ pub unsafe trait Alloc { { match Layout::array::(n) { Ok(ref k) if k.size() > 0 => { - Ok(self.dealloc(ptr.as_void(), k.clone())) + Ok(self.dealloc(ptr.as_opaque(), k.clone())) } _ => { Err(AllocErr) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index f4e668328ce..4a7d7c410eb 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2751,9 +2751,9 @@ impl NonNull { } } - /// Cast to a `Void` pointer + /// Cast to an `Opaque` pointer #[unstable(feature = "allocator_api", issue = "32838")] - pub fn as_void(self) -> NonNull<::alloc::Void> { + pub fn as_opaque(self) -> NonNull<::alloc::Opaque> { unsafe { NonNull::new_unchecked(self.as_ptr() as _) } diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 58d4c7f289c..305502e7f06 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -221,7 +221,7 @@ impl<'a> AllocFnFactory<'a> { let ident = ident(); args.push(self.cx.arg(self.span, ident, self.ptr_u8())); let arg = self.cx.expr_ident(self.span, ident); - self.cx.expr_cast(self.span, arg, self.ptr_void()) + self.cx.expr_cast(self.span, arg, self.ptr_opaque()) } AllocatorTy::Usize => { @@ -276,13 +276,13 @@ impl<'a> AllocFnFactory<'a> { self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable) } - fn ptr_void(&self) -> P { - let void = self.cx.path(self.span, vec![ + fn ptr_opaque(&self) -> P { + let opaque = self.cx.path(self.span, vec![ self.core, Ident::from_str("alloc"), - Ident::from_str("Void"), + Ident::from_str("Opaque"), ]); - let ty_void = self.cx.ty_path(void); - self.cx.ty_ptr(self.span, ty_void, Mutability::Mutable) + let ty_opaque = self.cx.ty_path(opaque); + self.cx.ty_ptr(self.span, ty_opaque, Mutability::Mutable) } } diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 4e728df010a..ff578ec42d2 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -21,7 +21,7 @@ #[doc(hidden)] #[allow(unused_attributes)] pub mod __default_lib_allocator { - use super::{System, Layout, GlobalAlloc, Void}; + use super::{System, Layout, GlobalAlloc, Opaque}; // for symbol names src/librustc/middle/allocator.rs // for signatures src/librustc_allocator/lib.rs @@ -46,7 +46,7 @@ pub mod __default_lib_allocator { pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) { - System.dealloc(ptr as *mut Void, Layout::from_size_align_unchecked(size, align)) + System.dealloc(ptr as *mut Opaque, Layout::from_size_align_unchecked(size, align)) } #[no_mangle] @@ -56,7 +56,7 @@ pub mod __default_lib_allocator { align: usize, new_size: usize) -> *mut u8 { let old_layout = Layout::from_size_align_unchecked(old_size, align); - System.realloc(ptr as *mut Void, old_layout, new_size) as *mut u8 + System.realloc(ptr as *mut Opaque, old_layout, new_size) as *mut u8 } #[no_mangle] diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 38c99373788..93f059076d7 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -1183,7 +1183,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { debug_assert!(!oflo, "should be impossible"); unsafe { - Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_void(), + Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), Layout::from_size_align(size, align).unwrap()); // Remember how everything was allocated out of one buffer // during initialization? We only need one call to free here. diff --git a/src/test/run-make-fulldeps/std-core-cycle/bar.rs b/src/test/run-make-fulldeps/std-core-cycle/bar.rs index 20b87028fd1..62fd2ade1ca 100644 --- a/src/test/run-make-fulldeps/std-core-cycle/bar.rs +++ b/src/test/run-make-fulldeps/std-core-cycle/bar.rs @@ -16,11 +16,11 @@ use std::alloc::*; pub struct A; unsafe impl GlobalAlloc for A { - unsafe fn alloc(&self, _: Layout) -> *mut Void { + unsafe fn alloc(&self, _: Layout) -> *mut Opaque { loop {} } - unsafe fn dealloc(&self, _ptr: *mut Void, _: Layout) { + unsafe fn dealloc(&self, _ptr: *mut Opaque, _: Layout) { loop {} } } diff --git a/src/test/run-pass/allocator/auxiliary/custom.rs b/src/test/run-pass/allocator/auxiliary/custom.rs index 95096efc7ef..e6a2e22983b 100644 --- a/src/test/run-pass/allocator/auxiliary/custom.rs +++ b/src/test/run-pass/allocator/auxiliary/custom.rs @@ -13,18 +13,18 @@ #![feature(heap_api, allocator_api)] #![crate_type = "rlib"] -use std::heap::{GlobalAlloc, System, Layout, Void}; +use std::heap::{GlobalAlloc, System, Layout, Opaque}; use std::sync::atomic::{AtomicUsize, Ordering}; pub struct A(pub AtomicUsize); unsafe impl GlobalAlloc for A { - unsafe fn alloc(&self, layout: Layout) -> *mut Void { + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { self.0.fetch_add(1, Ordering::SeqCst); System.alloc(layout) } - unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { self.0.fetch_add(1, Ordering::SeqCst); System.dealloc(ptr, layout) } diff --git a/src/test/run-pass/allocator/custom.rs b/src/test/run-pass/allocator/custom.rs index f7b2fd73c87..415d39a593e 100644 --- a/src/test/run-pass/allocator/custom.rs +++ b/src/test/run-pass/allocator/custom.rs @@ -15,7 +15,7 @@ extern crate helper; -use std::alloc::{self, Global, Alloc, System, Layout, Void}; +use std::alloc::{self, Global, Alloc, System, Layout, Opaque}; use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; static HITS: AtomicUsize = ATOMIC_USIZE_INIT; @@ -23,12 +23,12 @@ static HITS: AtomicUsize = ATOMIC_USIZE_INIT; struct A; unsafe impl alloc::GlobalAlloc for A { - unsafe fn alloc(&self, layout: Layout) -> *mut Void { + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { HITS.fetch_add(1, Ordering::SeqCst); System.alloc(layout) } - unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { HITS.fetch_add(1, Ordering::SeqCst); System.dealloc(ptr, layout) } diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index 49ab0ee3310..38cc23c16a9 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -64,7 +64,7 @@ unsafe fn test_triangle() -> bool { println!("deallocate({:?}, {:?}", ptr, layout); } - Global.dealloc(NonNull::new_unchecked(ptr).as_void(), layout); + Global.dealloc(NonNull::new_unchecked(ptr).as_opaque(), layout); } unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 { @@ -72,7 +72,7 @@ unsafe fn test_triangle() -> bool { println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new); } - let ret = Global.realloc(NonNull::new_unchecked(ptr).as_void(), old.clone(), new.size()) + let ret = Global.realloc(NonNull::new_unchecked(ptr).as_opaque(), old.clone(), new.size()) .unwrap_or_else(|_| Global.oom()); if PRINT { -- cgit 1.4.1-3-g733a5 From c5ffdd787d134c06735a1dc4457515a63bbce5f5 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 11 Apr 2018 20:16:45 +0200 Subject: Initial docs for the GlobalAlloc trait --- src/libcore/alloc.rs | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index fdba91bec80..8f8849e32e6 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -385,10 +385,25 @@ impl From for CollectionAllocErr { } } -// FIXME: docs +/// A memory allocator that can be registered to be the one backing `std::alloc::Global` +/// though the `#[global_allocator]` attributes. pub unsafe trait GlobalAlloc { + /// Allocate memory as described by the given `layout`. + /// + /// Returns a pointer to newly-allocated memory, + /// or NULL to indicate allocation failure. + /// + /// # Safety + /// + /// **FIXME:** what are the exact requirements? unsafe fn alloc(&self, layout: Layout) -> *mut Opaque; + /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`. + /// + /// # Safety + /// + /// **FIXME:** what are the exact requirements? + /// In particular around layout *fit*. (See docs for the `Alloc` trait.) unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout); unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { @@ -400,24 +415,43 @@ pub unsafe trait GlobalAlloc { ptr } + /// Shink or grow a block of memory to the given `new_size`. + /// The block is described by the given `ptr` pointer and `layout`. + /// + /// Return a new pointer (which may or may not be the same as `ptr`), + /// or NULL to indicate reallocation failure. + /// + /// If reallocation is successful, the old `ptr` pointer is considered + /// to have been deallocated. + /// /// # Safety /// /// `new_size`, when rounded up to the nearest multiple of `old_layout.align()`, /// must not overflow (i.e. the rounded value must be less than `usize::MAX`). - unsafe fn realloc(&self, ptr: *mut Opaque, old_layout: Layout, new_size: usize) -> *mut Opaque { - let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); + /// + /// **FIXME:** what are the exact requirements? + /// In particular around layout *fit*. (See docs for the `Alloc` trait.) + unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let new_ptr = self.alloc(new_layout); if !new_ptr.is_null() { ptr::copy_nonoverlapping( ptr as *const u8, new_ptr as *mut u8, - cmp::min(old_layout.size(), new_size), + cmp::min(layout.size(), new_size), ); - self.dealloc(ptr, old_layout); + self.dealloc(ptr, layout); } new_ptr } + /// Aborts the thread or process, optionally performing + /// cleanup or logging diagnostic information before panicking or + /// aborting. + /// + /// `oom` is meant to be used by clients unable to cope with an + /// unsatisfied allocation request, and wish to abandon + /// computation rather than attempt to recover locally. fn oom(&self) -> ! { unsafe { ::intrinsics::abort() } } -- cgit 1.4.1-3-g733a5 From ca4e458089d0fecb8684de0437534d5f40b003bf Mon Sep 17 00:00:00 2001 From: Fabian Zaiser Date: Thu, 12 Apr 2018 23:12:11 +0200 Subject: Address more nits. --- src/libcore/num/mod.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 89276fcee80..d11ee7cf740 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1050,9 +1050,9 @@ $EndFeature, " concat!("Wrapping Euclidean division. Computes `self.div_euc(rhs)`, wrapping around at the boundary of the type. -The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where -`MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value -that is too large to represent in the type. In such a case, this function returns `MIN` itself. +Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value +for the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the +type. In this case, this method returns `MIN` itself. # Panics @@ -1106,9 +1106,8 @@ $EndFeature, " concat!("Wrapping Euclidean modulo. Computes `self.mod_euc(rhs)`, wrapping around at the boundary of the type. -Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y` -invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case, -this function returns `0`. +Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value +for the type). In this case, this method returns 0. # Panics @@ -1399,7 +1398,7 @@ $EndFeature, " concat!("Calculates the quotient of Euclidean division `self.div_euc(rhs)`. Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would -occur. If an overflow would occur then self is returned. +occur. If an overflow would occur then `self` is returned. # Panics -- cgit 1.4.1-3-g733a5 From 2e73e76e732310ebefa7bde145f1da4ee6110443 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 10 Apr 2018 11:25:23 -0700 Subject: core: Inline `From for CollectionAllocErr` This shows up in allocations of vectors and such, so no need for it to not be inlined! --- src/libcore/alloc.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libcore') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 8f8849e32e6..22c67436378 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -380,6 +380,7 @@ pub enum CollectionAllocErr { #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] impl From for CollectionAllocErr { + #[inline] fn from(AllocErr: AllocErr) -> Self { CollectionAllocErr::AllocErr } -- cgit 1.4.1-3-g733a5 From 68e555b7d03eefe4a226e6a0ae3fd13a118cb27e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 11 Apr 2018 10:47:16 -0700 Subject: core: Remove panics from some `Layout` methods `Layout` is often used at the core of allocation APIs and is as a result pretty sensitive to codegen in various circumstances. I was profiling `-C opt-level=z` with a wasm project recently and noticed that the `unwrap()` wasn't removed inside of `Layout`, causing the program to be much larger than it otherwise would be. If inlining were more aggressive LLVM would have figured out that the panic could be eliminated, but in general the methods here can't panic in the first place! As a result this commit makes the following tweaks: * Removes `unwrap()` and replaces it with `unsafe` in `Layout::new` and `Layout::for_value`. For posterity though a debug assertion was left behind. * Removes an `unwrap()` in favor of `?` in the `repeat` method. The comment indicating that the function call couldn't panic wasn't quite right in that if `alloc_size` becomes too large and if `align` is high enough it could indeed cause a panic. This'll hopefully mean that panics never get introduced into code in the first place, ensuring that `opt-level=z` is closer to `opt-level=s` in this regard. --- src/libcore/alloc.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 8f8849e32e6..e4148f99803 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -145,7 +145,14 @@ impl Layout { /// Constructs a `Layout` suitable for holding a value of type `T`. pub fn new() -> Self { let (size, align) = size_align::(); - Layout::from_size_align(size, align).unwrap() + // Note that the align is guaranteed by rustc to be a power of two and + // the size+align combo is guaranteed to fit in our address space. As a + // result use the unchecked constructor here to avoid inserting code + // that panics if it isn't optimized well enough. + debug_assert!(Layout::from_size_align(size, align).is_ok()); + unsafe { + Layout::from_size_align_unchecked(size, align) + } } /// Produces layout describing a record that could be used to @@ -153,7 +160,11 @@ impl Layout { /// or other unsized type like a slice). pub fn for_value(t: &T) -> Self { let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); - Layout::from_size_align(size, align).unwrap() + // See rationale in `new` for why this us using an unsafe variant below + debug_assert!(Layout::from_size_align(size, align).is_ok()); + unsafe { + Layout::from_size_align_unchecked(size, align) + } } /// Creates a layout describing the record that can hold a value @@ -234,12 +245,7 @@ impl Layout { .ok_or(LayoutErr { private: () })?; let alloc_size = padded_size.checked_mul(n) .ok_or(LayoutErr { private: () })?; - - // We can assume that `self.align` is a power-of-two. - // Furthermore, `alloc_size` has already been rounded up - // to a multiple of `self.align`; therefore, the call to - // `Layout::from_size_align` below should never panic. - Ok((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) + Ok((Layout::from_size_align(alloc_size, self.align)?, padded_size)) } /// Creates a layout describing the record for `self` followed by -- cgit 1.4.1-3-g733a5 From c3a5d6b130e27d7d7587f56581247d5b08c38594 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 29 Mar 2018 14:59:13 -0700 Subject: std: Minimize size of panicking on wasm This commit applies a few code size optimizations for the wasm target to the standard library, namely around panics. We notably know that in most configurations it's impossible for us to print anything in wasm32-unknown-unknown so we can skip larger portions of panicking that are otherwise simply informative. This allows us to get quite a nice size reduction. Finally we can also tweak where the allocation happens for the `Box` that we panic with. By only allocating once unwinding starts we can reduce the size of a panicking wasm module from 44k to 350 bytes. --- src/ci/docker/wasm32-unknown/Dockerfile | 6 ++ src/libcore/panic.rs | 10 ++++ src/libpanic_abort/lib.rs | 2 +- src/libpanic_unwind/lib.rs | 12 ++-- src/libstd/lib.rs | 1 + src/libstd/panicking.rs | 88 ++++++++++++++++++++++------- src/libstd/sys/cloudabi/stdio.rs | 4 ++ src/libstd/sys/redox/stdio.rs | 4 ++ src/libstd/sys/unix/stdio.rs | 4 ++ src/libstd/sys/wasm/rwlock.rs | 4 +- src/libstd/sys/wasm/stdio.rs | 4 ++ src/libstd/sys/windows/stdio.rs | 4 ++ src/libstd/sys_common/backtrace.rs | 13 ++--- src/libstd/sys_common/mod.rs | 14 +++-- src/libstd/sys_common/thread_local.rs | 4 +- src/libstd/sys_common/util.rs | 5 +- src/libstd/thread/local.rs | 41 +++++++++++++- src/libstd/thread/mod.rs | 3 + src/test/run-make/wasm-panic-small/Makefile | 11 ++++ src/test/run-make/wasm-panic-small/foo.rs | 16 ++++++ 20 files changed, 205 insertions(+), 45 deletions(-) create mode 100644 src/test/run-make/wasm-panic-small/Makefile create mode 100644 src/test/run-make/wasm-panic-small/foo.rs (limited to 'src/libcore') diff --git a/src/ci/docker/wasm32-unknown/Dockerfile b/src/ci/docker/wasm32-unknown/Dockerfile index 853923ad947..56eda548071 100644 --- a/src/ci/docker/wasm32-unknown/Dockerfile +++ b/src/ci/docker/wasm32-unknown/Dockerfile @@ -25,6 +25,12 @@ ENV RUST_CONFIGURE_ARGS \ --set build.nodejs=/node-v9.2.0-linux-x64/bin/node \ --set rust.lld +# Some run-make tests have assertions about code size, and enabling debug +# assertions in libstd causes the binary to be much bigger than it would +# otherwise normally be. We already test libstd with debug assertions in lots of +# other contexts as well +ENV NO_DEBUG_ASSERTIONS=1 + ENV SCRIPT python2.7 /checkout/x.py test --target $TARGETS \ src/test/run-make \ src/test/ui \ diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 1720c9d8c60..37c79f2fafe 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -251,3 +251,13 @@ impl<'a> fmt::Display for Location<'a> { write!(formatter, "{}:{}:{}", self.file, self.line, self.col) } } + +/// An internal trait used by libstd to pass data from libstd to `panic_unwind` +/// and other panic runtimes. Not intended to be stabilized any time soon, do +/// not use. +#[unstable(feature = "std_internals", issue = "0")] +#[doc(hidden)] +pub unsafe trait BoxMeUp { + fn box_me_up(&mut self) -> *mut (Any + Send); + fn get(&self) -> &(Any + Send); +} diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index 43c5bbbc618..392bf17968f 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -52,7 +52,7 @@ pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8), // now hopefully. #[no_mangle] #[rustc_std_internal_symbol] -pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 { +pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 { abort(); #[cfg(any(unix, target_os = "cloudabi"))] diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 9321d6917d1..6c52c0fa10c 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -29,6 +29,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] +#![feature(allocator_api)] #![feature(alloc)] #![feature(core_intrinsics)] #![feature(lang_items)] @@ -36,6 +37,7 @@ #![feature(panic_unwind)] #![feature(raw)] #![feature(staged_api)] +#![feature(std_internals)] #![feature(unwind_attributes)] #![cfg_attr(target_env = "msvc", feature(raw))] @@ -47,9 +49,11 @@ extern crate libc; #[cfg(not(any(target_env = "msvc", all(windows, target_arch = "x86_64", target_env = "gnu"))))] extern crate unwind; +use alloc::boxed::Box; use core::intrinsics; use core::mem; use core::raw; +use core::panic::BoxMeUp; // Rust runtime's startup objects depend on these symbols, so make them public. #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] @@ -112,9 +116,7 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8), // implementation. #[no_mangle] #[unwind(allowed)] -pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 { - imp::panic(mem::transmute(raw::TraitObject { - data: data as *mut (), - vtable: vtable as *mut (), - })) +pub unsafe extern "C" fn __rust_start_panic(payload: usize) -> u32 { + let payload = payload as *mut &mut BoxMeUp; + imp::panic(Box::from_raw((*payload).box_me_up())) } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a34fcb5a7f9..dd96c57538c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -292,6 +292,7 @@ #![feature(rand)] #![feature(raw)] #![feature(rustc_attrs)] +#![feature(std_internals)] #![feature(stdsimd)] #![feature(shrink_to)] #![feature(slice_bytes)] diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index fba3269204e..715fd45e490 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -17,6 +17,8 @@ //! * Executing a panic up to doing the actual implementation //! * Shims around "try" +use core::panic::BoxMeUp; + use io::prelude::*; use any::Any; @@ -27,7 +29,7 @@ use intrinsics; use mem; use ptr; use raw; -use sys::stdio::Stderr; +use sys::stdio::{Stderr, stderr_prints_nothing}; use sys_common::rwlock::RWLock; use sys_common::thread_info; use sys_common::util; @@ -56,7 +58,7 @@ extern { data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32; #[unwind(allowed)] - fn __rust_start_panic(data: usize, vtable: usize) -> u32; + fn __rust_start_panic(payload: usize) -> u32; } #[derive(Copy, Clone)] @@ -163,6 +165,12 @@ fn default_hook(info: &PanicInfo) { #[cfg(feature = "backtrace")] use sys_common::backtrace; + // Some platforms know that printing to stderr won't ever actually print + // anything, and if that's the case we can skip everything below. + if stderr_prints_nothing() { + return + } + // If this is a double panic, make sure that we print a backtrace // for this panic. Otherwise only print it if logging is enabled. #[cfg(feature = "backtrace")] @@ -212,15 +220,15 @@ fn default_hook(info: &PanicInfo) { let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take()); match (prev, err.as_mut()) { - (Some(mut stderr), _) => { - write(&mut *stderr); - let mut s = Some(stderr); - LOCAL_STDERR.with(|slot| { - *slot.borrow_mut() = s.take(); - }); - } - (None, Some(ref mut err)) => { write(err) } - _ => {} + (Some(mut stderr), _) => { + write(&mut *stderr); + let mut s = Some(stderr); + LOCAL_STDERR.with(|slot| { + *slot.borrow_mut() = s.take(); + }); + } + (None, Some(ref mut err)) => { write(err) } + _ => {} } } @@ -344,7 +352,7 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, let mut s = String::new(); let _ = s.write_fmt(*msg); - rust_panic_with_hook(Box::new(s), Some(msg), file_line_col) + rust_panic_with_hook(&mut PanicPayload::new(s), Some(msg), file_line_col) } /// This is the entry point of panicking for panic!() and assert!(). @@ -360,7 +368,34 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 // be performed in the parent of this thread instead of the thread that's // panicking. - rust_panic_with_hook(Box::new(msg), None, file_line_col) + rust_panic_with_hook(&mut PanicPayload::new(msg), None, file_line_col) +} + +struct PanicPayload { + inner: Option, +} + +impl PanicPayload { + fn new(inner: A) -> PanicPayload { + PanicPayload { inner: Some(inner) } + } +} + +unsafe impl BoxMeUp for PanicPayload { + fn box_me_up(&mut self) -> *mut (Any + Send) { + let data = match self.inner.take() { + Some(a) => Box::new(a) as Box, + None => Box::new(()), + }; + Box::into_raw(data) + } + + fn get(&self) -> &(Any + Send) { + match self.inner { + Some(ref a) => a, + None => &(), + } + } } /// Executes the primary logic for a panic, including checking for recursive @@ -369,9 +404,7 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 /// This is the entry point or panics from libcore, formatted panics, and /// `Box` panics. Here we'll verify that we're not panicking recursively, /// run panic hooks, and then delegate to the actual implementation of panics. -#[inline(never)] -#[cold] -fn rust_panic_with_hook(payload: Box, +fn rust_panic_with_hook(payload: &mut BoxMeUp, message: Option<&fmt::Arguments>, file_line_col: &(&'static str, u32, u32)) -> ! { let (file, line, col) = *file_line_col; @@ -391,7 +424,7 @@ fn rust_panic_with_hook(payload: Box, unsafe { let info = PanicInfo::internal_constructor( - &*payload, + payload.get(), message, Location::internal_constructor(file, line, col), ); @@ -419,16 +452,29 @@ fn rust_panic_with_hook(payload: Box, /// Shim around rust_panic. Called by resume_unwind. pub fn update_count_then_panic(msg: Box) -> ! { update_panic_count(1); - rust_panic(msg) + + struct RewrapBox(Box); + + unsafe impl BoxMeUp for RewrapBox { + fn box_me_up(&mut self) -> *mut (Any + Send) { + Box::into_raw(mem::replace(&mut self.0, Box::new(()))) + } + + fn get(&self) -> &(Any + Send) { + &*self.0 + } + } + + rust_panic(&mut RewrapBox(msg)) } /// A private no-mangle function on which to slap yer breakpoints. #[no_mangle] #[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints -pub fn rust_panic(msg: Box) -> ! { +pub fn rust_panic(mut msg: &mut BoxMeUp) -> ! { let code = unsafe { - let obj = mem::transmute::<_, raw::TraitObject>(msg); - __rust_start_panic(obj.data as usize, obj.vtable as usize) + let obj = &mut msg as *mut &mut BoxMeUp; + __rust_start_panic(obj as usize) }; rtabort!("failed to initiate panic, error {}", code) } diff --git a/src/libstd/sys/cloudabi/stdio.rs b/src/libstd/sys/cloudabi/stdio.rs index 9519a926471..1d7344f921c 100644 --- a/src/libstd/sys/cloudabi/stdio.rs +++ b/src/libstd/sys/cloudabi/stdio.rs @@ -77,3 +77,7 @@ pub fn is_ebadf(err: &io::Error) -> bool { } pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; + +pub fn stderr_prints_nothing() -> bool { + false +} diff --git a/src/libstd/sys/redox/stdio.rs b/src/libstd/sys/redox/stdio.rs index 3abb094ac34..7a4d11b0ecb 100644 --- a/src/libstd/sys/redox/stdio.rs +++ b/src/libstd/sys/redox/stdio.rs @@ -75,3 +75,7 @@ pub fn is_ebadf(err: &io::Error) -> bool { } pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; + +pub fn stderr_prints_nothing() -> bool { + false +} diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs index e9b3d4affc7..87ba2aef4f1 100644 --- a/src/libstd/sys/unix/stdio.rs +++ b/src/libstd/sys/unix/stdio.rs @@ -75,3 +75,7 @@ pub fn is_ebadf(err: &io::Error) -> bool { } pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; + +pub fn stderr_prints_nothing() -> bool { + false +} diff --git a/src/libstd/sys/wasm/rwlock.rs b/src/libstd/sys/wasm/rwlock.rs index 8b06f541674..6516010af47 100644 --- a/src/libstd/sys/wasm/rwlock.rs +++ b/src/libstd/sys/wasm/rwlock.rs @@ -30,7 +30,7 @@ impl RWLock { if *mode >= 0 { *mode += 1; } else { - panic!("rwlock locked for writing"); + rtabort!("rwlock locked for writing"); } } @@ -51,7 +51,7 @@ impl RWLock { if *mode == 0 { *mode = -1; } else { - panic!("rwlock locked for reading") + rtabort!("rwlock locked for reading") } } diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/wasm/stdio.rs index beb19c0ed2c..023f29576a2 100644 --- a/src/libstd/sys/wasm/stdio.rs +++ b/src/libstd/sys/wasm/stdio.rs @@ -69,3 +69,7 @@ pub const STDIN_BUF_SIZE: usize = 0; pub fn is_ebadf(_err: &io::Error) -> bool { true } + +pub fn stderr_prints_nothing() -> bool { + !cfg!(feature = "wasm_syscall") +} diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index b43df20bddd..81b89da21d3 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -227,3 +227,7 @@ pub fn is_ebadf(err: &io::Error) -> bool { // idea is that on windows we use a slightly smaller buffer that's // been seen to be acceptable. pub const STDIN_BUF_SIZE: usize = 8 * 1024; + +pub fn stderr_prints_nothing() -> bool { + false +} diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 1955f3ec9a2..20109d2d0d5 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -139,10 +139,10 @@ pub fn __rust_begin_short_backtrace(f: F) -> T /// Controls how the backtrace should be formatted. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum PrintFormat { - /// Show all the frames with absolute path for files. - Full = 2, /// Show only relevant data from the backtrace. - Short = 3, + Short = 2, + /// Show all the frames with absolute path for files. + Full = 3, } // For now logging is turned off by default, and this function checks to see @@ -150,11 +150,10 @@ pub enum PrintFormat { pub fn log_enabled() -> Option { static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0); match ENABLED.load(Ordering::SeqCst) { - 0 => {}, + 0 => {} 1 => return None, - 2 => return Some(PrintFormat::Full), - 3 => return Some(PrintFormat::Short), - _ => unreachable!(), + 2 => return Some(PrintFormat::Short), + _ => return Some(PrintFormat::Full), } let val = match env::var_os("RUST_BACKTRACE") { diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index 27504d374dd..d0c4d6a7737 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -28,6 +28,16 @@ use sync::Once; use sys; +macro_rules! rtabort { + ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*))) +} + +macro_rules! rtassert { + ($e:expr) => (if !$e { + rtabort!(concat!("assertion failed: ", stringify!($e))); + }) +} + pub mod at_exit_imp; #[cfg(feature = "backtrace")] pub mod backtrace; @@ -101,10 +111,6 @@ pub fn at_exit(f: F) -> Result<(), ()> { if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())} } -macro_rules! rtabort { - ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*))) -} - /// One-time runtime cleanup. pub fn cleanup() { static CLEANUP: Once = Once::new(); diff --git a/src/libstd/sys_common/thread_local.rs b/src/libstd/sys_common/thread_local.rs index a4aa3d96d25..d0d6224de0a 100644 --- a/src/libstd/sys_common/thread_local.rs +++ b/src/libstd/sys_common/thread_local.rs @@ -169,7 +169,7 @@ impl StaticKey { self.key.store(key, Ordering::SeqCst); } INIT_LOCK.unlock(); - assert!(key != 0); + rtassert!(key != 0); return key } @@ -190,7 +190,7 @@ impl StaticKey { imp::destroy(key1); key2 }; - assert!(key != 0); + rtassert!(key != 0); match self.key.compare_and_swap(0, key as usize, Ordering::SeqCst) { // The CAS succeeded, so we've created the actual key 0 => key as usize, diff --git a/src/libstd/sys_common/util.rs b/src/libstd/sys_common/util.rs index a391c7cc6ef..a373e980b97 100644 --- a/src/libstd/sys_common/util.rs +++ b/src/libstd/sys_common/util.rs @@ -10,10 +10,13 @@ use fmt; use io::prelude::*; -use sys::stdio::Stderr; +use sys::stdio::{Stderr, stderr_prints_nothing}; use thread; pub fn dumb_print(args: fmt::Arguments) { + if stderr_prints_nothing() { + return + } let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args)); } diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 99479bc56ef..40d3280baa6 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -172,12 +172,16 @@ macro_rules! __thread_local_inner { &'static $crate::cell::UnsafeCell< $crate::option::Option<$t>>> { + #[cfg(target_arch = "wasm32")] + static __KEY: $crate::thread::__StaticLocalKeyInner<$t> = + $crate::thread::__StaticLocalKeyInner::new(); + #[thread_local] - #[cfg(target_thread_local)] + #[cfg(all(target_thread_local, not(target_arch = "wasm32")))] static __KEY: $crate::thread::__FastLocalKeyInner<$t> = $crate::thread::__FastLocalKeyInner::new(); - #[cfg(not(target_thread_local))] + #[cfg(all(not(target_thread_local), not(target_arch = "wasm32")))] static __KEY: $crate::thread::__OsLocalKeyInner<$t> = $crate::thread::__OsLocalKeyInner::new(); @@ -295,6 +299,39 @@ impl LocalKey { } } +/// On some platforms like wasm32 there's no threads, so no need to generate +/// thread locals and we can instead just use plain statics! +#[doc(hidden)] +#[cfg(target_arch = "wasm32")] +pub mod statik { + use cell::UnsafeCell; + use fmt; + + pub struct Key { + inner: UnsafeCell>, + } + + unsafe impl ::marker::Sync for Key { } + + impl fmt::Debug for Key { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Key { .. }") + } + } + + impl Key { + pub const fn new() -> Key { + Key { + inner: UnsafeCell::new(None), + } + } + + pub unsafe fn get(&self) -> Option<&'static UnsafeCell>> { + Some(&*(&self.inner as *const _)) + } + } +} + #[doc(hidden)] #[cfg(target_thread_local)] pub mod fast { diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 71aee673cfe..1b976b79b4c 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -202,6 +202,9 @@ pub use self::local::{LocalKey, AccessError}; // where fast TLS was not available; end-user code is compiled with fast TLS // where available, but both are needed. +#[unstable(feature = "libstd_thread_internals", issue = "0")] +#[cfg(target_arch = "wasm32")] +#[doc(hidden)] pub use self::local::statik::Key as __StaticLocalKeyInner; #[unstable(feature = "libstd_thread_internals", issue = "0")] #[cfg(target_thread_local)] #[doc(hidden)] pub use self::local::fast::Key as __FastLocalKeyInner; diff --git a/src/test/run-make/wasm-panic-small/Makefile b/src/test/run-make/wasm-panic-small/Makefile new file mode 100644 index 00000000000..a11fba23595 --- /dev/null +++ b/src/test/run-make/wasm-panic-small/Makefile @@ -0,0 +1,11 @@ +-include ../../run-make-fulldeps/tools.mk + +ifeq ($(TARGET),wasm32-unknown-unknown) +all: + $(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown + wc -c < $(TMPDIR)/foo.wasm + [ "`wc -c < $(TMPDIR)/foo.wasm`" -lt "1024" ] +else +all: +endif + diff --git a/src/test/run-make/wasm-panic-small/foo.rs b/src/test/run-make/wasm-panic-small/foo.rs new file mode 100644 index 00000000000..9654d5f7c09 --- /dev/null +++ b/src/test/run-make/wasm-panic-small/foo.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "cdylib"] + +#[no_mangle] +pub fn foo() { + panic!("test"); +} -- cgit 1.4.1-3-g733a5 From 2bb5b5c07c5cd015c567ce86eae07e92db07bb8a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 6 Apr 2018 14:20:22 -0700 Subject: core: Remove an implicit panic from Formatter::pad The expression `&s[..i]` in general can panic if `i` is out of bounds or not on a character boundary for a string, and this caused the codegen for `Formatter::pad` to be a bit larger than it otherwise needed to be. This commit replaces this with `s.get(..i).unwrap_or(&s)` which while having different behavior if `i` is out of bounds has a much smaller code footprint and otherwise avoids the need for `unsafe` code. --- src/libcore/fmt/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index d55219d7226..277bef2bf66 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1212,7 +1212,11 @@ impl<'a> Formatter<'a> { // truncation. However other flags like `fill`, `width` and `align` // must act as always. if let Some((i, _)) = s.char_indices().skip(max).next() { - &s[..i] + // LLVM here can't prove that `..i` won't panic `&s[..i]`, but + // we know that it can't panic. Use `get` + `unwrap_or` to avoid + // `unsafe` and otherwise don't emit any panic-related code + // here. + s.get(..i).unwrap_or(&s) } else { &s } -- cgit 1.4.1-3-g733a5 From 46d16b66e0b017430eb50b247926ea447c60ef07 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 6 Apr 2018 14:22:13 -0700 Subject: std: Avoid allocating panic message unless needed This commit removes allocation of the panic message in instances like `panic!("foo: {}", "bar")` if we don't actually end up needing the message. We don't need it in the case of wasm32 right now, and in general it's not needed for panic=abort instances that use the default panic hook. For now this commit only solves the wasm use case where with LTO the allocation is entirely removed, but the panic=abort use case can be implemented at a later date if needed. --- src/libcore/panic.rs | 14 +++- src/libstd/panicking.rs | 118 +++++++++++++++++----------- src/test/run-make/wasm-panic-small/Makefile | 8 +- src/test/run-make/wasm-panic-small/foo.rs | 13 +++ 4 files changed, 103 insertions(+), 50 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 37c79f2fafe..27ec4aaac75 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -49,11 +49,17 @@ impl<'a> PanicInfo<'a> { and related macros", issue = "0")] #[doc(hidden)] - pub fn internal_constructor(payload: &'a (Any + Send), - message: Option<&'a fmt::Arguments<'a>>, + #[inline] + pub fn internal_constructor(message: Option<&'a fmt::Arguments<'a>>, location: Location<'a>) -> Self { - PanicInfo { payload, location, message } + PanicInfo { payload: &(), location, message } + } + + #[doc(hidden)] + #[inline] + pub fn set_payload(&mut self, info: &'a (Any + Send)) { + self.payload = info; } /// Returns the payload associated with the panic. @@ -259,5 +265,5 @@ impl<'a> fmt::Display for Location<'a> { #[doc(hidden)] pub unsafe trait BoxMeUp { fn box_me_up(&mut self) -> *mut (Any + Send); - fn get(&self) -> &(Any + Send); + fn get(&mut self) -> &(Any + Send); } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 715fd45e490..24eae6a4c82 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -165,12 +165,6 @@ fn default_hook(info: &PanicInfo) { #[cfg(feature = "backtrace")] use sys_common::backtrace; - // Some platforms know that printing to stderr won't ever actually print - // anything, and if that's the case we can skip everything below. - if stderr_prints_nothing() { - return - } - // If this is a double panic, make sure that we print a backtrace // for this panic. Otherwise only print it if logging is enabled. #[cfg(feature = "backtrace")] @@ -185,9 +179,6 @@ fn default_hook(info: &PanicInfo) { }; let location = info.location().unwrap(); // The current implementation always returns Some - let file = location.file(); - let line = location.line(); - let col = location.column(); let msg = match info.payload().downcast_ref::<&'static str>() { Some(s) => *s, @@ -201,8 +192,8 @@ fn default_hook(info: &PanicInfo) { let name = thread.as_ref().and_then(|t| t.name()).unwrap_or(""); let write = |err: &mut ::io::Write| { - let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}:{}", - name, msg, file, line, col); + let _ = writeln!(err, "thread '{}' panicked at '{}', {}", + name, msg, location); #[cfg(feature = "backtrace")] { @@ -350,9 +341,38 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, // panic + OOM properly anyway (see comment in begin_panic // below). - let mut s = String::new(); - let _ = s.write_fmt(*msg); - rust_panic_with_hook(&mut PanicPayload::new(s), Some(msg), file_line_col) + rust_panic_with_hook(&mut PanicPayload::new(msg), Some(msg), file_line_col); + + struct PanicPayload<'a> { + inner: &'a fmt::Arguments<'a>, + string: Option, + } + + impl<'a> PanicPayload<'a> { + fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> { + PanicPayload { inner, string: None } + } + + fn fill(&mut self) -> &mut String { + let inner = self.inner; + self.string.get_or_insert_with(|| { + let mut s = String::new(); + drop(s.write_fmt(*inner)); + s + }) + } + } + + unsafe impl<'a> BoxMeUp for PanicPayload<'a> { + fn box_me_up(&mut self) -> *mut (Any + Send) { + let contents = mem::replace(self.fill(), String::new()); + Box::into_raw(Box::new(contents)) + } + + fn get(&mut self) -> &(Any + Send) { + self.fill() + } + } } /// This is the entry point of panicking for panic!() and assert!(). @@ -368,42 +388,41 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 // be performed in the parent of this thread instead of the thread that's // panicking. - rust_panic_with_hook(&mut PanicPayload::new(msg), None, file_line_col) -} - -struct PanicPayload { - inner: Option, -} + rust_panic_with_hook(&mut PanicPayload::new(msg), None, file_line_col); -impl PanicPayload { - fn new(inner: A) -> PanicPayload { - PanicPayload { inner: Some(inner) } + struct PanicPayload { + inner: Option, } -} -unsafe impl BoxMeUp for PanicPayload { - fn box_me_up(&mut self) -> *mut (Any + Send) { - let data = match self.inner.take() { - Some(a) => Box::new(a) as Box, - None => Box::new(()), - }; - Box::into_raw(data) + impl PanicPayload { + fn new(inner: A) -> PanicPayload { + PanicPayload { inner: Some(inner) } + } } - fn get(&self) -> &(Any + Send) { - match self.inner { - Some(ref a) => a, - None => &(), + unsafe impl BoxMeUp for PanicPayload { + fn box_me_up(&mut self) -> *mut (Any + Send) { + let data = match self.inner.take() { + Some(a) => Box::new(a) as Box, + None => Box::new(()), + }; + Box::into_raw(data) + } + + fn get(&mut self) -> &(Any + Send) { + match self.inner { + Some(ref a) => a, + None => &(), + } } } } -/// Executes the primary logic for a panic, including checking for recursive -/// panics and panic hooks. +/// Central point for dispatching panics. /// -/// This is the entry point or panics from libcore, formatted panics, and -/// `Box` panics. Here we'll verify that we're not panicking recursively, -/// run panic hooks, and then delegate to the actual implementation of panics. +/// Executes the primary logic for a panic, including checking for recursive +/// panics, panic hooks, and finally dispatching to the panic runtime to either +/// abort or unwind. fn rust_panic_with_hook(payload: &mut BoxMeUp, message: Option<&fmt::Arguments>, file_line_col: &(&'static str, u32, u32)) -> ! { @@ -423,15 +442,24 @@ fn rust_panic_with_hook(payload: &mut BoxMeUp, } unsafe { - let info = PanicInfo::internal_constructor( - payload.get(), + let mut info = PanicInfo::internal_constructor( message, Location::internal_constructor(file, line, col), ); HOOK_LOCK.read(); match HOOK { - Hook::Default => default_hook(&info), - Hook::Custom(ptr) => (*ptr)(&info), + // Some platforms know that printing to stderr won't ever actually + // print anything, and if that's the case we can skip the default + // hook. + Hook::Default if stderr_prints_nothing() => {} + Hook::Default => { + info.set_payload(payload.get()); + default_hook(&info); + } + Hook::Custom(ptr) => { + info.set_payload(payload.get()); + (*ptr)(&info); + } } HOOK_LOCK.read_unlock(); } @@ -460,7 +488,7 @@ pub fn update_count_then_panic(msg: Box) -> ! { Box::into_raw(mem::replace(&mut self.0, Box::new(()))) } - fn get(&self) -> &(Any + Send) { + fn get(&mut self) -> &(Any + Send) { &*self.0 } } diff --git a/src/test/run-make/wasm-panic-small/Makefile b/src/test/run-make/wasm-panic-small/Makefile index a11fba23595..330ae300c44 100644 --- a/src/test/run-make/wasm-panic-small/Makefile +++ b/src/test/run-make/wasm-panic-small/Makefile @@ -2,9 +2,15 @@ ifeq ($(TARGET),wasm32-unknown-unknown) all: - $(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown + $(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown --cfg a wc -c < $(TMPDIR)/foo.wasm [ "`wc -c < $(TMPDIR)/foo.wasm`" -lt "1024" ] + $(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown --cfg b + wc -c < $(TMPDIR)/foo.wasm + [ "`wc -c < $(TMPDIR)/foo.wasm`" -lt "5120" ] + $(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown --cfg c + wc -c < $(TMPDIR)/foo.wasm + [ "`wc -c < $(TMPDIR)/foo.wasm`" -lt "5120" ] else all: endif diff --git a/src/test/run-make/wasm-panic-small/foo.rs b/src/test/run-make/wasm-panic-small/foo.rs index 9654d5f7c09..1ea724ca94d 100644 --- a/src/test/run-make/wasm-panic-small/foo.rs +++ b/src/test/run-make/wasm-panic-small/foo.rs @@ -11,6 +11,19 @@ #![crate_type = "cdylib"] #[no_mangle] +#[cfg(a)] pub fn foo() { panic!("test"); } + +#[no_mangle] +#[cfg(b)] +pub fn foo() { + panic!("{}", 1); +} + +#[no_mangle] +#[cfg(c)] +pub fn foo() { + panic!("{}", "a"); +} -- cgit 1.4.1-3-g733a5 From b744e3d7f516f1c679a4f6315110e856b9731de4 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 12 Apr 2018 22:07:53 +0200 Subject: [doc] note the special type inference handling for shifts --- src/libcore/ops/bit.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/ops/bit.rs b/src/libcore/ops/bit.rs index a0ecd6cf75c..ec1e65be774 100644 --- a/src/libcore/ops/bit.rs +++ b/src/libcore/ops/bit.rs @@ -315,7 +315,12 @@ macro_rules! bitxor_impl { bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The left shift operator `<<`. +/// The left shift operator `<<`. Note that because this trait is implemented +/// for all integer types with multiple right-hand-side types, Rust's type +/// checker has special handling for `_ << _`, setting the result type for +/// integer operations to the type of the left-hand-side operand. This means +/// that though `a << b` and `a.shl(b)` are one and the same from an evaluation +/// standpoint, they are different when it comes to type inference. /// /// # Examples /// @@ -417,7 +422,12 @@ macro_rules! shl_impl_all { shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } -/// The right shift operator `>>`. +/// The right shift operator `>>`. Note that because this trait is implemented +/// for all integer types with multiple right-hand-side types, Rust's type +/// checker has special handling for `_ >> _`, setting the result type for +/// integer operations to the type of the left-hand-side operand. This means +/// that though `a >> b` and `a.shr(b)` are one and the same from an evaluation +/// standpoint, they are different when it comes to type inference. /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 447299130a6a088af33152d2cef966c7ab3d7fdb Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 11 Apr 2018 00:04:32 +0200 Subject: Add to_bytes and from_bytes to primitive integers --- src/libcore/num/mod.rs | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) (limited to 'src/libcore') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index dcda404721c..b89fb81c6f7 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -15,6 +15,7 @@ use convert::TryFrom; use fmt; use intrinsics; +use mem; #[allow(deprecated)] use nonzero::NonZero; use ops; use str::FromStr; @@ -1619,6 +1620,50 @@ $EndFeature, " #[inline] pub fn is_negative(self) -> bool { self < 0 } } + + /// Return the memory representation of this integer as a byte array. + /// + /// The target platform’s native endianness is used. + /// Portable code likely wants to use this after [`to_be`] or [`to_le`]. + /// + /// [`to_be`]: #method.to_be + /// [`to_le`]: #method.to_le + /// + /// # Examples + /// + /// ``` + /// #![feature(int_to_from_bytes)] + /// + /// let bytes = i32::min_value().to_be().to_bytes(); + /// assert_eq!(bytes, [0x80, 0, 0, 0]); + /// ``` + #[unstable(feature = "int_to_from_bytes", issue = "49792")] + #[inline] + pub fn to_bytes(self) -> [u8; mem::size_of::()] { + unsafe { mem::transmute(self) } + } + + /// Create an integer value from its memory representation as a byte array. + /// + /// The target platform’s native endianness is used. + /// Portable code likely wants to use [`from_be`] or [`from_le`] after this. + /// + /// [`from_be`]: #method.from_be + /// [`from_le`]: #method.from_le + /// + /// # Examples + /// + /// ``` + /// #![feature(int_to_from_bytes)] + /// + /// let int = i32::from_be(i32::from_bytes([0x80, 0, 0, 0])); + /// assert_eq!(int, i32::min_value()); + /// ``` + #[unstable(feature = "int_to_from_bytes", issue = "49792")] + #[inline] + pub fn from_bytes(bytes: [u8; mem::size_of::()]) -> Self { + unsafe { mem::transmute(bytes) } + } } } @@ -2933,6 +2978,50 @@ $EndFeature, " self.one_less_than_next_power_of_two().checked_add(1) } } + + /// Return the memory representation of this integer as a byte array. + /// + /// The target platform’s native endianness is used. + /// Portable code likely wants to use this after [`to_be`] or [`to_le`]. + /// + /// [`to_be`]: #method.to_be + /// [`to_le`]: #method.to_le + /// + /// # Examples + /// + /// ``` + /// #![feature(int_to_from_bytes)] + /// + /// let bytes = 0x1234_5678_u32.to_be().to_bytes(); + /// assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]); + /// ``` + #[unstable(feature = "int_to_from_bytes", issue = "49792")] + #[inline] + pub fn to_bytes(self) -> [u8; mem::size_of::()] { + unsafe { mem::transmute(self) } + } + + /// Create an integer value from its memory representation as a byte array. + /// + /// The target platform’s native endianness is used. + /// Portable code likely wants to use [`to_be`] or [`to_le`] after this. + /// + /// [`to_be`]: #method.to_be + /// [`to_le`]: #method.to_le + /// + /// # Examples + /// + /// ``` + /// #![feature(int_to_from_bytes)] + /// + /// let int = u32::from_be(u32::from_bytes([0x12, 0x34, 0x56, 0x78])); + /// assert_eq!(int, 0x1234_5678_u32); + /// ``` + #[unstable(feature = "int_to_from_bytes", issue = "49792")] + #[inline] + pub fn from_bytes(bytes: [u8; mem::size_of::()]) -> Self { + unsafe { mem::transmute(bytes) } + } } } -- cgit 1.4.1-3-g733a5 From c68c90a2327ef9e54fcf2973fdec885411242365 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Sat, 14 Apr 2018 15:20:25 +0200 Subject: stabilize fetch_nand --- src/libcore/sync/atomic.rs | 23 +++++++++++------------ src/libcore/tests/lib.rs | 2 +- 2 files changed, 12 insertions(+), 13 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index d336934ec72..a29ae90d8e1 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -1360,8 +1360,7 @@ Returns the previous value. # Examples ``` -", $extra_feature, "#![feature(atomic_nand)] - +", $extra_feature, " use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; let foo = ", stringify!($atomic_type), "::new(0x13); @@ -1555,7 +1554,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "atomic_nand", issue = "13226"), + unstable(feature = "integer_atomics", issue = "32976"), "i8", "../../../std/primitive.i8.html", "#![feature(integer_atomics)]\n\n", atomic_min, atomic_max, @@ -1568,7 +1567,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "atomic_nand", issue = "13226"), + unstable(feature = "integer_atomics", issue = "32976"), "u8", "../../../std/primitive.u8.html", "#![feature(integer_atomics)]\n\n", atomic_umin, atomic_umax, @@ -1581,7 +1580,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "atomic_nand", issue = "13226"), + unstable(feature = "integer_atomics", issue = "32976"), "i16", "../../../std/primitive.i16.html", "#![feature(integer_atomics)]\n\n", atomic_min, atomic_max, @@ -1594,7 +1593,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "atomic_nand", issue = "13226"), + unstable(feature = "integer_atomics", issue = "32976"), "u16", "../../../std/primitive.u16.html", "#![feature(integer_atomics)]\n\n", atomic_umin, atomic_umax, @@ -1607,7 +1606,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "atomic_nand", issue = "13226"), + unstable(feature = "integer_atomics", issue = "32976"), "i32", "../../../std/primitive.i32.html", "#![feature(integer_atomics)]\n\n", atomic_min, atomic_max, @@ -1620,7 +1619,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "atomic_nand", issue = "13226"), + unstable(feature = "integer_atomics", issue = "32976"), "u32", "../../../std/primitive.u32.html", "#![feature(integer_atomics)]\n\n", atomic_umin, atomic_umax, @@ -1633,7 +1632,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "atomic_nand", issue = "13226"), + unstable(feature = "integer_atomics", issue = "32976"), "i64", "../../../std/primitive.i64.html", "#![feature(integer_atomics)]\n\n", atomic_min, atomic_max, @@ -1646,7 +1645,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "atomic_nand", issue = "13226"), + unstable(feature = "integer_atomics", issue = "32976"), "u64", "../../../std/primitive.u64.html", "#![feature(integer_atomics)]\n\n", atomic_umin, atomic_umax, @@ -1659,7 +1658,7 @@ atomic_int!{ stable(feature = "atomic_debug", since = "1.3.0"), stable(feature = "atomic_access", since = "1.15.0"), stable(feature = "atomic_from", since = "1.23.0"), - unstable(feature = "atomic_nand", issue = "13226"), + stable(feature = "atomic_nand", since = "1.27.0"), "isize", "../../../std/primitive.isize.html", "", atomic_min, atomic_max, @@ -1672,7 +1671,7 @@ atomic_int!{ stable(feature = "atomic_debug", since = "1.3.0"), stable(feature = "atomic_access", since = "1.15.0"), stable(feature = "atomic_from", since = "1.23.0"), - unstable(feature = "atomic_nand", issue = "13226"), + stable(feature = "atomic_nand", since = "1.27.0"), "usize", "../../../std/primitive.usize.html", "", atomic_umin, atomic_umax, diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 149269263dc..bb875c7219a 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -38,7 +38,7 @@ #![feature(trusted_len)] #![feature(try_trait)] #![feature(exact_chunks)] -#![feature(atomic_nand)] +#![cfg_attr(stage0, feature(atomic_nand))] #![feature(reverse_bits)] #![feature(inclusive_range_fields)] #![feature(iterator_find_map)] -- cgit 1.4.1-3-g733a5 From 7cbeddb7b78cc54a52d63ed8556da7121d1d2e68 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 14 Apr 2018 23:49:37 +0200 Subject: Deprecate Read::chars and char::decode_utf8 Per FCP: * https://github.com/rust-lang/rust/issues/27802#issuecomment-377537778 * https://github.com/rust-lang/rust/issues/33906#issuecomment-377534308 --- src/libcore/char/decode.rs | 11 +++++++++++ src/libcore/char/mod.rs | 3 +++ src/libcore/tests/char.rs | 1 + src/libstd/io/buffered.rs | 2 ++ src/libstd/io/cursor.rs | 2 ++ src/libstd/io/mod.rs | 14 +++++++++++++- 6 files changed, 32 insertions(+), 1 deletion(-) (limited to 'src/libcore') diff --git a/src/libcore/char/decode.rs b/src/libcore/char/decode.rs index 48b531104f8..45a73191db2 100644 --- a/src/libcore/char/decode.rs +++ b/src/libcore/char/decode.rs @@ -17,11 +17,17 @@ use super::from_u32_unchecked; /// An iterator over an iterator of bytes of the characters the bytes represent /// as UTF-8 #[unstable(feature = "decode_utf8", issue = "33906")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] #[derive(Clone, Debug)] +#[allow(deprecated)] pub struct DecodeUtf8>(::iter::Peekable); /// Decodes an `Iterator` of bytes as UTF-8. #[unstable(feature = "decode_utf8", issue = "33906")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] +#[allow(deprecated)] #[inline] pub fn decode_utf8>(i: I) -> DecodeUtf8 { DecodeUtf8(i.into_iter().peekable()) @@ -29,10 +35,14 @@ pub fn decode_utf8>(i: I) -> DecodeUtf8 /// `::next` returns this for an invalid input sequence. #[unstable(feature = "decode_utf8", issue = "33906")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] #[derive(PartialEq, Eq, Debug)] +#[allow(deprecated)] pub struct InvalidSequence(()); #[unstable(feature = "decode_utf8", issue = "33906")] +#[allow(deprecated)] impl> Iterator for DecodeUtf8 { type Item = Result; #[inline] @@ -127,6 +137,7 @@ impl> Iterator for DecodeUtf8 { } #[unstable(feature = "decode_utf8", issue = "33906")] +#[allow(deprecated)] impl> FusedIterator for DecodeUtf8 {} /// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s. diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index 9edc0c88756..bfe05af3c1c 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -51,6 +51,9 @@ pub use unicode::tables::UNICODE_VERSION; #[unstable(feature = "unicode_version", issue = "49726")] pub use unicode::version::UnicodeVersion; #[unstable(feature = "decode_utf8", issue = "33906")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] +#[allow(deprecated)] pub use self::decode::{decode_utf8, DecodeUtf8, InvalidSequence}; use fmt::{self, Write}; diff --git a/src/libcore/tests/char.rs b/src/libcore/tests/char.rs index 4e10ceac878..ab90763abf8 100644 --- a/src/libcore/tests/char.rs +++ b/src/libcore/tests/char.rs @@ -364,6 +364,7 @@ fn eu_iterator_specializations() { } #[test] +#[allow(deprecated)] fn test_decode_utf8() { macro_rules! assert_decode_utf8 { ($input_bytes: expr, $expected_str: expr) => { diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index d6eac748334..ee297d3783e 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -1251,6 +1251,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn read_char_buffered() { let buf = [195, 159]; let reader = BufReader::with_capacity(1, &buf[..]); @@ -1258,6 +1259,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn test_chars() { let buf = [195, 159, b'a']; let reader = BufReader::with_capacity(1, &buf[..]); diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 2673f3ccfa3..8ac52572810 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -566,6 +566,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn test_read_char() { let b = &b"Vi\xE1\xBB\x87t"[..]; let mut c = Cursor::new(b).chars(); @@ -577,6 +578,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn test_read_bad_char() { let b = &b"\x80"[..]; let mut c = Cursor::new(b).chars(); diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index b02e133ee4d..eba4e9fe703 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -840,6 +840,9 @@ pub trait Read { of where errors happen is currently \ unclear and may change", issue = "27802")] + #[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] + #[allow(deprecated)] fn chars(self) -> Chars where Self: Sized { Chars { inner: self } } @@ -2010,16 +2013,22 @@ impl Iterator for Bytes { /// [chars]: trait.Read.html#method.chars #[unstable(feature = "io", reason = "awaiting stability of Read::chars", issue = "27802")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] #[derive(Debug)] +#[allow(deprecated)] pub struct Chars { inner: R, } /// An enumeration of possible errors that can be generated from the `Chars` /// adapter. -#[derive(Debug)] #[unstable(feature = "io", reason = "awaiting stability of Read::chars", issue = "27802")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] +#[derive(Debug)] +#[allow(deprecated)] pub enum CharsError { /// Variant representing that the underlying stream was read successfully /// but it did not contain valid utf8 data. @@ -2031,6 +2040,7 @@ pub enum CharsError { #[unstable(feature = "io", reason = "awaiting stability of Read::chars", issue = "27802")] +#[allow(deprecated)] impl Iterator for Chars { type Item = result::Result; @@ -2063,6 +2073,7 @@ impl Iterator for Chars { #[unstable(feature = "io", reason = "awaiting stability of Read::chars", issue = "27802")] +#[allow(deprecated)] impl std_error::Error for CharsError { fn description(&self) -> &str { match *self { @@ -2080,6 +2091,7 @@ impl std_error::Error for CharsError { #[unstable(feature = "io", reason = "awaiting stability of Read::chars", issue = "27802")] +#[allow(deprecated)] impl fmt::Display for CharsError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { -- cgit 1.4.1-3-g733a5 From 5fe8c59f1219705ea54f842f9868ad0017643a33 Mon Sep 17 00:00:00 2001 From: kennytm Date: Thu, 12 Apr 2018 21:47:38 +0800 Subject: Stabilize core::hint::unreachable_unchecked. Closes #43751. --- src/libcore/hint.rs | 61 +++++++++++++++++++++++++++++++++++++++++++++++ src/libcore/intrinsics.rs | 3 +++ src/libcore/lib.rs | 1 + src/libcore/macros.rs | 8 +++---- src/libcore/mem.rs | 12 ---------- src/libstd/lib.rs | 2 ++ 6 files changed, 71 insertions(+), 16 deletions(-) create mode 100644 src/libcore/hint.rs (limited to 'src/libcore') diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs new file mode 100644 index 00000000000..f4e96e67b2c --- /dev/null +++ b/src/libcore/hint.rs @@ -0,0 +1,61 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "core_hint", since = "1.27.0")] + +//! Hints to compiler that affects how code should be emitted or optimized. + +use intrinsics; + +/// Informs the compiler that this point in the code is not reachable, enabling +/// further optimizations. +/// +/// # Safety +/// +/// Reaching this function is completely *undefined behavior* (UB). In +/// particular, the compiler assumes that all UB must never happen, and +/// therefore will eliminate all branches that reach to a call to +/// `unreachable_unchecked()`. +/// +/// Like all instances of UB, if this assumption turns out to be wrong, i.e. the +/// `unreachable_unchecked()` call is actually reachable among all possible +/// control flow, the compiler will apply the wrong optimization strategy, and +/// may sometimes even corrupt seemingly unrelated code, causing +/// difficult-to-debug problems. +/// +/// Use this function only when you can prove that the code will never call it. +/// +/// The [`unreachable!()`] macro is the safe counterpart of this function, which +/// will panic instead when executed. +/// +/// [`unreachable!()`]: ../macro.unreachable.html +/// +/// # Example +/// +/// ``` +/// fn div_1(a: u32, b: u32) -> u32 { +/// use std::hint::unreachable_unchecked; +/// +/// // `b.saturating_add(1)` is always positive (not zero), +/// // hence `checked_div` will never return None. +/// // Therefore, the else branch is unreachable. +/// a.checked_div(b.saturating_add(1)) +/// .unwrap_or_else(|| unsafe { unreachable_unchecked() }) +/// } +/// +/// assert_eq!(div_1(7, 0), 7); +/// assert_eq!(div_1(9, 1), 4); +/// assert_eq!(div_1(11, std::u32::MAX), 0); +/// ``` +#[inline] +#[stable(feature = "unreachable", since = "1.27.0")] +pub unsafe fn unreachable_unchecked() -> ! { + intrinsics::unreachable() +} diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 83274682250..fb0d2d9c882 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -638,6 +638,9 @@ extern "rust-intrinsic" { /// NB: This is very different from the `unreachable!()` macro: Unlike the /// macro, which panics when it is executed, it is *undefined behavior* to /// reach code marked with this function. + /// + /// The stabilized version of this intrinsic is + /// [`std::hint::unreachable_unchecked`](../../std/hint/fn.unreachable_unchecked.html). pub fn unreachable() -> !; /// Informs the optimizer that a condition is always true. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5ebd9e4334c..1968c11d062 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -149,6 +149,7 @@ pub mod intrinsics; pub mod mem; pub mod nonzero; pub mod ptr; +pub mod hint; /* Core language traits */ diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 90a9cb3379b..1e2551e36f5 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -420,13 +420,13 @@ macro_rules! writeln { /// * Iterators that dynamically terminate. /// /// If the determination that the code is unreachable proves incorrect, the -/// program immediately terminates with a [`panic!`]. The function [`unreachable`], -/// which belongs to the [`std::intrinsics`] module, informs the compilier to +/// program immediately terminates with a [`panic!`]. The function [`unreachable_unchecked`], +/// which belongs to the [`std::hint`] module, informs the compilier to /// optimize the code out of the release version entirely. /// /// [`panic!`]: ../std/macro.panic.html -/// [`unreachable`]: ../std/intrinsics/fn.unreachable.html -/// [`std::intrinsics`]: ../std/intrinsics/index.html +/// [`unreachable_unchecked`]: ../std/hint/fn.unreachable_unchecked.html +/// [`std::hint`]: ../std/hint/index.html /// /// # Panics /// diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index e3f08926610..10efab82ddf 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1094,18 +1094,6 @@ impl ::hash::Hash for ManuallyDrop { } } -/// Tells LLVM that this point in the code is not reachable, enabling further -/// optimizations. -/// -/// NB: This is very different from the `unreachable!()` macro: Unlike the -/// macro, which panics when it is executed, it is *undefined behavior* to -/// reach code marked with this function. -#[inline] -#[unstable(feature = "unreachable", issue = "43751")] -pub unsafe fn unreachable() -> ! { - intrinsics::unreachable() -} - /// A pinned reference. /// /// A pinned reference is a lot like a mutable reference, except that it is not diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a34fcb5a7f9..d92a4526549 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -457,6 +457,8 @@ pub use alloc_crate::vec; pub use core::char; #[stable(feature = "i128", since = "1.26.0")] pub use core::u128; +#[stable(feature = "core_hint", since = "1.27.0")] +pub use core::hint; pub mod f32; pub mod f64; -- cgit 1.4.1-3-g733a5 From 598d836fff59787892de1d736e521b10d9117531 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 3 Apr 2018 11:11:49 -0700 Subject: Stabilize x86/x86_64 SIMD This commit stabilizes the SIMD in Rust for the x86/x86_64 platforms. Notably this commit is stabilizing: * The `std::arch::{x86, x86_64}` modules and the intrinsics contained inside. * The `is_x86_feature_detected!` macro in the standard library * The `#[target_feature(enable = "...")]` attribute * The `#[cfg(target_feature = "...")]` matcher Stabilization of the module and intrinsics were primarily done in rust-lang-nursery/stdsimd#414 and the two attribute stabilizations are done in this commit. The standard library is also tweaked a bit with the new way that stdsimd is integrated. Note that other architectures like `std::arch::arm` are not stabilized as part of this commit, they will likely stabilize in the future after they've been implemented and fleshed out. Similarly the `std::simd` module is also not being stabilized in this commit, only `std::arch`. Finally, nothing related to `__m64` is stabilized in this commit either (MMX), only SSE and up types and intrinsics are stabilized. Closes #29717 Closes #44839 Closes #48556 --- .gitmodules | 2 +- src/libcore/lib.rs | 21 +++++++++++-- src/libstd/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 16 ++++------ src/stdsimd | 2 +- src/test/ui/feature-gate-cfg-target-feature.rs | 21 ------------- src/test/ui/feature-gate-cfg-target-feature.stderr | 35 ---------------------- src/test/ui/feature-gate-target_feature.rs | 13 -------- src/test/ui/feature-gate-target_feature.stderr | 11 ------- 9 files changed, 26 insertions(+), 97 deletions(-) delete mode 100644 src/test/ui/feature-gate-cfg-target-feature.rs delete mode 100644 src/test/ui/feature-gate-cfg-target-feature.stderr delete mode 100644 src/test/ui/feature-gate-target_feature.rs delete mode 100644 src/test/ui/feature-gate-target_feature.stderr (limited to 'src/libcore') diff --git a/.gitmodules b/.gitmodules index 55f586389b1..1d56c0c637a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -49,7 +49,7 @@ url = https://github.com/rust-lang/llvm [submodule "src/stdsimd"] path = src/stdsimd - url = https://github.com/rust-lang-nursery/stdsimd + url = https://github.com/alexcrichton/stdsimd [submodule "src/tools/lld"] path = src/tools/lld url = https://github.com/rust-lang/lld.git diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5ebd9e4334c..d6861922f86 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -68,7 +68,6 @@ #![feature(asm)] #![feature(associated_type_defaults)] #![feature(attr_literals)] -#![feature(cfg_target_feature)] #![feature(cfg_target_has_atomic)] #![feature(concat_idents)] #![feature(const_fn)] @@ -96,11 +95,13 @@ #![feature(specialization)] #![feature(staged_api)] #![feature(stmt_expr_attributes)] -#![feature(target_feature)] #![feature(unboxed_closures)] #![feature(untagged_unions)] #![feature(unwind_attributes)] +#![cfg_attr(stage0, feature(target_feature))] +#![cfg_attr(stage0, feature(cfg_target_feature))] + #[prelude_import] #[allow(unused)] use prelude::v1::*; @@ -204,6 +205,20 @@ mod unit; // things like SIMD and such. Note that the actual source for all this lies in a // different repository, rust-lang-nursery/stdsimd. That's why the setup here is // a bit wonky. +#[allow(unused_macros)] +macro_rules! test_v16 { ($item:item) => {}; } +#[allow(unused_macros)] +macro_rules! test_v32 { ($item:item) => {}; } +#[allow(unused_macros)] +macro_rules! test_v64 { ($item:item) => {}; } +#[allow(unused_macros)] +macro_rules! test_v128 { ($item:item) => {}; } +#[allow(unused_macros)] +macro_rules! test_v256 { ($item:item) => {}; } +#[allow(unused_macros)] +macro_rules! test_v512 { ($item:item) => {}; } +#[allow(unused_macros)] +macro_rules! vector_impl { ($([$f:ident, $($args:tt)*]),*) => { $($f!($($args)*);)* } } #[path = "../stdsimd/coresimd/mod.rs"] #[allow(missing_docs, missing_debug_implementations, dead_code)] #[unstable(feature = "stdsimd", issue = "48556")] @@ -213,6 +228,6 @@ mod coresimd; #[unstable(feature = "stdsimd", issue = "48556")] #[cfg(not(stage0))] pub use coresimd::simd; -#[unstable(feature = "stdsimd", issue = "48556")] +#[stable(feature = "simd_arch", since = "1.27.0")] #[cfg(not(stage0))] pub use coresimd::arch; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a34fcb5a7f9..01de49ef5df 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -525,7 +525,7 @@ mod coresimd { #[unstable(feature = "stdsimd", issue = "48556")] #[cfg(all(not(stage0), not(test)))] pub use stdsimd::simd; -#[unstable(feature = "stdsimd", issue = "48556")] +#[stable(feature = "simd_arch", since = "1.27.0")] #[cfg(all(not(stage0), not(test)))] pub use stdsimd::arch; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 73ebfc20876..ab3364a18ec 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -231,9 +231,6 @@ declare_features! ( // allow `repr(simd)`, and importing the various simd intrinsics (active, repr_simd, "1.4.0", Some(27731), None), - // Allows cfg(target_feature = "..."). - (active, cfg_target_feature, "1.4.0", Some(29717), None), - // allow `extern "platform-intrinsic" { ... }` (active, platform_intrinsics, "1.4.0", Some(27731), None), @@ -293,9 +290,6 @@ declare_features! ( (active, use_extern_macros, "1.15.0", Some(35896), None), - // Allows #[target_feature(...)] - (active, target_feature, "1.15.0", None, None), - // `extern "ptx-*" fn()` (active, abi_ptx, "1.15.0", None, None), @@ -574,6 +568,10 @@ declare_features! ( (accepted, underscore_lifetimes, "1.26.0", Some(44524), None), // Allows attributes on lifetime/type formal parameters in generics (RFC 1327) (accepted, generic_param_attrs, "1.26.0", Some(48848), None), + // Allows cfg(target_feature = "..."). + (accepted, cfg_target_feature, "1.27.0", Some(29717), None), + // Allows #[target_feature(...)] + (accepted, target_feature, "1.27.0", None, None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -918,10 +916,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "the `#[naked]` attribute \ is an experimental feature", cfg_fn!(naked_functions))), - ("target_feature", Whitelisted, Gated( - Stability::Unstable, "target_feature", - "the `#[target_feature]` attribute is an experimental feature", - cfg_fn!(target_feature))), + ("target_feature", Normal, Ungated), ("export_name", Whitelisted, Ungated), ("inline", Whitelisted, Ungated), ("link", Whitelisted, Ungated), @@ -1052,7 +1047,6 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG // cfg(...)'s that are feature gated const GATED_CFGS: &[(&str, &str, fn(&Features) -> bool)] = &[ // (name in cfg, feature, function to check if the feature is enabled) - ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)), ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)), ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)), ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)), diff --git a/src/stdsimd b/src/stdsimd index bcb720e5586..01ed2bb1dea 160000 --- a/src/stdsimd +++ b/src/stdsimd @@ -1 +1 @@ -Subproject commit bcb720e55861c38db47f2ebdf26b7198338cb39d +Subproject commit 01ed2bb1dea492324fbe21c3069cb8efacb14ec0 diff --git a/src/test/ui/feature-gate-cfg-target-feature.rs b/src/test/ui/feature-gate-cfg-target-feature.rs deleted file mode 100644 index 7832e1c7c51..00000000000 --- a/src/test/ui/feature-gate-cfg-target-feature.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[cfg(target_feature = "x")] //~ ERROR `cfg(target_feature)` is experimental -#[cfg_attr(target_feature = "x", x)] //~ ERROR `cfg(target_feature)` is experimental -struct Foo(u64, u64); - -#[cfg(not(any(all(target_feature = "x"))))] //~ ERROR `cfg(target_feature)` is experimental -fn foo() {} - -fn main() { - cfg!(target_feature = "x"); - //~^ ERROR `cfg(target_feature)` is experimental and subject to change -} diff --git a/src/test/ui/feature-gate-cfg-target-feature.stderr b/src/test/ui/feature-gate-cfg-target-feature.stderr deleted file mode 100644 index bf9e596e71a..00000000000 --- a/src/test/ui/feature-gate-cfg-target-feature.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error[E0658]: `cfg(target_feature)` is experimental and subject to change (see issue #29717) - --> $DIR/feature-gate-cfg-target-feature.rs:12:12 - | -LL | #[cfg_attr(target_feature = "x", x)] //~ ERROR `cfg(target_feature)` is experimental - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(cfg_target_feature)] to the crate attributes to enable - -error[E0658]: `cfg(target_feature)` is experimental and subject to change (see issue #29717) - --> $DIR/feature-gate-cfg-target-feature.rs:11:7 - | -LL | #[cfg(target_feature = "x")] //~ ERROR `cfg(target_feature)` is experimental - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(cfg_target_feature)] to the crate attributes to enable - -error[E0658]: `cfg(target_feature)` is experimental and subject to change (see issue #29717) - --> $DIR/feature-gate-cfg-target-feature.rs:15:19 - | -LL | #[cfg(not(any(all(target_feature = "x"))))] //~ ERROR `cfg(target_feature)` is experimental - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(cfg_target_feature)] to the crate attributes to enable - -error[E0658]: `cfg(target_feature)` is experimental and subject to change (see issue #29717) - --> $DIR/feature-gate-cfg-target-feature.rs:19:10 - | -LL | cfg!(target_feature = "x"); - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(cfg_target_feature)] to the crate attributes to enable - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate-target_feature.rs b/src/test/ui/feature-gate-target_feature.rs deleted file mode 100644 index da2e41a0f5e..00000000000 --- a/src/test/ui/feature-gate-target_feature.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[target_feature = "+sse2"] -//~^ the `#[target_feature]` attribute is an experimental feature -fn foo() {} diff --git a/src/test/ui/feature-gate-target_feature.stderr b/src/test/ui/feature-gate-target_feature.stderr deleted file mode 100644 index 0f31abf7b42..00000000000 --- a/src/test/ui/feature-gate-target_feature.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: the `#[target_feature]` attribute is an experimental feature - --> $DIR/feature-gate-target_feature.rs:11:1 - | -LL | #[target_feature = "+sse2"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(target_feature)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. -- cgit 1.4.1-3-g733a5 From 1217d70465edb2079880347fea4baaac56895f51 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 5 Apr 2018 08:02:11 -0700 Subject: Separately gate each target_feature feature Use an explicit whitelist for what features are actually stable and can be enabled. --- .gitmodules | 2 +- src/libcore/lib.rs | 8 ++ src/librustc/ty/maps/mod.rs | 2 +- src/librustc_trans/attributes.rs | 4 +- src/librustc_trans/llvm_util.rs | 123 +++++++++++++++++++------ src/librustc_trans_utils/trans_crate.rs | 4 +- src/librustc_typeck/collect.rs | 87 ++++++++++------- src/libsyntax/feature_gate.rs | 11 +++ src/stdsimd | 2 +- src/test/run-pass/simd-target-feature-mixup.rs | 1 + src/test/ui/target-feature-gate.rs | 31 +++++++ src/test/ui/target-feature-gate.stderr | 11 +++ src/test/ui/target-feature-wrong.rs | 2 +- src/test/ui/target-feature-wrong.stderr | 4 +- 14 files changed, 220 insertions(+), 72 deletions(-) create mode 100644 src/test/ui/target-feature-gate.rs create mode 100644 src/test/ui/target-feature-gate.stderr (limited to 'src/libcore') diff --git a/.gitmodules b/.gitmodules index 1d56c0c637a..55f586389b1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -49,7 +49,7 @@ url = https://github.com/rust-lang/llvm [submodule "src/stdsimd"] path = src/stdsimd - url = https://github.com/alexcrichton/stdsimd + url = https://github.com/rust-lang-nursery/stdsimd [submodule "src/tools/lld"] path = src/tools/lld url = https://github.com/rust-lang/lld.git diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index d6861922f86..ea7a46f44ae 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -99,6 +99,14 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] +#![cfg_attr(not(stage0), feature(mmx_target_feature))] +#![cfg_attr(not(stage0), feature(tbm_target_feature))] +#![cfg_attr(not(stage0), feature(sse4a_target_feature))] +#![cfg_attr(not(stage0), feature(arm_target_feature))] +#![cfg_attr(not(stage0), feature(powerpc_target_feature))] +#![cfg_attr(not(stage0), feature(mips_target_feature))] +#![cfg_attr(not(stage0), feature(aarch64_target_feature))] + #![cfg_attr(stage0, feature(target_feature))] #![cfg_attr(stage0, feature(cfg_target_feature))] diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index d317f5a494b..2325b1893d9 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -437,7 +437,7 @@ define_maps! { <'tcx> substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool, [] fn target_features_whitelist: - target_features_whitelist_node(CrateNum) -> Lrc>, + target_features_whitelist_node(CrateNum) -> Lrc>>, // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. [] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>) diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index c968b8525a5..eb5c7396ae0 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -174,12 +174,12 @@ pub fn provide(providers: &mut Providers) { // rustdoc needs to be able to document functions that use all the features, so // whitelist them all Lrc::new(llvm_util::all_known_features() - .map(|c| c.to_string()) + .map(|(a, b)| (a.to_string(), b.map(|s| s.to_string()))) .collect()) } else { Lrc::new(llvm_util::target_feature_whitelist(tcx.sess) .iter() - .map(|c| c.to_string()) + .map(|&(a, b)| (a.to_string(), b.map(|s| s.to_string()))) .collect()) } }; diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index fa3ecb1cc11..bbd1c39a19e 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -15,6 +15,7 @@ use rustc::session::Session; use rustc::session::config::PrintRequest; use libc::c_int; use std::ffi::CString; +use syntax::feature_gate::UnstableFeatures; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Once; @@ -82,40 +83,95 @@ unsafe fn configure_llvm(sess: &Session) { // to LLVM or the feature detection code will walk past the end of the feature // array, leading to crashes. -const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"]; - -const AARCH64_WHITELIST: &'static [&'static str] = &["fp", "neon", "sve", "crc", "crypto", - "ras", "lse", "rdm", "fp16", "rcpc", - "dotprod", "v8.1a", "v8.2a", "v8.3a"]; - -const X86_WHITELIST: &'static [&'static str] = &["aes", "avx", "avx2", "avx512bw", - "avx512cd", "avx512dq", "avx512er", - "avx512f", "avx512ifma", "avx512pf", - "avx512vbmi", "avx512vl", "avx512vpopcntdq", - "bmi1", "bmi2", "fma", "fxsr", - "lzcnt", "mmx", "pclmulqdq", - "popcnt", "rdrand", "rdseed", - "sha", - "sse", "sse2", "sse3", "sse4.1", - "sse4.2", "sse4a", "ssse3", - "tbm", "xsave", "xsavec", - "xsaveopt", "xsaves"]; - -const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"]; - -const POWERPC_WHITELIST: &'static [&'static str] = &["altivec", - "power8-altivec", "power9-altivec", - "power8-vector", "power9-vector", - "vsx"]; - -const MIPS_WHITELIST: &'static [&'static str] = &["fp64", "msa"]; +const ARM_WHITELIST: &[(&str, Option<&str>)] = &[ + ("neon", Some("arm_target_feature")), + ("v7", Some("arm_target_feature")), + ("vfp2", Some("arm_target_feature")), + ("vfp3", Some("arm_target_feature")), + ("vfp4", Some("arm_target_feature")), +]; + +const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[ + ("fp", Some("aarch64_target_feature")), + ("neon", Some("aarch64_target_feature")), + ("sve", Some("aarch64_target_feature")), + ("crc", Some("aarch64_target_feature")), + ("crypto", Some("aarch64_target_feature")), + ("ras", Some("aarch64_target_feature")), + ("lse", Some("aarch64_target_feature")), + ("rdm", Some("aarch64_target_feature")), + ("fp16", Some("aarch64_target_feature")), + ("rcpc", Some("aarch64_target_feature")), + ("dotprod", Some("aarch64_target_feature")), + ("v8.1a", Some("aarch64_target_feature")), + ("v8.2a", Some("aarch64_target_feature")), + ("v8.3a", Some("aarch64_target_feature")), +]; + +const X86_WHITELIST: &[(&str, Option<&str>)] = &[ + ("aes", None), + ("avx", None), + ("avx2", None), + ("avx512bw", Some("avx512_target_feature")), + ("avx512cd", Some("avx512_target_feature")), + ("avx512dq", Some("avx512_target_feature")), + ("avx512er", Some("avx512_target_feature")), + ("avx512f", Some("avx512_target_feature")), + ("avx512ifma", Some("avx512_target_feature")), + ("avx512pf", Some("avx512_target_feature")), + ("avx512vbmi", Some("avx512_target_feature")), + ("avx512vl", Some("avx512_target_feature")), + ("avx512vpopcntdq", Some("avx512_target_feature")), + ("bmi1", None), + ("bmi2", None), + ("fma", None), + ("fxsr", None), + ("lzcnt", None), + ("mmx", Some("mmx_target_feature")), + ("pclmulqdq", None), + ("popcnt", None), + ("rdrand", None), + ("rdseed", None), + ("sha", None), + ("sse", None), + ("sse2", None), + ("sse3", None), + ("sse4.1", None), + ("sse4.2", None), + ("sse4a", Some("sse4a_target_feature")), + ("ssse3", None), + ("tbm", Some("tbm_target_feature")), + ("xsave", None), + ("xsavec", None), + ("xsaveopt", None), + ("xsaves", None), +]; + +const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[ + ("hvx", Some("hexagon_target_feature")), + ("hvx-double", Some("hexagon_target_feature")), +]; + +const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[ + ("altivec", Some("powerpc_target_feature")), + ("power8-altivec", Some("powerpc_target_feature")), + ("power9-altivec", Some("powerpc_target_feature")), + ("power8-vector", Some("powerpc_target_feature")), + ("power9-vector", Some("powerpc_target_feature")), + ("vsx", Some("powerpc_target_feature")), +]; + +const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[ + ("fp64", Some("mips_target_feature")), + ("msa", Some("mips_target_feature")), +]; /// When rustdoc is running, provide a list of all known features so that all their respective /// primtives may be documented. /// /// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this /// iterator! -pub fn all_known_features() -> impl Iterator { +pub fn all_known_features() -> impl Iterator)> { ARM_WHITELIST.iter().cloned() .chain(AARCH64_WHITELIST.iter().cloned()) .chain(X86_WHITELIST.iter().cloned()) @@ -144,6 +200,13 @@ pub fn target_features(sess: &Session) -> Vec { let target_machine = create_target_machine(sess, true); target_feature_whitelist(sess) .iter() + .filter_map(|&(feature, gate)| { + if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() { + Some(feature) + } else { + None + } + }) .filter(|feature| { let llvm_feature = to_llvm_feature(sess, feature); let cstr = CString::new(llvm_feature).unwrap(); @@ -152,7 +215,9 @@ pub fn target_features(sess: &Session) -> Vec { .map(|feature| Symbol::intern(feature)).collect() } -pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] { +pub fn target_feature_whitelist(sess: &Session) + -> &'static [(&'static str, Option<&'static str>)] +{ match &*sess.target.target.arch { "arm" => ARM_WHITELIST, "aarch64" => AARCH64_WHITELIST, diff --git a/src/librustc_trans_utils/trans_crate.rs b/src/librustc_trans_utils/trans_crate.rs index 5cf9819288b..b7895631c60 100644 --- a/src/librustc_trans_utils/trans_crate.rs +++ b/src/librustc_trans_utils/trans_crate.rs @@ -44,7 +44,7 @@ use rustc::middle::cstore::EncodedMetadata; use rustc::middle::cstore::MetadataLoader; use rustc::dep_graph::DepGraph; use rustc_back::target::Target; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxHashMap; use rustc_mir::monomorphize::collector; use link::{build_link_meta, out_filename}; @@ -203,7 +203,7 @@ impl TransCrate for MetadataOnlyTransCrate { ::symbol_names::provide(providers); providers.target_features_whitelist = |_tcx, _cnum| { - Lrc::new(FxHashSet()) // Just a dummy + Lrc::new(FxHashMap()) // Just a dummy }; } fn provide_extern(&self, _providers: &mut Providers) {} diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index f386e1d8b82..d9e5ac7f7c5 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -37,13 +37,14 @@ use rustc::ty::maps::Providers; use rustc::ty::util::IntTypeExt; use rustc::ty::util::Discr; use rustc::util::captures::Captures; -use rustc::util::nodemap::{FxHashSet, FxHashMap}; +use rustc::util::nodemap::FxHashMap; use syntax::{abi, ast}; use syntax::ast::MetaItemKind; use syntax::attr::{InlineAttr, list_contains_name, mark_used}; use syntax::codemap::Spanned; use syntax::symbol::{Symbol, keywords}; +use syntax::feature_gate; use syntax_pos::{Span, DUMMY_SP}; use rustc::hir::{self, map as hir_map, TransFnAttrs, TransFnAttrFlags, Unsafety}; @@ -1682,7 +1683,7 @@ fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn from_target_feature( tcx: TyCtxt, attr: &ast::Attribute, - whitelist: &FxHashSet, + whitelist: &FxHashMap>, target_features: &mut Vec, ) { let list = match attr.meta_item_list() { @@ -1694,16 +1695,19 @@ fn from_target_feature( return } }; - + let rust_features = tcx.features(); for item in list { + // Only `enable = ...` is accepted in the meta item list if !item.check_name("enable") { let msg = "#[target_feature(..)] only accepts sub-keys of `enable` \ currently"; tcx.sess.span_err(item.span, &msg); continue } + + // Must be of the form `enable = "..."` ( a string) let value = match item.value_str() { - Some(list) => list, + Some(value) => value, None => { let msg = "#[target_feature] attribute must be of the form \ #[target_feature(enable = \"..\")]"; @@ -1711,24 +1715,55 @@ fn from_target_feature( continue } }; - let value = value.as_str(); - for feature in value.split(',') { - if whitelist.contains(feature) { - target_features.push(Symbol::intern(feature)); - continue - } - - let msg = format!("the feature named `{}` is not valid for \ - this target", feature); - let mut err = tcx.sess.struct_span_err(item.span, &msg); - if feature.starts_with("+") { - let valid = whitelist.contains(&feature[1..]); - if valid { - err.help("consider removing the leading `+` in the feature name"); + // We allow comma separation to enable multiple features + for feature in value.as_str().split(',') { + + // Only allow whitelisted features per platform + let feature_gate = match whitelist.get(feature) { + Some(g) => g, + None => { + let msg = format!("the feature named `{}` is not valid for \ + this target", feature); + let mut err = tcx.sess.struct_span_err(item.span, &msg); + + if feature.starts_with("+") { + let valid = whitelist.contains_key(&feature[1..]); + if valid { + err.help("consider removing the leading `+` in the feature name"); + } + } + err.emit(); + continue } + }; + + // Only allow features whose feature gates have been enabled + let allowed = match feature_gate.as_ref().map(|s| &**s) { + Some("arm_target_feature") => rust_features.arm_target_feature, + Some("aarch64_target_feature") => rust_features.aarch64_target_feature, + Some("hexagon_target_feature") => rust_features.hexagon_target_feature, + Some("powerpc_target_feature") => rust_features.powerpc_target_feature, + Some("mips_target_feature") => rust_features.mips_target_feature, + Some("avx512_target_feature") => rust_features.avx512_target_feature, + Some("mmx_target_feature") => rust_features.mmx_target_feature, + Some("sse4a_target_feature") => rust_features.sse4a_target_feature, + Some("tbm_target_feature") => rust_features.tbm_target_feature, + Some(name) => bug!("unknown target feature gate {}", name), + None => true, + }; + if !allowed { + feature_gate::emit_feature_err( + &tcx.sess.parse_sess, + feature_gate.as_ref().unwrap(), + item.span, + feature_gate::GateIssue::Language, + &format!("the target feature `{}` is currently unstable", + feature), + ); + continue } - err.emit(); + target_features.push(Symbol::intern(feature)); } } } @@ -1835,20 +1870,6 @@ fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAt .emit(); } } else if attr.check_name("target_feature") { - // handle deprecated #[target_feature = "..."] - if let Some(val) = attr.value_str() { - for feat in val.as_str().split(",").map(|f| f.trim()) { - if !feat.is_empty() && !feat.contains('\0') { - trans_fn_attrs.target_features.push(Symbol::intern(feat)); - } - } - let msg = "#[target_feature = \"..\"] is deprecated and will \ - eventually be removed, use \ - #[target_feature(enable = \"..\")] instead"; - tcx.sess.span_warn(attr.span, &msg); - continue - } - if tcx.fn_sig(id).unsafety() == Unsafety::Normal { let msg = "#[target_feature(..)] can only be applied to \ `unsafe` function"; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ab3364a18ec..4a259366af3 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -446,6 +446,17 @@ declare_features! ( // Allows macro invocations in `extern {}` blocks (active, macros_in_extern, "1.27.0", Some(49476), None), + + // unstable #[target_feature] directives + (active, arm_target_feature, "1.27.0", None, None), + (active, aarch64_target_feature, "1.27.0", None, None), + (active, hexagon_target_feature, "1.27.0", None, None), + (active, powerpc_target_feature, "1.27.0", None, None), + (active, mips_target_feature, "1.27.0", None, None), + (active, avx512_target_feature, "1.27.0", None, None), + (active, mmx_target_feature, "1.27.0", None, None), + (active, sse4a_target_feature, "1.27.0", None, None), + (active, tbm_target_feature, "1.27.0", None, None), ); declare_features! ( diff --git a/src/stdsimd b/src/stdsimd index 01ed2bb1dea..effdcd0132d 160000 --- a/src/stdsimd +++ b/src/stdsimd @@ -1 +1 @@ -Subproject commit 01ed2bb1dea492324fbe21c3069cb8efacb14ec0 +Subproject commit effdcd0132d17b6c4badc67b4b6d3fdf749a2d22 diff --git a/src/test/run-pass/simd-target-feature-mixup.rs b/src/test/run-pass/simd-target-feature-mixup.rs index 3c54921ac6e..139da046452 100644 --- a/src/test/run-pass/simd-target-feature-mixup.rs +++ b/src/test/run-pass/simd-target-feature-mixup.rs @@ -11,6 +11,7 @@ // ignore-emscripten #![feature(repr_simd, target_feature, cfg_target_feature)] +#![feature(avx512_target_feature)] use std::process::{Command, ExitStatus}; use std::env; diff --git a/src/test/ui/target-feature-gate.rs b/src/test/ui/target-feature-gate.rs new file mode 100644 index 00000000000..69208f15136 --- /dev/null +++ b/src/test/ui/target-feature-gate.rs @@ -0,0 +1,31 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-arm +// ignore-aarch64 +// ignore-wasm +// ignore-emscripten +// gate-test-sse4a_target_feature +// gate-test-powerpc_target_feature +// gate-test-avx512_target_feature +// gate-test-tbm_target_feature +// gate-test-arm_target_feature +// gate-test-aarch64_target_feature +// gate-test-hexagon_target_feature +// gate-test-mips_target_feature +// gate-test-mmx_target_feature +// min-llvm-version 6.0 + +#[target_feature(enable = "avx512bw")] +//~^ ERROR: currently unstable +unsafe fn foo() { +} + +fn main() {} diff --git a/src/test/ui/target-feature-gate.stderr b/src/test/ui/target-feature-gate.stderr new file mode 100644 index 00000000000..dc5e174984b --- /dev/null +++ b/src/test/ui/target-feature-gate.stderr @@ -0,0 +1,11 @@ +error[E0658]: the target feature `avx512bw` is currently unstable + --> $DIR/target-feature-gate.rs:26:18 + | +LL | #[target_feature(enable = "avx512bw")] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(avx512_target_feature)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/target-feature-wrong.rs b/src/test/ui/target-feature-wrong.rs index eb83ee724c7..0edd51ba779 100644 --- a/src/test/ui/target-feature-wrong.rs +++ b/src/test/ui/target-feature-wrong.rs @@ -19,7 +19,7 @@ #![feature(target_feature)] #[target_feature = "+sse2"] -//~^ WARN: deprecated +//~^ ERROR: must be of the form #[target_feature(enable = "foo")] //~^ ERROR: not valid for this target #[target_feature(bar)] diff --git a/src/test/ui/target-feature-wrong.stderr b/src/test/ui/target-feature-wrong.stderr index b5e650eaf9a..ed86687bb2f 100644 --- a/src/test/ui/target-feature-wrong.stderr +++ b/src/test/ui/target-feature-wrong.stderr @@ -1,4 +1,4 @@ -warning: #[target_feature = ".."] is deprecated and will eventually be removed, use #[target_feature(enable = "..")] instead +error: #[target_feature] attribute must be of the form #[target_feature(..)] --> $DIR/target-feature-wrong.rs:21:1 | LL | #[target_feature = "+sse2"] @@ -43,5 +43,5 @@ error: cannot use #[inline(always)] with #[target_feature] LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors -- cgit 1.4.1-3-g733a5 From 05275dafaaa602fe4a5d275ef724ced39d30465f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 15 Apr 2018 16:17:18 +0200 Subject: Remove unwanted auto-linking and update --- src/libcore/iter/iterator.rs | 2 +- src/libcore/str/pattern.rs | 2 +- src/librustc/ty/sty.rs | 2 +- src/libstd/ffi/os_str.rs | 5 +++-- src/libstd/macros.rs | 4 ++-- src/libsyntax_pos/hygiene.rs | 4 ++-- src/libunwind/macros.rs | 4 ++-- src/test/run-pass/issue-16819.rs | 2 +- src/test/rustdoc-ui/intra-links-warning.rs | 2 +- 9 files changed, 14 insertions(+), 13 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 4ccf446aa63..6a77de2c986 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -998,7 +998,7 @@ pub trait Iterator { /// an extra layer of indirection. `flat_map()` will remove this extra layer /// on its own. /// - /// You can think of [`flat_map(f)`][flat_map] as the semantic equivalent + /// You can think of `flat_map(f)` as the semantic equivalent /// of [`map`]ping, and then [`flatten`]ing as in `map(f).flatten()`. /// /// Another way of thinking about `flat_map()`: [`map`]'s closure returns diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 95bb8f18947..464d57a2702 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -258,7 +258,7 @@ pub struct CharSearcher<'a> { /// `finger` is the current byte index of the forward search. /// Imagine that it exists before the byte at its index, i.e. - /// haystack[finger] is the first byte of the slice we must inspect during + /// `haystack[finger]` is the first byte of the slice we must inspect during /// forward searching finger: usize, /// `finger_back` is the current byte index of the reverse search. diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index d68393956ef..310fcbcfcb3 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1550,7 +1550,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - /// Returns the type of ty[i] + /// Returns the type of `ty[i]`. pub fn builtin_index(&self) -> Option> { match self.sty { TyArray(ty, _) | TySlice(ty) => Some(ty), diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 7520121a8c2..4850ed0c5be 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -61,7 +61,7 @@ use sys_common::{AsInner, IntoInner, FromInner}; /// # Conversions /// /// See the [module's toplevel documentation about conversions][conversions] for a discussion on -/// the traits which `OsString` implements for conversions from/to native representations. +/// the traits which `OsString` implements for [conversions] from/to native representations. /// /// [`OsStr`]: struct.OsStr.html /// [`&OsStr`]: struct.OsStr.html @@ -74,6 +74,7 @@ use sys_common::{AsInner, IntoInner, FromInner}; /// [`new`]: #method.new /// [`push`]: #method.push /// [`as_os_str`]: #method.as_os_str +/// [conversions]: index.html#conversions #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { @@ -89,7 +90,7 @@ pub struct OsString { /// references; the latter are owned strings. /// /// See the [module's toplevel documentation about conversions][conversions] for a discussion on -/// the traits which `OsStr` implements for conversions from/to native representations. +/// the traits which `OsStr` implements for [conversions] from/to native representations. /// /// [`OsString`]: struct.OsString.html /// [`&str`]: ../primitive.str.html diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 5ef7c159655..6902ec82047 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -787,13 +787,13 @@ pub mod builtin { } } -/// A macro for defining #[cfg] if-else statements. +/// A macro for defining `#[cfg]` if-else statements. /// /// This is similar to the `if/elif` C preprocessor macro by allowing definition /// of a cascade of `#[cfg]` cases, emitting the implementation which matches /// first. /// -/// This allows you to conveniently provide a long list #[cfg]'d blocks of code +/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code /// without having to rewrite each clause multiple times. macro_rules! cfg_if { ($( diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 8cb5776fdeb..5e96b5ce673 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Machinery for hygienic macros, inspired by the MTWT[1] paper. +//! Machinery for hygienic macros, inspired by the `MTWT[1]` paper. //! -//! [1] Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler. 2012. +//! `[1]` Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler. 2012. //! *Macros that work together: Compile-time bindings, partial expansion, //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216. //! DOI=10.1017/S0956796812000093 diff --git a/src/libunwind/macros.rs b/src/libunwind/macros.rs index 26376a3733f..a962d5fc415 100644 --- a/src/libunwind/macros.rs +++ b/src/libunwind/macros.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/// A macro for defining #[cfg] if-else statements. +/// A macro for defining `#[cfg]` if-else statements. /// /// This is similar to the `if/elif` C preprocessor macro by allowing definition /// of a cascade of `#[cfg]` cases, emitting the implementation which matches /// first. /// -/// This allows you to conveniently provide a long list #[cfg]'d blocks of code +/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code /// without having to rewrite each clause multiple times. macro_rules! cfg_if { ($( diff --git a/src/test/run-pass/issue-16819.rs b/src/test/run-pass/issue-16819.rs index fb35ce33157..ecd8a3390b7 100644 --- a/src/test/run-pass/issue-16819.rs +++ b/src/test/run-pass/issue-16819.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//`#[cfg]` on struct field permits empty unusable struct +// `#[cfg]` on struct field permits empty unusable struct struct S { #[cfg(untrue)] diff --git a/src/test/rustdoc-ui/intra-links-warning.rs b/src/test/rustdoc-ui/intra-links-warning.rs index 9a3709b0dd8..2a00d31e3d7 100644 --- a/src/test/rustdoc-ui/intra-links-warning.rs +++ b/src/test/rustdoc-ui/intra-links-warning.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// must-compile-successfully +// compile-pass //! Test with [Foo::baz], [Bar::foo], [Uniooon::X] -- cgit 1.4.1-3-g733a5 From edc412c5a9ce825d589dcb87dd6028b072139b51 Mon Sep 17 00:00:00 2001 From: tinaun Date: Tue, 17 Apr 2018 00:30:06 -0400 Subject: stabilize `slice_rsplit` feature --- .../src/library-features/slice-rsplit.md | 10 -------- src/liballoc/lib.rs | 1 - src/liballoc/slice.rs | 11 +++------ src/libcore/slice/mod.rs | 28 +++++++++++----------- 4 files changed, 17 insertions(+), 33 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/slice-rsplit.md (limited to 'src/libcore') diff --git a/src/doc/unstable-book/src/library-features/slice-rsplit.md b/src/doc/unstable-book/src/library-features/slice-rsplit.md deleted file mode 100644 index 8c2954f7294..00000000000 --- a/src/doc/unstable-book/src/library-features/slice-rsplit.md +++ /dev/null @@ -1,10 +0,0 @@ -# `slice_rsplit` - -The tracking issue for this feature is: [#41020] - -[#41020]: https://github.com/rust-lang/rust/issues/41020 - ------------------------- - -The `slice_rsplit` feature enables two methods on slices: -`slice.rsplit(predicate)` and `slice.rsplit_mut(predicate)`. diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 3a106a2ff5c..87ad2751c5b 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -108,7 +108,6 @@ #![feature(ptr_offset_from)] #![feature(rustc_attrs)] #![feature(slice_get_slice)] -#![feature(slice_rsplit)] #![feature(specialization)] #![feature(staged_api)] #![feature(str_internals)] diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 56c53fca62c..eb8a293013d 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -116,7 +116,7 @@ pub use core::slice::{Iter, IterMut}; pub use core::slice::{SplitMut, ChunksMut, Split}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut}; -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] pub use core::slice::{RSplit, RSplitMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{from_raw_parts, from_raw_parts_mut}; @@ -888,7 +888,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_rsplit)] /// /// let slice = [11, 22, 33, 0, 44, 55]; /// let mut iter = slice.rsplit(|num| *num == 0); @@ -902,8 +901,6 @@ impl [T] { /// slice will be the first (or last) item returned by the iterator. /// /// ``` - /// #![feature(slice_rsplit)] - /// /// let v = &[0, 1, 1, 2, 3, 5, 8]; /// let mut it = v.rsplit(|n| *n % 2 == 0); /// assert_eq!(it.next().unwrap(), &[]); @@ -912,7 +909,7 @@ impl [T] { /// assert_eq!(it.next().unwrap(), &[]); /// assert_eq!(it.next(), None); /// ``` - #[unstable(feature = "slice_rsplit", issue = "41020")] + #[stable(feature = "slice_rsplit", since = "1.27.0")] #[inline] pub fn rsplit(&self, pred: F) -> RSplit where F: FnMut(&T) -> bool @@ -927,8 +924,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_rsplit)] - /// /// let mut v = [100, 400, 300, 200, 600, 500]; /// /// let mut count = 0; @@ -939,7 +934,7 @@ impl [T] { /// assert_eq!(v, [3, 400, 300, 2, 600, 1]); /// ``` /// - #[unstable(feature = "slice_rsplit", issue = "41020")] + #[stable(feature = "slice_rsplit", since = "1.27.0")] #[inline] pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut where F: FnMut(&T) -> bool diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 0a22028da81..68f081c2e87 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -86,7 +86,7 @@ pub trait SliceExt { fn split